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.nervousync.beans.image.CutOptions;
import org.nervousync.beans.image.MarkOptions;
import org.nervousync.commons.Globals;

/**
 * 

Image Utilities

*

图片工具集

* * @author Steven Wee [email protected] * @version $Revision: 1.2.0 $ $Date: May 1, 2018 13:49:46 $ */ public final class ImageUtils { /** * Logger instance * 日志实例 */ private static final LoggerUtils.Logger LOGGER = LoggerUtils.getLogger(ImageUtils.class); /** *

Private constructor for ImageUtils

*

图片工具集的私有构造方法

*/ private ImageUtils() { } /** *

Retrieve image width value

*

获取图片宽度

* * @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) { LOGGER.error("Read_Image_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } } } return Globals.DEFAULT_VALUE_INT; } /** *

Retrieve image height value

*

获取图片高度

* * @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) { LOGGER.error("Read_Image_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } } } return Globals.DEFAULT_VALUE_INT; } /** *

Retrieve image ratio value

*

获取图片宽高比

* * @param imagePath Image file path * 图片地址 * * @return Image ratio value * 图片宽高比 */ 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 original image file and save to target path by given cut options

*

根据给定的切割参数对原始图片进行切割并存储到目标地址

* * @param origPath original image file path * 原始图片地址 * @param targetPath target image file path * 目标图片地址 * @param cutOptions cut options * 切割参数 * * @return Cut process result * 切割处理结果 */ public static boolean cutImage(final String origPath, final String targetPath, final CutOptions cutOptions) { if (origPath != null && FileUtils.isExists(origPath) && cutOptions != null) { if (cutOptions.getPositionX() + cutOptions.getCutWidth() > ImageUtils.imageWidth(origPath)) { LOGGER.error("Width_Exceeds_Original_Image_Error"); return Boolean.FALSE; } if (cutOptions.getPositionY() + cutOptions.getCutHeight() > ImageUtils.imageHeight(origPath)) { LOGGER.error("Height_Exceeds_Original_Image_Error"); 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(targetPath), FileUtils.getFile(targetPath)); } catch (Exception e) { LOGGER.error("Cut_Image_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } } } return Boolean.FALSE; } /** *

Resize original image file and save to target path by given ratio value

*

根据给定的缩放比例对原始图片进行放大/缩小并存储到目标地址

* * @param origPath original image file path * 原始图片地址 * @param targetPath target image file path * 目标图片地址 * @param ratio ratio value * 缩放比例 * * @return Resize process result * 修改尺寸处理结果 */ public static boolean resizeByRatio(final String origPath, final String targetPath, final double ratio) { return ImageUtils.resizeByRatio(origPath, targetPath, ratio, null); } /** *

Resize original image file and save to target path by given ratio value, and add mark to target image if configured

*

根据给定的缩放比例对原始图片进行放大/缩小并存储到目标地址,并添加水印到目标图片(如果设置了水印选项)

* * @param origPath original image file path * 原始图片地址 * @param targetPath target image file path * 目标图片地址 * @param ratio ratio value * 缩放比例 * @param markOptions Mark options * 水印选项 * * @return Resize process result * 修改尺寸处理结果 */ public static boolean resizeByRatio(final String origPath, final String targetPath, 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(targetPath), FileUtils.getFile(targetPath)); } catch (Exception e) { LOGGER.error("Resize_Image_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } } } return Boolean.FALSE; } /** *

Resize original image file to the given width and height, save to target path

*

将原始图片调整到指定的宽度、高度,并存储到目标地址

* * @param origPath original image file path * 原始图片地址 * @param targetPath target image file path * 目标图片地址 * @param targetWidth target width (if -1 width will auto set by height ratio) * 图片调整后的宽度,如果值为-1则自动根据图片宽高比进行调整 * @param targetHeight target height (if -1 height will auto set by width ratio) * 图片调整后的高度,如果值为-1则自动根据图片宽高比进行调整 * * @return Resize process result * 修改尺寸处理结果 */ public static boolean resizeTo(final String origPath, final String targetPath, final int targetWidth, final int targetHeight) { return ImageUtils.resizeTo(origPath, targetPath, targetWidth, targetHeight, null); } /** *

Resize original image file to the given width and height, save to target path, and add mark to target image if configured

*

将原始图片调整到指定的宽度、高度,并存储到目标地址,并添加水印到目标图片(如果设置了水印选项)

* * @param origPath original image file path * 原始图片地址 * @param targetPath target image file path * 目标图片地址 * @param targetWidth target width (if -1 width will auto set by height ratio) * 图片调整后的宽度,如果值为-1则自动根据图片宽高比进行调整 * @param targetHeight target height (if -1 height will auto set by width ratio) * 图片调整后的高度,如果值为-1则自动根据图片宽高比进行调整 * @param markOptions Mark options * 水印选项 * * @return Resize process result * 修改尺寸处理结果 */ public static boolean resizeTo(final String origPath, final String targetPath, 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(targetPath), FileUtils.getFile(targetPath)); } catch (Exception e) { LOGGER.error("Resize_Image_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } } } return Boolean.FALSE; } /** *

Add mark to original image and save result image to target path

*

添加水印到原始图片,并将添加好水印的图片保存到目标地址

* * @param origPath original image file path * 原始图片地址 * @param targetPath target image file path * 目标图片地址 * @param markOptions Mark options * 水印选项 * * @return Mark process result * 添加水印处理结果 */ public static boolean markImage(final String origPath, final String targetPath, final MarkOptions markOptions) { int imageWidth = ImageUtils.imageWidth(origPath); int imageHeight = ImageUtils.imageHeight(origPath); 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) { LOGGER.error("Water_Mark_Image_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } } return Boolean.FALSE; } /** *

Calculate dHash hamming between original image and target image

*

计算原始图片和目标图片间差异值哈希的汉明距离

* * @param origPath original image file path * 原始图片地址 * @param targetPath target image file path * 目标图片地址 * * @return Calculated hamming result * 计算的汉明距离 */ public static int dHashHamming(final String origPath, final String targetPath) { String origHash = ImageUtils.dHash(origPath); String destHash = ImageUtils.dHash(targetPath); 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 image file path * 原始图片地址 * @param targetPath target image file path * 目标图片地址 * * @return Calculated hamming result * 计算的汉明距离 */ public static int pHashHamming(final String origPath, final String targetPath) { String origHash = ImageUtils.pHash(origPath); String destHash = ImageUtils.pHash(targetPath); int diff = 0; for (int j = 0 ; j < origHash.length() ; j++) { diff += (origHash.charAt(j) ^ destHash.charAt(j)); } return diff; } /** *

Calculate dHash of given image file

*

计算给定图片的差异值哈希

* * @param filePath Image file path * 图片文件地址 * * @return dHash string * 差异值哈希字符串 */ public static String dHash(final String filePath) { try { return ImageUtils.dHash(FileUtils.getFile(filePath)); } catch (FileNotFoundException e) { LOGGER.error("Not_Found_File_Error", filePath); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } return Globals.DEFAULT_VALUE_STRING; } } /** *

Calculate dHash of given image file

*

计算给定图片的差异值哈希

* * @param file Image file instance * 图片文件实例对象 * * @return dHash string * 差异值哈希字符串 */ public static String dHash(final File file) { try { return ImageUtils.dHash(ImageIO.read(file)); } catch (IOException e) { LOGGER.error("Read_Files_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } return Globals.DEFAULT_VALUE_STRING; } } /** *

Calculate dHash of given image file

*

计算给定图片的差异值哈希

* * @param bufferedImage Buffered image * 缓冲图片实例对象 * * @return dHash string * 差异值哈希字符串 */ 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 dHash = new StringBuilder(); for (int x = 0 ; x < 8 ; x++) { for (int y = 0 ; y < 8 ; y++) { dHash.append((grayMatrix[x][y] > grayMatrix[x][y + 1]) ? "1" : "0"); } } return dHash.toString(); } /** *

Calculate pHash of given image file

*

计算给定图片的感知哈希

* * @param filePath Image file path * 图片文件地址 * * @return pHash string * 感知哈希字符串 */ public static String pHash(final String filePath) { try { return ImageUtils.pHash(FileUtils.getFile(filePath)); } catch (FileNotFoundException e) { LOGGER.error("Not_Found_File_Error", filePath); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } return Globals.DEFAULT_VALUE_STRING; } } /** *

Calculate pHash of given image file

*

计算给定图片的感知哈希

* * @param file Image file instance * 图片文件实例对象 * * @return pHash string * 感知哈希字符串 */ public static String pHash(final File file) { try { return ImageUtils.pHash(ImageIO.read(file)); } catch (IOException e) { LOGGER.error("Read_Files_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } return Globals.DEFAULT_VALUE_STRING; } } /** *

Calculate pHash of given image file

*

计算给定图片的感知哈希

* * @param bufferedImage Buffered image * 缓冲图片实例对象 * * @return pHash string * 感知哈希字符串 */ 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(); } /** *

Add text/image watermark to the target image

*

添加文字/图片水印到目标图片

* * @param graphics target image Graphics2D object * 目标图片的Graphics2D实例对象 * @param width image width * 图片宽度 * @param height image height * 图片高度 * @param markOptions Mark options * 水印选项 */ private static void markImage(final Graphics2D graphics, final int width, final int height, final MarkOptions markOptions) { Optional.ofNullable(markOptions.retrievePosition(width, height)) .ifPresent(markPosition -> { 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) { LOGGER.error("Water_Mark_Image_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_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 by given parameters

*

根据给定的参数处理图片

* * @param srcImage Buffered image * 缓冲图片实例对象 * @param targetWidth target width * 图片调整后的宽度 * @param targetHeight target height * 图片调整后的高度 * @param markOptions 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) { 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; } return srcImage; } /** *

Convert bufferedImage to gray matrix

*

转换缓冲图片实例对象为灰度二维数组

* * @param bufferedImage Buffered image * 缓冲图片实例对象 * * @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; } /** *

Process Discrete Cosine Transform to bufferedImage

*

对给定的缓冲图片实例对象做离散余弦变换

* * @param bufferedImage Buffered image * 缓冲图片实例对象 * * @return Process result * 处理结果 */ 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