/* * Copyright 2015 i-net software * * 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.inet.gradle.setup.image; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import javax.imageio.ImageIO; import org.gradle.api.GradleException; import org.gradle.api.Project; import com.inet.gradle.setup.image.icns.IcnsCodec; import com.inet.gradle.setup.image.icns.IconSuite; import com.inet.gradle.setup.image.image4j.codec.ico.ICODecoder; import com.inet.gradle.setup.image.image4j.codec.ico.ICOEncoder; import com.inet.gradle.setup.image.image4j.util.ImageUtil; /** * Factory for platform dependent image formats. * * @author Volker Berlin */ public class ImageFactory { /** * Get a file to an icon in the platform format if set or null if not set in the gradle script * * @param project current project for resolving the file locations * @param data the set values * @param dir directory for temporary build files if the file(s) need converted * @param format the platform format, currently "ico", "icns" and png<size> * @return a file or null * @throws IOException if an error occur on reading the image files */ public static File getImageFile( Project project, Object data, File dir, String format ) throws IOException { if( data == null ) { return null; } ArrayList<File> files = new ArrayList<>(); if( data instanceof Iterable ) { for( Object img : (Iterable)data ) { files.add( project.file( img ) ); } } else { files.add( project.file( data ) ); } if( files.size() == 0 ) { return null; } // Search if there is already an matching image for( File file : files ) { if( file.getName().endsWith( '.' + format ) ) { return file; } } String baseFileName = null; ArrayList<BufferedImage> images = new ArrayList<>(); for( File file : files ) { String extension = file.getName(); if( baseFileName == null ) { baseFileName = extension.substring( 0, extension.lastIndexOf( '.' ) + 1 ); } extension = extension.substring( extension.lastIndexOf( '.' ) + 1 ); switch( extension ) { case "ico": images.addAll( ICODecoder.read( file ) ); break; case "icns": try( FileInputStream fis = new FileInputStream( file ) ) { images.addAll( new IcnsCodec().decode( fis ) ); } break; default: images.add( ImageIO.read( file ) ); } } if( baseFileName == null ) { baseFileName = "icon."; } File file = new File( dir, baseFileName + format ); switch( format ) { case "ico": try( FileOutputStream fos = new FileOutputStream( file ) ) { ICOEncoder.write( images, fos ); } break; case "icns": try( FileOutputStream fos = new FileOutputStream( file ) ) { IconSuite suite = new IconSuite(); for( BufferedImage img : images ) { switch( img.getWidth() ) { case IcnsCodec.SMALL_SIZE: suite.setSmallIcon( img ); break; case IcnsCodec.LARGE_SIZE: suite.setLargeIcon( img ); break; case IcnsCodec.HUGE_SIZE: suite.setHugeIcon( img ); break; case IcnsCodec.THUMBNAIL_SIZE: suite.setThumbnailIcon( img ); break; default: project.getLogger().error( "Ignore icon size: " + img.getWidth() ); } } new IcnsCodec().encode( suite, fos ); } break; default: if( format.startsWith( "png" ) ) { try { int size = Integer.parseInt( format.substring( 3 ) ); BufferedImage scaledImage = scaleBestFromList( images, size ); if( scaledImage != null ) { ImageIO.write( scaledImage, "png", file ); } break; } catch( NumberFormatException e ) { // throw GradleException later } } throw new GradleException( "Unsupported image format: " + format ); } return file; } /** * Scales the best matching image from the specified list to the specified size. * @param images the source images * @param size the target size * @return the scaled image, or <tt>null</tt> when the list of source images is empty */ private static BufferedImage scaleBestFromList( Collection<BufferedImage> images, int size ) { BufferedImage best = null; int min = Integer.MAX_VALUE; for( BufferedImage img : images ) { int diff = Math.min( img.getWidth(), img.getHeight() ) - size; int p = diff < 0 ? 10000 - diff : diff; if( p < min ) { min = p; best = img; } } if( best == null ) { return null; } return ImageUtil.scaleImage( best, size, size ); } }