/** * Draw an image squeezed along the horizontal and/or vertical dimensions (no preservation of * aspect ratio) centered at (x, y). * * @param g - object to draw onto * @param x - horizontal center of where to draw the resulting image * @param y - vertical center of where to draw the resulting image * @param inputImageARGB * @param outputImageARGB - often this is the same as inputImageARGB for speed * @param srcW - source image width * @param srcH - source image height * @param maxW - target width * @param maxH - target height * @param processAlpha - set false for speed if the image is opaque */ public static void drawFlipshade( final Graphics g, final int x, final int y, final int[] inputImageARGB, final int[] outputImageARGB, int srcW, int srcH, int maxW, int maxH, final boolean processAlpha) { if (maxW < 1 || maxH < 1 || srcW < 1 || srcH < 1) { throw new IllegalArgumentException( "drawFlipshade requires maxW, maxH, srcW and srcH be >= 1"); } if (inputImageARGB == null || outputImageARGB == null) { throw new NullPointerException( "drawFlipshade requires non-null input and output image buffers"); } while (srcW >> 1 > maxW && srcH >> 1 > maxH) { JMEImageUtils.half(inputImageARGB, inputImageARGB, srcW, srcH >>= 1); srcW >>= 1; } if (srcW >> 1 == maxW && srcH >> 1 == maxH) { JMEImageUtils.half(inputImageARGB, outputImageARGB, maxW, maxH); } else { maxW = Math.min(srcW, maxW); maxH = Math.min(srcH, maxH); JMEImageUtils.fivePointSampleDownscale( inputImageARGB, outputImageARGB, srcW, srcH, maxW, maxH); } g.drawRGB(outputImageARGB, 0, maxW, x - (maxW >> 1), y - (maxH >> 1), maxW, maxH, processAlpha); }
/** * Return an image which is, if needed to fit inside a bounding box, down-scaled and smaller then * the original on one or both axes. The image will not be up-scaled if smaller than the bounding * box. * * <p>Using this variant receiving an <source>int[]</source> instead of <source>Image</source> * allows you to reduce peak memory usage during scaling. This reduces the likelihood you will see * OutOfMemory problems when scaling. A low-memory example usage pattern is below. The * <source>Task.LARGE_MEMORY_MUTEX</source> prevents multiple threads from entering memory-spike * sections simultaneously. The source and result data arrays can be the same for maximum speed * and minimal memory consumption. * * <p><source> * * <pre>synchronized (Task.LARGE_MEMORY_MUTEX) { * final int[] data = new int[w * h]; * image.getRGB(data, 0, w, 0, 0, w, h); * image = null; * image = JMEImageUtils.scaleImage(data, data, w, h, maxW, maxH, true, * false, false); * }</pre> * * </source> * * @param inputImageARGB - ARGB data for the original image * @param outputImageARGB - ARGB data buffer for the scaled image, can be the same as * inputImageARGB if downscaling (faster) * @param srcW - Source image width * @param srcH - Source image height * @param maxW - maximum (bounding box, will not upscale) width of scaled image * @param maxH - maximum (bounding box, will not upscale) height of scaled image * @param preserveAspectRatio - set true except for special effects * @param scalingAlgorithm - a constant from JMEImageUtils specifying how to scale * @return */ public static Image scaleImage( final int[] inputImageARGB, final int[] outputImageARGB, int srcW, int srcH, int maxW, int maxH, final boolean preserveAspectRatio, final int scalingAlgorithm) { if (scalingAlgorithm < 0 || scalingAlgorithm > MAX_SCALING_ALGORITHM) { throw new IllegalArgumentException( "Unsupported scaling algorithm " + scalingAlgorithm + ", should be [0-" + MAX_SCALING_ALGORITHM + "]"); } if (maxW < 1 || maxH < 1 || srcW < 1 || srcH < 1) { throw new IllegalArgumentException("scaleImage requires maxW, maxH, srcW and srcH be >= 1"); } if (inputImageARGB == null || outputImageARGB == null) { throw new NullPointerException("scaleImage requires non-null input and output image buffers"); } final float byWidth = maxW / (float) srcW; final float byHeight = maxH / (float) srcH; boolean widthIsMaxed = false; if (preserveAspectRatio) { if (byWidth <= byHeight) { maxW = (int) (srcW * byWidth); maxH = (int) (srcH * byWidth); } else { maxW = (int) (srcW * byHeight); maxH = (int) (srcH * byHeight); } } if (maxW >= srcW) { maxW = srcW; widthIsMaxed = true; } final boolean processAlpha = scalingAlgorithm != JMEImageUtils.WEIGHTED_AVERAGE_OPAQUE; if (maxH >= srcH) { if (widthIsMaxed) { // No resize needed maxH = srcH; return Image.createRGBImage(inputImageARGB, maxW, maxH, processAlpha); } maxH = srcH; } switch (scalingAlgorithm) { default: case ONE_POINT_PICK: while (srcW >> 1 > maxW && srcH >> 1 > maxH) { JMEImageUtils.half(inputImageARGB, inputImageARGB, srcW, srcH); srcW /= 2; srcH /= 2; } if (srcW >> 1 == maxW && srcH >> 1 == maxH) { JMEImageUtils.half(inputImageARGB, outputImageARGB, srcW, srcH); break; } case BASIC_ONE_POINT_PICK: JMEImageUtils.onePointPick(inputImageARGB, outputImageARGB, srcW, srcH, maxW, maxH); break; case FIVE_POINT_BLEND: while (srcW / 2 > maxW && srcH / 2 > maxH) { JMEImageUtils.half(inputImageARGB, inputImageARGB, srcW, srcH); srcH /= 2; srcW /= 2; } if (srcW / 2 == maxW && srcH / 2 == maxH) { JMEImageUtils.half(inputImageARGB, outputImageARGB, srcW, srcH); break; } JMEImageUtils.fivePointSampleDownscale( inputImageARGB, outputImageARGB, srcW, srcH, maxW, maxH); break; case WEIGHTED_AVERAGE_TRANSLUCENT: if (srcW < maxW || srcH < maxH) { JMEImageUtils.pureUpscale( inputImageARGB, outputImageARGB, srcW, srcH, maxW, maxH, preserveAspectRatio); } else { JMEImageUtils.pureDownscale( inputImageARGB, outputImageARGB, srcW, srcH, maxW, maxH, preserveAspectRatio); } break; case WEIGHTED_AVERAGE_OPAQUE: JMEImageUtils.pureOpaqueDownscale( inputImageARGB, outputImageARGB, srcW, srcH, maxW, maxH, preserveAspectRatio); break; } return Image.createRGBImage(outputImageARGB, maxW, maxH, processAlpha); }