package jp.crwdev.app.util; import java.awt.image.BufferedImage; import java.io.InputStream; import java.util.HashMap; import java.util.LinkedList; import jp.crwdev.app.BufferedImageIO; import jp.crwdev.app.gui.DebugWindow; import jp.crwdev.app.imagefilter.PreviewImageFilter; import jp.crwdev.app.interfaces.IImageFileInfo; import jp.crwdev.app.interfaces.IImageFileInfoList; import jp.crwdev.app.interfaces.IImageFilter; import jp.crwdev.app.setting.ImageFilterParamSet; public class ImageCache { public static boolean enable = false; private static ImageCache mInstance; public static ImageCache getInstance(){ if(mInstance == null){ mInstance = new ImageCache(); } return mInstance; } public static void clear(){ if(mInstance != null){ mInstance.clearCache(); } } public static void dispose(){ if(mInstance != null){ mInstance.release(); mInstance = null; } } public void setImageFileInfoList(IImageFileInfoList list){ release(); mFileInfoList = list; } protected ImageCache(){ mFileInfoList = null; } protected void release(){ finalizeThread(); mImageMap.clear(); } protected void clearCache(){ if(mTempMap != null){ mTempMap.clear(); } mImageMap.clear(); } private HashMap<Integer, ImageData> mImageMap = new HashMap<Integer, ImageData>(); private IImageFileInfoList mFileInfoList = null; private PreviewImageFilter mImageFilter = new PreviewImageFilter(); public void setImageFilterParam(ImageFilterParamSet params){ mImageFilter.setImageFilterParam(params); mImageMap.clear(); } public ImageData getImageData(int targetPage){ if(!mImageMap.containsKey(targetPage)){ return loadOriginalImage(targetPage); } return mImageMap.get(targetPage); } private LinkedList<Integer> mQueue = new LinkedList<Integer>(); private Object mThreadLock = new Object(); private Thread mThread = null; private boolean mThreadFinish = false; public void startRenderImage(int startPage){ if(mThread == null){ mThread = new Thread(){ @Override public void run(){ int targetPage = 0; while(!mThreadFinish){ synchronized(mThreadLock){ if(mQueue.isEmpty()){ try { mThreadLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if(!mQueue.isEmpty()){ targetPage = mQueue.pop(); } } try { boolean loop = true; storeImage(); while(loop && !mThreadFinish){ loadOriginalImage(targetPage); synchronized(mQueue){ loop = !mQueue.isEmpty(); if(loop){ targetPage = mQueue.pop(); } } } removeImage(); }catch(Exception e){ }catch(OutOfMemoryError e){ } } mThread = null; } }; mThread.setPriority(Thread.NORM_PRIORITY); mThread.start(); } synchronized(mThreadLock){ //while(mQueue.size() > 0){ // mQueue.remove(); //} for(int i=0; i<3; i++){ mQueue.addLast(startPage+i); } mThreadLock.notify(); } } private void finalizeThread(){ if(mThread != null){ mThreadFinish = true; synchronized(mThreadLock){ mThreadLock.notify(); } mThread = null; } } private HashMap<Integer, ImageData> mTempMap; private void storeImage(){ mTempMap = mImageMap; mImageMap = new HashMap<Integer, ImageData>(); } private void removeImage(){ mTempMap.clear(); outputCacheLog(); } private void outputCacheLog(){ StringBuffer sb = new StringBuffer("ImageCache "); for(ImageData image : mImageMap.values()){ sb.append("[page=" + image.getPage() + " "); if(image.hasOriginal()){ sb.append("o"); } if(image.hasDisplay()){ sb.append("d"); } if(image.hasZoom()){ sb.append("z"); } sb.append("]"); } DebugWindow.log(sb.toString()); } private ImageData loadOriginalImage(int targetPage){ int size = mFileInfoList.size(); if(targetPage < 0 || size <= targetPage){ return null; } if(mTempMap != null && mTempMap.containsKey(targetPage)){ ImageData data = mTempMap.remove(targetPage); mImageMap.put(targetPage, data); return data; } if(!mImageMap.containsKey(targetPage)){ DebugWindow.log("loadOriginalImage(" + targetPage + ") start"); ImageData data = new ImageData(targetPage, mFileInfoList.get(targetPage)); data.getOriginalImage(); mImageMap.put(targetPage, data); DebugWindow.log("loadOriginalImage(" + targetPage + ") end"); outputCacheLog(); return data; } return mImageMap.get(targetPage); } public class ImageData { private BufferedImage mOriginalImage; private BufferedImage mDisplayImage; private BufferedImage mZoomImage; private boolean mIsLoadingZoomImage = false; private boolean mIsLoadingDisplayImage = false; private int mPage; private IImageFileInfo mInfo; //private PreviewImageFilter mImageFilter = new PreviewImageFilter(); //private PreviewImageFilter mPreviewZoomFilter = new PreviewImageFilter(); public ImageData(int page, IImageFileInfo info){ mPage = page; mInfo = info; } public int getPage(){ return mPage; } public boolean hasOriginal(){ return mOriginalImage != null; } public boolean hasDisplay(){ return mDisplayImage != null; } public boolean hasZoom(){ return mZoomImage != null; } public BufferedImage getOriginalImage(){ if(mOriginalImage == null){ mIsLoadingDisplayImage = false; mIsLoadingZoomImage = false; InputStream stream = mInfo.getInputStream(); try { BufferedImage image = null; if(stream != null){ image = BufferedImageIO.read(stream, mInfo.isJpeg()); } else{ //boolean preview = true; image = mInfo.getImage(true); } mOriginalImage = image; }catch(OutOfMemoryError e){ } } return mOriginalImage; } public BufferedImage getDisplayImage(IImageFilter filter, boolean needUpdate){ if(needUpdate){ mDisplayImage = null; mIsLoadingDisplayImage = false; mZoomImage = null; mIsLoadingZoomImage = false; } if(mDisplayImage == null && !mIsLoadingDisplayImage){ mIsLoadingDisplayImage = true; DebugWindow.log("getDisplayImage(" + mPage + ") start"); BufferedImage originalImage = getOriginalImage(); if(originalImage != null){ BufferedImage filtered = filter.filter(BufferedImageIO.copyBufferedImage(mOriginalImage), mInfo.getFilterParam()); mDisplayImage = filtered; } DebugWindow.log("getDisplayImage(" + mPage + ") end"); outputCacheLog(); } return mDisplayImage; } public BufferedImage getZoomImage(IImageFilter filter){ if(mZoomImage == null && !mIsLoadingZoomImage){ mIsLoadingDisplayImage = true; DebugWindow.log("getZoomImage(" + mPage + ") start"); BufferedImage originalImage = getOriginalImage(); if(originalImage != null){ BufferedImage filtered = filter.filter(BufferedImageIO.copyBufferedImage(mOriginalImage), mInfo.getFilterParam()); mZoomImage = filtered; } DebugWindow.log("getZoomImage(" + mPage + ") end"); outputCacheLog(); } return mZoomImage; } } }