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}