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

org.fuzzydb.util.JpegManipulator Maven / Gradle / Ivy

Go to download

Contains classes not specific to fuzzydb implementation which could be used in any implementation of fuzzy matching, or as general utility classes such as those in the geo package.

The newest version!
/******************************************************************************
 * Copyright (c) 2004-2008 Whirlwind Match Limited. All rights reserved.
 *
 * This is open source software; you can use, redistribute and/or modify
 * it under the terms of the Open Software Licence v 3.0 as published by the 
 * Open Source Initiative.
 *
 * You should have received a copy of the Open Software Licence along with this
 * application. if not, contact the Open Source Initiative (www.opensource.org)
 *****************************************************************************/
package org.fuzzydb.util;

import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;


public class JpegManipulator {
	public static class Jpeg {
		private byte[] data;
		private int width;
		private int height;
		
		public Jpeg(byte[] data) throws IOException {
			if (data != null) {
				int soi_index = 0;
				this.data = data;

				// First check it looks like a jpeg. First find start-of-image marker FFD8
				int jpeg = 0;
				boolean soi = false;
				byte hi_soi = (byte)0xff;
				byte lo_soi = (byte)0xd8;
				while (jpeg < data.length-2 && !soi) {
					if (data[jpeg] == hi_soi && data[jpeg+1] == lo_soi) {
						soi = true;
						jpeg += 2;
						soi_index = jpeg;
						break;	// break while
					}
					jpeg++;
				}
				
				if (!soi) throw new IOException("Missing JPEG Start of Image marker");
				
				// Must have APP0 or APP1 markers
				if (data[jpeg] != 0xff || (data[jpeg+1] != 0xe1 && data[jpeg+1] != 0xe0) ) if (!soi) throw new IOException("Missing APPx marker");
				
				/*
				// Now look for FFE0 jFIF marker
				boolean jfif = false;
				byte hi_jfif = (byte)0xff;
				byte lo_jfif = (byte)0xE0;
				while (jpeg < data.length-2 && !jfif) {
					if (data[jpeg] == hi_jfif && data[jpeg+1] == lo_jfif) {
						if (data[jpeg+4] == (byte)0x4A &&
								data[jpeg+5] == (byte)0x46 &&
								data[jpeg+6] == (byte)0x49 &&
								data[jpeg+7] == (byte)0x46 &&
								data[jpeg+8] == (byte)0x00) {
							jfif = true;
							break;	// break while
						}
					}
					jpeg++;
				}
				
				
				if (!jfif) throw new ImageFormatException("Missing JPEG JFIF marker");
				*/
				
				// Look for the SoF marker 0xFF{C0,C1,C2,C3 or CF} and pull out image width and height
				byte hi = (byte)0xff;
				byte lo_baseDCT = (byte)0xc0;	// Baseline DCT
				byte lo_extSeq = (byte)0xc1;	// Extended Sequential
				byte lo_progDCT = (byte)0xc2;	// Progressive DCT
				byte lo_lossSeq = (byte)0xc3;	// Lossless Sequential	(rare)
				byte lo_diffLoss = (byte)0xcf;	// Differential Lossless	(rare)
				int i = soi_index;
				while (i < data.length-8) {
					if (data[i] == hi && 
						((data[i+1] == lo_baseDCT) || (data[i+1] == lo_extSeq) || (data[i+1] == lo_progDCT) ||
						(data[i+1] == lo_lossSeq) || (data[i+1] == lo_diffLoss))) {
						height = 0xff & data[i+5];
						height <<= 8;
						height |= 0xff & data[i+6];
						width = 0xff & data[i+7];
						width <<= 8;
						width |= 0xff & data[i+8];
						return;
					} else if (data[i] == (byte)0xff) {
						int skip = 0xff & data[i+2];
						skip <<= 8;
						skip |= 0xff & data[i+3];
						i += skip + 2;
					} else {
						i++;
					}
					
				}
			}
			throw new IOException("Missing JPEG Start of Frame marker");
		}
		
		public byte[] getData() {
			return data;
		}

		public int getHeight() {
			return height;
		}

		public int getWidth() {
			return width;
		}
	}
	
	private JpegManipulator() {
		// static only
	}
	
	public static BufferedImage decodeImage(byte[] data) throws IOException {

        Iterator iterator = ImageIO.getImageReadersByFormatName("jpeg");
        ImageReader reader = iterator.next();

        ByteArrayInputStream bis = new ByteArrayInputStream(data);
		ImageInputStream iis = ImageIO.createImageInputStream(bis);
        reader.setInput(iis);
	    BufferedImage bi = reader.read(0);
	    return bi;
	}
	
	public static byte[] encodeImage(BufferedImage image, float quality) throws IOException {
		assert(quality>=0.0 && quality <= 1.0);

        Iterator iterator = ImageIO.getImageWritersByFormatName("jpeg");
        ImageWriter writer = iterator.next();
        ImageWriteParam p = writer.getDefaultWriteParam();
        p.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        p.setCompressionQuality(quality);

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ImageOutputStream ios = ImageIO.createImageOutputStream(bos);
        writer.setOutput(ios);
        writer.write(null, new IIOImage(image, null, null), p);
        ios.flush();
        writer.dispose();
        ios.close();

		return bos.toByteArray();
	}

	
	public static BufferedImage limitSize(BufferedImage input, int maxWidth, int maxHeight) {
		
		float wScale = input.getWidth();
		wScale /= maxWidth;
		float hScale = input.getHeight();
		hScale /= maxHeight;
		
		double max = Math.max(wScale, hScale);
		if (max <= 1.0) return input;	// no rescale required

		int newWidth = input.getWidth();
		int newHeight = input.getHeight();
		
		if (wScale > hScale) {
			// width is controlling dimension
			newHeight /= wScale;
			newWidth = maxWidth;
		} else {
			// height is controlling dimension
			newHeight = maxHeight;
			newWidth /= hScale;
		}
		
		assert(newWidth <= maxWidth);
		assert(newHeight <= maxHeight);
		
		BufferedImage output=input;
		
		while (max > 2.0) {
			AffineTransform tx = AffineTransform.getScaleInstance(0.5, 0.5);
			AffineTransformOp scaleOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
			output = new BufferedImage(input.getWidth()/2, input.getHeight()/2, input.getType());
			scaleOp.filter(input, output);
			input = output;
			max /= 2.0;
		}
		
		if (max > 1.0) {
			AffineTransform tx = AffineTransform.getScaleInstance(1.0/max, 1.0/max);
			AffineTransformOp scaleOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_BICUBIC);
			output = new BufferedImage(newWidth, newHeight, input.getType());
			scaleOp.filter(input, output);
		}
		
		return output;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy