blob: 36a1aa61ae34533886093298d36bd736de00e5ec [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.hop.ui.util;
import java.io.InputStream;
import java.net.URL;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.hop.core.SwtUniversalImage;
import org.apache.hop.core.SwtUniversalImageBitmap;
import org.apache.hop.core.SwtUniversalImageSvg;
import org.apache.hop.core.exception.HopFileException;
import org.apache.hop.core.logging.ILogChannel;
import org.apache.hop.core.logging.LogChannel;
import org.apache.hop.core.svg.SvgCache;
import org.apache.hop.core.svg.SvgCacheEntry;
import org.apache.hop.core.svg.SvgFile;
import org.apache.hop.core.svg.SvgImage;
import org.apache.hop.core.svg.SvgSupport;
import org.apache.hop.core.vfs.HopVfs;
import org.apache.hop.ui.core.ConstUi;
import org.apache.hop.ui.core.PropsUi;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
/**
* Class for loading images from SVG, PNG, or other bitmap formats.
*
* <p>Logic is: if SVG is enabled, then SVG icon loaded if exist. Otherwise, class trying to change
* name into PNG and try to load. If initial name is PNG, then PNG icon will be loaded.
*/
public class SwtSvgImageUtil {
private static ILogChannel log = new LogChannel("SwtSvgImageUtil");
private static final String NO_IMAGE = "ui/images/no_image.svg";
private static FileObject base;
private static double zoomFactor = PropsUi.getInstance().getZoomFactor();
static {
try {
base = HopVfs.getFileSystemManager().resolveFile(System.getProperty("user.dir"));
} catch (FileSystemException e) {
e.printStackTrace();
base = null;
}
}
/**
* Get the image for when all other fallbacks have failed. This is an image drawn on the canvas, a
* square with a red X.
*
* @param display the device to render the image to
* @return the missing image
*/
public static SwtUniversalImage getMissingImage(Display display) {
Image img = new Image(display, ConstUi.ICON_SIZE, ConstUi.ICON_SIZE);
// RAP only allows painting on the Canvas widget
if (!EnvironmentUtils.getInstance().isWeb()) {
GC gc = new GC(img);
gc.setForeground(new Color(display, PropsUi.getInstance().contrastColor(0, 0, 0)));
gc.drawRectangle(4, 4, ConstUi.ICON_SIZE - 8, ConstUi.ICON_SIZE - 8);
gc.setForeground(new Color(display, PropsUi.getInstance().contrastColor(255, 0, 0)));
gc.drawLine(4, 4, ConstUi.ICON_SIZE - 4, ConstUi.ICON_SIZE - 4);
gc.drawLine(ConstUi.ICON_SIZE - 4, 4, 4, ConstUi.ICON_SIZE - 4);
gc.dispose();
}
return new SwtUniversalImageBitmap(img, zoomFactor);
}
/** Load image from several sources. */
private static SwtUniversalImage getImageAsResourceInternal(Display display, String location) {
SwtUniversalImage result = null;
result = loadFromCurrentClasspath(location);
if (result == null) {
result = loadFromBasedVFS(display, location);
}
if (result == null) {
result = loadFromSimpleVFS(display, location);
}
return result;
}
/** Load image from several sources. */
public static SwtUniversalImage getImageAsResource(Display display, String location) {
if (location == null) {
throw new RuntimeException("No location given to load image resource");
}
SwtUniversalImage result = null;
if (result == null && SvgSupport.isSvgEnabled()) {
result = getImageAsResourceInternal(display, SvgSupport.toSvgName(location));
}
if (result == null) {
result = getImageAsResourceInternal(display, SvgSupport.toPngName(location));
}
if (result == null && !location.equals(NO_IMAGE)) {
log.logError("Unable to load image [" + location + "]", new Exception());
result = getImageAsResource(display, NO_IMAGE);
}
if (result == null) {
log.logError("Unable to load image [" + location + "]", new Exception());
result = getMissingImage(display);
}
return result;
}
/**
* Get an image using the provided classLoader and path. An attempt will be made to load the image
* with the classLoader first using SVG (regardless of extension), and falling back to PNG. If the
* image cannot be loaded with the provided classLoader, the search path will be expanded to
* include the file system (ui/images).
*
* @param display the device to render the image to
* @param classLoader the classLoader to use to load the image resource
* @param filename the path to the image
* @param width the width to scale the image to
* @param height the height to scale the image to
* @return an swt Image with width/height dimensions
*/
public static Image getImage(
Display display, ClassLoader classLoader, String filename, int width, int height) {
SwtUniversalImage u = getUniversalImage(display, classLoader, filename);
return u.getAsBitmapForSize(display, width, height);
}
private static SwtUniversalImage getUniversalImageInternal(
Display display, ClassLoader classLoader, String filename) {
SwtUniversalImage result = loadFromClassLoader(classLoader, filename);
if (result == null) {
result = loadFromClassLoader(classLoader, "/" + filename);
if (result == null) {
result = loadFromClassLoader(classLoader, "ui/images/" + filename);
if (result == null) {
result = getImageAsResourceInternal(display, filename);
}
}
}
return result;
}
/** Load image from several sources. */
public static SwtUniversalImage getUniversalImage(
Display display, ClassLoader classLoader, String filename) {
if (StringUtils.isBlank(filename)) {
return getImageAsResource(display, NO_IMAGE);
}
SwtUniversalImage result = null;
if (SvgSupport.isSvgEnabled()) {
result = getUniversalImageInternal(display, classLoader, SvgSupport.toSvgName(filename));
}
// if we haven't loaded SVG attempt to use PNG
if (result == null) {
result = getUniversalImageInternal(display, classLoader, SvgSupport.toPngName(filename));
}
// if we can't load PNG, use default "no_image" graphic
if (result == null) {
log.logError("Unable to load image [" + filename + "]", new Exception());
result = getImageAsResource(display, NO_IMAGE);
}
return result;
}
/** Load image from several sources. */
public static SwtUniversalImage getImage(Display display, String location) {
return getImageAsResource(display, location);
}
/** Internal image loading by ClassLoader.getResourceAsStream. */
private static SwtUniversalImage loadFromClassLoader(ClassLoader classLoader, String location) {
try {
SvgCacheEntry cacheEntry = SvgCache.loadSvg(new SvgFile(location, classLoader));
SvgImage svgImage = new SvgImage(cacheEntry.getSvgDocument());
return new SwtUniversalImageSvg(svgImage);
} catch (Throwable e) {
log.logError("Error loading image from location '" + location + "'", e);
return null;
}
}
/** Internal image loading by Thread.currentThread.getContextClassLoader.getResource. */
private static SwtUniversalImage loadFromCurrentClasspath(String location) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
// Can't count on Thread.currentThread().getContextClassLoader() being non-null on Mac
// Have to provide some fallback
cl = SwtSvgImageUtil.class.getClassLoader();
}
URL res = null;
try {
res = cl.getResource(location);
} catch (Throwable t) {
log.logDebug("Unable to load image from classloader [" + location + "]", t);
}
if (res == null) {
return null;
}
return loadFromClassLoader(cl, location);
}
/** Internal image loading from Hop's user.dir VFS. */
private static SwtUniversalImage loadFromBasedVFS(Display display, String location) {
try {
FileObject imageFileObject = HopVfs.getFileSystemManager().resolveFile(base, location);
InputStream s = HopVfs.getInputStream(imageFileObject);
if (s == null) {
return null;
}
try {
return loadImage(display, s, location);
} finally {
IOUtils.closeQuietly(s);
}
} catch (FileSystemException ex) {
return null;
}
}
/** Internal image loading from Hop's VFS. */
private static SwtUniversalImage loadFromSimpleVFS(Display display, String location) {
try {
InputStream s = HopVfs.getInputStream(location);
if (s == null) {
return null;
}
try {
return loadImage(display, s, location);
} finally {
IOUtils.closeQuietly(s);
}
} catch (HopFileException e) {
// do nothing. try to load next
}
return null;
}
/** Load image from InputStream as bitmap image, or SVG image conversion to bitmap image. */
private static SwtUniversalImage loadImage(Display display, InputStream in, String filename) {
if (!SvgSupport.isSvgName(filename)) {
// bitmap image
return new SwtUniversalImageBitmap(new Image(display, in), zoomFactor);
} else {
// svg image - need to convert to bitmap
try {
return new SwtUniversalImageSvg(SvgSupport.loadSvgImage(in));
} catch (Exception ex) {
throw new RuntimeException("Error loading file " + filename, ex);
}
}
}
}