Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Cache rendered math SVG for perfomance

AuthorDaveJarvis <email>
Date2020-09-12 14:31:37 GMT-0700
Commita8a443f766a4533a6b65c659f5a81d7045498538
Parent20bb20d
Delta41 lines added, 28 lines removed, 13-line increase
src/main/java/com/scrivenvar/graphics/SvgRasterizer.java
import java.net.URL;
import java.text.NumberFormat;
-import java.text.ParseException;
import static com.scrivenvar.graphics.RenderingSettings.RENDERING_HINTS;
*/
public class SvgRasterizer {
- private static final Notifier NOTIFIER = Services.load( Notifier.class );
+ private static final Notifier sNotifier = Services.load( Notifier.class );
private static final SAXSVGDocumentFactory FACTORY_DOM =
return rasterize( new URL( url ), width );
} catch( final Exception e ) {
- NOTIFIER.notify( e );
+ notify( e );
return BROKEN_IMAGE_PLACEHOLDER;
}
* @param xml The SVG xml document.
* @return The vector graphic transcoded into a raster image format.
- * @throws TranscoderException Could not convert the vector graphic to an
- * instance of {@link Image}.
*/
- public static BufferedImage rasterizeString( final String xml )
- throws IOException, TranscoderException, ParseException {
- final var doc = toDocument( xml );
- final var root = doc.getDocumentElement();
- final var width = root.getAttribute( "width" );
- return rasterizeString( xml, INT_FORMAT.parse( width ).intValue() );
+ public static BufferedImage rasterizeString( final String xml ) {
+ try {
+ final var doc = toDocument( xml );
+ final var root = doc.getDocumentElement();
+ final var width = root.getAttribute( "width" );
+ return rasterizeString( xml, INT_FORMAT.parse( width ).intValue() );
+ } catch( final Exception e ) {
+ notify( e );
+ return BROKEN_IMAGE_PLACEHOLDER;
+ }
}
private static Document toDocument( final String xml ) throws IOException {
try( final var reader = new StringReader( xml ) ) {
- return FACTORY_DOM.createSVGDocument( "http://www.w3.org/2000/svg",
- reader );
+ return FACTORY_DOM.createSVGDocument(
+ "http://www.w3.org/2000/svg", reader );
}
}
public static BufferedImage rasterize( final Document svg, final int width )
throws TranscoderException {
final var transcoder = new BufferedImageTranscoder();
final var input = new TranscoderInput( svg );
- //transcoder.addTranscodingHint( KEY_BACKGROUND_COLOR, WHITE );
transcoder.addTranscodingHint( KEY_WIDTH, (float) width );
transcoder.transcode( input, null );
return writer.toString().replaceAll( "xmlns=\"\" ", "" );
}
+ }
+
+ private static void notify( final Exception e ) {
+ sNotifier.notify( e );
}
}
src/main/java/com/scrivenvar/graphics/SvgReplacedElementFactory.java
import org.xhtmlrenderer.swing.ImageReplacedElement;
-import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
-import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.function.Function;
-import static com.scrivenvar.graphics.SvgRasterizer.*;
+import static com.scrivenvar.graphics.SvgRasterizer.rasterize;
+import static com.scrivenvar.graphics.SvgRasterizer.toSvg;
/**
if( SVG_FILE.equalsIgnoreCase( ext ) ) {
try {
- image = getImage( src, box.getContentWidth() );
+ image = getCachedImage(
+ src, svg -> rasterize( svg, box.getContentWidth() ) );
} catch( final Exception ex ) {
- getNotifier().notify( ex );
+ notify( ex );
}
}
}
else if( HTML_SVG.equalsIgnoreCase( nodeName ) ) {
// Convert the <svg> element to a raster graphic.
try {
- //final int width = box.getContentWidth();
- final var svg = toSvg( e );
- image = rasterizeString( svg );
- ImageIO.write( image, "png", new File( "/tmp/svg.png" ) );
+ final String src = toSvg( e );
+ image = getCachedImage( src, SvgRasterizer::rasterizeString );
} catch( final Exception ex ) {
- getNotifier().notify( ex );
+ notify( ex );
}
}
}
- private BufferedImage getImage( final String src, final int width ) {
- return mImageCache.computeIfAbsent( src, v -> rasterize( src, width ) );
+ /**
+ * Returns an image associated with a string; the string's pre-computed
+ * hash code is returned as the string value, making this operation very
+ * quick to return the corresponding {@link BufferedImage}.
+ *
+ * @param src The SVG used for the key into the image cache.
+ * @param rasterizer {@link Function} to call to convert SVG to an image.
+ * @return The image that corresponds to the given source string.
+ */
+ private BufferedImage getCachedImage(
+ final String src, final Function<String, BufferedImage> rasterizer ) {
+ return mImageCache.computeIfAbsent( src, v -> rasterizer.apply( src ) );
}
- private Notifier getNotifier() {
- return sNotifier;
+ private static void notify( final Exception e ) {
+ sNotifier.notify( e );
}
}