package util; /* * Copyright 2009, Morten Nobel-Joergensen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.awt.image.Raster; import java.awt.image.WritableRaster; /** * @author Heinz Doerr */ public class ImageUtils { /** * @param img * @return */ static public String imageTypeName(final BufferedImage img) { switch (img.getType()) { case BufferedImage.TYPE_3BYTE_BGR: return "TYPE_3BYTE_BGR"; case BufferedImage.TYPE_4BYTE_ABGR: return "TYPE_4BYTE_ABGR"; case BufferedImage.TYPE_4BYTE_ABGR_PRE: return "TYPE_4BYTE_ABGR_PRE"; case BufferedImage.TYPE_BYTE_BINARY: return "TYPE_BYTE_BINARY"; case BufferedImage.TYPE_BYTE_GRAY: return "TYPE_BYTE_GRAY"; case BufferedImage.TYPE_BYTE_INDEXED: return "TYPE_BYTE_INDEXED"; case BufferedImage.TYPE_CUSTOM: return "TYPE_CUSTOM"; case BufferedImage.TYPE_INT_ARGB: return "TYPE_INT_ARGB"; case BufferedImage.TYPE_INT_ARGB_PRE: return "TYPE_INT_ARGB_PRE"; case BufferedImage.TYPE_INT_BGR: return "TYPE_INT_BGR"; case BufferedImage.TYPE_INT_RGB: return "TYPE_INT_RGB"; case BufferedImage.TYPE_USHORT_555_RGB: return "TYPE_USHORT_555_RGB"; case BufferedImage.TYPE_USHORT_565_RGB: return "TYPE_USHORT_565_RGB"; case BufferedImage.TYPE_USHORT_GRAY: return "TYPE_USHORT_GRAY"; } return "unknown image type #" + img.getType(); } /** * @param img * @return */ static public int nrChannels(final BufferedImage img) { switch (img.getType()) { case BufferedImage.TYPE_3BYTE_BGR: return 3; case BufferedImage.TYPE_4BYTE_ABGR: return 4; case BufferedImage.TYPE_BYTE_GRAY: return 1; case BufferedImage.TYPE_INT_BGR: return 3; case BufferedImage.TYPE_INT_ARGB: return 4; case BufferedImage.TYPE_INT_RGB: return 3; case BufferedImage.TYPE_CUSTOM: return 4; case BufferedImage.TYPE_4BYTE_ABGR_PRE: return 4; case BufferedImage.TYPE_INT_ARGB_PRE: return 4; case BufferedImage.TYPE_USHORT_555_RGB: return 3; case BufferedImage.TYPE_USHORT_565_RGB: return 3; case BufferedImage.TYPE_USHORT_GRAY: return 1; } return 0; } /** * * returns one row (height == 1) of byte packed image data in BGR or AGBR form * * @param img * @param y * @param w * @param array * @param temp must be either null or a array with length of w*h * @return */ public static byte[] getPixelsBGR(final BufferedImage img, final int y, final int w, final byte[] array, final int[] temp) { final int x= 0; final int h= 1; assert array.length == temp.length * nrChannels(img); assert (temp.length == w); int imageType= img.getType(); Raster raster; switch (imageType) { case BufferedImage.TYPE_3BYTE_BGR: case BufferedImage.TYPE_4BYTE_ABGR: case BufferedImage.TYPE_4BYTE_ABGR_PRE: case BufferedImage.TYPE_BYTE_GRAY: raster= img.getRaster(); //int ttype= raster.getTransferType(); raster.getDataElements(x, y, w, h, array); break; case BufferedImage.TYPE_INT_BGR: raster= img.getRaster(); raster.getDataElements(x, y, w, h, temp); ints2bytes(temp, array, 0, 1, 2); // bgr --> bgr break; case BufferedImage.TYPE_INT_RGB: raster= img.getRaster(); raster.getDataElements(x, y, w, h, temp); ints2bytes(temp, array, 2, 1, 0); // rgb --> bgr break; case BufferedImage.TYPE_INT_ARGB: case BufferedImage.TYPE_INT_ARGB_PRE: raster= img.getRaster(); raster.getDataElements(x, y, w, h, temp); ints2bytes(temp, array, 2, 1, 0, 3); // argb --> abgr break; case BufferedImage.TYPE_CUSTOM: // TODO: works for my icon image loader, but else ??? img.getRGB(x, y, w, h, temp, 0, w); ints2bytes(temp, array, 2, 1, 0, 3); // argb --> abgr break; default: img.getRGB(x, y, w, h, temp, 0, w); ints2bytes(temp, array, 2, 1, 0); // rgb --> bgr break; } return array; } /** * converts and copies byte packed BGR or ABGR into the img buffer, * the img type may vary (e.g. RGB or BGR, int or byte packed) * but the number of components (w/o alpha, w alpha, gray) must match * * does not unmange the image for all (A)RGN and (A)BGR and gray imaged * @param bgrPixels * @param img * @param x * @param y * @param w * @param h * */ public static void setBGRPixels(final byte[] bgrPixels, final BufferedImage img, final int x, final int y, final int w, final int h) { int imageType= img.getType(); WritableRaster raster= img.getRaster(); //int ttype= raster.getTransferType(); if (imageType == BufferedImage.TYPE_3BYTE_BGR || imageType == BufferedImage.TYPE_4BYTE_ABGR || imageType == BufferedImage.TYPE_4BYTE_ABGR_PRE || imageType == BufferedImage.TYPE_BYTE_GRAY) { raster.setDataElements(x, y, w, h, bgrPixels); } else { int[] pixels; if (imageType == BufferedImage.TYPE_INT_BGR) { pixels= bytes2int(bgrPixels, 2, 1, 0); // bgr --> bgr } else if (imageType == BufferedImage.TYPE_INT_ARGB || imageType == BufferedImage.TYPE_INT_ARGB_PRE) { pixels= bytes2int(bgrPixels, 3, 0, 1, 2); // abgr --> argb } else { pixels= bytes2int(bgrPixels, 0, 1, 2); // bgr --> rgb } if (w == 0 || h == 0) { return; } else if (pixels.length < w * h) { throw new IllegalArgumentException("pixels array must have a length" + " >= w*h"); } if (imageType == BufferedImage.TYPE_INT_ARGB || imageType == BufferedImage.TYPE_INT_RGB || imageType == BufferedImage.TYPE_INT_ARGB_PRE || imageType == BufferedImage.TYPE_INT_BGR) { raster.setDataElements(x, y, w, h, pixels); } else { // Unmanages the image img.setRGB(x, y, w, h, pixels, 0, w); } } } /** * @param in * @param out * @param index1 * @param index2 * @param index3 */ public static void ints2bytes(final int[] in, final byte[] out, final int index1, final int index2, final int index3) { for (int i= 0; i < in.length; i++) { int index= i * 3; int value= in[i]; out[index + index1]= (byte)value; value= value >> 8; out[index + index2]= (byte)value; value= value >> 8; out[index + index3]= (byte)value; } } /** * @param in * @param out * @param index1 * @param index2 * @param index3 * @param index4 */ public static void ints2bytes(final int[] in, final byte[] out, final int index1, final int index2, final int index3, final int index4) { for (int i= 0; i < in.length; i++) { int index= i * 4; int value= in[i]; out[index + index1]= (byte)value; value= value >> 8; out[index + index2]= (byte)value; value= value >> 8; out[index + index3]= (byte)value; value= value >> 8; out[index + index4]= (byte)value; } } /** * @param in * @param index1 * @param index2 * @param index3 * @return */ public static int[] bytes2int(final byte[] in, final int index1, final int index2, final int index3) { int[] out= new int[in.length / 3]; for (int i= 0; i < out.length; i++) { int index= i * 3; int b1= (in[index +index1] & 0xff) << 16; int b2= (in[index + index2] & 0xff) << 8; int b3= in[index + index3] & 0xff; out[i]= b1 | b2 | b3; } return out; } /** * @param in * @param index1 * @param index2 * @param index3 * @param index4 * @return */ public static int[] bytes2int(final byte[] in, final int index1, final int index2, final int index3, final int index4) { int[] out= new int[in.length / 4]; for (int i= 0; i < out.length; i++) { int index= i * 4; int b1= (in[index +index1] & 0xff) << 24; int b2= (in[index +index2] & 0xff) << 16; int b3= (in[index + index3] & 0xff) << 8; int b4= in[index + index4] & 0xff; out[i]= b1 | b2 | b3 | b4; } return out; } /** * Converts the {@link BufferedImage} type. * @param srcImage * @param destImgType * @return */ public static BufferedImage convert(final BufferedImage srcImage, final int destImgType) { BufferedImage img= new BufferedImage(srcImage.getWidth(), srcImage.getHeight(), destImgType); Graphics2D g2d= img.createGraphics(); g2d.drawImage(srcImage, 0, 0, null); g2d.dispose(); return img; } }