mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fix SVG viewer: use url if possible, handle scale correctly
This commit is contained in:
@@ -18,7 +18,7 @@ package org.intellij.images.editor;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Image document to show or edit in {@link ImageEditor}.
|
||||
@@ -30,7 +30,7 @@ public interface ImageDocument {
|
||||
/**
|
||||
* A scaled image provider.
|
||||
*/
|
||||
interface ScaledImageProvider extends Function<Double/* scale */, BufferedImage> {}
|
||||
interface ScaledImageProvider extends BiFunction<Double/* scale */, Component, BufferedImage> {}
|
||||
|
||||
/**
|
||||
* Return image for rendering
|
||||
|
||||
@@ -39,7 +39,7 @@ public final class ImageEditorManagerImpl {
|
||||
ui.getImageComponent().setGridVisible(gridOptions.isShowDefault());
|
||||
ui.getImageComponent().setTransparencyChessboardVisible(transparencyChessboardOptions.isShowDefault());
|
||||
|
||||
ui.setImageProvider(ignore -> image, null);
|
||||
ui.setImageProvider((scale, ancestor) -> image, null);
|
||||
return ui;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,8 +382,8 @@ final class ThumbnailViewUI extends JPanel implements DataProvider, Disposable {
|
||||
// File rendering
|
||||
setFileSize(file.getLength());
|
||||
try {
|
||||
BufferedImage image = IfsUtil.getImage(file);
|
||||
ImageComponent imageComponent = getImageComponent();
|
||||
BufferedImage image = IfsUtil.getImage(file, imageComponent);
|
||||
imageComponent.getDocument().setValue(image);
|
||||
setFormat(IfsUtil.getFormat(file));
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -73,7 +73,7 @@ public class ImageComponent extends JComponent {
|
||||
UIManager.getDefaults().put(uiClassID, ImageComponentUI.class.getName());
|
||||
}
|
||||
|
||||
private final ImageDocument document = new ImageDocumentImpl();
|
||||
private final ImageDocument document = new ImageDocumentImpl(this);
|
||||
private final Grid grid = new Grid();
|
||||
private final Chessboard chessboard = new Chessboard();
|
||||
private boolean myFileSizeVisible = true;
|
||||
@@ -247,6 +247,11 @@ public class ImageComponent extends JComponent {
|
||||
private ScaledImageProvider imageProvider;
|
||||
private String format;
|
||||
private Image renderer;
|
||||
private Component myComponent;
|
||||
|
||||
public ImageDocumentImpl(Component component) {
|
||||
this.myComponent = component;
|
||||
}
|
||||
|
||||
public Image getRenderer() {
|
||||
return renderer;
|
||||
@@ -263,12 +268,12 @@ public class ImageComponent extends JComponent {
|
||||
|
||||
@Override
|
||||
public BufferedImage getValue(double scale) {
|
||||
return imageProvider != null ? imageProvider.apply(scale) : null;
|
||||
return imageProvider != null ? imageProvider.apply(scale, myComponent) : null;
|
||||
}
|
||||
|
||||
public void setValue(BufferedImage image) {
|
||||
this.renderer = image != null ? Toolkit.getDefaultToolkit().createImage(image.getSource()) : null;
|
||||
setValue(image != null ? ignore -> image : null);
|
||||
setValue(image != null ? (scale, anchor) -> image : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,14 +18,15 @@
|
||||
|
||||
package org.intellij.images.vfs;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.reference.SoftReference;
|
||||
import com.intellij.util.ImageLoader;
|
||||
import com.intellij.util.LogicalRoot;
|
||||
import com.intellij.util.LogicalRootsManager;
|
||||
import com.intellij.util.SVGLoader;
|
||||
@@ -41,6 +42,7 @@ import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
@@ -50,12 +52,16 @@ import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static com.intellij.util.ui.JBUI.ScaleType.OBJ_SCALE;
|
||||
|
||||
/**
|
||||
* Image loader utility.
|
||||
*
|
||||
* @author <a href="mailto:aefimov.box@gmail.com">Alexey Efimov</a>
|
||||
*/
|
||||
public final class IfsUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#org.intellij.images.vfs.IfsUtil");
|
||||
|
||||
public static final String ICO_FORMAT = "ico";
|
||||
public static final String SVG_FORMAT = "svg";
|
||||
|
||||
@@ -82,27 +88,43 @@ public final class IfsUtil {
|
||||
try {
|
||||
final BufferedImage image = ICO_IMAGE_PARSER.getBufferedImage(new ByteSourceArray(content), null);
|
||||
file.putUserData(FORMAT_KEY, ICO_FORMAT);
|
||||
file.putUserData(IMAGE_PROVIDER_REF_KEY, new SoftReference<>(zoom -> image));
|
||||
file.putUserData(IMAGE_PROVIDER_REF_KEY, new SoftReference<>((scale, ancestor) -> image));
|
||||
return true;
|
||||
}
|
||||
catch (ImageReadException ignore) { }
|
||||
}
|
||||
|
||||
if (isScalableImage(file)) {
|
||||
final Ref<URL> url = Ref.create();
|
||||
try {
|
||||
URL url = new File(file.getPath()).toURI().toURL();
|
||||
|
||||
// ensure that image can be displayed (or throw exception otherwise)
|
||||
SVGLoader.load(url, new ByteArrayInputStream(content), 1.0f);
|
||||
|
||||
file.putUserData(FORMAT_KEY, SVG_FORMAT);
|
||||
file.putUserData(IMAGE_PROVIDER_REF_KEY, new SoftReference<>(zoom -> {
|
||||
ScaleContext ctx = ScaleContext.create(); // todo: lack component, defaults to main monitor
|
||||
return (BufferedImage)ImageLoader.loadFromUrl(url, true, false, null, ctx);
|
||||
}));
|
||||
return true;
|
||||
url.set(new File(file.getPath()).toURI().toURL());
|
||||
}
|
||||
catch (MalformedURLException ignored) {}
|
||||
catch (MalformedURLException ex) {
|
||||
LOG.warn(ex.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
// ensure svg can be displayed
|
||||
SVGLoader.load(url.get(), new ByteArrayInputStream(content), 1.0f);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
LOG.warn(url.get() + " " + t.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
file.putUserData(FORMAT_KEY, SVG_FORMAT);
|
||||
file.putUserData(IMAGE_PROVIDER_REF_KEY, new SoftReference<>((zoom, ancestor) -> {
|
||||
try {
|
||||
final ScaleContext ctx = ScaleContext.create(ancestor);
|
||||
ctx.update(OBJ_SCALE.of(zoom));
|
||||
return SVGLoader.loadHiDPI(url.get(), new ByteArrayInputStream(content), ctx);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
LOG.warn(url.get() + " " + t.getMessage());
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
InputStream inputStream = new ByteArrayInputStream(content, 0, content.length);
|
||||
@@ -117,7 +139,7 @@ public final class IfsUtil {
|
||||
imageReader.setInput(imageInputStream, true, true);
|
||||
int minIndex = imageReader.getMinIndex();
|
||||
BufferedImage image = imageReader.read(minIndex, param);
|
||||
file.putUserData(IMAGE_PROVIDER_REF_KEY, new SoftReference<>(zoom -> image));
|
||||
file.putUserData(IMAGE_PROVIDER_REF_KEY, new SoftReference<>((zoom, ancestor) -> image));
|
||||
return true;
|
||||
} finally {
|
||||
imageReader.dispose();
|
||||
@@ -136,9 +158,14 @@ public final class IfsUtil {
|
||||
|
||||
@Nullable
|
||||
public static BufferedImage getImage(@NotNull VirtualFile file) throws IOException {
|
||||
return getImage(file, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static BufferedImage getImage(@NotNull VirtualFile file, @Nullable Component ancestor) throws IOException {
|
||||
ScaledImageProvider imageProvider = getImageProvider(file);
|
||||
if (imageProvider == null) return null;
|
||||
return imageProvider.apply(1d);
|
||||
return imageProvider.apply(1d, ancestor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -46,7 +46,6 @@ import java.util.concurrent.ConcurrentMap;
|
||||
import static com.intellij.util.ImageLoader.ImageDesc.Type.IMG;
|
||||
import static com.intellij.util.ImageLoader.ImageDesc.Type.SVG;
|
||||
import static com.intellij.util.ui.JBUI.ScaleType.PIX_SCALE;
|
||||
import static com.intellij.util.ui.JBUI.ScaleType.SYS_SCALE;
|
||||
|
||||
public class ImageLoader implements Serializable {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.util.ImageLoader");
|
||||
@@ -294,10 +293,7 @@ public class ImageLoader implements Serializable {
|
||||
return with(new ImageConverter() {
|
||||
@Override
|
||||
public Image convert(Image source, ImageDesc desc) {
|
||||
if (source != null && UIUtil.isJreHiDPI(ctx)) {
|
||||
return RetinaImage.createFrom(source, ctx.getScale(SYS_SCALE), ourComponent);
|
||||
}
|
||||
return source;
|
||||
return ImageUtil.ensureHiDPI(source, ctx);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -318,6 +314,7 @@ public class ImageLoader implements Serializable {
|
||||
public static final Component ourComponent = new Component() {
|
||||
};
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
private static boolean waitForImage(Image image) {
|
||||
if (image == null) return false;
|
||||
if (image.getWidth(null) > 0) return true;
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.intellij.util;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ui.ImageUtil;
|
||||
import com.intellij.util.ui.JBUI.ScaleContext;
|
||||
import org.apache.batik.anim.dom.*;
|
||||
import org.apache.batik.dom.AbstractDocument;
|
||||
import org.apache.batik.transcoder.SVGAbstractTranscoder;
|
||||
@@ -33,6 +35,7 @@ import org.w3c.dom.Element;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
@@ -40,6 +43,8 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.util.ui.JBUI.ScaleType.PIX_SCALE;
|
||||
|
||||
/**
|
||||
* @author tav
|
||||
*/
|
||||
@@ -147,6 +152,12 @@ public class SVGLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T extends BufferedImage> T loadHiDPI(@Nullable URL url, @NotNull InputStream stream , ScaleContext ctx) throws IOException {
|
||||
BufferedImage image = (BufferedImage)load(url, stream, ctx.getScale(PIX_SCALE));
|
||||
//noinspection unchecked
|
||||
return (T)ImageUtil.ensureHiDPI(image, ctx);
|
||||
}
|
||||
|
||||
public static Couple<Integer> loadInfo(@Nullable URL url, @NotNull InputStream stream , double scale) throws IOException {
|
||||
SVGLoader loader = new SVGLoader(url, stream, scale);
|
||||
return Couple.of((int)loader.size.width, (int)loader.size.height);
|
||||
|
||||
@@ -17,11 +17,17 @@ package com.intellij.util.ui;
|
||||
|
||||
import com.intellij.util.ImageLoader;
|
||||
import com.intellij.util.JBHiDPIScaledImage;
|
||||
import com.intellij.util.RetinaImage;
|
||||
import com.intellij.util.ui.JBUI.ScaleContext;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
|
||||
import static com.intellij.util.ui.JBUI.ScaleType.SYS_SCALE;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
@@ -127,4 +133,16 @@ public class ImageUtil {
|
||||
public static Image scaleImage(Image image, double scale) {
|
||||
return ImageLoader.scaleImage(image, scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the {@code image} with {@link JBHiDPIScaledImage} according to {@code ctx} when applicable.
|
||||
*/
|
||||
@Contract("null, _ -> null; !null, _ -> !null")
|
||||
public static Image ensureHiDPI(@Nullable Image image, @NotNull ScaleContext ctx) {
|
||||
if (image == null) return null;
|
||||
if (UIUtil.isJreHiDPI(ctx)) {
|
||||
return RetinaImage.createFrom(image, ctx.getScale(SYS_SCALE), null);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,9 +998,9 @@ public class JBUI {
|
||||
* Creates a context based on the comp's system scale and sticks to it via the {@link #update()} method.
|
||||
*/
|
||||
@NotNull
|
||||
public static ScaleContext create(@NotNull Component comp) {
|
||||
public static ScaleContext create(@Nullable Component comp) {
|
||||
final ScaleContext ctx = new ScaleContext(SYS_SCALE.of(sysScale(comp)));
|
||||
ctx.compRef = new WeakReference<Component>(comp);
|
||||
if (comp != null) ctx.compRef = new WeakReference<Component>(comp);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user