1a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk/*
2a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk * Copyright (C) 2012 The Android Open Source Project
3a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk *
4a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
5a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk * you may not use this file except in compliance with the License.
6a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk * You may obtain a copy of the License at
7a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk *
8a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
9a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk *
10a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk * Unless required by applicable law or agreed to in writing, software
11a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
12a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk * See the License for the specific language governing permissions and
14a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk * limitations under the License.
15a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk */
167bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk
177bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunkpackage com.android.gallery3d.filtershow.filters;
187bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk
197bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunkimport android.graphics.Bitmap;
207bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunkimport android.graphics.Canvas;
21e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroardimport android.graphics.Matrix;
227bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunkimport android.graphics.Paint;
2362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunkimport android.graphics.Rect;
2462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunkimport android.graphics.RectF;
257bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk
26a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunkimport com.android.gallery3d.filtershow.imageshow.GeometryMath;
277bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunkimport com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
287bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk
297bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunkpublic class ImageFilterGeometry extends ImageFilter {
307bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk    private final Bitmap.Config mConfig = Bitmap.Config.ARGB_8888;
317bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk    private GeometryMetadata mGeometry = null;
32a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk    private static final String LOGTAG = "ImageFilterGeometry";
33a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk    private static final boolean LOGV = false;
34a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk    private static final int BOTH = 3;
35a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk    private static final int VERTICAL = 2;
36a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk    private static final int HORIZONTAL = 1;
3718fc4c1c247897db0dc74e4598a512827af816e9Ruben Brunk    private static final int NINETY = 1;
3818fc4c1c247897db0dc74e4598a512827af816e9Ruben Brunk    private static final int ONE_EIGHTY = 2;
3918fc4c1c247897db0dc74e4598a512827af816e9Ruben Brunk    private static final int TWO_SEVENTY = 3;
407bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk
417bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk    public ImageFilterGeometry() {
427bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk        mName = "Geometry";
437bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk    }
447bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk
457bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk    @Override
467bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk    public ImageFilter clone() throws CloneNotSupportedException {
477bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk        ImageFilterGeometry filter = (ImageFilterGeometry) super.clone();
487bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk        return filter;
497bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk    }
507bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk
51a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk    public void setGeometryMetadata(GeometryMetadata m) {
527bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk        mGeometry = m;
537bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk    }
547bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk
557bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk    native protected void nativeApplyFilterFlip(Bitmap src, int srcWidth, int srcHeight,
567bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk            Bitmap dst, int dstWidth, int dstHeight, int flip);
577bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk
58a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk    native protected void nativeApplyFilterRotate(Bitmap src, int srcWidth, int srcHeight,
5918fc4c1c247897db0dc74e4598a512827af816e9Ruben Brunk            Bitmap dst, int dstWidth, int dstHeight, int rotate);
60a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk
61a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk    native protected void nativeApplyFilterCrop(Bitmap src, int srcWidth, int srcHeight,
62a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk            Bitmap dst, int dstWidth, int dstHeight, int offsetWidth, int offsetHeight);
63a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk
64a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk    native protected void nativeApplyFilterStraighten(Bitmap src, int srcWidth, int srcHeight,
65a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk            Bitmap dst, int dstWidth, int dstHeight, float straightenAngle);
66a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk
67e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard    @Override
68e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard    public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
69e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard        // TODO: implement bilinear or bicubic here... for now, just use
70e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard        // canvas to do a simple implementation...
71e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard        // TODO: and be more memory efficient! (do it in native?)
7262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk        Rect cropBounds = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
73b470b229fbfd782db6758f331e4a6f918e305b02nicolasroard        RectF crop = mGeometry.getCropBounds(bitmap);
7400d64dd584c6d08310a32a28e75aebc6eb8238eaRuben Brunk        if (crop.width() > 0 && crop.height() > 0)
756a94446de01e8b6b034cc537ee3e65d507d47a47Ruben Brunk            cropBounds = GeometryMath.roundNearest(crop);
76e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard        Bitmap temp = null;
7762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk        if (mGeometry.hasSwitchedWidthHeight()) {
7862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk            temp = Bitmap.createBitmap(cropBounds.height(), cropBounds.width(), mConfig);
79e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard        } else {
8062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk            temp = Bitmap.createBitmap(cropBounds.width(), cropBounds.height(), mConfig);
817bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk        }
82a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk        float[] displayCenter = {
83a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk                temp.getWidth() / 2f, temp.getHeight() / 2f
84a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk        };
85a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk
86a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk        Matrix m1 = mGeometry.buildTotalXform(bitmap.getWidth(), bitmap.getHeight(), displayCenter);
87e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard
88e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard        Canvas canvas = new Canvas(temp);
89104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard        Paint paint = new Paint();
90104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard        paint.setAntiAlias(true);
91104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard        paint.setFilterBitmap(true);
92104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard        paint.setDither(true);
93a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk        canvas.drawBitmap(bitmap, m1, paint);
94e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard        return temp;
957bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk    }
967bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk
977bd602506fee36f3ef0a68bfa1ba5dd1e74ca5ddRuben Brunk}
98