001package net.gdface.image; 002 003import java.io.File; 004import java.io.FileNotFoundException; 005import java.io.IOException; 006import java.io.OutputStream; 007import java.util.Iterator; 008import java.util.ServiceLoader; 009 010import net.gdface.utils.Assert; 011import net.gdface.utils.BaseVolatile; 012import net.gdface.utils.FaceUtilits; 013import net.gdface.utils.ILazyInitVariable; 014import net.gdface.utils.Judge; 015/** 016 * 图像数据处理对象<br> 017 * @author guyadong 018 * 019 */ 020public abstract class BaseLazyImage implements ImageMatrix { 021 private static final ILazyInitVariable<LazyImageFactory> lazyImageFactory = new BaseVolatile<LazyImageFactory>(){ 022 023 @Override 024 protected LazyImageFactory doGet() { 025 /* SPI(Service Provider Interface)机制加载 {@link LazyImageFactory}实例,没有找到则抛出异常 */ 026 ServiceLoader<LazyImageFactory> providers = ServiceLoader.load(LazyImageFactory.class); 027 Iterator<LazyImageFactory> itor = providers.iterator(); 028 if(!itor.hasNext()){ 029 throw new NotFoundLazyImageFactoryException(); 030 } 031 return itor.next(); 032 }}; 033 /** 034 * 图像原始数据(未解码) 035 */ 036 protected byte[] imgBytes = null; 037 /** 038 * 图像数据本地存储文件 039 */ 040 protected File localFile = null; 041 /** 042 * 图像数据的MD5校验码 043 */ 044 protected String md5 = null; 045 /** 046 * 图像文件后缀 047 */ 048 protected String suffix = null; 049 /** 050 * 是否在读取图像结束时自动执行 {@link #close()}释放资源<br> 051 * 默认为{@code true} 052 */ 053 protected boolean autoClose = true; 054 protected int width; 055 protected int height; 056 /** 057 * RGB格式的图像矩阵数据(全图) 058 */ 059 protected byte[] matrixRGB = null; 060 /** 061 * BGR格式的图像矩阵数据(全图) 062 */ 063 protected byte[] matrixBGR = null; 064 /** 065 * 灰度图像矩阵数据(全图) 066 */ 067 protected byte[] matrixGray = null; 068 /** 069 * RGBA格式的图像矩阵数据(全图) 070 */ 071 protected byte[] matrixRGBA = null; 072 073 protected BaseLazyImage() { 074 } 075 /** 076 * @param imgBytes 图像数据,{@code imgBytes}为null或为空,则抛出 {@link IllegalArgumentException} 077 */ 078 public BaseLazyImage(byte[] imgBytes) { 079 Assert.notEmpty(imgBytes, "imgBytes"); 080 this.imgBytes=imgBytes; 081 } 082 /** 083 * 用本地图像文件创建对象 084 * @param src 085 * @param md5 文件的MD5校验码,为{@code null}时自动计算 086 * @throws FileNotFoundException 087 */ 088 public BaseLazyImage(File src, String md5) throws FileNotFoundException { 089 Assert.notNull(src, "src"); 090 this.localFile = src; 091 if(!localFile.exists()||!localFile.isFile()||0==localFile.length()){ 092 throw new FileNotFoundException(String.format("NOT EXIST OR NOT FILE OR ZERO bytes%s",localFile.getAbsolutePath())); 093 } 094 String fileName = localFile.getName(); 095 this.suffix = fileName.substring(fileName.lastIndexOf(".") + 1); 096 this.md5 = md5; 097 } 098 /** 099 * 返回图像数据字节数组<br> 100 * 如果图像数据在本地文件中,则方法第一次被调用时将数据从文件中读取到内存 101 * @return the imgBytes,如果为无效图像,则返回null 102 * @throws IllegalArgumentException 参数错误 103 */ 104 public byte[] getImgBytes() { 105 106 if(null==imgBytes){ 107 if(null!=localFile){ 108 try { 109 imgBytes = FaceUtilits.getBytesNotEmpty(localFile); 110 } catch (IOException e) { 111 throw new RuntimeException(e); 112 } 113 }else 114 throw new IllegalArgumentException("while isValidImage be true localFile & imgBytes can't be NULL all"); 115 } 116 return imgBytes; 117 } 118 119 /** 120 * @return the md5 121 */ 122 public String getMd5() { 123 if (null == md5) 124 md5 = FaceUtilits.getMD5String(getImgBytes()); 125 return md5; 126 } 127 128 /** 129 * @return the suffix 130 */ 131 public String getSuffix() { 132 return suffix; 133 } 134 135 /** 136 * @return localFile 137 */ 138 public File getLocalFile() { 139 return localFile; 140 } 141 142 @Override 143 public int getWidth() { 144 return width; 145 } 146 147 @Override 148 public int getHeight() { 149 return height; 150 } 151 152 /** 153 * 在执行 {@link #read()}或 {@link #open()}之前调用,才有效 154 * @param autoClose 要设置的 autoClose 155 * @return 156 * @see #autoClose 157 */ 158 public BaseLazyImage setAutoClose(boolean autoClose) { 159 this.autoClose = autoClose; 160 return this; 161 } 162 /** 163 * 释放资源 164 * @throws IOException 165 */ 166 public void close() throws IOException{ 167 168 } 169 @Override 170 public void finalize() throws Throwable { 171 close(); 172 this.imgBytes=null; 173 this.localFile=null; 174 } 175 /** 176 * 读取图像基本信息,检查图像数据有效性 177 * @return 178 * @throws UnsupportedFormatException 179 * @throws NotImageException 180 */ 181 public abstract <T extends BaseLazyImage>T open() throws UnsupportedFormatException, NotImageException; 182 /** 183 * 以 {@link #md5}为名字将文件保存在{@code folder}文件夹下<br> 184 * 如果同名文件存在,且长度不为0时不覆盖 185 * @param folder 186 * @return 187 * @throws IOException 188 * @see FaceUtilits#saveBytes(byte[], File, boolean) 189 */ 190 public File save(File folder) throws IOException { 191 File file = new File(folder,getMd5()+(Judge.isEmpty(this.suffix)?"":"."+this.suffix)); 192 localFile= FaceUtilits.saveBytes(getImgBytes(), file, file.exists()&&file.isFile()&&0==file.length()); 193 return localFile; 194 } 195 public abstract byte[] wirtePNGBytes(); 196 public abstract byte[] wirteJPEGBytes(); 197 public void wirtePNGB(OutputStream out) throws IOException{ 198 Assert.notNull(out, "out"); 199 out.write(wirtePNGBytes()); 200 } 201 public void wirteJPEG(OutputStream out) throws IOException{ 202 Assert.notNull(out, "out"); 203 out.write(wirteJPEGBytes()); 204 } 205 /** 206 * 返回当前 {@link LazyImageFactory}实例 207 * @return 208 * @throws NotFoundLazyImageFactoryException 209 */ 210 public static final LazyImageFactory getLazyImageFactory() throws NotFoundLazyImageFactoryException{ 211 return lazyImageFactory.get(); 212 } 213 214}