You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
6.5 KiB
182 lines
6.5 KiB
4 years ago
|
package com.fr.base.svg;
|
||
|
|
||
|
import com.fr.stable.AssistUtils;
|
||
|
import com.fr.value.AtomicNotNullLazyValue;
|
||
|
import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
|
||
|
import org.apache.batik.anim.dom.SVGOMDocument;
|
||
|
import org.apache.batik.bridge.BridgeContext;
|
||
|
import org.apache.batik.bridge.UserAgent;
|
||
|
import org.apache.batik.transcoder.SVGAbstractTranscoder;
|
||
|
import org.apache.batik.transcoder.TranscoderException;
|
||
|
import org.apache.batik.transcoder.TranscoderInput;
|
||
|
import org.apache.batik.transcoder.TranscoderOutput;
|
||
|
import org.apache.batik.transcoder.image.ImageTranscoder;
|
||
|
import org.apache.batik.util.XMLResourceDescriptor;
|
||
|
import org.jetbrains.annotations.NotNull;
|
||
|
import org.jetbrains.annotations.Nullable;
|
||
|
import org.w3c.dom.Element;
|
||
|
import org.w3c.dom.svg.SVGDocument;
|
||
|
|
||
|
import java.awt.GraphicsDevice;
|
||
|
import java.awt.GraphicsEnvironment;
|
||
|
import java.awt.Rectangle;
|
||
|
import java.awt.geom.AffineTransform;
|
||
|
import java.awt.image.BufferedImage;
|
||
|
import java.io.IOException;
|
||
|
import java.io.StringReader;
|
||
|
|
||
|
/**
|
||
|
* 可以根据某个缩放倍数scale,将SVG图片转化为Image对象
|
||
|
* @author Yvan
|
||
|
* @version 10.0
|
||
|
* Created by Yvan on 2020/12/17
|
||
|
*/
|
||
|
public class SVGTranscoder extends ImageTranscoder {
|
||
|
|
||
|
private static final float DEFAULT_VALUE = -1.0F;
|
||
|
public static final float ICON_DEFAULT_SIZE = 16F;
|
||
|
private float origDocWidth;
|
||
|
private float origDocHeight;
|
||
|
@Nullable
|
||
|
private BufferedImage image;
|
||
|
private final double scale;
|
||
|
|
||
|
@NotNull
|
||
|
private static AtomicNotNullLazyValue<Double> iconMaxSize = new AtomicNotNullLazyValue<Double>() {
|
||
|
@NotNull
|
||
|
@Override
|
||
|
protected Double compute() {
|
||
|
double maxSize = Double.MAX_VALUE;
|
||
|
if (!GraphicsEnvironment.isHeadless()) {
|
||
|
GraphicsDevice defaultScreenDevice = GraphicsEnvironment
|
||
|
.getLocalGraphicsEnvironment()
|
||
|
.getDefaultScreenDevice();
|
||
|
Rectangle bounds = defaultScreenDevice.getDefaultConfiguration().getBounds();
|
||
|
AffineTransform tx = defaultScreenDevice
|
||
|
.getDefaultConfiguration()
|
||
|
.getDefaultTransform();
|
||
|
maxSize = Math.max(bounds.width * tx.getScaleX(), bounds.height * tx.getScaleY());
|
||
|
}
|
||
|
return maxSize;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
public SVGTranscoder(double scale) {
|
||
|
this.scale = scale;
|
||
|
this.width = ICON_DEFAULT_SIZE;
|
||
|
this.height = ICON_DEFAULT_SIZE;
|
||
|
}
|
||
|
|
||
|
public SVGTranscoder(double scale, float width, float height) {
|
||
|
this.scale = scale;
|
||
|
this.width = width;
|
||
|
this.height = height;
|
||
|
}
|
||
|
|
||
|
public final float getOrigDocWidth() {
|
||
|
return this.origDocWidth;
|
||
|
}
|
||
|
|
||
|
public final void setOrigDocWidth(float origDocWidth) {
|
||
|
this.origDocWidth = origDocWidth;
|
||
|
}
|
||
|
|
||
|
public final float getOrigDocHeight() {
|
||
|
return this.origDocHeight;
|
||
|
}
|
||
|
|
||
|
public final void setOrigDocHeight(float origDocHeight) {
|
||
|
this.origDocHeight = origDocHeight;
|
||
|
}
|
||
|
|
||
|
public static double getIconMaxSize() {
|
||
|
return iconMaxSize.getValue();
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
public final BufferedImage getImage() {
|
||
|
return this.image;
|
||
|
}
|
||
|
|
||
|
@NotNull
|
||
|
public static SVGTranscoder createImage(double scale, @NotNull TranscoderInput input) throws TranscoderException {
|
||
|
return createImage(scale, input, -1, -1);
|
||
|
}
|
||
|
|
||
|
@NotNull
|
||
|
public static SVGTranscoder createImage(double scale, @NotNull TranscoderInput input, float overriddenWidth, float overriddenHeight) throws TranscoderException {
|
||
|
return createImage(scale, input, overriddenWidth, overriddenHeight, ICON_DEFAULT_SIZE, ICON_DEFAULT_SIZE);
|
||
|
}
|
||
|
|
||
|
@NotNull
|
||
|
public static SVGTranscoder createImage(double scale, @NotNull TranscoderInput input, float overriddenWidth, float overriddenHeight, float width, float height) throws TranscoderException {
|
||
|
SVGTranscoder transcoder = new SVGTranscoder(scale, width, height);
|
||
|
if (!AssistUtils.equals(overriddenWidth, DEFAULT_VALUE)) {
|
||
|
transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, overriddenWidth);
|
||
|
}
|
||
|
|
||
|
if (!AssistUtils.equals(overriddenHeight, DEFAULT_VALUE)) {
|
||
|
transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, overriddenHeight);
|
||
|
}
|
||
|
|
||
|
double iconMaxSize = SVGTranscoder.iconMaxSize.getValue();
|
||
|
transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_MAX_WIDTH, (float) iconMaxSize);
|
||
|
transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_MAX_HEIGHT, (float) iconMaxSize);
|
||
|
transcoder.transcode(input, null);
|
||
|
return transcoder;
|
||
|
}
|
||
|
|
||
|
private static SVGDocument createFallbackPlaceholder() {
|
||
|
try {
|
||
|
String fallbackIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\">\n" +
|
||
|
" <rect x=\"1\" y=\"1\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"red\" stroke-width=\"2\"/>\n" +
|
||
|
" <line x1=\"1\" y1=\"1\" x2=\"15\" y2=\"15\" stroke=\"red\" stroke-width=\"2\"/>\n" +
|
||
|
" <line x1=\"1\" y1=\"15\" x2=\"15\" y2=\"1\" stroke=\"red\" stroke-width=\"2\"/>\n" +
|
||
|
"</svg>\n";
|
||
|
|
||
|
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName());
|
||
|
return (SVGDocument) factory.createDocument(null, new StringReader(fallbackIcon));
|
||
|
} catch (IOException e) {
|
||
|
throw new IllegalStateException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void setImageSize(float docWidth, float docHeight) {
|
||
|
super.setImageSize((float) (docWidth * this.scale), (float) (docHeight * this.scale));
|
||
|
this.origDocWidth = docWidth;
|
||
|
this.origDocHeight = docHeight;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
@NotNull
|
||
|
public BufferedImage createImage(int width, int height) {
|
||
|
return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void writeImage(@NotNull BufferedImage image, @Nullable TranscoderOutput output) {
|
||
|
this.image = image;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
@NotNull
|
||
|
protected UserAgent createUserAgent() {
|
||
|
return new SVGAbstractTranscoderUserAgent() {
|
||
|
@Override
|
||
|
@NotNull
|
||
|
public SVGDocument getBrokenLinkDocument(@NotNull Element e, @NotNull String url, @NotNull String message) {
|
||
|
return createFallbackPlaceholder();
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 开放访问权限
|
||
|
*/
|
||
|
@Override
|
||
|
public BridgeContext createBridgeContext(SVGOMDocument doc) {
|
||
|
return super.createBridgeContext(doc);
|
||
|
}
|
||
|
}
|