1666ea1b28a76aeba74744148b15099254d918671Owen Lin/*
2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2009 The Android Open Source Project
3666ea1b28a76aeba74744148b15099254d918671Owen Lin *
4666ea1b28a76aeba74744148b15099254d918671Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5666ea1b28a76aeba74744148b15099254d918671Owen Lin * you may not use this file except in compliance with the License.
6666ea1b28a76aeba74744148b15099254d918671Owen Lin * You may obtain a copy of the License at
7666ea1b28a76aeba74744148b15099254d918671Owen Lin *
8666ea1b28a76aeba74744148b15099254d918671Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9666ea1b28a76aeba74744148b15099254d918671Owen Lin *
10666ea1b28a76aeba74744148b15099254d918671Owen Lin * Unless required by applicable law or agreed to in writing, software
11666ea1b28a76aeba74744148b15099254d918671Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12666ea1b28a76aeba74744148b15099254d918671Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13666ea1b28a76aeba74744148b15099254d918671Owen Lin * See the License for the specific language governing permissions and
14666ea1b28a76aeba74744148b15099254d918671Owen Lin * limitations under the License.
15666ea1b28a76aeba74744148b15099254d918671Owen Lin */
16666ea1b28a76aeba74744148b15099254d918671Owen Lin
17666ea1b28a76aeba74744148b15099254d918671Owen Linpackage com.android.camera.gallery;
18666ea1b28a76aeba74744148b15099254d918671Owen Lin
198aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Linimport com.android.camera.BitmapManager;
20666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.Util;
21666ea1b28a76aeba74744148b15099254d918671Owen Lin
22666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentResolver;
23666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentValues;
24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap;
25666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.BitmapFactory;
26666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.media.ExifInterface;
27666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.net.Uri;
28666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.BaseColumns;
29666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore.Images;
30666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore.Images.ImageColumns;
31666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.Log;
32666ea1b28a76aeba74744148b15099254d918671Owen Lin
33666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.IOException;
34666ea1b28a76aeba74744148b15099254d918671Owen Lin
35666ea1b28a76aeba74744148b15099254d918671Owen Lin/**
36666ea1b28a76aeba74744148b15099254d918671Owen Lin * The class for normal images in gallery.
37666ea1b28a76aeba74744148b15099254d918671Owen Lin */
38666ea1b28a76aeba74744148b15099254d918671Owen Linpublic class Image extends BaseImage implements IImage {
39666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final String TAG = "BaseImage";
40666ea1b28a76aeba74744148b15099254d918671Owen Lin
41666ea1b28a76aeba74744148b15099254d918671Owen Lin    private ExifInterface mExif;
42666ea1b28a76aeba74744148b15099254d918671Owen Lin
43666ea1b28a76aeba74744148b15099254d918671Owen Lin    private int mRotation;
44666ea1b28a76aeba74744148b15099254d918671Owen Lin
45666ea1b28a76aeba74744148b15099254d918671Owen Lin    public Image(BaseImageList container, ContentResolver cr,
46b62254a185d04ecfe2ddc837b7e0e54f0273c478Owen Lin            long id, int index, Uri uri, String dataPath,
47185a1a7c5f33ecc5cb9a36d23cecb719c8727178Chih-Chung Chang            String mimeType, long dateTaken, String title,
48666ea1b28a76aeba74744148b15099254d918671Owen Lin            int rotation) {
49b62254a185d04ecfe2ddc837b7e0e54f0273c478Owen Lin        super(container, cr, id, index, uri, dataPath,
50185a1a7c5f33ecc5cb9a36d23cecb719c8727178Chih-Chung Chang                mimeType, dateTaken, title);
51666ea1b28a76aeba74744148b15099254d918671Owen Lin        mRotation = rotation;
52666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
53666ea1b28a76aeba74744148b15099254d918671Owen Lin
54666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
55666ea1b28a76aeba74744148b15099254d918671Owen Lin    public int getDegreesRotated() {
56666ea1b28a76aeba74744148b15099254d918671Owen Lin        return mRotation;
57666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
58666ea1b28a76aeba74744148b15099254d918671Owen Lin
59666ea1b28a76aeba74744148b15099254d918671Owen Lin    protected void setDegreesRotated(int degrees) {
60666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mRotation == degrees) return;
61666ea1b28a76aeba74744148b15099254d918671Owen Lin        mRotation = degrees;
62666ea1b28a76aeba74744148b15099254d918671Owen Lin        ContentValues values = new ContentValues();
63666ea1b28a76aeba74744148b15099254d918671Owen Lin        values.put(ImageColumns.ORIENTATION, mRotation);
64666ea1b28a76aeba74744148b15099254d918671Owen Lin        mContentResolver.update(mUri, values, null, null);
65666ea1b28a76aeba74744148b15099254d918671Owen Lin
66666ea1b28a76aeba74744148b15099254d918671Owen Lin        //TODO: Consider invalidate the cursor in container
67666ea1b28a76aeba74744148b15099254d918671Owen Lin        // ((BaseImageList) getContainer()).invalidateCursor();
68666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
69666ea1b28a76aeba74744148b15099254d918671Owen Lin
70666ea1b28a76aeba74744148b15099254d918671Owen Lin    public boolean isReadonly() {
71666ea1b28a76aeba74744148b15099254d918671Owen Lin        String mimeType = getMimeType();
72666ea1b28a76aeba74744148b15099254d918671Owen Lin        return !"image/jpeg".equals(mimeType) && !"image/png".equals(mimeType);
73666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
74666ea1b28a76aeba74744148b15099254d918671Owen Lin
75666ea1b28a76aeba74744148b15099254d918671Owen Lin    public boolean isDrm() {
76666ea1b28a76aeba74744148b15099254d918671Owen Lin        return false;
77666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
78666ea1b28a76aeba74744148b15099254d918671Owen Lin
79666ea1b28a76aeba74744148b15099254d918671Owen Lin    /**
80666ea1b28a76aeba74744148b15099254d918671Owen Lin     * Replaces the tag if already there. Otherwise, adds to the exif tags.
81666ea1b28a76aeba74744148b15099254d918671Owen Lin     * @param tag
82666ea1b28a76aeba74744148b15099254d918671Owen Lin     * @param value
83666ea1b28a76aeba74744148b15099254d918671Owen Lin     */
84666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void replaceExifTag(String tag, String value) {
85666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mExif == null) {
86666ea1b28a76aeba74744148b15099254d918671Owen Lin            loadExifData();
87666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
88666ea1b28a76aeba74744148b15099254d918671Owen Lin        mExif.setAttribute(tag, value);
89666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
90666ea1b28a76aeba74744148b15099254d918671Owen Lin
91666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void loadExifData() {
92666ea1b28a76aeba74744148b15099254d918671Owen Lin        try {
93666ea1b28a76aeba74744148b15099254d918671Owen Lin            mExif = new ExifInterface(mDataPath);
94666ea1b28a76aeba74744148b15099254d918671Owen Lin        } catch (IOException ex) {
95666ea1b28a76aeba74744148b15099254d918671Owen Lin            Log.e(TAG, "cannot read exif", ex);
96666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
97666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
98666ea1b28a76aeba74744148b15099254d918671Owen Lin
99666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void saveExifData() throws IOException {
100666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mExif != null) {
101666ea1b28a76aeba74744148b15099254d918671Owen Lin            mExif.saveAttributes();
102666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
103666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
104666ea1b28a76aeba74744148b15099254d918671Owen Lin
105666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void setExifRotation(int degrees) {
106666ea1b28a76aeba74744148b15099254d918671Owen Lin        try {
107666ea1b28a76aeba74744148b15099254d918671Owen Lin            degrees %= 360;
108666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (degrees < 0) degrees += 360;
109666ea1b28a76aeba74744148b15099254d918671Owen Lin
110666ea1b28a76aeba74744148b15099254d918671Owen Lin            int orientation = ExifInterface.ORIENTATION_NORMAL;
111666ea1b28a76aeba74744148b15099254d918671Owen Lin            switch (degrees) {
112666ea1b28a76aeba74744148b15099254d918671Owen Lin                case 0:
113666ea1b28a76aeba74744148b15099254d918671Owen Lin                    orientation = ExifInterface.ORIENTATION_NORMAL;
114666ea1b28a76aeba74744148b15099254d918671Owen Lin                    break;
115666ea1b28a76aeba74744148b15099254d918671Owen Lin                case 90:
116666ea1b28a76aeba74744148b15099254d918671Owen Lin                    orientation = ExifInterface.ORIENTATION_ROTATE_90;
117666ea1b28a76aeba74744148b15099254d918671Owen Lin                    break;
118666ea1b28a76aeba74744148b15099254d918671Owen Lin                case 180:
119666ea1b28a76aeba74744148b15099254d918671Owen Lin                    orientation = ExifInterface.ORIENTATION_ROTATE_180;
120666ea1b28a76aeba74744148b15099254d918671Owen Lin                    break;
121666ea1b28a76aeba74744148b15099254d918671Owen Lin                case 270:
122666ea1b28a76aeba74744148b15099254d918671Owen Lin                    orientation = ExifInterface.ORIENTATION_ROTATE_270;
123666ea1b28a76aeba74744148b15099254d918671Owen Lin                    break;
124666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
125666ea1b28a76aeba74744148b15099254d918671Owen Lin
126666ea1b28a76aeba74744148b15099254d918671Owen Lin            replaceExifTag(ExifInterface.TAG_ORIENTATION,
127666ea1b28a76aeba74744148b15099254d918671Owen Lin                    Integer.toString(orientation));
128666ea1b28a76aeba74744148b15099254d918671Owen Lin            saveExifData();
129666ea1b28a76aeba74744148b15099254d918671Owen Lin        } catch (Exception ex) {
130666ea1b28a76aeba74744148b15099254d918671Owen Lin            Log.e(TAG, "unable to save exif data with new orientation "
131666ea1b28a76aeba74744148b15099254d918671Owen Lin                    + fullSizeImageUri(), ex);
132666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
133666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
134666ea1b28a76aeba74744148b15099254d918671Owen Lin
135666ea1b28a76aeba74744148b15099254d918671Owen Lin    /**
136666ea1b28a76aeba74744148b15099254d918671Owen Lin     * Save the rotated image by updating the Exif "Orientation" tag.
137666ea1b28a76aeba74744148b15099254d918671Owen Lin     * @param degrees
138666ea1b28a76aeba74744148b15099254d918671Owen Lin     */
139666ea1b28a76aeba74744148b15099254d918671Owen Lin    public boolean rotateImageBy(int degrees) {
140666ea1b28a76aeba74744148b15099254d918671Owen Lin        int newDegrees = (getDegreesRotated() + degrees) % 360;
141666ea1b28a76aeba74744148b15099254d918671Owen Lin        setExifRotation(newDegrees);
142666ea1b28a76aeba74744148b15099254d918671Owen Lin        setDegreesRotated(newDegrees);
143666ea1b28a76aeba74744148b15099254d918671Owen Lin
144666ea1b28a76aeba74744148b15099254d918671Owen Lin        return true;
145666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
146666ea1b28a76aeba74744148b15099254d918671Owen Lin
147666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final String[] THUMB_PROJECTION = new String[] {
148666ea1b28a76aeba74744148b15099254d918671Owen Lin        BaseColumns._ID,
149666ea1b28a76aeba74744148b15099254d918671Owen Lin    };
150666ea1b28a76aeba74744148b15099254d918671Owen Lin
151666ea1b28a76aeba74744148b15099254d918671Owen Lin    public Bitmap thumbBitmap(boolean rotateAsNeeded) {
152666ea1b28a76aeba74744148b15099254d918671Owen Lin        Bitmap bitmap = null;
153666ea1b28a76aeba74744148b15099254d918671Owen Lin        BitmapFactory.Options options = new BitmapFactory.Options();
154666ea1b28a76aeba74744148b15099254d918671Owen Lin        options.inDither = false;
155666ea1b28a76aeba74744148b15099254d918671Owen Lin        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
1568aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin        bitmap = BitmapManager.instance().getThumbnail(mContentResolver, mId,
1578aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin                Images.Thumbnails.MINI_KIND, options, false);
158666ea1b28a76aeba74744148b15099254d918671Owen Lin
159666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (bitmap != null && rotateAsNeeded) {
160666ea1b28a76aeba74744148b15099254d918671Owen Lin            bitmap = Util.rotate(bitmap, getDegreesRotated());
161666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
162666ea1b28a76aeba74744148b15099254d918671Owen Lin
163666ea1b28a76aeba74744148b15099254d918671Owen Lin        return bitmap;
164666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
165666ea1b28a76aeba74744148b15099254d918671Owen Lin}
166