/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2015 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * 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 org.pentaho.di.ui.util; import java.io.IOException; 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.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.pentaho.di.core.SwtUniversalImage; import org.pentaho.di.core.SwtUniversalImageBitmap; import org.pentaho.di.core.SwtUniversalImageSvg; import org.pentaho.di.core.exception.KettleFileException; import org.pentaho.di.core.logging.LogChannel; import org.pentaho.di.core.logging.LogChannelInterface; import org.pentaho.di.core.svg.SvgSupport; import org.pentaho.di.core.vfs.KettleVFS; import org.pentaho.di.ui.core.ConstUI; /** * Class for loading images from SVG, PNG, or other bitmap formats. * * 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 LogChannelInterface log = new LogChannel( "SwtSvgImageUtil" ); private static final String NO_IMAGE = "ui/images/no_image.svg"; private static FileObject base; static { try { base = KettleVFS.getInstance().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 ); GC gc = new GC( img ); gc.setForeground( new Color( display, 0, 0, 0 ) ); gc.drawRectangle( 4, 4, ConstUI.ICON_SIZE - 8, ConstUI.ICON_SIZE - 8 ); gc.setForeground( new Color( display, 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 ); } /** * Load image from several sources. */ private static SwtUniversalImage getImageAsResourceInternal( Display display, String location ) { SwtUniversalImage result = null; if ( result == null ) { result = loadFromCurrentClasspath( display, 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 ) { 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 + "]" ); result = getImageAsResource( display, NO_IMAGE ); } if ( result == null ) { log.logError( "Unable to load image [" + location + "]" ); 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( display, classLoader, filename ); if ( result == null ) { result = loadFromClassLoader( display, classLoader, "/" + filename ); if ( result == null ) { result = loadFromClassLoader( display, 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 ) ) { log.logError( "Unable to load image [" + 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 + "]" ); 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( Display display, ClassLoader classLoader, String location ) { InputStream s = null; try { s = classLoader.getResourceAsStream( location ); } catch ( Throwable t ) { log.logDebug( "Unable to load image from classloader [" + location + "]" ); } if ( s == null ) { return null; } try { return loadImage( display, s, location ); } finally { IOUtils.closeQuietly( s ); } } /** * Internal image loading by Thread.currentThread.getContextClassLoader.getResource. */ private static SwtUniversalImage loadFromCurrentClasspath( Display display, 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 + "]" ); } if ( res == null ) { return null; } InputStream s; try { s = res.openStream(); } catch ( IOException ex ) { return null; } if ( s == null ) { return null; } try { return loadImage( display, s, location ); } finally { IOUtils.closeQuietly( s ); } } /** * Internal image loading from Kettle's user.dir VFS. */ private static SwtUniversalImage loadFromBasedVFS( Display display, String location ) { try { FileObject imageFileObject = KettleVFS.getInstance().getFileSystemManager().resolveFile( base, location ); InputStream s = KettleVFS.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 Kettle's VFS. */ private static SwtUniversalImage loadFromSimpleVFS( Display display, String location ) { try { InputStream s = KettleVFS.getInputStream( location ); if ( s == null ) { return null; } try { return loadImage( display, s, location ); } finally { IOUtils.closeQuietly( s ); } } catch ( KettleFileException 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 ) ); } else { // svg image - need to convert to bitmap try { return new SwtUniversalImageSvg( SvgSupport.loadSvgImage( in ) ); } catch ( Exception ex ) { throw new RuntimeException( ex ); } } } }