001package net.gdface.image; 002 003import java.awt.Rectangle; 004import java.awt.image.BufferedImage; 005import java.io.ByteArrayInputStream; 006import java.io.File; 007import java.io.FileInputStream; 008import java.io.FileNotFoundException; 009import java.io.IOException; 010import java.util.Iterator; 011 012import javax.imageio.ImageIO; 013import javax.imageio.ImageReadParam; 014import javax.imageio.ImageReader; 015import javax.imageio.ImageTypeSpecifier; 016import javax.imageio.stream.ImageInputStream; 017import javax.imageio.stream.MemoryCacheImageInputStream; 018 019import net.gdface.utils.Assert; 020import net.gdface.utils.FaceUtilits; 021 022/** 023 * å›¾åƒæ•°æ®å¤„ç†å¯¹è±¡<br> 024 * {@link #open()}å¯ä»¥åœ¨ä¸å°†å›¾åƒå…¨éƒ¨è§£ç åŠ è½½åˆ°å†…å˜è€ŒèŽ·å–图åƒçš„基本信æ¯<br> 025 * {@link #read(ImageReadParam)}使用内å˜åšcache读å–(ä¸ä½¿ç”¨ä¸´æ—¶æ–‡ä»¶åšcache)<br> 026 * {@link #read(Rectangle, ImageTypeSpecifier)}å¯ä»¥å¯¹å›¾åƒæŒ‡å®šåŒºåŸŸè§£ç 027 * @author guyadong 028 * 029 */ 030public class LazyImage extends BaseLazyImage implements ImageMatrix{ 031 private Rectangle rectangle=null; 032 private ImageReader imageReader; 033 private MemoryCacheImageInputStream imageInputstream; 034 private BufferedImage bufferedImage=null; 035 /** 036 * 通过{@link ImageReader}æ¥è¯»å–图åƒåŸºæœ¬ä¿¡æ¯ï¼Œæ£€æŸ¥å›¾åƒæ•°æ®æœ‰æ•ˆæ€§ 037 * @return 038 * @throws UnsupportedFormatException 039 * @throws NotImageException 040 */ 041 @SuppressWarnings("unchecked") 042 @Override 043 public LazyImage open() throws UnsupportedFormatException, NotImageException { 044 try { 045 if(bufferedImage == null){ 046 Iterator<ImageReader> it = ImageIO.getImageReaders(getImageInputstream()); 047 if (it.hasNext()) 048 try { 049 imageReader = it.next(); 050 imageReader.setInput(getImageInputstream(), true, true); 051 this.suffix = imageReader.getFormatName().trim().toLowerCase(); 052 this.width = imageReader.getWidth(0); 053 this.height = imageReader.getHeight(0); 054 } catch (Exception e) { 055 throw new UnsupportedFormatException(e); 056 } 057 else { 058 // 没有找到对应的图åƒè§£ç 则招è˜å¼‚常 059 throw new NotImageException("NOT FOUND MATCHED ImageReader"); 060 } 061 }else{ 062 this.width = bufferedImage.getWidth(); 063 this.height = bufferedImage.getHeight(); 064 } 065 return this; 066 } finally { 067 if (autoClose) 068 try { 069 close(); 070 } catch (IOException e) { 071 throw new RuntimeException(e); 072 } 073 } 074 } 075 076 077 /** 078 * å¯¹å›¾åƒæ•°æ®è§£ç ç”Ÿæˆ {@link BufferedImage}对象 079 * 080 * @param param 081 * 图åƒè¯»å–傿•°å¯¹è±¡,为nullä½¿ç”¨é»˜è®¤å‚æ•°<br> 082 * å‚è§ {@link ImageReader#getDefaultReadParam()} 083 * @return 084 * @throws UnsupportedFormatException 085 * @see ImageReadParam 086 */ 087 protected BufferedImage read(ImageReadParam param) throws UnsupportedFormatException { 088 try { 089 if(null==this.bufferedImage||null!=param){ 090 ImageReader imageReader=getImageReader(); 091 if(null==imageReader.getInput()) 092 imageReader.setInput(getImageInputstream(), true,true); 093 BufferedImage bi = imageReader.read(0, null==param?imageReader.getDefaultReadParam():param); 094 if (null==param) 095 this.bufferedImage = bi; 096 else 097 return bi; 098 } 099 return this.bufferedImage; 100 } catch (Exception e) { 101 throw new UnsupportedFormatException(e); 102 } finally { 103 if(autoClose) 104 try { 105 close(); 106 } catch (IOException e) { 107 throw new RuntimeException(e); 108 } 109 } 110 } 111 public BufferedImage read() throws UnsupportedFormatException{ 112 return read(null); 113 } 114 /** 115 * å¯¹å›¾åƒæ•°æ®æŒ‡å®šçš„区域解ç 116 * 117 * @param rect 118 * è§£ç 区域对象, 默认({@code null})全图解ç <br> 119 * å‚è§ {@link ImageReadParam#setSourceRegion(Rectangle)} 120 * @param destinationType 121 * ç›®æ ‡å›¾åƒçš„æ‰€éœ€å›¾åƒç±»åž‹,默认为null, <br> 122 * 例如用æ¤å‚æ•°å¯ä»¥åœ¨è§£ç 时指定输出的图åƒç±»åž‹ä¸ºRGB,<br> 123 * 如下代ç ç”Ÿæˆ destinationType傿•°å¯¹è±¡ï¼š<br> 124 * {@code 125 * ImageTypeSpecifier destinationType=ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR); 126 * }<br> 127 * 用上é¢çš„ImageTypeSpecifier对象æ¥è°ƒç”¨æ¤æ–¹æ³•返回的BufferedImage对象ä¸çš„rasteræˆå‘˜(通过BufferedImage.getData()获å–) 128 * çš„getDataElements()方法返回的就是包å«RGBæ•°æ®byte[]类型的数组<br> 129 * 而直接用BufferedImage.getRGB()æ–¹å¼åªèƒ½èŽ·å–ARGB类型的int[]数组 å‚è§ 130 * {@link ImageReadParam#setDestinationType(ImageTypeSpecifier) } 131 * @return 132 * @throws UnsupportedFormatException 133 * @see #read(ImageReadParam) 134 */ 135 public BufferedImage read(Rectangle rect, ImageTypeSpecifier destinationType) throws UnsupportedFormatException { 136 ImageReadParam param = getImageReader().getDefaultReadParam(); 137 if (rect != null && !rect.equals(getRectangle())) 138 param.setSourceRegion(rect); 139 param.setDestinationType(destinationType); 140 if(null!=destinationType) 141 param.setDestination(destinationType.createBufferedImage(width, height)); 142 return read(param); 143 } 144 @Override 145 public byte[] getMatrixRGBA() throws UnsupportedFormatException{ 146 if (matrixRGBA==null){ 147 matrixRGBA=ImageUtil.getMatrixRGBA(read()); 148 } 149 return matrixRGBA; 150 } 151 152 @Override 153 public byte[] getMatrixRGB() throws UnsupportedFormatException{ 154 if (matrixRGB==null){ 155 matrixRGB=ImageUtil.getMatrixRGB(read()); 156 } 157 return matrixRGB; 158 } 159 160 @Override 161 public byte[] getMatrixBGR() throws UnsupportedFormatException{ 162 if (matrixBGR==null){ 163 matrixBGR=ImageUtil.getMatrixBGR(read()); 164 } 165 return matrixBGR; 166 } 167 /** 168 * å¯¹å›¾åƒæ•°æ®æŒ‡å®šçš„区域解ç 返回ç°åº¦å›¾åƒæ•°æ® 169 * @return ç°åº¦å›¾åƒçŸ©é˜µæ•°æ® 170 * @throws UnsupportedFormatException 171 */ 172 @Override 173 public byte[] getMatrixGray() throws UnsupportedFormatException{ 174 if(null==matrixGray){ 175 matrixGray = ImageUtil.getMatrixGRAY(read()); 176 } 177 return matrixGray; 178 179 } 180 @Override 181 public byte[] wirtePNGBytes(){ 182 try { 183 if("PNG".equalsIgnoreCase(getSuffix())){ 184 if(getImgBytes() != null){ 185 return getImgBytes(); 186 } 187 } 188 return ImageUtil.wirtePNGBytes(read()); 189 } catch (UnsupportedFormatException e) { 190 throw new RuntimeException(e); 191 } 192 } 193 @Override 194 public byte[] wirteJPEGBytes(){ 195 try { 196 if("JPEG".equalsIgnoreCase(getSuffix())){ 197 if(getImgBytes() != null){ 198 return getImgBytes(); 199 } 200 } 201 return ImageUtil.wirteJPEGBytes(read(),0.9f); 202 } catch (UnsupportedFormatException e) { 203 throw new RuntimeException(e); 204 } 205 } 206 /** 207 * 创建并打开对象 208 * @param imgBytes 209 * @return 210 * @throws NotImageException 211 * @throws UnsupportedFormatException 212 * @see #LazyImage(byte[]) 213 * @see #open() 214 */ 215 public static LazyImage create(final byte[] imgBytes) throws NotImageException, UnsupportedFormatException { 216 return new LazyImage(imgBytes).open(); 217 } 218 /** 219 * 创建对象 220 * @param bufferedImage 221 * @see #LazyImage(BufferedImage) 222 * @see #open() 223 * @return 224 */ 225 public static LazyImage create(final BufferedImage bufferedImage) { 226 try { 227 return new LazyImage(bufferedImage).open(); 228 } catch (ImageErrorException e) { 229 throw new RuntimeException(e); 230 } 231 } 232 /** 233 * ç”¨æœ¬åœ°å›¾åƒæ–‡ä»¶åˆ›å»ºå¯¹è±¡ 234 * @param file 235 * @param md5 {@code file}çš„MD5较验ç ,å¯ä»¥ä¸ºnull 236 * @return 237 * @throws NotImageException 238 * @throws UnsupportedFormatException 239 */ 240 public static LazyImage create(final File file, String md5) throws NotImageException, UnsupportedFormatException { 241 try { 242 return new LazyImage(file, md5).open(); 243 } catch (FileNotFoundException e) { 244 throw new RuntimeException(e); 245 } 246 } 247 248 /** 249 * 多æºåˆ›å»ºå¯¹è±¡ 250 * @param src 251 * @return 252 * @throws NotImageException 253 * @throws UnsupportedFormatException 254 * @see #LazyImage(Object) 255 * @see FaceUtilits#getBytesNotEmpty(Object) 256 */ 257 public static <T> LazyImage create(final T src) throws NotImageException, UnsupportedFormatException { 258 try { 259 return new LazyImage(src).open(); 260 } catch (IOException e) { 261 throw new RuntimeException(e); 262 } 263 } 264 265 /** 266 * @param bufferedImage å·²ç»è§£ç çš„å›¾åƒæ•°æ®,为null或为空,则抛出 {@link IllegalArgumentException} 267 */ 268 public LazyImage(BufferedImage bufferedImage) 269 { 270 Assert.notNull(bufferedImage, "bufferedImage"); 271 this.bufferedImage = bufferedImage; 272 } 273 /** 274 * @param imgBytes å›¾åƒæ•°æ®,{@code imgBytes}为null或为空,则抛出 {@link IllegalArgumentException} 275 */ 276 public LazyImage(byte[] imgBytes) { 277 super(imgBytes); 278 } 279 280 /** 281 * ç”¨æœ¬åœ°å›¾åƒæ–‡ä»¶åˆ›å»ºå¯¹è±¡ 282 * @param src 283 * @param md5 284 * @throws FileNotFoundException 285 */ 286 public LazyImage(File src, String md5) throws FileNotFoundException { 287 super(src, md5); 288 } 289 290 /** 291 * 多æºåˆ›å»ºå¯¹è±¡ 292 * @param src 293 * @throws IOException 294 * @see FaceUtilits#getBytesNotEmpty(Object) 295 */ 296 public <T>LazyImage(T src) throws IOException { 297 this(FaceUtilits.getBytesNotEmpty(src)); 298 } 299 300 /** 301 * 返回{@link ImageInputStream}对象<br> 302 * 如果 {@link #imageInputstream} 为{@code null},åˆ™æ ¹æ® {@link #imgBytes}或 {@link #localFile}创建 303 * @return imageInputstream 304 */ 305 private ImageInputStream getImageInputstream() { 306 if (null == imageInputstream) { 307 if (null == imgBytes) { 308 if (null == localFile) 309 throw new IllegalArgumentException( 310 "while isValidImage be true localFile & imgBytes can't be NULL all"); 311 try { 312 this.imageInputstream = new MemoryCacheImageInputStream(new FileInputStream(localFile)); 313 } catch (FileNotFoundException e) { 314 throw new RuntimeException(e); 315 } 316 }else{ 317 this.imageInputstream = new MemoryCacheImageInputStream(new ByteArrayInputStream(imgBytes)); 318 } 319 } 320 return imageInputstream; 321 } 322 323 /** 324 * 返回{@link ImageReader}对象<br> 325 * 如果 {@link #imageReader}为{@code null},åˆ™æ ¹æ® {@link #suffix}创建,失败抛出 326 * @return imageReader {@link ImageReader}对象 327 * @throws IllegalStateException æ— æ³•æ ¹æ®{@link #suffix}获å–{@link ImageReader} 328 */ 329 private ImageReader getImageReader() throws IllegalStateException { 330 if (null == imageReader) { 331 Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(suffix); 332 if (it.hasNext()) 333 imageReader = it.next(); 334 else 335 throw new IllegalStateException(String.format("invalid suffix %s", suffix)); 336 } 337 return imageReader; 338 } 339 340 /** 341 * é‡Šæ”¾èµ„æº 342 * @throws IOException 343 */ 344 public void close() throws IOException{ 345 if(null!=imageReader){ 346 imageReader.dispose(); 347 imageReader=null; 348 } 349 if(null!=imageInputstream){ 350 imageInputstream.close(); 351 imageInputstream=null; 352 } 353 super.close(); 354 } 355 @Override 356 public void finalize() throws Throwable { 357 this.bufferedImage=null; 358 this.rectangle=null; 359 super.finalize(); 360 } 361 362 363 /** 364 * 获å–图åƒçŸ©å½¢å¯¹è±¡ 365 * @return rectangle 366 */ 367 public Rectangle getRectangle() { 368 if(null==rectangle) 369 rectangle=new Rectangle(0,0,width,height); 370 return rectangle; 371 } 372}