summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java
blob: 535a39d1af3e0bcabf5d6a4b1a674f17dc3ade0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.gallery3d.filtershow.filters;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;

import com.adobe.xmp.XMPException;
import com.adobe.xmp.XMPMeta;
import com.android.gallery3d.R;
import com.android.gallery3d.app.Log;
import com.android.gallery3d.filtershow.editors.EditorTinyPlanet;
import com.android.gallery3d.filtershow.presets.ImagePreset;

/**
 * An image filter which creates a tiny planet projection.
 */
public class ImageFilterTinyPlanet extends SimpleImageFilter {


    private static final String LOGTAG = ImageFilterTinyPlanet.class.getSimpleName();
    public static final String GOOGLE_PANO_NAMESPACE = "http://ns.google.com/photos/1.0/panorama/";
    FilterTinyPlanetRepresentation mParameters = new FilterTinyPlanetRepresentation();

    public static final String CROPPED_AREA_IMAGE_WIDTH_PIXELS =
            "CroppedAreaImageWidthPixels";
    public static final String CROPPED_AREA_IMAGE_HEIGHT_PIXELS =
            "CroppedAreaImageHeightPixels";
    public static final String CROPPED_AREA_FULL_PANO_WIDTH_PIXELS =
            "FullPanoWidthPixels";
    public static final String CROPPED_AREA_FULL_PANO_HEIGHT_PIXELS =
            "FullPanoHeightPixels";
    public static final String CROPPED_AREA_LEFT =
            "CroppedAreaLeftPixels";
    public static final String CROPPED_AREA_TOP =
            "CroppedAreaTopPixels";

    public ImageFilterTinyPlanet() {
        mName = "TinyPlanet";
    }

    @Override
    public int getEditingViewId() {
        return EditorTinyPlanet.ID;
    }

    @Override
    public boolean hasDefaultRepresentation() {
        return true;
    }

    @Override
    public void useRepresentation(FilterRepresentation representation) {
        FilterTinyPlanetRepresentation parameters = (FilterTinyPlanetRepresentation) representation;
        mParameters = parameters;
    }

    @Override
    public FilterRepresentation getDefaultRepresentation() {
        FilterTinyPlanetRepresentation representation = new FilterTinyPlanetRepresentation();
        representation.setName("TinyPlanet");
        representation.setFilterClass(ImageFilterTinyPlanet.class);
        representation.setFilterType(FilterRepresentation.TYPE_TINYPLANET);
        return representation;
    }

    @Override
    public int getButtonId() {
        return R.id.tinyplanetButton;
    }

    @Override
    public int getTextId() {
        return R.string.tinyplanet;
    }

    public boolean isNil() {
        // TinyPlanet always has an effect
        return false;
    }

    native protected void nativeApplyFilter(
            Bitmap bitmapIn, int width, int height, Bitmap bitmapOut, int outSize, float scale,
            float angle);

    @Override
    public Bitmap apply(Bitmap bitmapIn, float scaleFactor, boolean highQuality) {
        int w = bitmapIn.getWidth();
        int h = bitmapIn.getHeight();
        int outputSize = (int) (w / 2f);
        ImagePreset preset = getImagePreset();

        if (preset != null) {
            XMPMeta xmp = preset.getImageLoader().getXmpObject();
            // Do nothing, just use bitmapIn as is if we don't have XMP.
            if(xmp != null) {
              bitmapIn = applyXmp(bitmapIn, xmp, w);
            }
        }

        Bitmap mBitmapOut = null;
        while (mBitmapOut == null) {
            try {
                mBitmapOut = Bitmap.createBitmap(
                        outputSize, outputSize, Bitmap.Config.ARGB_8888);
            } catch (java.lang.OutOfMemoryError e) {
                System.gc();
                outputSize /= 2;
                Log.v(LOGTAG, "No memory to create Full Tiny Planet create half");
            }
        }
        nativeApplyFilter(bitmapIn, bitmapIn.getWidth(), bitmapIn.getHeight(), mBitmapOut,
                outputSize, mParameters.getZoom() / 100f, mParameters.getAngle());

        if (true) {
            // TODO(hoford): FIXME and remove this section
            String text = "Tiny Planet Not Working";
            int w2 = bitmapIn.getWidth() / 2;
            int h2 = bitmapIn.getHeight() / 2;
            Canvas c = new Canvas(bitmapIn);
            Paint p = new Paint();
            Rect src = new Rect(0, 0, mBitmapOut.getWidth(), mBitmapOut.getHeight());
            Rect dst = new Rect(0, 0, bitmapIn.getWidth(), bitmapIn.getHeight());
            c.drawBitmap(mBitmapOut, 0, 0, p);
            float size = Math.min(w2, h2) / 4f;
            p.setTextSize(size);
            p.setColor(0xFF000000);
            p.setStyle(Paint.Style.STROKE);
            p.setStrokeWidth(20);
            Rect bounds = new Rect();
            p.getTextBounds(text, 0, text.length(), bounds);
            int tw = bounds.width() / 2;
            c.drawText(text, w2 - tw, h2, p);

            p.setColor(0xFFFF0000);
            p.setStyle(Paint.Style.FILL);
            p.setStrokeWidth(0);

            c.drawText(text, w2 - tw, h2, p);
        }
        return mBitmapOut;
    }

    private Bitmap applyXmp(Bitmap bitmapIn, XMPMeta xmp, int intermediateWidth) {
        try {
            int croppedAreaWidth =
                    getInt(xmp, CROPPED_AREA_IMAGE_WIDTH_PIXELS);
            int croppedAreaHeight =
                    getInt(xmp, CROPPED_AREA_IMAGE_HEIGHT_PIXELS);
            int fullPanoWidth =
                    getInt(xmp, CROPPED_AREA_FULL_PANO_WIDTH_PIXELS);
            int fullPanoHeight =
                    getInt(xmp, CROPPED_AREA_FULL_PANO_HEIGHT_PIXELS);
            int left = getInt(xmp, CROPPED_AREA_LEFT);
            int top = getInt(xmp, CROPPED_AREA_TOP);

            // Make sure the intermediate image has the similar size to the
            // input.
            Bitmap paddedBitmap = null;
            float scale = intermediateWidth / (float) fullPanoWidth;
            while (paddedBitmap == null) {
                try {
                    paddedBitmap = Bitmap.createBitmap(
                    (int) (fullPanoWidth * scale), (int) (fullPanoHeight * scale),
                    Bitmap.Config.ARGB_8888);
                } catch (java.lang.OutOfMemoryError e) {
                    System.gc();
                    scale /= 2;
                }
            }
            Canvas paddedCanvas = new Canvas(paddedBitmap);

            int right = left + croppedAreaWidth;
            int bottom = top + croppedAreaHeight;
            RectF destRect = new RectF(left * scale, top * scale, right * scale, bottom * scale);
            paddedCanvas.drawBitmap(bitmapIn, null, destRect, null);
            bitmapIn = paddedBitmap;
        } catch (XMPException ex) {
            // Do nothing, just use bitmapIn as is.
        }
        return bitmapIn;
    }

    private static int getInt(XMPMeta xmp, String key) throws XMPException {
        if (xmp.doesPropertyExist(GOOGLE_PANO_NAMESPACE, key)) {
            return xmp.getPropertyInteger(GOOGLE_PANO_NAMESPACE, key);
        } else {
            return 0;
        }
    }
}