1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.gallery3d.filtershow.pipeline;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.graphics.Bitmap;
22 import android.graphics.Canvas;
23 import android.graphics.Matrix;
24 import android.graphics.Paint;
25 import android.graphics.Rect;
26 import android.graphics.RectF;
27 import android.util.Log;
28 
29 import com.android.gallery3d.filtershow.cache.BitmapCache;
30 import com.android.gallery3d.filtershow.cache.ImageLoader;
31 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
32 import com.android.gallery3d.filtershow.filters.FiltersManager;
33 import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
34 import com.android.gallery3d.filtershow.imageshow.PrimaryImage;
35 
36 import java.util.Vector;
37 
38 public class CachingPipeline implements PipelineInterface {
39     private static final String LOGTAG = "CachingPipeline";
40     private boolean DEBUG = false;
41 
42     private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
43 
44     private FiltersManager mFiltersManager = null;
45     private volatile Bitmap mOriginalBitmap = null;
46     private volatile Bitmap mResizedOriginalBitmap = null;
47 
48     private FilterEnvironment mEnvironment = new FilterEnvironment();
49     private CacheProcessing mCachedProcessing = new CacheProcessing();
50 
51     private volatile int mWidth = 0;
52     private volatile int mHeight = 0;
53 
54     private volatile float mPreviewScaleFactor = 1.0f;
55     private volatile float mHighResPreviewScaleFactor = 1.0f;
56     private volatile String mName = "";
57 
CachingPipeline(FiltersManager filtersManager, String name)58     public CachingPipeline(FiltersManager filtersManager, String name) {
59         mFiltersManager = filtersManager;
60         mName = name;
61     }
62 
stop()63     public void stop() {
64         mEnvironment.setStop(true);
65     }
66 
reset()67     public synchronized void reset() {
68         synchronized (CachingPipeline.class) {
69             mOriginalBitmap = null; // just a reference to the bitmap in ImageLoader
70             if (mResizedOriginalBitmap != null) {
71                 mResizedOriginalBitmap.recycle();
72                 mResizedOriginalBitmap = null;
73             }
74 
75             mPreviewScaleFactor = 1.0f;
76             mHighResPreviewScaleFactor = 1.0f;
77 
78             mWidth = 0;
79             mHeight = 0;
80         }
81     }
82 
getType(RenderingRequest request)83     private String getType(RenderingRequest request) {
84         if (request.getType() == RenderingRequest.ICON_RENDERING) {
85             return "ICON_RENDERING";
86         }
87         if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
88             return "FILTERS_RENDERING";
89         }
90         if (request.getType() == RenderingRequest.FULL_RENDERING) {
91             return "FULL_RENDERING";
92         }
93         if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
94             return "GEOMETRY_RENDERING";
95         }
96         if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
97             return "PARTIAL_RENDERING";
98         }
99         if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
100             return "HIGHRES_RENDERING";
101         }
102         return "UNKNOWN TYPE!";
103     }
104 
setupEnvironment(ImagePreset preset, boolean highResPreview)105     private void setupEnvironment(ImagePreset preset, boolean highResPreview) {
106         mEnvironment.setPipeline(this);
107         mEnvironment.setFiltersManager(mFiltersManager);
108         mEnvironment.setBitmapCache(PrimaryImage.getImage().getBitmapCache());
109         if (highResPreview) {
110             mEnvironment.setScaleFactor(mHighResPreviewScaleFactor);
111         } else {
112             mEnvironment.setScaleFactor(mPreviewScaleFactor);
113         }
114         mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
115         mEnvironment.setImagePreset(preset);
116         mEnvironment.setStop(false);
117     }
118 
setOriginal(Bitmap bitmap)119     public void setOriginal(Bitmap bitmap) {
120         mOriginalBitmap = bitmap;
121         Log.v(LOGTAG,"setOriginal, size " + bitmap.getWidth() + " x " + bitmap.getHeight());
122         ImagePreset preset = PrimaryImage.getImage().getPreset();
123         setupEnvironment(preset, false);
124         updateOriginalAllocation(preset);
125     }
126 
updateOriginalAllocation(ImagePreset preset)127     private synchronized boolean updateOriginalAllocation(ImagePreset preset) {
128         if (preset == null) {
129             return false;
130         }
131         Bitmap originalBitmap = mOriginalBitmap;
132 
133         if (originalBitmap == null) {
134             return false;
135         }
136 
137         mResizedOriginalBitmap = preset.applyGeometry(originalBitmap, mEnvironment);
138 
139         return true;
140     }
141 
renderHighres(RenderingRequest request)142     public void renderHighres(RenderingRequest request) {
143         synchronized (CachingPipeline.class) {
144             ImagePreset preset = request.getImagePreset();
145             setupEnvironment(preset, false);
146             Bitmap bitmap = PrimaryImage.getImage().getOriginalBitmapHighres();
147             if (bitmap == null) {
148                 return;
149             }
150             bitmap = mEnvironment.getBitmapCopy(bitmap, BitmapCache.HIGHRES);
151             bitmap = preset.applyGeometry(bitmap, mEnvironment);
152 
153             mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
154             Bitmap bmp = preset.apply(bitmap, mEnvironment);
155             if (!mEnvironment.needsStop()) {
156                 request.setBitmap(bmp);
157             } else {
158                 mEnvironment.cache(bmp);
159             }
160             mFiltersManager.freeFilterResources(preset);
161         }
162     }
163 
renderGeometry(RenderingRequest request)164     public void renderGeometry(RenderingRequest request) {
165         synchronized (CachingPipeline.class) {
166             ImagePreset preset = request.getImagePreset();
167             setupEnvironment(preset, false);
168             Bitmap bitmap = PrimaryImage.getImage().getOriginalBitmapHighres();
169             if (bitmap == null) {
170                 return;
171             }
172             bitmap = mEnvironment.getBitmapCopy(bitmap, BitmapCache.GEOMETRY);
173             bitmap = preset.applyGeometry(bitmap, mEnvironment);
174             if (!mEnvironment.needsStop()) {
175                 request.setBitmap(bitmap);
176             } else {
177                 mEnvironment.cache(bitmap);
178             }
179             mFiltersManager.freeFilterResources(preset);
180         }
181     }
182 
renderFilters(RenderingRequest request)183     public void renderFilters(RenderingRequest request) {
184         synchronized (CachingPipeline.class) {
185             ImagePreset preset = request.getImagePreset();
186             setupEnvironment(preset, false);
187             Bitmap bitmap = PrimaryImage.getImage().getOriginalBitmapHighres();
188             if (bitmap == null) {
189                 return;
190             }
191             bitmap = mEnvironment.getBitmapCopy(bitmap, BitmapCache.FILTERS);
192             bitmap = preset.apply(bitmap, mEnvironment);
193             if (!mEnvironment.needsStop()) {
194                 request.setBitmap(bitmap);
195             } else {
196                 mEnvironment.cache(bitmap);
197             }
198             mFiltersManager.freeFilterResources(preset);
199         }
200     }
201 
render(RenderingRequest request)202     public synchronized void render(RenderingRequest request) {
203         // TODO: cleanup/remove GEOMETRY / FILTERS paths
204         synchronized (CachingPipeline.class) {
205             if ((request.getType() != RenderingRequest.PARTIAL_RENDERING
206                   && request.getType() != RenderingRequest.ICON_RENDERING
207                     && request.getBitmap() == null)
208                     || request.getImagePreset() == null) {
209                 return;
210             }
211 
212             if (DEBUG) {
213                 Log.v(LOGTAG, "render image of type " + getType(request));
214             }
215 
216             Bitmap bitmap = request.getBitmap();
217             ImagePreset preset = request.getImagePreset();
218             setupEnvironment(preset, true);
219             mFiltersManager.freeFilterResources(preset);
220 
221             if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
222                 PrimaryImage primary = PrimaryImage.getImage();
223                 bitmap = ImageLoader.getScaleOneImageForPreset(primary.getActivity(),
224                         mEnvironment.getBimapCache(),
225                         primary.getUri(), request.getBounds(),
226                         request.getDestination());
227                 if (bitmap == null) {
228                     Log.w(LOGTAG, "could not get bitmap for: " + getType(request));
229                     return;
230                 }
231             }
232 
233             if (request.getType() == RenderingRequest.FULL_RENDERING
234                     || request.getType() == RenderingRequest.GEOMETRY_RENDERING
235                     || request.getType() == RenderingRequest.FILTERS_RENDERING) {
236                 updateOriginalAllocation(preset);
237             }
238 
239             if (DEBUG && bitmap != null) {
240                 Log.v(LOGTAG, "after update, req bitmap (" + bitmap.getWidth() + "x"
241                         + bitmap.getHeight() + " ? resizeOriginal ("
242                         + mResizedOriginalBitmap.getWidth() + "x"
243                         + mResizedOriginalBitmap.getHeight());
244             }
245 
246             if (request.getType() == RenderingRequest.FULL_RENDERING
247                     || request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
248                 bitmap = mResizedOriginalBitmap;
249             } else if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
250                 bitmap = mOriginalBitmap;
251             }
252 
253             if (request.getType() == RenderingRequest.FULL_RENDERING
254                     || request.getType() == RenderingRequest.FILTERS_RENDERING
255                     || request.getType() == RenderingRequest.ICON_RENDERING
256                     || request.getType() == RenderingRequest.PARTIAL_RENDERING
257                     || request.getType() == RenderingRequest.STYLE_ICON_RENDERING) {
258 
259                 if (request.getType() == RenderingRequest.ICON_RENDERING) {
260                     mEnvironment.setQuality(FilterEnvironment.QUALITY_ICON);
261                 } else {
262                     mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
263                 }
264 
265                 if (request.getType() == RenderingRequest.ICON_RENDERING) {
266                     Rect iconBounds = request.getIconBounds();
267                     Bitmap source = PrimaryImage.getImage().getThumbnailBitmap();
268                     if (iconBounds.width() > source.getWidth() * 2) {
269                         source = PrimaryImage.getImage().getLargeThumbnailBitmap();
270                     }
271                     if (iconBounds != null) {
272                         bitmap = mEnvironment.getBitmap(iconBounds.width(),
273                                 iconBounds.height(), BitmapCache.ICON);
274                         Canvas canvas = new Canvas(bitmap);
275                         Matrix m = new Matrix();
276                         float minSize = Math.min(source.getWidth(), source.getHeight());
277                         float maxSize = Math.max(iconBounds.width(), iconBounds.height());
278                         float scale = maxSize / minSize;
279                         m.setScale(scale, scale);
280                         float dx = (iconBounds.width() - (source.getWidth() * scale))/2.0f;
281                         float dy = (iconBounds.height() - (source.getHeight() * scale))/2.0f;
282                         m.postTranslate(dx, dy);
283                         canvas.drawBitmap(source, m, new Paint(Paint.FILTER_BITMAP_FLAG));
284                     } else {
285                         bitmap = mEnvironment.getBitmapCopy(source, BitmapCache.ICON);
286                     }
287                 }
288                 Bitmap bmp = preset.apply(bitmap, mEnvironment);
289                 if (!mEnvironment.needsStop()) {
290                     request.setBitmap(bmp);
291                 }
292                 mFiltersManager.freeFilterResources(preset);
293             }
294         }
295     }
296 
renderFinalImage(Bitmap bitmap, ImagePreset preset)297     public synchronized Bitmap renderFinalImage(Bitmap bitmap, ImagePreset preset) {
298         synchronized (CachingPipeline.class) {
299             setupEnvironment(preset, false);
300             mEnvironment.setQuality(FilterEnvironment.QUALITY_FINAL);
301             mEnvironment.setScaleFactor(1.0f);
302             mFiltersManager.freeFilterResources(preset);
303             bitmap = preset.applyGeometry(bitmap, mEnvironment);
304             bitmap = preset.apply(bitmap, mEnvironment);
305             return bitmap;
306         }
307     }
308 
renderGeometryIcon(Bitmap bitmap, ImagePreset preset)309     public Bitmap renderGeometryIcon(Bitmap bitmap, ImagePreset preset) {
310         return GeometryMathUtils.applyGeometryRepresentations(preset.getGeometryFilters(), bitmap);
311     }
312 
compute(SharedBuffer buffer, ImagePreset preset, int type)313     public void compute(SharedBuffer buffer, ImagePreset preset, int type) {
314         setupEnvironment(preset, false);
315         Vector<FilterRepresentation> filters = preset.getFilters();
316         Bitmap result = mCachedProcessing.process(mOriginalBitmap, filters, mEnvironment);
317         buffer.setProducer(result);
318         mEnvironment.cache(result);
319     }
320 
needsRepaint()321     public boolean needsRepaint() {
322         SharedBuffer buffer = PrimaryImage.getImage().getPreviewBuffer();
323         return buffer.checkRepaintNeeded();
324     }
325 
setPreviewScaleFactor(float previewScaleFactor)326     public void setPreviewScaleFactor(float previewScaleFactor) {
327         mPreviewScaleFactor = previewScaleFactor;
328     }
329 
setHighResPreviewScaleFactor(float highResPreviewScaleFactor)330     public void setHighResPreviewScaleFactor(float highResPreviewScaleFactor) {
331         mHighResPreviewScaleFactor = highResPreviewScaleFactor;
332     }
333 
isInitialized()334     public synchronized boolean isInitialized() {
335         return mOriginalBitmap != null;
336     }
337 
getName()338     public String getName() {
339         return mName;
340     }
341 }
342