我正在尝试将SVG图像转换为JPEG,如https://xmlgraphics.apache.org/batik/using/transcoder.html#createImage示例所示。这是代码:
public void saveAsjpeg() throws Exception {
// Create a JPEG transcoder
JPEGTranscoder t = new JPEGTranscoder();
// Set the transcoding hints.
t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new Float(.8));
// Create the transcoder input.
String svgURI = new File(inputFilePath).toURL().toString();
TranscoderInput input = new TranscoderInput(svgURI);
// Create the transcoder output.
OutputStream ostream = new FileOutputStream(outputFilePath);
TranscoderOutput output = new TranscoderOutput(ostream);
// Save the image.
t.transcode(input, output);
// Flush and close the stream.
ostream.flush();
ostream.close();
System.exit(0);
}
下面是我的pom.xml。我正在尝试春季启动项目:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-codec</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svgpp</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-rasterizer</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-squiggle</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>xmlgraphics-commons</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-ttf2svg</artifactId>
<version>1.8</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
我遇到了以下异常:
org.apache.batik.transcoder.TranscoderException: null
Enclosed Exception:
null
at org.apache.batik.transcoder.image.ImageTranscoder.transcode(Unknown Source)
at org.apache.batik.transcoder.XMLAbstractTranscoder.transcode(Unknown Source)
at org.apache.batik.transcoder.SVGAbstractTranscoder.transcode(Unknown Source)
at SaveToJPEG.saveAsjpeg(SaveToJPEG.java:31)
at SaveToJPEG.main(SaveToJPEG.java:42)
我在这里有几个问题:
答案 0 :(得分:6)
我不知道是谁发布了这个神器,但它已经为我解决了这个问题
<dependency>
<groupId>fr.avianey.apache-xmlgraphics</groupId>
<artifactId>batik</artifactId>
<version>1.8</version>
</dependency>
这些类包含在此工件中
答案 1 :(得分:3)
这是Apache Batik 1.8中的一个错误,在BATIK-1136中引用。
问题如下:JPEGTranscoder
正在使用服务提供程序API来获取处理ImageWriter
格式的"image/jpeg"
实例。但是,在batik-codec
points a class org.apache.batik.ext.awt.image.codec.imageio.ImageIOJPEGImageWriter
内的工件META-INF/services
中配置的类显然是wasn't released in the final package(因为它存在于源代码中)。
因此,有两种解决方案。
使用以下标准降级至1.7版
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-codec</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>xmlgraphics-commons</artifactId>
<version>2.1</version>
</dependency>
这个版本在这个版本中正确发布。
将必要的类从Apache Batik复制到您自己的源中。在包org.apache.batik.ext.awt.image.codec.imageio
内,创建以下两个类。
首先,ImageIOImageWriter
:
package org.apache.batik.ext.awt.image.codec.imageio;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.event.IIOWriteWarningListener;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageOutputStream;
import org.apache.batik.ext.awt.image.spi.ImageWriter;
import org.apache.batik.ext.awt.image.spi.ImageWriterParams;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class ImageIOImageWriter implements ImageWriter, IIOWriteWarningListener {
private String targetMIME;
/**
* Main constructor.
* @param mime the MIME type of the image format
*/
public ImageIOImageWriter(String mime) {
this.targetMIME = mime;
}
/**
* @see ImageWriter#writeImage(java.awt.image.RenderedImage, java.io.OutputStream)
*/
public void writeImage(RenderedImage image, OutputStream out) throws IOException {
writeImage(image, out, null);
}
/**
* @see ImageWriter#writeImage(java.awt.image.RenderedImage, java.io.OutputStream, ImageWriterParams)
*/
public void writeImage(RenderedImage image, OutputStream out,
ImageWriterParams params)
throws IOException {
Iterator iter;
iter = ImageIO.getImageWritersByMIMEType(getMIMEType());
javax.imageio.ImageWriter iiowriter = null;
try {
iiowriter = (javax.imageio.ImageWriter)iter.next();
if (iiowriter != null) {
iiowriter.addIIOWriteWarningListener(this);
ImageOutputStream imgout = null;
try {
imgout = ImageIO.createImageOutputStream(out);
ImageWriteParam iwParam = getDefaultWriteParam(iiowriter, image, params);
ImageTypeSpecifier type;
if (iwParam.getDestinationType() != null) {
type = iwParam.getDestinationType();
} else {
type = ImageTypeSpecifier.createFromRenderedImage(image);
}
//Handle metadata
IIOMetadata meta = iiowriter.getDefaultImageMetadata(
type, iwParam);
//meta might be null for some JAI codecs as they don't support metadata
if (params != null && meta != null) {
meta = updateMetadata(meta, params);
}
//Write image
iiowriter.setOutput(imgout);
IIOImage iioimg = new IIOImage(image, null, meta);
iiowriter.write(null, iioimg, iwParam);
} finally {
if (imgout != null) {
imgout.close();
}
}
} else {
throw new UnsupportedOperationException("No ImageIO codec for writing "
+ getMIMEType() + " is available!");
}
} finally {
if (iiowriter != null) {
iiowriter.dispose();
}
}
}
/**
* Returns the default write parameters for encoding the image.
* @param iiowriter The IIO ImageWriter that will be used
* @param image the image to be encoded
* @param params the parameters for this writer instance
* @return the IIO ImageWriteParam instance
*/
protected ImageWriteParam getDefaultWriteParam(
javax.imageio.ImageWriter iiowriter, RenderedImage image,
ImageWriterParams params) {
ImageWriteParam param = iiowriter.getDefaultWriteParam();
if ((params != null) && (params.getCompressionMethod() != null)) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType(params.getCompressionMethod());
}
return param;
}
/**
* Updates the metadata information based on the parameters to this writer.
* @param meta the metadata
* @param params the parameters
* @return the updated metadata
*/
protected IIOMetadata updateMetadata(IIOMetadata meta, ImageWriterParams params) {
final String stdmeta = "javax_imageio_1.0";
if (meta.isStandardMetadataFormatSupported()) {
IIOMetadataNode root = (IIOMetadataNode)meta.getAsTree(stdmeta);
IIOMetadataNode dim = getChildNode(root, "Dimension");
IIOMetadataNode child;
if (params.getResolution() != null) {
child = getChildNode(dim, "HorizontalPixelSize");
if (child == null) {
child = new IIOMetadataNode("HorizontalPixelSize");
dim.appendChild(child);
}
child.setAttribute("value",
Double.toString(params.getResolution().doubleValue() / 25.4));
child = getChildNode(dim, "VerticalPixelSize");
if (child == null) {
child = new IIOMetadataNode("VerticalPixelSize");
dim.appendChild(child);
}
child.setAttribute("value",
Double.toString(params.getResolution().doubleValue() / 25.4));
}
try {
meta.mergeTree(stdmeta, root);
} catch (IIOInvalidTreeException e) {
throw new RuntimeException("Cannot update image metadata: "
+ e.getMessage());
}
}
return meta;
}
/**
* Returns a specific metadata child node
* @param n the base node
* @param name the name of the child
* @return the requested child node
*/
protected static IIOMetadataNode getChildNode(Node n, String name) {
NodeList nodes = n.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node child = nodes.item(i);
if (name.equals(child.getNodeName())) {
return (IIOMetadataNode)child;
}
}
return null;
}
/**
* @see ImageWriter#getMIMEType()
*/
public String getMIMEType() {
return this.targetMIME;
}
/**
* @see javax.imageio.event.IIOWriteWarningListener#warningOccurred(javax.imageio.ImageWriter, int, java.lang.String)
*/
public void warningOccurred(javax.imageio.ImageWriter source,
int imageIndex, String warning) {
System.err.println("Problem while writing image using ImageI/O: "
+ warning);
}
}
然后ImageIOJPEGImageWriter
:
package org.apache.batik.ext.awt.image.codec.imageio;
import java.awt.image.RenderedImage;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import org.apache.batik.ext.awt.image.codec.imageio.ImageIOImageWriter;
import org.apache.batik.ext.awt.image.spi.ImageWriterParams;
public class ImageIOJPEGImageWriter extends ImageIOImageWriter {
private static final String JPEG_NATIVE_FORMAT = "javax_imageio_jpeg_image_1.0";
/**
* Main constructor.
*/
public ImageIOJPEGImageWriter() {
super("image/jpeg");
}
/** {@inheritDoc} */
@Override
protected IIOMetadata updateMetadata(IIOMetadata meta, ImageWriterParams params) {
//ImageIODebugUtil.dumpMetadata(meta);
if (JPEG_NATIVE_FORMAT.equals(meta.getNativeMetadataFormatName())) {
meta = addAdobeTransform(meta);
IIOMetadataNode root = (IIOMetadataNode)meta.getAsTree(JPEG_NATIVE_FORMAT);
IIOMetadataNode jv = getChildNode(root, "JPEGvariety");
if (jv == null) {
jv = new IIOMetadataNode("JPEGvariety");
root.appendChild(jv);
}
IIOMetadataNode child;
if (params.getResolution() != null) {
child = getChildNode(jv, "app0JFIF");
if (child == null) {
child = new IIOMetadataNode("app0JFIF");
jv.appendChild(child);
}
//JPEG gets special treatment because there seems to be a bug in
//the JPEG codec in ImageIO converting the pixel size incorrectly
//(or not at all) when using standard metadata format.
child.setAttribute("majorVersion", null);
child.setAttribute("minorVersion", null);
child.setAttribute("resUnits", "1"); //dots per inch
child.setAttribute("Xdensity", params.getResolution().toString());
child.setAttribute("Ydensity", params.getResolution().toString());
child.setAttribute("thumbWidth", null);
child.setAttribute("thumbHeight", null);
}
try {
meta.setFromTree(JPEG_NATIVE_FORMAT, root);
} catch (IIOInvalidTreeException e) {
throw new RuntimeException("Cannot update image metadata: "
+ e.getMessage(), e);
}
//ImageIODebugUtil.dumpMetadata(meta);
}
return meta;
}
private static IIOMetadata addAdobeTransform(IIOMetadata meta) {
// add the adobe transformation (transform 1 -> to YCbCr)
IIOMetadataNode root = (IIOMetadataNode)meta.getAsTree(JPEG_NATIVE_FORMAT);
IIOMetadataNode markerSequence = getChildNode(root, "markerSequence");
if (markerSequence == null) {
throw new RuntimeException("Invalid metadata!");
}
IIOMetadataNode adobeTransform = getChildNode(markerSequence, "app14Adobe");
if (adobeTransform == null) {
adobeTransform = new IIOMetadataNode("app14Adobe");
adobeTransform.setAttribute("transform" , "1"); // convert RGB to YCbCr
adobeTransform.setAttribute("version", "101");
adobeTransform.setAttribute("flags0", "0");
adobeTransform.setAttribute("flags1", "0");
markerSequence.appendChild(adobeTransform);
} else {
adobeTransform.setAttribute("transform" , "1");
}
try {
meta.setFromTree(JPEG_NATIVE_FORMAT, root);
} catch (IIOInvalidTreeException e) {
throw new RuntimeException("Cannot update image metadata: "
+ e.getMessage(), e);
}
return meta;
}
/** {@inheritDoc} */
@Override
protected ImageWriteParam getDefaultWriteParam(
ImageWriter iiowriter, RenderedImage image,
ImageWriterParams params) {
JPEGImageWriteParam param = new JPEGImageWriteParam(iiowriter.getLocale());
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(params.getJPEGQuality());
if (params.getCompressionMethod() != null
&& !"JPEG".equals(params.getCompressionMethod())) {
throw new IllegalArgumentException(
"No compression method other than JPEG is supported for JPEG output!");
}
if (params.getJPEGForceBaseline()) {
param.setProgressiveMode(JPEGImageWriteParam.MODE_DISABLED);
}
return param;
}
}
保留1.8版本并添加上面的类,代码将按原样运行。