mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-146564 support SVG icons
This commit is contained in:
@@ -968,6 +968,8 @@ def layout_core(String home, String target) {
|
||||
include(name: "snappy-in-java-0.3.1.jar")
|
||||
include(name: "jayatana-1.2.4.jar")
|
||||
include(name: "imgscalr-lib-4.2.jar")
|
||||
include(name: "batik-all-1.8.jar")
|
||||
include(name: "xmlgraphics-commons-1.5.jar")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,8 @@ libraryLicense(name: "Guava", version: "17.0", license: "Apache 2.0", url: "http
|
||||
libraryLicense(name: "hamcrest", version: "1.3", license: "BSD", url: "http://hamcrest.org/", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause")
|
||||
libraryLicense(name: "HttpComponents HttpClient", libraryName: "http-client", version: "4.3.2", license: "Apache 2.0", url: "http://hc.apache.org/httpcomponents-client-ga/index.html")
|
||||
libraryLicense(name: "imgscalr", libraryName: "imgscalr", version: "4.2", license: "Apache 2.0", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://github.com/thebuzzmedia/imgscalr")
|
||||
libraryLicense(name: "batik", libraryName: "batik", version: "1.8", license: "Apache 2.0", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://svn.apache.org/repos/asf/xmlgraphics/batik")
|
||||
libraryLicense(name: "xmlgraphics-commons", libraryName: "xmlgraphics-commons", version: "1.5", license: "Apache 2.0", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://svn.apache.org/repos/asf/xmlgraphics/commons")
|
||||
libraryLicense(name: "ini4j", libraryName: "ini4j-0.5.2-patched", version: "0.5.2 (with a patch by JetBrains)", license: "Apache 2.0", url: "http://ini4j.sourceforge.net/", attachedTo: "git4idea")
|
||||
libraryLicense(name: "ISO RELAX", libraryName: "isorelax.jar", license: "MIT License", url: "http://sourceforge.net/projects/iso-relax/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html")
|
||||
libraryLicense(name: "Jakarta ORO", libraryName: "OroMatcher", version: "2.0.8", license: "Apache", url: "http://jakarta.apache.org/oro/", licenseUrl: "http://svn.apache.org/repos/asf/jakarta/oro/trunk/LICENSE")
|
||||
|
||||
Binary file not shown.
@@ -22,6 +22,8 @@ gson-2.3.1.jar
|
||||
guava-17.0.jar
|
||||
hamcrest-core-1.3.jar
|
||||
imgscalr-lib-4.2.jar
|
||||
batik-all-1.8.jar
|
||||
xmlgraphics-commons-1.5.jar
|
||||
jaxen-1.1.3.jar
|
||||
jayatana-1.2.4.jar
|
||||
jcip-annotations.jar
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16px" height="16px"
|
||||
viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
|
||||
<g>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#717171" d="M20,19c0-0.6-0.1-1.2-0.4-1.7L28,1h-2l-9.4,14.1
|
||||
C16.4,15,16.2,15,16,15c-0.2,0-0.4,0-0.6,0.1L6,1H4l8.4,16.2C12.1,17.8,12,18.4,12,19c0,0.3,0,0.5,0.1,0.8L10,21l2,6l3.1-4.1
|
||||
C15.4,23,15.7,23,16,23c0.3,0,0.6,0,0.9-0.1L20,27l2-6l-2.1-1.3C19.9,19.5,20,19.2,20,19z M16,21c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2
|
||||
c1.1,0,2,0.9,2,2C18,20.1,17.1,21,16,21z"/>
|
||||
<path fill="#A784BB" d="M8,19c-3.3,0-6,2.7-6,6c0,3.3,2.7,6,6,6c3.3,0,6-2.7,6-6C14,21.7,11.3,19,8,19z M8,27c-1.1,0-2-0.9-2-2
|
||||
c0-1.1,0.9-2,2-2c1.1,0,2,0.9,2,2C10,26.1,9.1,27,8,27z"/>
|
||||
<path fill="#A784BB" d="M24,19c-3.3,0-6,2.7-6,6c0,3.3,2.7,6,6,6s6-2.7,6-6C30,21.7,27.3,19,24,19z M24,27c-1.1,0-2-0.9-2-2
|
||||
c0-1.1,0.9-2,2-2s2,0.9,2,2C26,26.1,25.1,27,24,27z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16px" height="16px"
|
||||
viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#717171" d="M26.9,31L19,23.2l4.1-4.1l7.8,7.8L26.9,31z"/>
|
||||
<path fill="#717171" d="M13,1C6.4,1,1,6.4,1,13s5.4,12,12,12c6.6,0,12-5.4,12-12S19.6,1,13,1z M13,21c-4.4,0-8-3.6-8-8s3.6-8,8-8
|
||||
c4.4,0,8,3.6,8,8S17.4,21,13,21z"/>
|
||||
<path fill="#4C92BB" d="M19,13c0,3.3-2.7,6-6,6c-3.3,0-6-2.7-6-6s2.7-6,6-6C16.3,7,19,9.7,19,13z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 619 B |
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16px" height="16px"
|
||||
viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#4C92BB" d="M9.7,22.2C7.5,20.6,6,18,6,15c0-4.6,3.5-8.4,8-8.9V2C7.3,2.5,2,8.1,2,15c0,4.1,1.9,7.7,4.9,10.1L2,30h14
|
||||
l-0.1-14L9.7,22.2z"/>
|
||||
<path fill="#4C92BB" d="M25.1,6.9L30,2H16l0.1,14l6.2-6.2C24.5,11.4,26,14,26,17c0,4.6-3.5,8.4-8,8.9v4c6.7-0.5,12-6.1,12-12.9
|
||||
C30,12.9,28.1,9.3,25.1,6.9z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 594 B |
@@ -85,6 +85,8 @@ ide.appIcon.progress=true
|
||||
ide.appIcon.badge=true
|
||||
ide.appIcon.requestAttention=true
|
||||
|
||||
ide.svg.icon=false
|
||||
|
||||
ide.windowSystem.hScrollChars=5
|
||||
ide.windowSystem.vScrollChars=5
|
||||
ide.windowSystem.autoShowProcessPopup=false
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
*/
|
||||
package com.intellij.openapi.util;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.registry.RegistryValue;
|
||||
import com.intellij.openapi.util.registry.RegistryValueListener;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.reference.SoftReference;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
@@ -90,6 +93,15 @@ public final class IconLoader {
|
||||
ourDeprecatedIconsReplacements.put("/vcs/messageHistory.png", "AllIcons.General.MessageHistory");
|
||||
}
|
||||
|
||||
private static Disposable myDisposable = Disposer.newDisposable();
|
||||
static {
|
||||
Registry.get("ide.svg.icon").addListener(new RegistryValueListener.Adapter() {
|
||||
public void afterValueChanged(RegistryValue value) {
|
||||
clearCache();
|
||||
}
|
||||
}, myDisposable);
|
||||
}
|
||||
|
||||
private static final ImageIcon EMPTY_ICON = new ImageIcon(UIUtil.createImage(1, 1, BufferedImage.TYPE_3BYTE_BGR)) {
|
||||
@NonNls
|
||||
public String toString() {
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.util.ui.ImageUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
@@ -38,11 +38,164 @@ import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Deprecated
|
||||
public class ImageLoader implements Serializable {
|
||||
|
||||
private static class ImageDesc {
|
||||
public enum Type {
|
||||
PNG,
|
||||
|
||||
SVG {
|
||||
@Override
|
||||
public Image load(URL url, InputStream is, float scale) throws IOException {
|
||||
return SVGLoader.load(url, is, scale);
|
||||
}
|
||||
},
|
||||
|
||||
UNDEFINED;
|
||||
|
||||
public Image load(URL url, InputStream stream, float scale) throws IOException {
|
||||
return ImageLoader.load(stream, (int)scale);
|
||||
}
|
||||
}
|
||||
|
||||
public final String path;
|
||||
public final @Nullable Class cls; // resource class if present
|
||||
public final float scale; // initial scale factor
|
||||
public final Type type;
|
||||
|
||||
public ImageDesc(String path, Class cls, float scale, Type type) {
|
||||
this.path = path;
|
||||
this.cls = cls;
|
||||
this.scale = scale;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Image load() throws IOException {
|
||||
InputStream stream = null;
|
||||
URL url = null;
|
||||
if (cls != null) {
|
||||
stream = cls.getResourceAsStream(path);
|
||||
if (stream == null) return null;
|
||||
}
|
||||
if (stream == null) {
|
||||
url = new URL(path);
|
||||
stream = url.openStream();
|
||||
}
|
||||
return type.load(url, stream, scale);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ImageDescList extends ArrayList<ImageDesc> {
|
||||
private ImageDescList() {}
|
||||
|
||||
@Nullable
|
||||
public Image load() {
|
||||
return load(ImageConverterChain.create());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Image load(@NotNull ImageConverterChain converters) {
|
||||
for (ImageDesc desc : this) {
|
||||
try {
|
||||
Image image = desc.load();
|
||||
if (image == null) continue;
|
||||
return converters.convert(image, desc);
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImageDescList create(@NotNull String file,
|
||||
@Nullable Class cls,
|
||||
boolean dark,
|
||||
boolean retina,
|
||||
boolean allowFloatScaling)
|
||||
{
|
||||
ImageDescList vars = new ImageDescList();
|
||||
if (retina || dark) {
|
||||
final String name = FileUtil.getNameWithoutExtension(file);
|
||||
final String ext = FileUtilRt.getExtension(file);
|
||||
|
||||
float scale = calcScaleFactor(allowFloatScaling);
|
||||
|
||||
// TODO: allow SVG images to freely scale on Retina
|
||||
|
||||
if (Registry.is("ide.svg.icon") && dark) {
|
||||
vars.add(new ImageDesc(name + "_dark.svg", cls, UIUtil.isRetina() ? 2f : scale, ImageDesc.Type.SVG));
|
||||
}
|
||||
|
||||
if (Registry.is("ide.svg.icon")) {
|
||||
vars.add(new ImageDesc(name + ".svg", cls, UIUtil.isRetina() ? 2f : scale, ImageDesc.Type.SVG));
|
||||
}
|
||||
|
||||
if (dark && retina) {
|
||||
vars.add(new ImageDesc(name + "@2x_dark." + ext, cls, 2f, ImageDesc.Type.PNG));
|
||||
}
|
||||
|
||||
if (dark) {
|
||||
vars.add(new ImageDesc(name + "_dark." + ext, cls, 1f, ImageDesc.Type.PNG));
|
||||
}
|
||||
|
||||
if (retina) {
|
||||
vars.add(new ImageDesc(name + "@2x." + ext, cls, 2f, ImageDesc.Type.PNG));
|
||||
}
|
||||
}
|
||||
vars.add(new ImageDesc(file, cls, 1f, ImageDesc.Type.PNG));
|
||||
return vars;
|
||||
}
|
||||
}
|
||||
|
||||
private interface ImageConverter {
|
||||
Image convert(@Nullable Image source, ImageDesc desc);
|
||||
}
|
||||
|
||||
private static class ImageConverterChain extends ArrayList<ImageConverter> {
|
||||
private ImageConverterChain() {}
|
||||
|
||||
public static ImageConverterChain create() {
|
||||
return new ImageConverterChain();
|
||||
}
|
||||
|
||||
public ImageConverterChain withFilter(final ImageFilter filter) {
|
||||
return with(new ImageConverter() {
|
||||
@Override
|
||||
public Image convert(Image source, ImageDesc desc) {
|
||||
return ImageUtil.filter(source, filter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ImageConverterChain withRetina() {
|
||||
return with(new ImageConverter() {
|
||||
@Override
|
||||
public Image convert(Image source, ImageDesc desc) {
|
||||
if (source != null && UIUtil.isRetina() && desc.scale > 1) {
|
||||
return RetinaImage.createFrom(source, (int)desc.scale, ourComponent);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ImageConverterChain with(ImageConverter f) {
|
||||
add(f);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Image convert(Image image, ImageDesc desc) {
|
||||
for (ImageConverter f : this) {
|
||||
image = f.convert(image, desc);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
public static final Component ourComponent = new Component() {
|
||||
};
|
||||
|
||||
@@ -74,8 +227,7 @@ public class ImageLoader implements Serializable {
|
||||
|
||||
@Nullable
|
||||
public static Image loadFromUrl(@NotNull URL url, boolean allowFloatScaling, ImageFilter filter) {
|
||||
final float scaleFactor = allowFloatScaling ? JBUI.scale(1f) : JBUI.scale(1f) > 1.5f ? 2f : 1f;
|
||||
assert scaleFactor >= 1.0f : "By design, only scale factors >= 1.0 are supported";
|
||||
final float scaleFactor = calcScaleFactor(allowFloatScaling);
|
||||
|
||||
// We can't check all 3rd party plugins and convince the authors to add @2x icons.
|
||||
// (scaleFactor > 1.0) != isRetina() => we should scale images manually.
|
||||
@@ -86,22 +238,27 @@ public class ImageLoader implements Serializable {
|
||||
// retina images provides a better result than upscaling non-retina images.
|
||||
final boolean loadRetinaImages = UIUtil.isRetina() || scaleImages;
|
||||
|
||||
for (Pair<String, Integer> each : getFileNames(url.toString(), UIUtil.isUnderDarcula(), loadRetinaImages)) {
|
||||
try {
|
||||
Image image = loadFromStream(URLUtil.openStream(new URL(each.first)), each.second, filter);
|
||||
if (image != null && scaleImages) {
|
||||
if (each.first.contains("@2x"))
|
||||
image = scaleImage(image, scaleFactor / 2.0f); // divide by 2.0 as Retina images are 2x the resolution.
|
||||
else
|
||||
image = scaleImage(image, scaleFactor);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
// Image file may not exist, try next one
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return ImageDescList.create(url.toString(), null, UIUtil.isUnderDarcula(), loadRetinaImages, allowFloatScaling).load(
|
||||
ImageConverterChain.create().
|
||||
withFilter(filter).
|
||||
withRetina().
|
||||
with(new ImageConverter() {
|
||||
public Image convert(Image source, ImageDesc desc) {
|
||||
if (source != null && scaleImages && desc.type != ImageDesc.Type.SVG) {
|
||||
if (desc.path.contains("@2x"))
|
||||
return scaleImage(source, scaleFactor / 2.0f); // divide by 2.0 as Retina images are 2x the resolution.
|
||||
else
|
||||
return scaleImage(source, scaleFactor);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private static float calcScaleFactor(boolean allowFloatScaling) {
|
||||
float scaleFactor = allowFloatScaling ? JBUI.scale(1f) : JBUI.scale(1f) > 1.5f ? 2f : 1f;
|
||||
assert scaleFactor >= 1.0f : "By design, only scale factors >= 1.0 are supported";
|
||||
return scaleFactor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -121,14 +278,8 @@ public class ImageLoader implements Serializable {
|
||||
|
||||
@Nullable
|
||||
public static Image loadFromUrl(URL url, boolean dark, boolean retina, ImageFilter filter) {
|
||||
for (Pair<String, Integer> each : getFileNames(url.toString(), dark, retina || JBUI.isHiDPI())) {
|
||||
try {
|
||||
return loadFromStream(URLUtil.openStream(new URL(each.first)), each.second, filter);
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return ImageDescList.create(url.toString(), null, dark, retina, true).
|
||||
load(ImageConverterChain.create().withFilter(filter).withRetina());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -140,43 +291,8 @@ public class ImageLoader implements Serializable {
|
||||
|
||||
@Nullable
|
||||
public static Image loadFromResource(@NonNls @NotNull String path, @NotNull Class aClass) {
|
||||
for (Pair<String, Integer> each : getFileNames(path)) {
|
||||
InputStream stream = aClass.getResourceAsStream(each.first);
|
||||
if (stream == null) continue;
|
||||
Image image = loadFromStream(stream, each.second);
|
||||
if (image != null) return image;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<Pair<String, Integer>> getFileNames(@NotNull String file) {
|
||||
return getFileNames(file, UIUtil.isUnderDarcula(), UIUtil.isRetina() || JBUI.scale(1.0f) >= 1.5f);
|
||||
}
|
||||
|
||||
public static List<Pair<String, Integer>> getFileNames(@NotNull String file, boolean dark, boolean retina) {
|
||||
if (retina || dark) {
|
||||
List<Pair<String, Integer>> answer = new ArrayList<Pair<String, Integer>>(4);
|
||||
|
||||
final String name = FileUtil.getNameWithoutExtension(file);
|
||||
final String ext = FileUtilRt.getExtension(file);
|
||||
if (dark && retina) {
|
||||
answer.add(Pair.create(name + "@2x_dark." + ext, 2));
|
||||
}
|
||||
|
||||
if (dark) {
|
||||
answer.add(Pair.create(name + "_dark." + ext, 1));
|
||||
}
|
||||
|
||||
if (retina) {
|
||||
answer.add(Pair.create(name + "@2x." + ext, 2));
|
||||
}
|
||||
|
||||
answer.add(Pair.create(file, 1));
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
return Collections.singletonList(Pair.create(file, 1));
|
||||
return ImageDescList.create(path, aClass, UIUtil.isUnderDarcula(), UIUtil.isRetina() || JBUI.scale(1.0f) >= 1.5f, true).
|
||||
load(ImageConverterChain.create().withRetina());
|
||||
}
|
||||
|
||||
public static Image loadFromStream(@NotNull final InputStream inputStream) {
|
||||
@@ -188,7 +304,13 @@ public class ImageLoader implements Serializable {
|
||||
}
|
||||
|
||||
public static Image loadFromStream(@NotNull final InputStream inputStream, final int scale, ImageFilter filter) {
|
||||
if (scale <= 0) throw new IllegalArgumentException("Scale must 1 or more");
|
||||
Image image = load(inputStream, scale);
|
||||
ImageDesc desc = new ImageDesc("", null, scale, ImageDesc.Type.UNDEFINED);
|
||||
return ImageConverterChain.create().withFilter(filter).withRetina().convert(image, desc);
|
||||
}
|
||||
|
||||
private static Image load(@NotNull final InputStream inputStream, final int scale) {
|
||||
if (scale <= 0) throw new IllegalArgumentException("Scale must be 1 or greater");
|
||||
try {
|
||||
BufferExposingByteArrayOutputStream outputStream = new BufferExposingByteArrayOutputStream();
|
||||
try {
|
||||
@@ -207,11 +329,6 @@ public class ImageLoader implements Serializable {
|
||||
|
||||
waitForImage(image);
|
||||
|
||||
image = ImageUtil.filter(image, filter);
|
||||
if (UIUtil.isRetina() && scale > 1) {
|
||||
image = RetinaImage.createFrom(image, scale, ourComponent);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
@@ -224,4 +341,19 @@ public class ImageLoader implements Serializable {
|
||||
public static boolean isGoodSize(final Icon icon) {
|
||||
return IconLoader.isGoodSize(icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link ImageDescList}
|
||||
*/
|
||||
public static List<Pair<String, Integer>> getFileNames(@NotNull String file) {
|
||||
return getFileNames(file, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link ImageDescList}
|
||||
*/
|
||||
public static List<Pair<String, Integer>> getFileNames(@NotNull String file, boolean dark, boolean retina) {
|
||||
new UnsupportedOperationException("unsupported method").printStackTrace();
|
||||
return new ArrayList<Pair<String, Integer>>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.util;
|
||||
|
||||
import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
|
||||
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.Document;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author tav
|
||||
*/
|
||||
public class SVGLoader {
|
||||
private TranscoderInput input;
|
||||
private BufferedImage img;
|
||||
private float width;
|
||||
private float height;
|
||||
|
||||
private enum SizeAttr {
|
||||
width,
|
||||
height;
|
||||
|
||||
static final int FALLBACK_VALUE = 16;
|
||||
|
||||
public int value(@NotNull Document document) {
|
||||
String value = document.getDocumentElement().getAttribute(name());
|
||||
assert value.endsWith("px") : "unexpected '" + name() + "' format in " + document.getBaseURI();
|
||||
try {
|
||||
return Integer.parseInt(value.substring(0, value.length() - 2));
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
ex.printStackTrace();
|
||||
return FALLBACK_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyTranscoder extends ImageTranscoder {
|
||||
@Override
|
||||
public BufferedImage createImage(int w, int h) {
|
||||
return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeImage(BufferedImage img, TranscoderOutput output) throws TranscoderException {
|
||||
SVGLoader.this.img = img;
|
||||
}
|
||||
}
|
||||
|
||||
public static Image load(@NotNull URL url, float scale) throws IOException {
|
||||
return load(url, url.openStream(), scale);
|
||||
}
|
||||
|
||||
public static Image load(@NotNull InputStream stream , float scale) throws IOException {
|
||||
return load(null, stream, scale);
|
||||
}
|
||||
|
||||
public static Image load(@Nullable URL url, @NotNull InputStream stream , float scale) throws IOException {
|
||||
try {
|
||||
return new SVGLoader(url, stream, scale).createImage();
|
||||
}
|
||||
catch (TranscoderException ex) {
|
||||
throw new IOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private SVGLoader(@Nullable URL url, InputStream stream, float scale) throws IOException {
|
||||
Document document = null;
|
||||
String uri = null;
|
||||
try {
|
||||
uri = url != null ? url.toURI().toString() : null;
|
||||
}
|
||||
catch (URISyntaxException ignore) {
|
||||
}
|
||||
document = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName()).
|
||||
createDocument(uri, stream);
|
||||
if (document == null) {
|
||||
throw new IOException("document not created");
|
||||
}
|
||||
input = new TranscoderInput(document);
|
||||
|
||||
width = SizeAttr.width.value(document) * scale;
|
||||
height = SizeAttr.height.value(document) * scale;
|
||||
}
|
||||
|
||||
private BufferedImage createImage() throws TranscoderException {
|
||||
MyTranscoder r = new MyTranscoder();
|
||||
r.addTranscodingHint(ImageTranscoder.KEY_WIDTH, new Float(width));
|
||||
r.addTranscodingHint(ImageTranscoder.KEY_HEIGHT, new Float(height));
|
||||
r.transcode(input, null);
|
||||
return img;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@
|
||||
<orderEntry type="library" exported="" name="ForkJoin" level="project" />
|
||||
<orderEntry type="library" exported="" name="Snappy-Java" level="project" />
|
||||
<orderEntry type="library" name="imgscalr" level="project" />
|
||||
<orderEntry type="library" name="batik" level="project" />
|
||||
<orderEntry type="library" name="xmlgraphics-commons" level="project" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
|
||||
Reference in New Issue
Block a user