/* * [Cropper.java] * * Summary: convert group of image files to a common size, with resize and crop. * * Copyright: (c) 2011-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2011-09-07 initial version * 1.1 2014-06-23 add support for *.jpeg, explicit do not support webp */ package com.mindprod.cropper; import com.mindprod.commandline.CommandLine; import com.mindprod.common18.EIO; import com.mindprod.entities.DeEntifyStrings; import com.mindprod.filter.AllButSVNDirectoriesFilter; import com.mindprod.filter.ExtensionListFilter; import javax.imageio.ImageIO; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import static java.lang.System.*; /** * convert group of image files to a common size, with resize and crop. *

* * @author Roedy Green, Canadian Mind Products * @version 1.1 2014-06-23 add support for *.jpeg, explicit do not support webp * @noinspection WeakerAccess * @since 2011-09-07 */ public final class Cropper extends DeEntifyStrings { private static final int FIRST_COPYRIGHT_YEAR = 2011; /** * undisplayed copyright notice. * * @noinspection UnusedDeclaration */ private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 2011-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; /** * date this version released. * * @noinspection UnusedDeclaration */ private static final String RELEASE_DATE = "2014-06-23"; /** * how to use the command line */ private static final String USAGE = "\nCropper needs {desired width} {desired height} {filename.jpg} or a space-separated list of" + " png, jpg, jpeg and gif files, (no webp) with optional -s -q -v switches"; /** * embedded version string. * * @noinspection UnusedDeclaration */ private static final String VERSION_STRING = "1.1"; /** * ratio of width to height */ static double desiredAspectRatio; /** * desired height of image in pixels */ static int desiredHeight; /** * desired width of image in pixels */ static int desiredWidth; /** * constructor, not used. * * @noinspection WeakerAccess */ private Cropper() { } /** * converts image files to a common size using a combination of resize and crop. * Images should bu roughly cropped to start, but can be any size, and any mix * of *.jpg, *.png and *.gif. * * @param args width, height, names of width height files to process, dirs, files, -s, *.*, no wildcards. */ public static void main( String[] args ) { // gather all the files mentioned on the command line. // either directories, files, with -s and subdirs option. // warning. Windows expands any wildcards in a nasty way. // do not use wildcards. // See http://mindprod.com/jgloss/wildcard.html if ( args.length < 3 ) { throw new IllegalArgumentException( USAGE ); } desiredWidth = Integer.parseInt( args[ 0 ] ); args[ 0 ] = null; desiredHeight = Integer.parseInt( args[ 1 ] ); args[ 1 ] = null; desiredAspectRatio = ( double ) desiredWidth / ( double ) desiredHeight; out.println( "Gathering html files to crop..." ); CommandLine commandLine = new CommandLine( args, new AllButSVNDirectoriesFilter(), new ExtensionListFilter( ExtensionListFilter.BASIC_IMAGE_EXTENSIONS /* includes *.jpeg but not *.webp */ ) ); final boolean quiet = commandLine.isQuiet(); if ( commandLine.size() == 0 ) { throw new IllegalArgumentException( "No files found to process\n" + USAGE ); } for ( File file : commandLine ) { try { final BufferedImage oldBufferedImage = ImageIO.read( file ); final String filename = file.getName(); final String extension = filename.substring( filename.length() - 3 ).toLowerCase(); final int oldWidth = oldBufferedImage.getWidth(); final int oldHeight = oldBufferedImage.getHeight(); if ( oldWidth < 1 || oldHeight < 1 ) { throw new IOException( EIO.getCanOrAbsPath( file ) + " is only " + oldWidth + "x" + oldHeight + " Too " + "small to scale." ); } if ( oldWidth == desiredWidth && oldHeight == desiredHeight ) { if ( !quiet ) { out.println( EIO.getCanOrAbsPath( file ) + " already " + desiredWidth + "x" + desiredHeight ); } continue; } final double oldAspectRatio = ( double ) oldWidth / ( double ) oldHeight; final BufferedImage croppedImage; if ( oldAspectRatio > desiredAspectRatio ) { // old image is too wide, logically chop off sides to make same shape, and scale to desired size. final int croppedWidth = ( int ) ( oldHeight * desiredAspectRatio + .5 ); croppedImage = oldBufferedImage.getSubimage( ( oldWidth - croppedWidth ) / 2, 0, croppedWidth, oldHeight ); } else { // old image is too wide, logically chop off sides to make same shape, and scale to desired size. final int croppedHeight = ( int ) ( oldWidth / desiredAspectRatio + .5 ); croppedImage = oldBufferedImage.getSubimage( 0, ( oldHeight - croppedHeight ) / 2, oldWidth, croppedHeight ); } final BufferedImage desiredBufferedImage = new BufferedImage( desiredWidth, desiredHeight, croppedImage.getType() ); final Graphics2D gr = desiredBufferedImage.createGraphics(); // Enable smooth scaling gr.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR ); // Scale and copy the entire cropped image into the desired image gr.drawImage( croppedImage, 0, 0, desiredWidth, desiredHeight, null ); // drawImage will return even before work is complete. // Save the scaled version out on top of the original file. ImageIO.write( desiredBufferedImage, extension, file ); if ( !quiet ) { out.println( EIO.getCanOrAbsPath( file ) + " converted from " + oldWidth + "x" + oldHeight + " to " + desiredWidth + "x" + desiredHeight ); } } catch ( FileNotFoundException e ) { err.println( "Error: " + EIO.getCanOrAbsPath( file ) + " not found." ); } catch ( Exception e ) { e.printStackTrace( err ); err.println( e.getMessage() + " in file " + EIO.getCanOrAbsPath( file ) ); } } // end for } // end main }