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

org.nervousync.utils.ImageUtils Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Licensed to the Nervousync Studio (NSYC) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.nervousync.utils;

import java.awt.AlphaComposite;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Optional;

import javax.imageio.ImageIO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.nervousync.beans.image.CutOptions;
import org.nervousync.beans.image.MarkOptions;
import org.nervousync.beans.image.MarkOptions.MarkPosition;
import org.nervousync.commons.core.Globals;

/**
 * Image utils
 * implements:
 * Resize image by ratio
 * Resize image to target width/height
 * Retrieve image width value
 * Retrieve image height value
 * Cut image
 * @author Steven Wee	[email protected]
 * @version $Revision: 1.0 $ $Date: May 1, 2018 1:49:46 PM $
 */
public final class ImageUtils {

	private static final Logger LOGGER = LoggerFactory.getLogger(ImageUtils.class);

	private ImageUtils() {
	}

	/**
	 * Read image width
	 * @param imagePath		image file path
	 * @return	image width value
	 */
	public static int imageWidth(final String imagePath) {
		if (FileUtils.isExists(imagePath) && FileUtils.imageFile(imagePath)) {
			try {
				BufferedImage srcImage = ImageIO.read(FileUtils.getFile(imagePath));
				return srcImage.getWidth(null);
			} catch (Exception e) {
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug("Read picture error! ", e);
				}
			}
		}
		return Globals.DEFAULT_VALUE_INT;
	}

	/**
	 * Read image height
	 * @param imagePath		image file path
	 * @return	image height value
	 */
	public static int imageHeight(final String imagePath) {
		if (FileUtils.isExists(imagePath) && FileUtils.imageFile(imagePath)) {
			try {
				BufferedImage srcImage = ImageIO.read(FileUtils.getFile(imagePath));
				return srcImage.getHeight(null);
			} catch (Exception e) {
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug("Read picture error! ", e);
				}
			}
		}
		return Globals.DEFAULT_VALUE_INT;
	}

	/**
	 * Read the image ratio
	 * @param imagePath		image file path
	 * @return  image ratio
	 */
	public static double imageRatio(final String imagePath) {
		double imageHeight = ImageUtils.imageHeight(imagePath);
		double imageWidth = ImageUtils.imageHeight(imagePath);

		if (imageHeight == Globals.DEFAULT_VALUE_DOUBLE || imageWidth == Globals.DEFAULT_VALUE_DOUBLE) {
			return Globals.DEFAULT_VALUE_DOUBLE;
		}

		return imageWidth / imageHeight;
	}

	/**
	 * Cut image
	 * @param origPath			original image file path
	 * @param destPath			target output file path
	 * @param cutOptions		cut options
	 * @return		truesuccess	falsefailed
	 */
	public static boolean cutImage(final String origPath, final String destPath, final CutOptions cutOptions) {
		if (origPath != null && FileUtils.isExists(origPath) && cutOptions != null) {
			if (cutOptions.getPositionX() + cutOptions.getCutWidth() > ImageUtils.imageWidth(origPath)) {
				LOGGER.error("Width is out of original file");
				return Boolean.FALSE;
			}
			if (cutOptions.getPositionY() + cutOptions.getCutHeight() > ImageUtils.imageHeight(origPath)) {
				LOGGER.error("Height is out of original file");
				return Boolean.FALSE;
			}

			try {
				BufferedImage srcImage = ImageIO.read(FileUtils.getFile(origPath));
				BufferedImage bufferedImage =
						new BufferedImage(cutOptions.getCutWidth(), cutOptions.getCutHeight(),
								BufferedImage.TYPE_INT_RGB);

				for (int i = 0 ; i < cutOptions.getCutWidth() ; i++) {
					for (int j = 0 ; j < cutOptions.getCutHeight() ; j++) {
						bufferedImage.setRGB(i, j,
								srcImage.getRGB(cutOptions.getPositionX() + i, cutOptions.getPositionY() + j));
					}
				}

				return ImageIO.write(bufferedImage, StringUtils.getFilenameExtension(destPath), FileUtils.getFile(destPath));
			} catch (Exception e) {
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug("Read picture error! ", e);
				}
			}
		}
		return Boolean.FALSE;
	}

	/**
	 * Resize picture by given ratio
	 * @param origPath		original picture file path
	 * @param destPath		target picture file path
	 * @param ratio			resize ratio
	 * @return		truesuccess	falsefailed
	 */
	public static boolean resizeByRatio(final String origPath, final String destPath, final double ratio) {
		return ImageUtils.resizeByRatio(origPath, destPath, ratio, null);
	}

	/**
	 * Resize picture by given ratio
	 * @param origPath		original picture file path
	 * @param destPath		target picture file path
	 * @param ratio			resize ratio
	 * @param markOptions	mark options
	 * @see MarkOptions
	 * @return		truesuccess	falsefailed
	 */
	public static boolean resizeByRatio(final String origPath, final String destPath, final double ratio,
	                                    final MarkOptions markOptions) {
		if (FileUtils.isExists(origPath) && FileUtils.imageFile(origPath) && ratio > 0) {
			try {
				BufferedImage srcImage = ImageIO.read(FileUtils.getFile(origPath));

				int origWidth = srcImage.getWidth(null);
				int origHeight = srcImage.getHeight(null);

				int targetWidth = Double.valueOf(origWidth * ratio).intValue();
				int targetHeight = Double.valueOf(origHeight * ratio).intValue();

				return ImageIO.write(processImage(srcImage, targetWidth, targetHeight, markOptions),
						StringUtils.getFilenameExtension(destPath),
						FileUtils.getFile(destPath));
			} catch (Exception e) {
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug("Resize picture error! ", e);
				}
			}
		}
		return Boolean.FALSE;
	}

	/**
	 * Resize picture with given width and height
	 * @param origPath			original picture file path
	 * @param destPath			target picture file path
	 * @param targetWidth		target width	(if -1 width will auto set by height ratio)
	 * @param targetHeight		target height	(if -1 height will auto set by width ratio)
	 * @return		truesuccess	falsefailed
	 */
	public static boolean resizeTo(final String origPath, final String destPath,
	                               final int targetWidth, final int targetHeight) {
		return ImageUtils.resizeTo(origPath, destPath, targetWidth, targetHeight, null);
	}

	/**
	 * Resize picture with given width and height
	 * @param origPath			original picture file path
	 * @param destPath			target picture file path
	 * @param targetWidth		target width	(if -1 width will auto set by height ratio)
	 * @param targetHeight		target height	(if -1 height will auto set by width ratio)
	 * @param markOptions		mark options
	 * @see MarkOptions
	 * @return		truesuccess	falsefailed
	 */
	public static boolean resizeTo(final String origPath, final String destPath,
	                               final int targetWidth, final int targetHeight, final MarkOptions markOptions) {
		if (FileUtils.isExists(origPath) && FileUtils.imageFile(origPath)
				&& (targetWidth > 0 || targetHeight > 0)) {
			try {
				BufferedImage srcImage = ImageIO.read(FileUtils.getFile(origPath));

				int origWidth = srcImage.getWidth(null);
				int origHeight = srcImage.getHeight(null);

				int resizeWidth;
				if (targetWidth == Globals.DEFAULT_VALUE_INT) {
					double ratio = targetHeight * 1.0 / origHeight;
					resizeWidth = Double.valueOf(ratio * origWidth).intValue();
				} else {
					resizeWidth = targetWidth;
				}

				int resizeHeight;
				if (targetHeight == Globals.DEFAULT_VALUE_INT) {
					double ratio = targetWidth * 1.0 / origWidth;
					resizeHeight = Double.valueOf(ratio * origHeight).intValue();
				} else {
					resizeHeight = targetHeight;
				}

				return ImageIO.write(processImage(srcImage, resizeWidth, resizeHeight, markOptions),
						StringUtils.getFilenameExtension(destPath), FileUtils.getFile(destPath));
			} catch (Exception e) {
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug("Resize picture error! ", e);
				}
			}
		}
		return Boolean.FALSE;
	}

	/**
	 * Mark image
	 * @param filePath          original picture file path
	 * @param targetPath        target picture file path
	 * @param markOptions       mark options
	 * @return                  operate result
	 */
	public static boolean markImage(final String filePath, final String targetPath, final MarkOptions markOptions) {
		int imageWidth = ImageUtils.imageWidth(filePath);
		int imageHeight = ImageUtils.imageHeight(filePath);
		try {
			BufferedImage bufferedImage = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
			return ImageIO.write(processImage(bufferedImage, imageWidth, imageHeight, markOptions),
					StringUtils.getFilenameExtension(targetPath),
					FileUtils.getFile(targetPath));
		} catch (Exception e) {
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("Mark picture error! ", e);
			}
		}
		return Boolean.FALSE;
	}

	/**
	 * Calculate dHash hamming between original image and target image
	 * @param origPath			original picture file path
	 * @param destPath			target picture file path
	 * @return                  Hamming result
	 */
	public static int dHashHamming(final String origPath, final String destPath) {
		String origHash = ImageUtils.dHash(origPath);
		String destHash = ImageUtils.dHash(destPath);
		int diff = 0;
		for (int j = 0 ; j < origHash.length() ; j++) {
			diff += (origHash.charAt(j) ^ destHash.charAt(j));
		}
		return diff;
	}

	/**
	 * Calculate pHash hamming between original image and target image
	 * @param origPath			original picture file path
	 * @param destPath			target picture file path
	 * @return                  Hamming result
	 */
	public static int pHashHamming(final String origPath, final String destPath) {
		String origHash = ImageUtils.pHash(origPath);
		String destHash = ImageUtils.pHash(destPath);
		int diff = 0;
		for (int j = 0 ; j < origHash.length() ; j++) {
			diff += (origHash.charAt(j) ^ destHash.charAt(j));
		}
		return diff;
	}

	/**
	 * dHash signature
	 * @param filePath  picture file path
	 * @return          signature value
	 */
	public static String dHash(final String filePath) {
		try {
			return ImageUtils.dHash(FileUtils.getFile(filePath));
		} catch (FileNotFoundException e) {
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("Calculate picture pHash error! ", e);
			}
			return Globals.DEFAULT_VALUE_STRING;
		}
	}

	/**
	 * dHash signature
	 * @param file      picture file instance
	 * @return          signature value
	 */
	public static String dHash(final File file) {
		try {
			return ImageUtils.dHash(ImageIO.read(file));
		} catch (IOException e) {
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("Calculate picture pHash error! ", e);
			}
			return Globals.DEFAULT_VALUE_STRING;
		}
	}

	/**
	 * dHash signature
	 * @param bufferedImage     picture file with bufferedImage instance
	 * @return                  signature value
	 */
	public static String dHash(final BufferedImage bufferedImage) {
		BufferedImage prepareImage;
		if (bufferedImage.getWidth() != 9 || bufferedImage.getHeight() != 8) {
			prepareImage = ImageUtils.processImage(bufferedImage, 9, 8, null);
		} else {
			prepareImage = bufferedImage;
		}

		double[][] grayMatrix = ImageUtils.grayMatrix(prepareImage);
		StringBuilder pHash = new StringBuilder();
		for (int x = 0 ; x < 8 ; x++) {
			for (int y = 0 ; y < 8 ; y++) {
				pHash.append((grayMatrix[x][y] > grayMatrix[x][y + 1]) ? "1" : "0");
			}
		}
		return pHash.toString();
	}

	/**
	 * pHash signature
	 * @param filePath  picture file path
	 * @return          signature value
	 */
	public static String pHash(final String filePath) {
		try {
			return ImageUtils.pHash(FileUtils.getFile(filePath));
		} catch (FileNotFoundException e) {
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("Calculate picture pHash error! ", e);
			}
			return Globals.DEFAULT_VALUE_STRING;
		}
	}

	/**
	 * pHash signature
	 * @param file      picture file instance
	 * @return          signature value
	 */
	public static String pHash(final File file) {
		try {
			return ImageUtils.pHash(ImageIO.read(file));
		} catch (IOException e) {
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("Calculate picture pHash error! ", e);
			}
			return Globals.DEFAULT_VALUE_STRING;
		}
	}

	/**
	 * pHash signature
	 * @param bufferedImage     picture file with bufferedImage instance
	 * @return                  signature value
	 */
	public static String pHash(final BufferedImage bufferedImage) {
		BufferedImage prepareImage;
		if (bufferedImage.getWidth() != 8 || bufferedImage.getHeight() != 8) {
			prepareImage = ImageUtils.processImage(bufferedImage, 8, 8, null);
		} else {
			prepareImage = bufferedImage;
		}

		double[][] DCT = ImageUtils.applyDCT(prepareImage);
		double total = 0.0;
		for (int x = 0 ; x < 8 ; x++) {
			for (int y = 0 ; y < 8 ; y++) {
				total += DCT[x][y];
			}
		}
		total -= DCT[0][0];
		double average = total / 63;
		StringBuilder pHash = new StringBuilder();
		for (int x = 0 ; x < 8 ; x++) {
			for (int y = 0 ; y < 8 ; y++) {
				pHash.append((DCT[x][y] > average) ? "1" : "0");
			}
		}
		return pHash.toString();
	}

	/**
	 * Process image mark
	 * @param graphics			target image graphics object
	 * @param width				image width
	 * @param height			image height
	 * @param markOptions		image mark options
	 */
	private static void markImage(final Graphics2D graphics, final int width, final int height,
	                              final MarkOptions markOptions) {
		MarkPosition markPosition = markOptions.retrievePosition(width, height);

		if (markPosition != null) {
			switch (markOptions.getMarkType()) {
			case ICON:
				try {
					BufferedImage iconImg = ImageIO.read(FileUtils.getFile(markOptions.getMarkPath()));
					if (iconImg != null && markOptions.getTransparency() >= 0
							&& markOptions.getTransparency() <= 1) {
						graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
								markOptions.getTransparency()));
						graphics.drawImage(iconImg, markPosition.getPositionX(), markPosition.getPositionY(), null);

						graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
					}
				} catch (Exception e) {
					if (LOGGER.isDebugEnabled()) {
						LOGGER.debug("Read icon file error! ", e);
					}
				}
				break;
			case TEXT:
				if (markOptions.getMarkText() != null && markOptions.getFontName() != null
						&& markOptions.getFontSize() > 0) {
					graphics.setColor(markOptions.getColor());
					graphics.setFont(new Font(markOptions.getFontName(), Font.PLAIN, markOptions.getFontSize()));

					graphics.drawString(markOptions.getMarkText(), markPosition.getPositionX(), markPosition.getPositionY());
				}
				break;
			}
		}
	}

	/**
	 * Process image operates
	 * @param srcImage				original image object
	 * @param targetWidth			target width
	 * @param targetHeight			target height
	 * @param markOptions			image mark options
	 * @return		truesuccess	falsefailed
	 */
	private static BufferedImage processImage(final BufferedImage srcImage, final int targetWidth,
	                                          final int targetHeight, final MarkOptions markOptions) {
		if (srcImage != null && targetWidth > 0 && targetHeight > 0) {
			try {
				BufferedImage bufferedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
				Graphics2D graphics = bufferedImage.createGraphics();
				graphics.drawImage(srcImage, 0, 0, targetWidth, targetHeight, null);

				Optional.ofNullable(markOptions)
						.ifPresent(options -> markImage(graphics, targetWidth, targetHeight, options));
				graphics.dispose();

				return bufferedImage;
			} catch (Exception e) {
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug("Resize picture error! ", e);
				}
			}
		}
		return srcImage;
	}

	/**
	 * Convert bufferedImage to grayMatrix
	 * @param bufferedImage     BufferedImage instance
	 * @return                  Gray matrix
	 */
	private static double[][] grayMatrix(final BufferedImage bufferedImage) {
		if (bufferedImage == null) {
			return new double[0][0];
		}
		int width = bufferedImage.getWidth();
		int height = bufferedImage.getHeight();
		double[][] grayMatrix = new double[height][width];
		for (int y = 0 ; y < height ; y++) {
			for (int x = 0 ; x < width ; x++) {
				int pixel = bufferedImage.getRGB(x, y);
				grayMatrix[y][x] = ((pixel & 0xFF0000) >> 16) * 0.3
						+ ((pixel & 0xFF00) >> 8) * 0.59
						+ ((pixel & 0xFF) * 0.11);
			}
		}
		return grayMatrix;
	}

	/**
	 * Convert bufferedImage to DCT matrix
	 * @param bufferedImage     BufferedImage instance
	 * @return                  DCT matrix
	 */
	private static double[][] applyDCT(final BufferedImage bufferedImage) {
		if (bufferedImage == null) {
			return new double[0][0];
		}
		int width = bufferedImage.getWidth();
		int height = bufferedImage.getHeight();
		int length = Math.max(width, height);
		double[] uv = new double[length];
		for (int i = 1 ; i < length ; i++) {
			uv[i] = 1;
		}
		uv[0] = 1 / Math.sqrt(2.0);
		double[][] DCT = new double[width][height];
		for (int x = 0 ; x < width ; x++) {
			for (int y = 0 ; y < height ; y++) {
				double sum = 0.0;
				int pixel = bufferedImage.getRGB(x, y);
				double gray = ((pixel & 0xFF0000) >> 16) * 0.3
						+ ((pixel & 0xFF00) >> 8) * 0.59
						+ ((pixel & 0xFF) * 0.11);
				for (int i = 0 ; i < width ; i++) {
					for (int j = 0 ; j < height ; j++) {
						sum += Math.cos(((2 * i + 1) / (width * height * 1.0)) * x * Math.PI)
								* Math.cos(((2 * j + 1) / (width * height * 1.0)) * y * Math.PI)
								* gray;
					}
				}
				DCT[x][y] = sum * ((uv[x] * uv[y]) / 4.0);
			}
		}
		return DCT;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy