All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mortennobel.imagescaling.ImageUtils Maven / Gradle / Ivy

Go to download

The purpose of the library is to provide better image scaling options than the Java runtime provides.

The newest version!
/*
 * Copyright 2013, Morten Nobel-Joergensen
 *
 * License: The BSD 3-Clause License
 * http://opensource.org/licenses/BSD-3-Clause
 */
package com.mortennobel.imagescaling;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.*;
import java.util.Iterator;

/**
 * @author Heinz Doerr
 * @author Morten Nobel-Joergensen
 */
public class ImageUtils {


	static public String imageTypeName(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();
	}

	static public int nrChannels(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(BufferedImage img, int y, int w, byte[] array, 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
	 *
	 */
	public static void setBGRPixels(byte[] bgrPixels, BufferedImage img, int x, int y, int w, 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);
			}
		}
	}


	public static void ints2bytes(int[] in, byte[] out, int index1, int index2, 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;
		}
	}

	public static void ints2bytes(int[] in, byte[] out, int index1, int index2, int index3, 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;
		}
	}

	public static int[] bytes2int(byte[] in, int index1, int index2, 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;
	}

	public static int[] bytes2int(byte[] in, int index1, int index2, int index3, 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;
	}

	public static BufferedImage convert(BufferedImage src, int bufImgType) {
		BufferedImage img= new BufferedImage(src.getWidth(), src.getHeight(), bufImgType);
		Graphics2D g2d= img.createGraphics();
		g2d.drawImage(src, 0, 0, null);
		g2d.dispose();
		return img;
	}

    /**
     * Copy jpeg meta data (exif) from source to dest and save it to out.
     *
     * @param source
     * @param dest
     * @return result
     * @throws IOException
     */
    public static byte[] copyJpegMetaData(byte[] source, byte[] dest) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageOutputStream out = new MemoryCacheImageOutputStream(baos);
        copyJpegMetaData(new ByteArrayInputStream(source),new ByteArrayInputStream(dest), out);
        return baos.toByteArray();
    }

    /**
     * Copy jpeg meta data (exif) from source to dest and save it to out
     *
     * @param source
     * @param dest
     * @param out
     * @throws IOException
     */
    public static void copyJpegMetaData(InputStream source, InputStream dest, ImageOutputStream out) throws IOException {
        // Read meta data from src image
        Iterator iter = ImageIO.getImageReadersByFormatName("jpeg");
        ImageReader reader=(ImageReader) iter.next();
        ImageInputStream iis = new MemoryCacheImageInputStream(source);
        reader.setInput(iis);
        IIOMetadata metadata = reader.getImageMetadata(0);
        iis.close();
        // Read dest image
        ImageInputStream outIis = new MemoryCacheImageInputStream(dest);
        reader.setInput(outIis);
        IIOImage image = reader.readAll(0,null);
        image.setMetadata(metadata);
        outIis.close();
        // write dest image
        iter = ImageIO.getImageWritersByFormatName("jpeg");
        ImageWriter writer=(ImageWriter) iter.next();
        writer.setOutput(out);
        writer.write(image);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy