Home | History | Annotate | Download | only in filters
      1 /*
      2  * Copyright (C) 2012 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.filters;
     18 
     19 import android.graphics.Bitmap;
     20 import android.graphics.Canvas;
     21 import android.graphics.RectF;
     22 
     23 import com.adobe.xmp.XMPException;
     24 import com.adobe.xmp.XMPMeta;
     25 import com.android.gallery3d.app.Log;
     26 import com.android.gallery3d.filtershow.cache.BitmapCache;
     27 import com.android.gallery3d.filtershow.cache.ImageLoader;
     28 import com.android.gallery3d.filtershow.imageshow.MasterImage;
     29 import com.android.gallery3d.filtershow.pipeline.ImagePreset;
     30 
     31 /**
     32  * An image filter which creates a tiny planet projection.
     33  */
     34 public class ImageFilterTinyPlanet extends SimpleImageFilter {
     35 
     36 
     37     private static final String LOGTAG = ImageFilterTinyPlanet.class.getSimpleName();
     38     public static final String GOOGLE_PANO_NAMESPACE = "http://ns.google.com/photos/1.0/panorama/";
     39     FilterTinyPlanetRepresentation mParameters = new FilterTinyPlanetRepresentation();
     40 
     41     public static final String CROPPED_AREA_IMAGE_WIDTH_PIXELS =
     42             "CroppedAreaImageWidthPixels";
     43     public static final String CROPPED_AREA_IMAGE_HEIGHT_PIXELS =
     44             "CroppedAreaImageHeightPixels";
     45     public static final String CROPPED_AREA_FULL_PANO_WIDTH_PIXELS =
     46             "FullPanoWidthPixels";
     47     public static final String CROPPED_AREA_FULL_PANO_HEIGHT_PIXELS =
     48             "FullPanoHeightPixels";
     49     public static final String CROPPED_AREA_LEFT =
     50             "CroppedAreaLeftPixels";
     51     public static final String CROPPED_AREA_TOP =
     52             "CroppedAreaTopPixels";
     53 
     54     public ImageFilterTinyPlanet() {
     55         mName = "TinyPlanet";
     56     }
     57 
     58     @Override
     59     public void useRepresentation(FilterRepresentation representation) {
     60         FilterTinyPlanetRepresentation parameters = (FilterTinyPlanetRepresentation) representation;
     61         mParameters = parameters;
     62     }
     63 
     64     @Override
     65     public FilterRepresentation getDefaultRepresentation() {
     66         return new FilterTinyPlanetRepresentation();
     67     }
     68 
     69 
     70     native protected void nativeApplyFilter(
     71             Bitmap bitmapIn, int width, int height, Bitmap bitmapOut, int outSize, float scale,
     72             float angle);
     73 
     74 
     75     @Override
     76     public Bitmap apply(Bitmap bitmapIn, float scaleFactor, int quality) {
     77         int w = bitmapIn.getWidth();
     78         int h = bitmapIn.getHeight();
     79         int outputSize = (int) (w / 2f);
     80         ImagePreset preset = getEnvironment().getImagePreset();
     81         Bitmap mBitmapOut = null;
     82         if (preset != null) {
     83             XMPMeta xmp = ImageLoader.getXmpObject(MasterImage.getImage().getActivity());
     84             // Do nothing, just use bitmapIn as is if we don't have XMP.
     85             if(xmp != null) {
     86                 bitmapIn = applyXmp(bitmapIn, xmp, w);
     87             }
     88         }
     89         if (mBitmapOut != null) {
     90             if (outputSize != mBitmapOut.getHeight()) {
     91                 mBitmapOut = null;
     92             }
     93         }
     94         while (mBitmapOut == null) {
     95             try {
     96                 mBitmapOut = getEnvironment().getBitmap(outputSize,
     97                         outputSize, BitmapCache.TINY_PLANET);
     98             } catch (java.lang.OutOfMemoryError e) {
     99                 System.gc();
    100                 outputSize /= 2;
    101                 Log.v(LOGTAG, "No memory to create Full Tiny Planet create half");
    102             }
    103         }
    104         nativeApplyFilter(bitmapIn, bitmapIn.getWidth(), bitmapIn.getHeight(), mBitmapOut,
    105                 outputSize, mParameters.getZoom() / 100f, mParameters.getAngle());
    106 
    107         return mBitmapOut;
    108     }
    109 
    110     private Bitmap applyXmp(Bitmap bitmapIn, XMPMeta xmp, int intermediateWidth) {
    111         try {
    112             int croppedAreaWidth =
    113                     getInt(xmp, CROPPED_AREA_IMAGE_WIDTH_PIXELS);
    114             int croppedAreaHeight =
    115                     getInt(xmp, CROPPED_AREA_IMAGE_HEIGHT_PIXELS);
    116             int fullPanoWidth =
    117                     getInt(xmp, CROPPED_AREA_FULL_PANO_WIDTH_PIXELS);
    118             int fullPanoHeight =
    119                     getInt(xmp, CROPPED_AREA_FULL_PANO_HEIGHT_PIXELS);
    120             int left = getInt(xmp, CROPPED_AREA_LEFT);
    121             int top = getInt(xmp, CROPPED_AREA_TOP);
    122 
    123             if (fullPanoWidth == 0 || fullPanoHeight == 0) {
    124                 return bitmapIn;
    125             }
    126             // Make sure the intermediate image has the similar size to the
    127             // input.
    128             Bitmap paddedBitmap = null;
    129             float scale = intermediateWidth / (float) fullPanoWidth;
    130             while (paddedBitmap == null) {
    131                 try {
    132                     paddedBitmap = Bitmap.createBitmap(
    133                             (int) (fullPanoWidth * scale), (int) (fullPanoHeight * scale),
    134                             Bitmap.Config.ARGB_8888);
    135                 } catch (java.lang.OutOfMemoryError e) {
    136                     System.gc();
    137                     scale /= 2;
    138                 }
    139             }
    140             Canvas paddedCanvas = new Canvas(paddedBitmap);
    141 
    142             int right = left + croppedAreaWidth;
    143             int bottom = top + croppedAreaHeight;
    144             RectF destRect = new RectF(left * scale, top * scale, right * scale, bottom * scale);
    145             paddedCanvas.drawBitmap(bitmapIn, null, destRect, null);
    146             bitmapIn = paddedBitmap;
    147         } catch (XMPException ex) {
    148             // Do nothing, just use bitmapIn as is.
    149         }
    150         return bitmapIn;
    151     }
    152 
    153     private static int getInt(XMPMeta xmp, String key) throws XMPException {
    154         if (xmp.doesPropertyExist(GOOGLE_PANO_NAMESPACE, key)) {
    155             return xmp.getPropertyInteger(GOOGLE_PANO_NAMESPACE, key);
    156         } else {
    157             return 0;
    158         }
    159     }
    160 }
    161