java中经常需要上传图片,对图片类型进行校验,常常使用的校验是通过文件后缀或者getContentType来判断文件类型是否符合,但是如果你使用了flash上传,有可能得到的图片类型为:application/octet-stream(任意的二进制数),如果你将这个类型加入到了判断条件里边实际上就没有多大意义了,所以确切的文件类型校验就需要如下判断了。所以可以考虑如下操作。
java图片处理类包含如下类:
第一:图片类型类:
- /**
- * 图片类型
- *
- * @author
- * @since 2010-5-19
- */
- public enum ImageType {
- unknown(0, "unknown"), jpg(1, "jpg"), gif(2, "gif"), png(3, "png"), bmp(4,
- "bmp");
- private int code;
- private String name;
- ImageType(int code, String name) {
- this.code = code;
- this.name = name;
- }
- public int getCode() {
- return code;
- }
- public String getName() {
- return name;
- }
- /**
- * 将后缀转换成图片类型, JPEG将转成jpg
- *
- * @param suffix
- * @return
- */
- public static ImageType toImageType(String suffix) {
- if (suffix == null || "".equals(suffix)) {
- return unknown;
- }
- suffix = suffix.toLowerCase();
- if ("jpeg".equals(suffix)) {
- suffix = "jpg";
- }
- try {
- return valueOf(suffix);
- } catch (Exception e) {
- return unknown;
- }
- }
- /**
- * 判断图片类型
- *
- * @param suffix
- * @return
- */
- public static boolean isAcceptType(String suffix) {
- if (suffix == null || "".equals(suffix)) {
- return false;
- }
- if ("jpeg".equalsIgnoreCase(suffix)) {
- return true;
- }
- ImageType type = ImageType.valueOf(suffix.toLowerCase());
- if (type != null && type.getCode() > 0 && type.getCode() < 5) {
- return true;
- }
- return false;
- }
- public static boolean isAcceptType(ImageType type) {
- if (type == null) {
- return false;
- }
- return isAcceptType(type.getName());
- }
- }
图片扩展信息类:
- import java.io.Serializable;
- /**
- * JPG的EXIT信息 ,相关规范参考: 1.* EXIF.org http://www.exif.org/ 2.* Opanda
- * http://www.opanda.com/cn/iexif/exif.htm 3.* EXIF 2.1
- * 官方标准(PDF文档)http://www.exif.org/Exif2-1.PDF 4.* EXIF 2.2
- * 官方标准(PDF文档)http://www.exif.org/Exif2-2.PDF 5.* EXIF 文件格式说明
- * http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
- *
- * @author
- * @since 2010-5-19
- */
- public class ImageExif implements Serializable {
- private static final long serialVersionUID = 4713490466591635082L;
- private String ImageDescription;// 图像描述、来源. 指生成图像的工具
- private String Artist;// 作者 有些相机可以输入使用者的名字
- private String Make;// 生产者 指产品生产厂家
- private String Model;// 型号 指设备型号
- private String Orientation;// 方向 有的相机支持,有的不支持
- private String XResolution; // X方向分辨率
- private String YResolution;// Y方向分辨率
- private String ResolutionUnit;// 分辨率单位 一般为PPI
- private String Software;// 软件 显示固件
- private String Firmware;// 版本
- private String DateTime;// 日期和时间
- private String YCbCrPositioning;// 色相定位
- private String ExifOffsetExif;// 信息位置,定义Exif在信息在文件中的写入,有些软件不显示。
- private String ExposureTime;// 曝光时间 即快门速度
- private String FNumber; // 光圈系数
- private String ExposureProgram;// 曝光程序 指程序式自动曝光的设置,各相机不同,可能是Sutter
- // Priority(快门优先)、Aperture Priority(快门优先)等等。
- private String IsoSpeedRatings;// 感光度
- private String ExifVersion;// Exif版本
- private String DateTimeOriginal;// 创建时间
- private String DateTimeDigitized;// 数字化时间
- private String ComponentsConfiguration;// 图像构造(多指色彩组合方案)
- private String CompressedBitsPerPixel;// (BPP)压缩时每像素色彩位 指压缩程度
- private String ExposureBiasValue;// 曝光补偿。
- private String MaxApertureValue;// 最大光圈
- private String MeteringMode;// 测光方式,平均式测光、中央重点测光、点测光等。
- private String Lightsource;// 光源 指白平衡设置
- private String Flash;// 是否使用闪光灯。
- private String FocalLength;// 焦距,一般显示镜头物理焦距,有些软件可以定义一个系数,从而显示相当于35mm相机的焦距
- private String MakerNote;// (User Comment)作者标记、说明、记录
- private String FlashPixVersionFlashPix;// 版本 (个别机型支持)
- private String ColorSpace;// 色域、色彩空间
- private String ExifImageWidth;// (Pixel X Dimension)图像宽度 指横向像素数
- private String ExifImageLength;// (Pixel Y Dimension)图像高度 指纵向像素数
- private String Interoperability;// IFD通用性扩展项定义指针 和TIFF文件相关,具体含义不详
- private String FileSource;// 源文件 Compression压缩比
- public String getImageDescription() {
- return ImageDescription;
- }
- public void setImageDescription(String imageDescription) {
- ImageDescription = imageDescription;
- }
- public String getArtist() {
- return Artist;
- }
- public void setArtist(String artist) {
- Artist = artist;
- }
- public String getMake() {
- return Make;
- }
- public void setMake(String make) {
- Make = make;
- }
- public String getModel() {
- return Model;
- }
- public void setModel(String model) {
- Model = model;
- }
- public String getOrientation() {
- return Orientation;
- }
- public void setOrientation(String orientation) {
- Orientation = orientation;
- }
- public String getXResolution() {
- return XResolution;
- }
- public void setXResolution(String xResolution) {
- XResolution = xResolution;
- }
- public String getYResolution() {
- return YResolution;
- }
- public void setYResolution(String yResolution) {
- YResolution = yResolution;
- }
- public String getResolutionUnit() {
- return ResolutionUnit;
- }
- public void setResolutionUnit(String resolutionUnit) {
- ResolutionUnit = resolutionUnit;
- }
- public String getSoftware() {
- return Software;
- }
- public void setSoftware(String software) {
- Software = software;
- }
- public String getFirmware() {
- return Firmware;
- }
- public void setFirmware(String firmware) {
- Firmware = firmware;
- }
- public String getDateTime() {
- return DateTime;
- }
- public void setDateTime(String dateTime) {
- DateTime = dateTime;
- }
- public String getYCbCrPositioning() {
- return YCbCrPositioning;
- }
- public void setYCbCrPositioning(String yCbCrPositioning) {
- YCbCrPositioning = yCbCrPositioning;
- }
- public String getExifOffsetExif() {
- return ExifOffsetExif;
- }
- public void setExifOffsetExif(String exifOffsetExif) {
- ExifOffsetExif = exifOffsetExif;
- }
- public String getExposureTime() {
- return ExposureTime;
- }
- public void setExposureTime(String exposureTime) {
- ExposureTime = exposureTime;
- }
- public String getFNumber() {
- return FNumber;
- }
- public void setFNumber(String fNumber) {
- FNumber = fNumber;
- }
- public String getExposureProgram() {
- return ExposureProgram;
- }
- public void setExposureProgram(String exposureProgram) {
- ExposureProgram = exposureProgram;
- }
- public String getIsoSpeedRatings() {
- return IsoSpeedRatings;
- }
- public void setIsoSpeedRatings(String isoSpeedRatings) {
- IsoSpeedRatings = isoSpeedRatings;
- }
- public String getExifVersion() {
- return ExifVersion;
- }
- public void setExifVersion(String exifVersion) {
- ExifVersion = exifVersion;
- }
- public String getDateTimeOriginal() {
- return DateTimeOriginal;
- }
- public void setDateTimeOriginal(String dateTimeOriginal) {
- DateTimeOriginal = dateTimeOriginal;
- }
- public String getDateTimeDigitized() {
- return DateTimeDigitized;
- }
- public void setDateTimeDigitized(String dateTimeDigitized) {
- DateTimeDigitized = dateTimeDigitized;
- }
- public String getComponentsConfiguration() {
- return ComponentsConfiguration;
- }
- public void setComponentsConfiguration(String componentsConfiguration) {
- ComponentsConfiguration = componentsConfiguration;
- }
- public String getCompressedBitsPerPixel() {
- return CompressedBitsPerPixel;
- }
- public void setCompressedBitsPerPixel(String compressedBitsPerPixel) {
- CompressedBitsPerPixel = compressedBitsPerPixel;
- }
- public String getExposureBiasValue() {
- return ExposureBiasValue;
- }
- public void setExposureBiasValue(String exposureBiasValue) {
- ExposureBiasValue = exposureBiasValue;
- }
- public String getMaxApertureValue() {
- return MaxApertureValue;
- }
- public void setMaxApertureValue(String maxApertureValue) {
- MaxApertureValue = maxApertureValue;
- }
- public String getMeteringMode() {
- return MeteringMode;
- }
- public void setMeteringMode(String meteringMode) {
- MeteringMode = meteringMode;
- }
- public String getLightsource() {
- return Lightsource;
- }
- public void setLightsource(String lightsource) {
- Lightsource = lightsource;
- }
- public String getFlash() {
- return Flash;
- }
- public void setFlash(String flash) {
- Flash = flash;
- }
- public String getFocalLength() {
- return FocalLength;
- }
- public void setFocalLength(String focalLength) {
- FocalLength = focalLength;
- }
- public String getMakerNote() {
- return MakerNote;
- }
- public void setMakerNote(String makerNote) {
- MakerNote = makerNote;
- }
- public String getFlashPixVersionFlashPix() {
- return FlashPixVersionFlashPix;
- }
- public void setFlashPixVersionFlashPix(String flashPixVersionFlashPix) {
- FlashPixVersionFlashPix = flashPixVersionFlashPix;
- }
- public String getColorSpace() {
- return ColorSpace;
- }
- public void setColorSpace(String colorSpace) {
- ColorSpace = colorSpace;
- }
- public String getExifImageWidth() {
- return ExifImageWidth;
- }
- public void setExifImageWidth(String exifImageWidth) {
- ExifImageWidth = exifImageWidth;
- }
- public String getExifImageLength() {
- return ExifImageLength;
- }
- public void setExifImageLength(String exifImageLength) {
- ExifImageLength = exifImageLength;
- }
- public String getInteroperability() {
- return Interoperability;
- }
- public void setInteroperability(String interoperability) {
- Interoperability = interoperability;
- }
- public String getFileSource() {
- return FileSource;
- }
- public void setFileSource(String fileSource) {
- FileSource = fileSource;
- }
- }
图片文件对象:
- import java.io.File;
- import java.io.Serializable;
- /**
- * 图片文件信息
- *
- * @author
- * @since 2010-5-19
- */
- public class ImageFile implements Serializable {
- private static final long serialVersionUID = -337911125594555523L;
- /**
- * 图片宽,单位:px
- */
- private double width;
- /**
- * 图片高,单位:px
- */
- private double height;
- /**
- * 图片大小,单位:byte
- */
- private double size;
- /**
- * 图片类型
- */
- private ImageType type;
- /**
- * 图片文件
- */
- private File file;
- /**
- * 图片EXIF信息
- */
- private ImageExif exif;
- public double getWidth() {
- return width;
- }
- public void setWidth(double width) {
- this.width = width;
- }
- public double getHeight() {
- return height;
- }
- public void setHeight(double height) {
- this.height = height;
- }
- public double getSize() {
- return size;
- }
- public void setSize(double size) {
- this.size = size;
- }
- public ImageType getType() {
- return type;
- }
- public void setType(ImageType type) {
- this.type = type;
- }
- public File getFile() {
- return file;
- }
- public void setFile(File file) {
- this.file = file;
- }
- public ImageExif getExif() {
- return exif;
- }
- public void setExif(ImageExif exif) {
- this.exif = exif;
- }
- }
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.Image;
- import java.awt.RenderingHints;
- import java.awt.Toolkit;
- import java.awt.image.BufferedImage;
- import java.awt.image.CropImageFilter;
- import java.awt.image.FilteredImageSource;
- import java.awt.image.ImageFilter;
- import java.awt.image.RenderedImage;
- import java.io.BufferedInputStream;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.lang.reflect.Method;
- import java.util.Iterator;
- import javax.imageio.ImageIO;
- import javax.imageio.ImageReader;
- import javax.imageio.stream.MemoryCacheImageInputStream;
- import magick.MagickImage;
- import org.apache.commons.lang.StringUtils;
- import com.sun.image.codec.jpeg.JPEGCodec;
- import com.sun.image.codec.jpeg.JPEGEncodeParam;
- import com.sun.image.codec.jpeg.JPEGImageEncoder;
- import com.sun.imageio.plugins.bmp.BMPImageReader;
- import com.sun.imageio.plugins.gif.GIFImageReader;
- import com.sun.imageio.plugins.jpeg.JPEGImageReader;
- import com.sun.imageio.plugins.png.PNGImageReader;
- import com.sun.imageio.plugins.wbmp.WBMPImageReader;
- /**
- * 使用 imageio 实现的图片处理工具
- *
- * @author
- * @since 2010-7-14
- */
- public class ImageIOUtil {
- /**
- * 是否是合法图片
- *
- * @param suffix
- * 图片文件后缀
- * @param imageContent
- * 图片内容
- * @return
- */
- public static boolean isImage(byte[] imageContent) {
- return isImage(null, imageContent);
- }
- /**
- * 是否是合法图片
- *
- * @param imageContent
- * 图片内容
- * @return
- */
- public static boolean isImage(String suffix, byte[] imageContent) {
- if (imageContent == null || imageContent.length == 0) {
- return false;
- }
- Image img = null;
- InputStream is = null;
- try {
- is = new ByteArrayInputStream(imageContent);
- img = ImageIO.read(is);
- if (img == null || img.getWidth(null) <= 0
- || img.getHeight(null) <= 0) {
- return false;
- }
- return true;
- } catch (Exception e) {
- return false;
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- }
- }
- /**
- * 是否是合法图片
- *
- * @param imageFullPath
- * 图片本地绝对路径
- * @return
- */
- public static boolean isImage(String localImagePath) {
- File imgFile = new File(localImagePath);
- if (!imgFile.isFile()) {
- return false;
- }
- Image img;
- try {
- img = ImageIO.read(imgFile);
- if (imgFile.length() == 0 || img == null || img.getWidth(null) <= 0
- || img.getHeight(null) <= 0) {
- return false;
- }
- return true;
- } catch (Exception e) {
- return false;
- }
- }
- /**
- * 根据要求的坐标截取图片
- *
- * @param source
- * @param x
- * @param y
- * @param width
- * @param height
- */
- public static void cropPart(String imageFullPath, int x, int y, int width,
- int height) throws RuntimeException {
- Image img = null;
- ImageFilter cropFilter = null;
- BufferedImage bi = null;
- try {
- bi = ImageIO.read(new File(imageFullPath));
- if (bi == null) {
- throw new RuntimeException("ImageIO.read return null");
- }
- } catch (Exception e) {
- throw new RuntimeException(String.format("read image fail, src=",
- imageFullPath));
- }
- int srcW = bi.getWidth();
- int srcH = bi.getHeight();
- if (srcW <= 0 || srcH <= 0) {
- throw new RuntimeException(String.format("invalid image, src=",
- imageFullPath));
- }
- // 异常的图片参数
- if (x >= srcW || y >= srcH) {
- throw new RuntimeException(
- String
- .format(
- "cropPart fail, point (x=%s,y=%s) not in the image(width=%s,height=%s)",
- x, y, srcW, srcH));
- }
- width = Math.min(width, srcW - x);
- height = Math.min(height, srcH - y);
- try {
- Image image = bi.getScaledInstance(srcW, srcH, Image.SCALE_DEFAULT);
- cropFilter = new CropImageFilter(x, y, width, height);
- img = Toolkit.getDefaultToolkit().createImage(
- new FilteredImageSource(image.getSource(), cropFilter));
- BufferedImage tag = new BufferedImage(width, height,
- BufferedImage.TYPE_INT_RGB);
- Graphics2D g = (Graphics2D) tag.getGraphics();
- g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
- RenderingHints.VALUE_INTERPOLATION_BILINEAR);
- g.drawImage(img, 0, 0, null);
- g.dispose();
- ImageIO.write(tag, "jpg", new File(imageFullPath));
- } catch (Exception e) {
- throw new RuntimeException("process image error, src="
- + imageFullPath, e);
- }
- }
- /**
- * 将imageFullPath指定的图片进行等比缩放,最长的边为<t>maxEdgeLength</t>
- *
- * @param imageFullPath
- * :需要裁剪的图片绝对路径
- * @param maxEdgeLength
- * : 边长
- * @return
- */
- public static boolean resizeImage(String imageFullPath, int maxEdgeLength)
- throws Exception {
- File file = new File(imageFullPath);
- if (!file.exists()) {
- return false;
- }
- Image img = ImageIO.read(file);
- // 判断图片格式是否正确
- if (img == null || img.getWidth(null) <= 0 || img.getHeight(null) <= 0) {
- return false;
- }
- int width = img.getWidth(null);
- int height = img.getHeight(null);
- boolean isWidthLonger = width > height ? true : false;
- // 得到调整后的尺寸及缩小的比例,如果{width,height}都小于等于maxEdgeLength,直接返回
- if (width > maxEdgeLength || height > maxEdgeLength) {
- double ratio;
- if (isWidthLonger) {
- ratio = ((double) maxEdgeLength) / width;
- width = maxEdgeLength;
- height = ((Double) Math.floor(ratio * height)).intValue();
- } else {
- ratio = ((double) maxEdgeLength) / height;
- width = ((Double) Math.floor(ratio * width)).intValue();
- height = maxEdgeLength;
- }
- } else {
- return true;
- }
- FileOutputStream out = null;
- try {
- BufferedImage tag = new BufferedImage((int) width, (int) height,
- BufferedImage.TYPE_INT_RGB);
- tag.getGraphics().drawImage(
- img.getScaledInstance(width, height, Image.SCALE_SMOOTH),
- 0, 0, null);
- out = new FileOutputStream(imageFullPath);
- ImageIO.write(tag, "jpg", out);
- } catch (Exception e) {
- throw new RuntimeException("resize image error, img="
- + imageFullPath, e);
- } finally {
- if (out != null) {
- out.close();
- }
- }
- return true;
- }
- /**
- * 对imageFullPath 指定的文件按要求的质量quality进行压缩(gif将不会进行压缩)。quality的范围是(0-100)
- *
- * @param imageFullPath
- * 文件的绝对路径
- * @param quality
- * 压缩的质量,范围是(0-100)
- * @param maxFileSize
- * 文件超过该大小才进行质量有损压缩,单位:byte
- * @return 文件大小,单位:byte
- */
- public static int compressImage(String imageFullPath, int quality,
- long maxFileSize) {
- // 1. entry validation
- if (StringUtil.isEmpty(imageFullPath) || quality < 0 || quality > 100) {
- throw new RuntimeException("invalid parameters, src="
- + imageFullPath + ",quality=" + quality);
- }
- File img = new File(imageFullPath);
- if (!img.isFile()) {
- throw new RuntimeException("file not exists, src=" + imageFullPath);
- }
- if (img.length() <= maxFileSize) {
- return (int) img.length();
- }
- // 2. compress
- FileOutputStream out = null;
- try {
- // Retrieve jpg image to be compressed
- RenderedImage rendImage = ImageIO.read(new File(imageFullPath));
- if (rendImage == null || rendImage.getWidth() <= 0
- || rendImage.getHeight() <= 0) {
- throw new RuntimeException("file is not an image, src="
- + imageFullPath);
- }
- out = new FileOutputStream(img);
- BufferedImage tag = new BufferedImage(rendImage.getWidth(),
- rendImage.getHeight(), BufferedImage.TYPE_INT_RGB);
- tag.getGraphics().drawImage((Image) rendImage, 0, 0,
- rendImage.getWidth(), rendImage.getHeight(), null);
- JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
- JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(tag);
- jep.setQuality(quality / 100f, true);
- encoder.encode(tag, jep);
- } catch (Exception e) {
- throw new RuntimeException("compressImage fail, src="
- + imageFullPath, e);
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- }
- }
- }
- return (int) new File(imageFullPath).length();
- }
- /**
- * 获取图片信息,包括宽/高/大小/类型,如果取不到会抛异常
- *
- * @param imageFullPath
- * @return
- * @throws Exception
- */
- public static ImageFile getImageInfo(String imageFullPath) throws Exception {
- return getImageInfo(imageFullPath, false);
- }
- /**
- * (本方法暂不支持)获取图片信息+EXIF信息,如果非图片格式会抛异常
- *
- * @param localImagePath
- * 本地图片路径
- * @param isReadExif
- * 是否需要读取exif信息
- * @return
- * @throws Exception
- */
- @SuppressWarnings("unchecked")
- public static ImageFile getImageInfo(String localImagePath,
- boolean isReadExif) {
- File imgFile = new File(localImagePath);
- if (!imgFile.isFile()) {
- throw new RuntimeException("file not exists or not a file, file="
- + localImagePath);
- }
- Image img;
- try {
- img = ImageIO.read(imgFile);
- if (imgFile.length() == 0 || img == null || img.getWidth(null) <= 0
- || img.getHeight(null) <= 0) {
- throw new RuntimeException(
- "get image's size/width/height error, file="
- + localImagePath);
- }
- } catch (IOException e) {
- throw new RuntimeException(
- "get image's size/width/height error, file="
- + localImagePath);
- }
- ImageFile imageFile = new ImageFile();
- imageFile.setWidth(img.getWidth(null));
- imageFile.setHeight(img.getHeight(null));
- imageFile.setSize(imgFile.length());
- imageFile.setFile(imgFile);
- FileInputStream fis = null;
- BufferedInputStream buff = null;
- int leng;
- byte[] mapObj;
- try {
- fis = new FileInputStream(imgFile);
- leng = fis.available();
- buff = new BufferedInputStream(fis);
- mapObj = new byte[leng];
- buff.read(mapObj, 0, leng);
- } catch (IOException e) {
- throw new RuntimeException("read image file stream error, file="
- + localImagePath);
- }
- String type = null;
- ByteArrayInputStream bais = null;
- MemoryCacheImageInputStream mcis = null;
- try {
- bais = new ByteArrayInputStream(mapObj);
- mcis = new MemoryCacheImageInputStream(bais);
- Iterator itr = ImageIO.getImageReaders(mcis);
- while (itr.hasNext()) {
- ImageReader reader = (ImageReader) itr.next();
- if (reader instanceof GIFImageReader) {
- type = "gif";
- } else if (reader instanceof JPEGImageReader) {
- type = "jpg";
- } else if (reader instanceof PNGImageReader) {
- type = "png";
- } else if (reader instanceof BMPImageReader
- || reader instanceof WBMPImageReader) {
- type = "bmp";
- }
- }
- if (type != null) {
- imageFile.setType(ImageType.valueOf(type));
- if (isReadExif) {
- // TODO read exif information
- }
- return imageFile;
- }
- } finally {
- if (bais != null) {
- try {
- bais.close();
- } catch (IOException ioe) {
- }
- }
- if (mcis != null) {
- try {
- mcis.close();
- } catch (IOException ioe) {
- }
- }
- if (buff != null) {
- try {
- buff.close();
- } catch (IOException ioe) {
- }
- }
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException ioe) {
- }
- }
- }
- return null;
- }
- private static Method[] exifMethods = ImageExif.class.getMethods();
- private static ImageExif readImageExif(MagickImage image) {
- ImageExif exif = new ImageExif();
- if (image == null) {
- return exif;
- }
- try {
- for (Method method : exifMethods) {
- if ("set".equals(method.getName().substring(0, 3))) {
- if (method.getName().length() > 3) {
- method.invoke(exif, image.getImageAttribute("EXIF:"
- + method.getName().substring(3)));
- }
- }
- }
- } catch (Exception e) {
- throw new RuntimeException("read image exif error", e);
- }
- return exif;
- }
- /**
- * 给图片打水印(本地图片会被替换成有水印的图片),如果图片宽高要小于水印宽高+x或y,则不会打水印
- *
- * @param localImage
- * 源图的本地绝对路径
- * @param markImage
- * 水印图片的绝对路径
- * @param maskType
- * 0-右下角, 1-左下角, 2-正中间, 3-左上角, 4-右上角, 5-自定义
- * @param x
- * 离横向边间隔距离,如左对齐则左边距,右对齐则是右边距,居中传0,自定义则为左边距,单位:px
- * @param y
- * 离纵向边距离,如上对齐则上边距,下对齐则是下边距,居中传0,自定义则为上边距,单位:px
- * @return
- * @throws Exception
- */
- public static boolean mask(String localImage, String markImage,
- int maskType, int x, int y) throws Exception {
- return mask(localImage, localImage, markImage, maskType, x, y);
- }
- /**
- * 给图片打水印(生成目标图片会带水印),如果图片宽高要小于水印宽高+endX或endY,则不会打水印
- *
- * @param imageBytes
- * 源图的byte数组
- * @param markImage
- * 水印图片的绝对路径
- * @param maskType
- * 0-右下角, 1-左下角, 2-正中间, 3-左上角, 4-右上角, 5-自定义
- * @param x
- * 离横向边间隔距离,如左对齐则左边距,右对齐则是右边距,居中传0,自定义则为左边距,单位:px
- * @param y
- * 离纵向边距离,如上对齐则上边距,下对齐则是下边距,居中传0,自定义则为上边距,单位:px
- * @return 处理后图片的byte数组
- * @throws Exception
- */
- public static byte[] mask(byte[] imageBytes, String markImage,
- int maskType, int x, int y) throws Exception {
- File srcTmp = File.createTempFile("ImageIOUtil", null);
- Image src = ImageIO.read(new ByteArrayInputStream(imageBytes));
- Image logo = ImageIO.read(new File(markImage));
- maskCore(src, srcTmp, logo, maskType, x, y);
- InputStream input = null;
- ByteArrayOutputStream out = null;
- try {
- input = new FileInputStream(srcTmp);
- out = new ByteArrayOutputStream(4096);
- byte[] b = new byte[4096];
- int n;
- while ((n = input.read(b)) != -1) {
- out.write(b, 0, n);
- out.flush();
- }
- return out.toByteArray();
- } finally {
- if (input != null) {
- try {
- input.close();
- } catch (Exception e) {
- }
- }
- if (out != null) {
- try {
- out.close();
- } catch (Exception e) {
- }
- }
- }
- }
- /**
- * 给图片打水印(生成目标图片会带水印),如果图片宽高要小于水印宽高+x或y,则不会打水印
- *
- * @param localImage
- * 源图的本地绝对路径
- * @param destImage
- * 目标图片的本地绝对路径
- * @param markImage
- * 水印图片的绝对路径
- * @param maskType
- * 0-右下角, 1-左下角, 2-正中间, 3-左上角, 4-右上角, 5-自定义
- * @param x
- * 离横向边间隔距离,如左对齐则左边距,右对齐则是右边距,居中传0,自定义则为左边距,单位:px
- * @param y
- * 离纵向边距离,如上对齐则上边距,下对齐则是下边距,居中传0,自定义则为上边距,单位:px
- * @return
- * @throws Exception
- */
- public static boolean mask(String localImage, String destImage,
- String markImage, int maskType, int x, int y) throws Exception {
- Image src = ImageIO.read(new File(localImage));
- Image logo = ImageIO.read(new File(markImage));
- File dest = new File(destImage);
- return maskCore(src, dest, logo, maskType, x, y);
- }
- /**
- * 打水印主逻辑
- *
- * @param src
- * 源图
- * @param dest
- * 目标输出文件
- * @param logo
- * 水印
- * @param maskType
- * 0-右下角, 1-左下角, 2-正中间, 3-左上角, 4-右上角, 5-自定义
- * @param marginX
- * 离横向边间隔距离,如左对齐则左边距,右对齐则是右边距,居中传0,自定义则为左边距,单位:px
- * @param marginY
- * 离纵向边距离,如上对齐则上边距,下对齐则是下边距,居中传0,自定义则为上边距,单位:px
- * @return
- * @throws Exception
- */
- private static boolean maskCore(Image src, File dest, Image logo,
- int maskType, int marginX, int marginY) throws Exception {
- // 校验图片合法性
- if (src == null || src.getWidth(null) <= 0 || src.getHeight(null) <= 0
- || dest == null || logo == null || src.getWidth(null) <= 0
- || src.getHeight(null) <= 0) {
- return false;
- }
- int srcW = src.getWidth(null);
- int srcH = src.getHeight(null);
- int logoW = logo.getWidth(null);
- int logoH = logo.getHeight(null);
- int x = 0, y = 0;
- switch (maskType) {
- // 左下角
- case 1:
- x = marginX;
- y = (int) (srcH - logoH - marginY);
- break;
- // 正中间
- case 2:
- x = (int) ((srcW - logoW) / 2);
- y = (int) ((srcH - logoH) / 2);
- break;
- // 左上角
- case 3:
- x = marginX;
- y = marginY;
- break;
- // 右上角
- case 4:
- x = (int) (srcW - logoW - marginX);
- y = marginY;
- break;
- // 自定义
- case 5:
- x = marginX;
- y = marginY;
- break;
- // 右下角
- case 0:
- // 其它值默认右下角
- default:
- x = (int) (srcW - logoW - marginX);
- y = (int) (srcH - logoH - marginY);
- }
- // 校验水印是否全部落在图片中
- if (x <= 0 || y <= 0 || x > srcW - logoW || y > srcH - logoH) {
- return false;
- }
- FileOutputStream out = null;
- try {
- BufferedImage tag = new BufferedImage((int) srcW, (int) srcH,
- BufferedImage.TYPE_INT_RGB);
- Graphics g = tag.getGraphics();
- g.drawImage(src, 0, 0, srcW, srcH, null);
- g.drawImage(logo, x, y, logoW, logoH, null);
- out = new FileOutputStream(dest);
- ImageIO.write(tag, "jpg", out);
- g.dispose();
- } catch (Exception e) {
- throw new RuntimeException("resize image error", e);
- } finally {
- if (out != null) {
- out.close();
- }
- }
- return true;
- }
- }
上边的图片是要exif是需要使用JMagick获取所以如果有兴趣就需要同学安装,下面给出
JMagickUtil
- import java.awt.Rectangle;
- import java.io.File;
- import java.lang.reflect.Method;
- import magick.CompositeOperator;
- import magick.ImageInfo;
- import magick.MagickImage;
- import org.apache.commons.lang.StringUtils;
- import com.taobao.communitypsc.common.image.ImageExif;
- import com.taobao.communitypsc.common.image.ImageFile;
- import com.taobao.communitypsc.common.image.ImageType;
- /**
- * JMagick 处理图片
- *
- * @author
- * @since 2010-5-20
- */
- public class JMagickUtil {
- static {
- System.setProperty("jmagick.systemclassloader", "no");
- }
- /**
- * 是否是合法图片
- *
- * @param suffix
- * 图片文件后缀
- * @param imageContent
- * 图片内容
- * @return
- */
- public static boolean isImage(String suffix, byte[] imageContent) {
- try {
- MagickImage image = new MagickImage(new ImageInfo(suffix),
- imageContent);
- if (image == null || image.getDimension().getWidth() <= 0) {
- return false;
- }
- } catch (Exception e) {
- return false;
- }
- return true;
- }
- /**
- * 是否是合法图片
- *
- * @param imageFullPath
- * 图片本地绝对路径
- * @return
- */
- public static boolean isImage(String localImagePath) {
- if (localImagePath == null || !new File(localImagePath).isFile()) {
- return false;
- }
- try {
- MagickImage image = new MagickImage(new ImageInfo(localImagePath));
- if (image.getDimension() == null
- || image.getDimension().getWidth() <= 0) {
- return false;
- }
- } catch (Exception e) {
- return false;
- }
- return true;
- }
- /**
- * 根据要求的坐标截取图片
- *
- * @param source
- * @param x
- * @param y
- * @param width
- * @param height
- */
- public static void cropPart(String imageFullPath, int x, int y, int width,
- int height) throws Exception {
- MagickImage image = null;
- ImageInfo info = null;
- // 取得原文件
- try {
- info = new ImageInfo(imageFullPath);
- // 获取图片
- image = new MagickImage(info);
- // 原始尺寸
- int beforeScaleX = image.getDimension().width;
- int beforeScaleY = image.getDimension().height;
- // 是否需要这个约束
- int cropWidth = (x + width > beforeScaleX) ? (beforeScaleX - x)
- : width;
- int cropHeight = (y + height > beforeScaleY) ? (beforeScaleY - y)
- : height;
- MagickImage small = image.cropImage(new Rectangle(x, y, cropWidth,
- cropHeight));
- small.setFileName(imageFullPath);
- small.writeImage(new ImageInfo());
- small.destroyImages();
- } finally {
- if (image != null) {
- image.destroyImages();
- }
- }
- }
- /**
- * 将imageFullPath指定的图片进行等比缩放,最长的边为<t>maxEdgeLength</t>
- *
- * @param imageFullPath
- * :需要裁剪的图片绝对路径
- * @param edgeLength
- * : 边长
- * @return
- */
- public static boolean resizeImage(String imageFullPath, int maxEdgeLength)
- throws Exception {
- // 取得原文件
- MagickImage image = new MagickImage(new ImageInfo(imageFullPath));
- String suffix = image.getImageFormat();
- if (suffix.equalsIgnoreCase("gif")) {
- image = extractFirstFrame(image);
- }
- // 原始尺寸
- int width = image.getDimension().width;
- int height = image.getDimension().height;
- boolean isWidthLonger = width > height ? true : false;
- // 得到调整后的尺寸及缩小的比例,如果{width,height}都小于等于maxEdgeLength,直接返回
- if (width > maxEdgeLength || height > maxEdgeLength) {
- double ratio;
- if (isWidthLonger) {
- ratio = ((double) maxEdgeLength) / width;
- width = maxEdgeLength;
- height = ((Double) Math.floor(ratio * height)).intValue();
- } else {
- ratio = ((double) maxEdgeLength) / height;
- width = ((Double) Math.floor(ratio * width)).intValue();
- height = maxEdgeLength;
- }
- MagickImage small = image.scaleImage(width, height);
- small.setFileName(imageFullPath);
- small.writeImage(new ImageInfo());
- small.destroyImages();
- }
- return true;
- }
- /**
- * 截取第一帧
- *
- * @param image
- * gif动画
- * @return
- */
- private static MagickImage extractFirstFrame(MagickImage image)
- throws Exception {
- MagickImage[] frames = image.breakFrames();
- return frames[0];
- }
- /**
- * 对imageFullPath 指定的文件按要求的质量quality进行压缩(gif将不会进行压缩)。quality的范围是(0-100)
- *
- * @param imageFullPath
- * 文件的绝对路径
- * @param quality
- * 压缩的质量,范围是(0-100)
- * @param maxFileSize
- * 文件超过该大小才进行质量有损压缩,单位:byte
- * @return 文件大小,单位:byte
- */
- public static int compressImage(String imageFullPath, int quality,
- long maxFileSize) throws Exception {
- // 1. entry validation
- if (StringUtil.isEmpty(imageFullPath) || quality <= 0 || quality >= 100) {
- return -1;
- }
- int i = imageFullPath.lastIndexOf(".");
- if (i < 0) {
- return -1;
- }
- // 2. compress
- String fileName = imageFullPath.substring(0, i);
- File fileSrc = new File(imageFullPath);
- ImageInfo info = null;
- MagickImage image = null;
- try {
- info = new ImageInfo(imageFullPath);
- image = new MagickImage(info);
- if (null == image || image.getDimension() == null
- || image.getDimension().getWidth() <= 0) {
- return -1;
- }
- String type = image.getImageFormat();
- if ("gif".equalsIgnoreCase(type)) {
- // 解决 trojan.giframe 病毒 问题,gif 也通过MagickImage另存一下图片
- fileName = fileName + ".gif";
- image.setFileName(fileName);
- image.writeImage(new ImageInfo());
- } else {
- if (fileSrc.length() > maxFileSize) {// 大于指定文件大小,进行压缩
- // 调整图片品质 最佳为40~50
- info.setQuality(quality);
- image.profileImage("*", null);
- image.setImageAttribute("comment", null);
- image.setImageAttribute("JPEG-Sampling-factors", null);
- image.setFileName(imageFullPath);
- image.writeImage(info);
- }
- }
- return (int) fileSrc.length();
- } finally {
- if (image != null) {
- image.destroyImages();
- }
- }
- }
- /**
- * 获取图片信息,包括宽/高/大小/类型,如果取不到会抛异常
- *
- * @param imageFullPath
- * @return
- * @throws Exception
- */
- public static ImageFile getImageInfo(String imageFullPath) throws Exception {
- return getImageInfo(imageFullPath, false);
- }
- /**
- * 获取图片信息+EXIF信息,如果非图片格式会抛异常
- *
- * @param localImagePath
- * 本地图片路径
- * @param isReadExif
- * 是否需要读取exif信息
- * @return
- * @throws Exception
- */
- public static ImageFile getImageInfo(String localImagePath,
- boolean isReadExif) throws Exception {
- File file = new File(localImagePath);
- if (!file.isFile()) {
- throw new Exception("file not exists or not a file, file="
- + localImagePath);
- }
- ImageFile imageFile = new ImageFile();
- MagickImage image = new MagickImage(new ImageInfo(localImagePath));
- if (image.getDimension() == null
- || image.getDimension().getWidth() <= 0) {
- throw new Exception("get image's dimension error, file="
- + localImagePath);
- }
- imageFile.setFile(new File(localImagePath));
- imageFile.setHeight(image.getDimension().getHeight());
- imageFile.setWidth(image.getDimension().getWidth());
- imageFile.setType(ImageType.toImageType(image.getImageFormat()));
- imageFile.setSize(file.length());
- if (isReadExif) {
- imageFile.setExif(readImageExif(image));
- }
- return imageFile;
- }
- private static Method[] exifMethods = ImageExif.class.getMethods();
- private static ImageExif readImageExif(MagickImage image) {
- ImageExif exif = new ImageExif();
- if (image == null) {
- return exif;
- }
- try {
- for (Method method : exifMethods) {
- if ("set".equals(method.getName().substring(0, 3))) {
- if (method.getName().length() > 3) {
- method.invoke(exif, image.getImageAttribute("EXIF:"
- + method.getName().substring(3)));
- }
- }
- }
- } catch (Exception e) {
- throw new RuntimeException("read image exif error", e);
- }
- return exif;
- }
- /**
- * 给图片打水印(本地图片会被替换成有水印的图片),如果图片宽高要小于水印宽高+x或y,则不会打水印
- *
- * @param localImage
- * 源图的本地绝对路径
- * @param markImage
- * 水印图片的绝对路径
- * @param maskType
- * 0-右下角, 1-左下角, 2-正中间, 3-左上角, 4-右上角, 5-自定义
- * @param x
- * 离横向边间隔距离,如左对齐则左边距,右对齐则是右边距,居中传0,自定义则为左边距,单位:px
- * @param y
- * 离纵向边距离,如上对齐则上边距,下对齐则是下边距,居中传0,自定义则为上边距,单位:px
- * @return
- * @throws Exception
- */
- public static boolean mask(String localImage, String markImage,
- int maskType, int x, int y) throws Exception {
- return mask(localImage, localImage, markImage, maskType, x, y);
- }
- /**
- * 给图片打水印(生成目标图片会带水印),如果图片宽高要小于水印宽高+endX或endY,则不会打水印
- *
- * @param imageBytes
- * 源图的byte数组
- * @param markImage
- * 水印图片的绝对路径
- * @param maskType
- * 0-右下角, 1-左下角, 2-正中间, 3-左上角, 4-右上角, 5-自定义
- * @param x
- * 离横向边间隔距离,如左对齐则左边距,右对齐则是右边距,居中传0,自定义则为左边距,单位:px
- * @param y
- * 离纵向边距离,如上对齐则上边距,下对齐则是下边距,居中传0,自定义则为上边距,单位:px
- * @return 处理后图片的byte数组
- * @throws Exception
- */
- public static byte[] mask(byte[] imageBytes, String markImage,
- int maskType, int x, int y) throws Exception {
- ImageInfo info = new ImageInfo();
- MagickImage src = null;
- MagickImage logo = null;
- try {
- src = new MagickImage(info, imageBytes);
- logo = new MagickImage(new ImageInfo(markImage));
- maskCore(src, src, info, logo, maskType, x, y);
- return src.imageToBlob(info);
- } finally {
- if (src != null) {
- src.destroyImages();
- }
- if (logo != null) {
- logo.destroyImages();
- }
- }
- }
- /**
- * 给图片打水印(生成目标图片会带水印),如果图片宽高要小于水印宽高+x或y,则不会打水印
- *
- * @param localImage
- * 源图的本地绝对路径
- * @param destImage
- * 目标图片的本地绝对路径
- * @param markImage
- * 水印图片的绝对路径
- * @param maskType
- * 0-右下角, 1-左下角, 2-正中间, 3-左上角, 4-右上角, 5-自定义
- * @param x
- * 离横向边间隔距离,如左对齐则左边距,右对齐则是右边距,居中传0,自定义则为左边距,单位:px
- * @param y
- * 离纵向边距离,如上对齐则上边距,下对齐则是下边距,居中传0,自定义则为上边距,单位:px
- * @return
- * @throws Exception
- */
- public static boolean mask(String localImage, String destImage,
- String markImage, int maskType, int x, int y) throws Exception {
- MagickImage src = null;
- MagickImage logo = null;
- MagickImage dest = null;
- try {
- ImageInfo info = new ImageInfo(localImage);
- src = new MagickImage(info);
- logo = new MagickImage(new ImageInfo(markImage));
- dest = new MagickImage(info);
- dest.setFileName(destImage);
- return maskCore(src, dest, info, logo, maskType, x, y);
- } finally {
- if (src != null) {
- src.destroyImages();
- }
- if (logo != null) {
- logo.destroyImages();
- }
- if (dest != null) {
- dest.destroyImages();
- }
- }
- }
- /**
- * 打水印主逻辑
- *
- * @param src
- * 源图
- * @param dest
- * 目标图
- * @param writeInfo
- * 目标图的ImageInfo
- * @param logo
- * 水印
- * @param maskType
- * 0-右下角, 1-左下角, 2-正中间, 3-左上角, 4-右上角, 5-自定义
- * @param marginX
- * 离横向边间隔距离,如左对齐则左边距,右对齐则是右边距,居中传0,自定义则为左边距,单位:px
- * @param marginY
- * 离纵向边距离,如上对齐则上边距,下对齐则是下边距,居中传0,自定义则为上边距,单位:px
- * @return
- * @throws Exception
- */
- private static boolean maskCore(MagickImage src, MagickImage dest,
- ImageInfo writeInfo, MagickImage logo, int maskType, int marginX,
- int marginY) throws Exception {
- // 校验图片合法性
- if (src == null || src.getDimension() == null || dest == null
- || dest.getDimension() == null || logo == null
- || logo.getDimension() == null) {
- return false;
- }
- // gif图片处理,gif多桢不处理,单桢则处理
- String suffix = src.getImageFormat();
- if (suffix.equalsIgnoreCase("gif")) {
- MagickImage[] frames = src.breakFrames();
- if (frames.length > 1) {
- return false;
- }
- src = frames[0];
- }
- double srcW = src.getDimension().getWidth();
- double srcH = src.getDimension().getHeight();
- double logoW = logo.getDimension().getWidth();
- double logoH = logo.getDimension().getHeight();
- if (srcW <= 0 || dest.getDimension().getWidth() <= 0 || logoW <= 0) {
- return false;
- }
- int x = 0, y = 0;
- switch (maskType) {
- // 左下角
- case 1:
- x = marginX;
- y = (int) (srcH - logoH - marginY);
- break;
- // 正中间
- case 2:
- x = (int) ((srcW - logoW) / 2);
- y = (int) ((srcH - logoH) / 2);
- break;
- // 左上角
- case 3:
- x = marginX;
- y = marginY;
- break;
- // 右上角
- case 4:
- x = (int) (srcW - logoW - marginX);
- y = marginY;
- break;
- // 自定义
- case 5:
- x = marginX;
- y = marginY;
- break;
- // 右下角
- case 0:
- // 其它值默认右下角
- default:
- x = (int) (srcW - logoW - marginX);
- y = (int) (srcH - logoH - marginY);
- }
- // 校验水印是否全部落在图片中
- if (x <= 0 || y <= 0 || x > srcW - logoW || y > srcH - logoH) {
- return false;
- }
- dest.compositeImage(CompositeOperator.AtopCompositeOp, logo, x, y);
- dest.writeImage(writeInfo);
- return true;
- }
- }
上传文件为流所以告诉大家一个不常用的好方法:
log4j中有一个StreamUtils.copyThenClose(InputStream, OutputStream);的方法,相信大家都会在自己的项目中使用log4j,所以可以考虑偷个懒试用一下这个类。