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