package workers; import javafx.concurrent.Task; import javafx.embed.swing.SwingFXUtils; import model.SOMConfig; import model.SOMImage; import model.SOMLayout; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.CropImageFilter; import java.awt.image.FilteredImageSource; import java.io.File; import java.io.IOException; public class ScaleWorker extends Thread { public static final int SOURCE = 0; public static final int PREVIEW = 1; public static final int THUMBNAIL = 2; SOMConfig config = SOMConfig.getInstance(); public static SOMImage scale(SOMImage somImage1, final int type) { final SOMImage somImage = somImage1; Task task = new Task() { @Override protected SOMImage call() throws Exception { // Do the scale work return prepareandStart(somImage, type); } }; // open Thread Thread thread = new Thread(task); // start Thread thread.start(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //return the somImage1 return somImage1; } // Overload of scale() that lets you enter Arrays of Pictures public static SOMImage[] scale(SOMImage[] somImages, int type) { // loop through Array of SOMImages for (SOMImage image : somImages) { //update the image image = scale(image, type); } // return the imagearray return somImages; } private static SOMImage prepareandStart(SOMImage somImage, int type) { // the image before scaling // Image sourceImage; // the image after scaling // Image resultImage; // type of image to be used to scale down int source = SOURCE; // check for scaled versions of the image somImage.updateImageState(); // preview if (type == PREVIEW) { // check if the requested image already exists if (somImage.isPrvthere()) // exit the scaler return somImage; // The requested image does not exist, } // thumbnail if (type == THUMBNAIL) { // check if the requested image already exists if (somImage.isTmbthere()) { return somImage; } // The requested image does not exist, // check for Preview to scale faster if (somImage.isPrvthere()) { source = PREVIEW; } } // In any other case we need to scale the // full sized image, which is default somImage = generateScaledImage(somImage, type, source); return somImage; } private static SOMImage generateScaledImage(SOMImage somImage, int target, int source) { // the source image size double sourceWidth = 0; double sourceHeight = 0; // the scaled sources width and height // before cropping int scaledSourceHeight; int scaledSourceWidth; // the later image size int targetWidth = 0; int targetHeight = 0; // Aspect ratio before cropping double sourceAspect; // The ImageViews' cropped aspect ratio double targetAspect; // Source File File sourceFile = somImage.getSrc(); // Target File File targetFile = null; // ImageIcons ImageIcon sourceImageIcon; ImageIcon targetImageIcon; // JAVAFX Images javafx.scene.image.Image targetImage; // Buffered Images BufferedImage scaledSourceBufferedImage; BufferedImage croppedBufferedImage; // Graphics for Buffered Images Graphics2D scaledSourceGraphics; Graphics croppedGraphics; // get the target IMAGE SIZES // and the target FILE switch (target) { // for the preview case PREVIEW: targetWidth = SOMLayout.screenWidth; targetHeight = SOMLayout.screenHeight; targetFile = somImage.getPrv(); // for the Thumbnail break; case THUMBNAIL: targetWidth = SOMLayout.getColumn(1); targetHeight = SOMLayout.getRow(1); targetFile = somImage.getTmb(); break; } // get the SOURCE FILE switch (source) { case SOURCE: sourceFile = somImage.getSrc(); break; case PREVIEW: sourceFile = somImage.getPrv(); break; } switch (SOMConfig.SCALING_ALGORITHM) { // GRAPHICS 2D ---------------------------------------------------------- case SOMConfig.SCALING_GRAPHICS_2D: { // Generate an ImageIcon from the Source File sourceImageIcon = new ImageIcon(sourceFile.getPath()); // the sources original width and height sourceWidth = sourceImageIcon.getIconWidth(); sourceHeight = sourceImageIcon.getIconHeight(); // Calculate the aspect ratio before cropping sourceAspect = (sourceWidth) / (sourceHeight); // Calculate the ImageViews' cropped aspect ratio targetAspect = ((double) targetWidth) / ((double) targetHeight); // if picture is higher than frame if (sourceAspect < targetAspect) { scaledSourceHeight = (int) Math.ceil(targetWidth / sourceAspect); scaledSourceWidth = targetWidth; } // if Picture is narrower (or equal) else { scaledSourceWidth = (int) Math.ceil(targetHeight * sourceAspect); scaledSourceHeight = targetHeight; } // Probably way faster than ImageIcon System.out.println("Scale with Graphics2D:"); // Print the File Path System.out.println(sourceFile.toString()); // SCALE ----------------------------------------------------------- // THE ------------------------------------------------------------- // SOURCE ---------------------------------------------------------- // Get the ImageIcon Image sourceImageIconImage = sourceImageIcon.getImage(); // Open a buffered Image in the specified size // (with no data at this point --> black image) scaledSourceBufferedImage = new BufferedImage( scaledSourceWidth, scaledSourceHeight, BufferedImage.TYPE_INT_RGB ); // Get the Graphics2D scaledSourceGraphics = scaledSourceBufferedImage.createGraphics(); // Set the Rendering hints scaledSourceGraphics.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR ); // Actually Scale the Image scaledSourceGraphics.drawImage(sourceImageIconImage, 0, 0, scaledSourceWidth, scaledSourceHeight, null); scaledSourceGraphics.dispose(); // System Resources Released // Calculate the Offsets int wOffset; int hOffset; // CROP ------------------------------------------------------------ // THE ------------------------------------------------------------- // IMAGE ----------------------------------------------------------- if (sourceAspect > targetAspect) { hOffset = 0; wOffset = (scaledSourceWidth - targetWidth) / 2; } else { hOffset = (scaledSourceHeight - targetHeight) / 2; wOffset = 0; } CropImageFilter cropimgf = new CropImageFilter( // Crop by moving the image half the way // it is wider to the left wOffset, // Crop by moving the image half the way // it is higher to the top hOffset, targetWidth, targetHeight ); FilteredImageSource producer = new FilteredImageSource( scaledSourceBufferedImage.getSource(), cropimgf ); Image image = Toolkit.getDefaultToolkit().createImage( producer ); targetImageIcon = new ImageIcon( image ); // save the smaller image croppedBufferedImage = new BufferedImage( targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB ); croppedGraphics = croppedBufferedImage.getGraphics(); croppedGraphics.drawImage(targetImageIcon.getImage(), 0, 0, null); // WRITE --------------------------------------------------------------- // THE ----------------------------------------------------------------- // IMAGE --------------------------------------------------------------- writeJPEG(targetFile, croppedBufferedImage); // UPDATE --------------------------------------------------------------- // IMAGE ---------------------------------------------------------------- // STATE ---------------------------------------------------------------- somImage.updateImageState(); System.out.println("Image State Updated: Scaled"); // Clean up croppedGraphics.dispose(); scaledSourceGraphics.dispose(); image.flush(); sourceImageIconImage.flush(); System.gc(); break; } // JAVAFX ---------------------------------------------------------- case SOMConfig.SCALING_JAVAFX: { // Scale with javafx // FIXME breaks up targetImage = new javafx.scene.image.Image(sourceFile.toString(), targetWidth, targetHeight, true, false, true); BufferedImage bi = SwingFXUtils.fromFXImage(targetImage, null); writeJPEG(targetFile, bi); somImage.updateImageState(); System.out.println("Image State Updated: Scaled"); somImage.updateImageState(); break; } } return somImage; } private static void writeJPEG(File targetFile, BufferedImage bi) { try { boolean iw = ImageIO.write(bi, "JPEG", targetFile); } catch (IOException e) { e.printStackTrace(); } } }