Class EmbedAndCrop

java.lang.Object
edu.emory.cellbio.svg.EmbedAndCrop

public class EmbedAndCrop extends Object
Inkscape extension: Embed and Crop Images

This java-based extension for Inkscape facilitates image embedding by:

  • Automatically identifying all linked images.
  • Cropping image data that lies outside the images' clipping frame.
  • Optionally applying jpeg compression.
  • Optionally resampling images.
  • Writing the cropped and possibly compressed image data directly in the SVG file.

By cropping image data that lies outside the clipping frame, applying jpeg compression, or resampling to lower resolution, the resulting file size can be reduced significantly. If preserving image quality is a priority jpeg compression and resampling can be explicitly avoided.

Author:
Benjamin Nanes
  • Field Details

    • imgFileType

      private String imgFileType
    • compQual

      private float compQual
    • doResampling

      private boolean doResampling
    • targetRes

      private double targetRes
    • maxRes

      private double maxRes
    • embeddedImageSizeMin

      private long embeddedImageSizeMin
    • VERBOSE

      private final boolean VERBOSE
      See Also:
  • Constructor Details

    • EmbedAndCrop

      public EmbedAndCrop()
  • Method Details

    • runInkscapeExtension

      public void runInkscapeExtension(String[] args)
      Run the extension
      Parameters:
      args - Command line arguments
      [<input>] [-o <output> | -s] [-t <type> [-q <quality>]] [-r [<target res.> [<max res.>]]] [-e <size>]
      • <input> Path to the input SVG file. If missing, the user will be presented with a file open dialog box.
      • -o <output> Path to save the output SVG file with embedded images
      • -s Present the user with a file save dialog to specify the output file
        Note: If neither -o nor -s is specified, the output is sent to the standard output stream
      • -t <type> Specify the type of image for encoding. Supported options are png, jpeg, or mix. The latter option indicates that for each image, the format resulting in the smaller file size should be used. If this flag is not set, the user will be presented with a selection dialog.
      • -q <quality> Quality parameter for jpeg compression. Default value is 0.85.
      • -r <target res.> <max res.> Images with resolution above <max res.> should be downsampled to <target res.>. Resolution is specified in pixels per mm. If this flag is not set, no resampling will be done. If this flag is set, but no target resolution is provided, the default value is 11.811, approximately equal to 300dpi. If only the target resolution is provided, the max resolution defaults to 4/3 of the target resolution.
      • -e <size> Minimum size at which already embedded images will be processed. Set to -1 to skip processing of all embedded images (default behavior). Format using common units (20KB, 1MB, etc.)
      Examples:
      input.svg -s -t jpeg -q 0.95
      input.svg -o output.svg
    • runWithoutExit

      public boolean runWithoutExit(String[] args)
      Run the extension, but do not exit the JVM when finished. This method allows an alternate entry point to allow use of the extension programmatically, rather than from Inkscape or the command line.
      See Also:
    • parseArgs

      private void parseArgs(String[] args)
    • process

      private void process(Document dom, String basePath) throws EmbedAndCropException
      Process an SVG DOM
      Throws:
      EmbedAndCropException
    • SVGToStream

      private void SVGToStream(Document dom, OutputStream os) throws EmbedAndCropException
      Push XML(SVG) to a stream
      Throws:
      EmbedAndCropException
    • getOutputParams

      private void getOutputParams() throws EmbedAndCropException
      Harvest output parameters from dialog
      Throws:
      EmbedAndCropException
    • checkImageOutputType

      private void checkImageOutputType() throws EmbedAndCropException
      Validate the image output type
      Throws:
      EmbedAndCropException
    • saveAs

      private void saveAs(Document dom) throws EmbedAndCropException
      Save an XML(SVG) file
      Throws:
      EmbedAndCropException
    • save

      private void save(Document dom, File f) throws EmbedAndCropException
      Save an XML(SVG) file
      Throws:
      EmbedAndCropException
    • processImg

      private void processImg(Element img, Element clip, String basePath) throws EmbedAndCropException
      Process an image element
      Throws:
      EmbedAndCropException
    • loadImageData

      private BufferedImage loadImageData(Element imgElement, String basePath, long embedSizeMin) throws EmbedAndCropException
      Load image data from an SVG image element
      Parameters:
      imgElement -
      basePath -
      embedSizeMin - Do not process (i.e. return null) embedded images below this size (bytes). Set to -1 to skip all embedded images.
      Returns:
      Returns the image data in a BufferedImage, or null if an embedded image cannot be loaded and the element should be skipped.
      Throws:
      EmbedAndCropException - Image data cannot be loaded and simply skipping the element is not appropriate (i.e. broken link).
    • putImgData

      private void putImgData(Element img, BufferedImage origImg, double[] crop) throws EmbedAndCropException
      Load image data to embed
      Parameters:
      img - Image element
      origImg - Image data as a BufferedImage
      crop - Fraction of image to crop from each edge, {top, bottom, left, right}
      Throws:
      EmbedAndCropException
    • readEmbeddedImageData

      private Map.Entry<BufferedImage,Integer> readEmbeddedImageData(String imgString) throws EmbedAndCropException
      Read a BufferedImage from image data embedded in the SVG file. Following the SVG standard, PNG and Jpeg images are supported. Requires base64 encoding. Transparency is not supported.
      Parameters:
      imgString -
      Returns:
      Throws:
      EmbedAndCropException
    • convertToRGB

      private BufferedImage convertToRGB(BufferedImage img)
      Quick and dirty conversion to TYPE_INT_RGB
      Parameters:
      img -
      Returns:
    • adjustImgPlacement

      private void adjustImgPlacement(Element img, double[] crop)
      Adjust placement of the image element to account for cropping
      Parameters:
      img - The image element
      crop - Fraction of image actually cropped from each edge, {top, bottom, left, right}; note that this must account for rounding to pixels
    • getElementDims

      private double[] getElementDims(Element e)
      Transform the width and height attributes of an element to document space.
      Parameters:
      e -
      Returns:
    • limitResolution

      private BufferedImage limitResolution(BufferedImage I, double[] wh, double rTarget, double rMax)
      Down-sample an image if above a maximum resolution
      Parameters:
      I - Source image
      wh - Image dimensions, width x height (physical units)
      rTarget - Target resolution (pixels per physical unit)
      rMax - Max resolution (pixels per physical unit)
      Returns:
      A resampled image with the lowest possible resolution not less than r, or the source image unchanged if the source image resolution is less than or equal to r.
    • getCropFraction

      private double[] getCropFraction(Element img, Element clip) throws EmbedAndCropException
      Get the fraction of image that should be cropped off each side
      Parameters:
      img - The image element
      clip - The clip-path element
      Returns:
      Fraction of image to crop from each edge, {top, bottom, left, right}
      Throws:
      EmbedAndCropException
    • isPointInRect

      private boolean isPointInRect(double[] p, double[] r)
      Is a point within a rectangle (edges excluded)?
      Parameters:
      p - {x,y}
      r - Bounding points of the rectangle, {x0, x1, y0, y1}
    • distanceFromRect

      private double[] distanceFromRect(double[] p, double[] r)
      How far is a point from each edge of a rectangle?
      Parameters:
      p - {x,y}
      r - Bounding points of the rectangle, {x0, x1, y0, y1}
      Returns:
      Distance from each edge (negative if point is on exterior side of the edge), {top, bottom, left, right}
    • scaleToRectFraction

      private double[] scaleToRectFraction(double[] d, double[] r)
      Scale a set of distances from rectangle edges by the width and height of the rectangle.
      Parameters:
      d - Absolute distances, {top, bottom, left, right}
      r - Bounding points of the rectangle, {x0, x1, y0, y1}
      Returns:
      Relative distances, {top/height, bottom/height, left/width, right/width}
    • distanceFromLine

      private double distanceFromLine(double[] lp0, double[] lp1, double[] x)
      Get the minimum distance between a pont and a line defined by two other points
      Parameters:
      lp0 - 1st point on the line, {x,y}
      lp1 - 2nd point on the line, {x,y}
      x - How far is this point from the line, {x,y}
      Returns:
      Distance of point x from the line
    • getClipPoints

      private double[][] getClipPoints(Element clip) throws EmbedAndCropException
      Extract the coordinates of a clip path
      Returns:
      double[][] coordinates[point]{x,y}
      Throws:
      EmbedAndCropException
    • getPathPointList

      private double[][] getPathPointList(Element path) throws EmbedAndCropException
      Get the points along a path ////Not working
      Returns:
      double[point][{x,y}]
      Throws:
      EmbedAndCropException
    • getRectBounds

      private double[] getRectBounds(Element e)
      Get the boundaries of a rect element (or similar) without transformation
      Returns:
      An array: {x0, x1, y0, y1}
    • rectBoundsToPointList

      private double[][] rectBoundsToPointList(double[] b)
      Convert rect boundary points to a list of corner points
      Parameters:
      b - {x0, x1, y0, y1}, as returned by getRectBounds(org.w3c.dom.Element)
      Returns:
      double[point][{x,y}]
    • transformToDocumentSpace

      private double[] transformToDocumentSpace(double[] point, Node n)
      Transform a point ({x,y}) to document space by recursively looking for transform attributes in the given nodes and all parent nodes.
      Parameters:
      point -
      n -
      Returns:
      {x,y}
    • transformToDocumentSpace

      private double[][] transformToDocumentSpace(double[][] points, Node n)
      Transform a set of points to document space
      Parameters:
      points - Array of points ({x,y})
      n -
      Returns:
    • parseTransform

      private double[] parseTransform(double[] point, String transform)
      Transform a coordinate pair using a transform attribute
      Parameters:
      point - {x,y}
      transform - The transform atribute value
      Returns:
      {x,y}
    • transformMatrix

      private double[] transformMatrix(double[] point, double[] matrix)
      Apply a matrix transformation.

      WARNING - Matrix specification (by row) differs from standard SVG order (by column)

      Parameters:
      point - {x,y}
      matrix - {a,c,e,b,d,f}
      Returns:
      {x,y}
    • transformTranslate

      private double[] transformTranslate(double[] point, double tx, double ty)
      Apply a translation
      Parameters:
      point - {x,y}
      tx - Delta x
      ty - Delta y
      Returns:
      {x,y}
    • transformScale

      private double[] transformScale(double[] point, double sx, double sy)
      Apply a scale
      Parameters:
      point - {x,y}
      sx - x scale factor
      sy - y scale factor
      Returns:
      {x,y}
    • transformRotate

      private double[] transformRotate(double[] point, double a)
      Apply a rotation about the origin
      Parameters:
      point - {x,y}
      a - Angle, in degrees
      Returns:
      {x,y}
    • transformRotate

      private double[] transformRotate(double[] point, double a, double cx, double cy)
      Apply a rotation about center point {cx,cy}
      Parameters:
      point - {x,y}
      a - Angle, in degrees
      Returns:
      {x,y}
    • transformSkewX

      private double[] transformSkewX(double[] point, double a)
      Skew along the x-axis
      Parameters:
      point - {x,y}
      a - Angle, in degrees
      Returns:
      {x,y}
    • transformSkewY

      private double[] transformSkewY(double[] point, double a)
      Skew along the y-axis
      Parameters:
      point - {x,y}
      a - Angle, in degrees
      Returns:
      {x,y}
    • getClipPath

      private Element getClipPath(Element img, Document dom)
      Get the clipping path of an image
    • openDialog

      private File openDialog()
      Get a file using a file open dialog
    • readSVG

      private Document readSVG(File f) throws EmbedAndCropException
      Read an XML file and return a DOM
      Throws:
      EmbedAndCropException
    • processFileSize

      private long processFileSize(String s)
      Turn a file size string into the number of bytes
      Parameters:
      s -
      Returns:
    • test

      public void test() throws EmbedAndCropException
      Throws:
      EmbedAndCropException
    • main

      public static void main(String[] args)