1a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard/* 2a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * Copyright (C) 2012 The Android Open Source Project 3a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * 4a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * Licensed under the Apache License, Version 2.0 (the "License"); 5a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * you may not use this file except in compliance with the License. 6a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * You may obtain a copy of the License at 7a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * 8a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * http://www.apache.org/licenses/LICENSE-2.0 9a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * 10a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * Unless required by applicable law or agreed to in writing, software 11a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * distributed under the License is distributed on an "AS IS" BASIS, 12a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * See the License for the specific language governing permissions and 14a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * limitations under the License. 15a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard */ 162576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberling 172576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberlingpackage com.android.gallery3d.filtershow.filters; 182576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberling 192576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberlingimport android.graphics.Bitmap; 20c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberlingimport android.graphics.Canvas; 21044513931d31a4b86f622b1af36e9ce947672be7Sascha Haeberlingimport android.graphics.RectF; 222576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberling 23c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberlingimport com.adobe.xmp.XMPException; 24c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberlingimport com.adobe.xmp.XMPMeta; 254cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hofordimport com.android.gallery3d.app.Log; 26ec1e009a7faea0478e361bc2d48d856ab48a0209nicolasroardimport com.android.gallery3d.filtershow.cache.BitmapCache; 270c1b4c6422a4d2d9b81cc0946d1c9675440a94e2Ruben Brunkimport com.android.gallery3d.filtershow.cache.ImageLoader; 280c1b4c6422a4d2d9b81cc0946d1c9675440a94e2Ruben Brunkimport com.android.gallery3d.filtershow.imageshow.MasterImage; 29ce9ceff5776a9b0479c30cbeb2a9388b44df1865nicolasroardimport com.android.gallery3d.filtershow.pipeline.ImagePreset; 30e9c55b28a4a155c2e1c1f5aec615a0c56e38ade4John Hoford 312f879102d630815df64636b8d37e3a7eea8e8b65Sascha Haeberling/** 322f879102d630815df64636b8d37e3a7eea8e8b65Sascha Haeberling * An image filter which creates a tiny planet projection. 332f879102d630815df64636b8d37e3a7eea8e8b65Sascha Haeberling */ 3471f04cbaedbb89e313e0b86b531640db2d3f6016nicolasroardpublic class ImageFilterTinyPlanet extends SimpleImageFilter { 352c6ea941a80ea22317d664e329aed51f5f7417b9nicolasroard 3644a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford 3744a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford private static final String LOGTAG = ImageFilterTinyPlanet.class.getSimpleName(); 38c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling public static final String GOOGLE_PANO_NAMESPACE = "http://ns.google.com/photos/1.0/panorama/"; 3944a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford FilterTinyPlanetRepresentation mParameters = new FilterTinyPlanetRepresentation(); 40c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling 41c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling public static final String CROPPED_AREA_IMAGE_WIDTH_PIXELS = 42c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling "CroppedAreaImageWidthPixels"; 43c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling public static final String CROPPED_AREA_IMAGE_HEIGHT_PIXELS = 44c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling "CroppedAreaImageHeightPixels"; 45c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling public static final String CROPPED_AREA_FULL_PANO_WIDTH_PIXELS = 46c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling "FullPanoWidthPixels"; 47c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling public static final String CROPPED_AREA_FULL_PANO_HEIGHT_PIXELS = 48c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling "FullPanoHeightPixels"; 49c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling public static final String CROPPED_AREA_LEFT = 50c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling "CroppedAreaLeftPixels"; 51c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling public static final String CROPPED_AREA_TOP = 52c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling "CroppedAreaTopPixels"; 532576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberling 542576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberling public ImageFilterTinyPlanet() { 552576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberling mName = "TinyPlanet"; 562c6ea941a80ea22317d664e329aed51f5f7417b9nicolasroard } 572c6ea941a80ea22317d664e329aed51f5f7417b9nicolasroard 588cc3b55d615b349b4fcdff0eeeefe6907d4950ffnicolasroard @Override 5944a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford public void useRepresentation(FilterRepresentation representation) { 6044a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford FilterTinyPlanetRepresentation parameters = (FilterTinyPlanetRepresentation) representation; 6144a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford mParameters = parameters; 6244a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford } 6344a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford 6444a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford @Override 6544a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford public FilterRepresentation getDefaultRepresentation() { 666900cad45d240c9a54b92991538b6a33652e766cnicolasroard return new FilterTinyPlanetRepresentation(); 67dffe6a6f8bbf4565df211b07bcfc23d6864a48b6nicolasroard } 68dffe6a6f8bbf4565df211b07bcfc23d6864a48b6nicolasroard 6991d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford 702f879102d630815df64636b8d37e3a7eea8e8b65Sascha Haeberling native protected void nativeApplyFilter( 7167fefdb9b77644c955e1c0c5b1fcd51e2374f212John Hoford Bitmap bitmapIn, int width, int height, Bitmap bitmapOut, int outSize, float scale, 7267fefdb9b77644c955e1c0c5b1fcd51e2374f212John Hoford float angle); 732f879102d630815df64636b8d37e3a7eea8e8b65Sascha Haeberling 7491d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford 752576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberling @Override 7699baf61387ab1ef15bb9db5fa3b2b55591e87059John Hoford public Bitmap apply(Bitmap bitmapIn, float scaleFactor, int quality) { 77c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling int w = bitmapIn.getWidth(); 78c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling int h = bitmapIn.getHeight(); 79044513931d31a4b86f622b1af36e9ce947672be7Sascha Haeberling int outputSize = (int) (w / 2f); 8036e567afff815bc821c2859ebdeec86b1fca1ef6nicolasroard ImagePreset preset = getEnvironment().getImagePreset(); 8191d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford Bitmap mBitmapOut = null; 82769d38db5736cd690ab7837c0824572739c39184Sascha Haeberling if (preset != null) { 830c1b4c6422a4d2d9b81cc0946d1c9675440a94e2Ruben Brunk XMPMeta xmp = ImageLoader.getXmpObject(MasterImage.getImage().getActivity()); 84769d38db5736cd690ab7837c0824572739c39184Sascha Haeberling // Do nothing, just use bitmapIn as is if we don't have XMP. 85769d38db5736cd690ab7837c0824572739c39184Sascha Haeberling if(xmp != null) { 8691d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford bitmapIn = applyXmp(bitmapIn, xmp, w); 8791d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford } 8891d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford } 8991d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford if (mBitmapOut != null) { 9091d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford if (outputSize != mBitmapOut.getHeight()) { 9191d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford mBitmapOut = null; 92769d38db5736cd690ab7837c0824572739c39184Sascha Haeberling } 93e9c55b28a4a155c2e1c1f5aec615a0c56e38ade4John Hoford } 944cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford while (mBitmapOut == null) { 954cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford try { 96ec1e009a7faea0478e361bc2d48d856ab48a0209nicolasroard mBitmapOut = getEnvironment().getBitmap(outputSize, 97ec1e009a7faea0478e361bc2d48d856ab48a0209nicolasroard outputSize, BitmapCache.TINY_PLANET); 984cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford } catch (java.lang.OutOfMemoryError e) { 994cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford System.gc(); 1004cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford outputSize /= 2; 10144a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford Log.v(LOGTAG, "No memory to create Full Tiny Planet create half"); 1024cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford } 1034cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford } 104c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling nativeApplyFilter(bitmapIn, bitmapIn.getWidth(), bitmapIn.getHeight(), mBitmapOut, 10544a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford outputSize, mParameters.getZoom() / 100f, mParameters.getAngle()); 10644a499a64158cd5a12f8e44655f82b68c33bf3b2John Hoford 1072f879102d630815df64636b8d37e3a7eea8e8b65Sascha Haeberling return mBitmapOut; 1082576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberling } 109c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling 110769d38db5736cd690ab7837c0824572739c39184Sascha Haeberling private Bitmap applyXmp(Bitmap bitmapIn, XMPMeta xmp, int intermediateWidth) { 111d49d53206a197b08ec4754d8751b6860e33d9f48John Reck try { 112d49d53206a197b08ec4754d8751b6860e33d9f48John Reck int croppedAreaWidth = 113d49d53206a197b08ec4754d8751b6860e33d9f48John Reck getInt(xmp, CROPPED_AREA_IMAGE_WIDTH_PIXELS); 114d49d53206a197b08ec4754d8751b6860e33d9f48John Reck int croppedAreaHeight = 115d49d53206a197b08ec4754d8751b6860e33d9f48John Reck getInt(xmp, CROPPED_AREA_IMAGE_HEIGHT_PIXELS); 116d49d53206a197b08ec4754d8751b6860e33d9f48John Reck int fullPanoWidth = 117d49d53206a197b08ec4754d8751b6860e33d9f48John Reck getInt(xmp, CROPPED_AREA_FULL_PANO_WIDTH_PIXELS); 118d49d53206a197b08ec4754d8751b6860e33d9f48John Reck int fullPanoHeight = 119d49d53206a197b08ec4754d8751b6860e33d9f48John Reck getInt(xmp, CROPPED_AREA_FULL_PANO_HEIGHT_PIXELS); 120d49d53206a197b08ec4754d8751b6860e33d9f48John Reck int left = getInt(xmp, CROPPED_AREA_LEFT); 121d49d53206a197b08ec4754d8751b6860e33d9f48John Reck int top = getInt(xmp, CROPPED_AREA_TOP); 122d49d53206a197b08ec4754d8751b6860e33d9f48John Reck 1234ea01ce27d0aecd1b63d7e99b747c9858fa93b02nicolasroard if (fullPanoWidth == 0 || fullPanoHeight == 0) { 1244ea01ce27d0aecd1b63d7e99b747c9858fa93b02nicolasroard return bitmapIn; 1254ea01ce27d0aecd1b63d7e99b747c9858fa93b02nicolasroard } 126044513931d31a4b86f622b1af36e9ce947672be7Sascha Haeberling // Make sure the intermediate image has the similar size to the 127044513931d31a4b86f622b1af36e9ce947672be7Sascha Haeberling // input. 1284cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford Bitmap paddedBitmap = null; 129044513931d31a4b86f622b1af36e9ce947672be7Sascha Haeberling float scale = intermediateWidth / (float) fullPanoWidth; 1304cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford while (paddedBitmap == null) { 1314cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford try { 1324cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford paddedBitmap = Bitmap.createBitmap( 13391d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford (int) (fullPanoWidth * scale), (int) (fullPanoHeight * scale), 13491d26f6c3b183862eeffc1856e2d758e800d13f4John Hoford Bitmap.Config.ARGB_8888); 1354cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford } catch (java.lang.OutOfMemoryError e) { 1364cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford System.gc(); 1374cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford scale /= 2; 1384cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford } 1394cdb22512f322d2749aa57e07abeebf65b47c26fJohn Hoford } 140d49d53206a197b08ec4754d8751b6860e33d9f48John Reck Canvas paddedCanvas = new Canvas(paddedBitmap); 141d49d53206a197b08ec4754d8751b6860e33d9f48John Reck 142d49d53206a197b08ec4754d8751b6860e33d9f48John Reck int right = left + croppedAreaWidth; 143d49d53206a197b08ec4754d8751b6860e33d9f48John Reck int bottom = top + croppedAreaHeight; 144044513931d31a4b86f622b1af36e9ce947672be7Sascha Haeberling RectF destRect = new RectF(left * scale, top * scale, right * scale, bottom * scale); 145d49d53206a197b08ec4754d8751b6860e33d9f48John Reck paddedCanvas.drawBitmap(bitmapIn, null, destRect, null); 146d49d53206a197b08ec4754d8751b6860e33d9f48John Reck bitmapIn = paddedBitmap; 147d49d53206a197b08ec4754d8751b6860e33d9f48John Reck } catch (XMPException ex) { 148d49d53206a197b08ec4754d8751b6860e33d9f48John Reck // Do nothing, just use bitmapIn as is. 149d49d53206a197b08ec4754d8751b6860e33d9f48John Reck } 150d49d53206a197b08ec4754d8751b6860e33d9f48John Reck return bitmapIn; 151d49d53206a197b08ec4754d8751b6860e33d9f48John Reck } 152d49d53206a197b08ec4754d8751b6860e33d9f48John Reck 153c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling private static int getInt(XMPMeta xmp, String key) throws XMPException { 154c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling if (xmp.doesPropertyExist(GOOGLE_PANO_NAMESPACE, key)) { 155c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling return xmp.getPropertyInteger(GOOGLE_PANO_NAMESPACE, key); 156c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling } else { 157c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling return 0; 158c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling } 159c60752b28bcdc859b24040f77883568e0838ed74Sascha Haeberling } 1602576a29cccf1d96edeef071914e8b775c230e8e8Sascha Haeberling} 161