MediaImageItem.java revision e5867ef3f096521c4a7a289d83e75904b3a977c5
1/*
2 * Copyright (C) 2010 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
17package android.media.videoeditor;
18
19import java.io.IOException;
20
21import android.graphics.Bitmap;
22import android.graphics.BitmapFactory;
23import android.graphics.Canvas;
24import android.graphics.Paint;
25import android.graphics.Rect;
26import android.util.Log;
27import android.util.Pair;
28
29/**
30 * This class represents an image item on the storyboard. Note that images are
31 * scaled down to the maximum supported resolution by preserving the native
32 * aspect ratio. To learn the scaled image dimensions use
33 * {@link #getScaledWidth()} and {@link #getScaledHeight()} respectively.
34 *
35 * {@hide}
36 */
37public class MediaImageItem extends MediaItem {
38    // Logging
39    private static final String TAG = "MediaImageItem";
40
41    // The resize paint
42    private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
43
44    // Instance variables
45    private final int mWidth;
46    private final int mHeight;
47    private final int mAspectRatio;
48    private long mDurationMs;
49    private int mScaledWidth, mScaledHeight;
50
51    /**
52     * This class cannot be instantiated by using the default constructor
53     */
54    @SuppressWarnings("unused")
55    private MediaImageItem() throws IOException {
56        this(null, null, 0, RENDERING_MODE_BLACK_BORDER);
57    }
58
59    /**
60     * Constructor
61     *
62     * @param mediaItemId The media item id
63     * @param filename The image file name
64     * @param durationMs The duration of the image on the storyboard
65     * @param renderingMode The rendering mode
66     *
67     * @throws IOException
68     */
69    public MediaImageItem(String mediaItemId, String filename, long durationMs, int renderingMode)
70            throws IOException {
71        super(mediaItemId, filename, renderingMode);
72
73        // Determine the dimensions of the image
74        final BitmapFactory.Options dbo = new BitmapFactory.Options();
75        dbo.inJustDecodeBounds = true;
76        BitmapFactory.decodeFile(filename, dbo);
77
78        mWidth = dbo.outWidth;
79        mHeight = dbo.outHeight;
80        mDurationMs = durationMs;
81
82        // TODO: Determine the aspect ratio from the width and height
83        mAspectRatio = MediaProperties.ASPECT_RATIO_4_3;
84
85        // Images are stored in memory scaled to the maximum resolution to
86        // save memory.
87        final Pair<Integer, Integer>[] resolutions =
88            MediaProperties.getSupportedResolutions(mAspectRatio);
89        // Get the highest resolution
90        final Pair<Integer, Integer> maxResolution = resolutions[resolutions.length - 1];
91        if (mHeight > maxResolution.second) {
92            // We need to scale the image
93            scaleImage(filename, maxResolution.first, maxResolution.second);
94            mScaledWidth = maxResolution.first;
95            mScaledHeight = maxResolution.second;
96        } else {
97            mScaledWidth = mWidth;
98            mScaledHeight = mHeight;
99        }
100    }
101
102    /*
103     * {@inheritDoc}
104     */
105    @Override
106    public int getFileType() {
107        if (mFilename.endsWith(".jpg") || mFilename.endsWith(".jpeg")) {
108            return MediaProperties.FILE_JPEG;
109        } else if (mFilename.endsWith(".png")) {
110            return MediaProperties.FILE_PNG;
111        } else {
112            return MediaProperties.FILE_UNSUPPORTED;
113        }
114    }
115
116    /*
117     * {@inheritDoc}
118     */
119    @Override
120    public int getWidth() {
121        return mWidth;
122    }
123
124    /*
125     * {@inheritDoc}
126     */
127    @Override
128    public int getHeight() {
129        return mHeight;
130    }
131
132    /**
133     * @return The scaled width of the image.
134     */
135    public int getScaledWidth() {
136        return mScaledWidth;
137    }
138
139    /**
140     * @return The scaled height of the image.
141     */
142    public int getScaledHeight() {
143        return mScaledHeight;
144    }
145
146    /*
147     * {@inheritDoc}
148     */
149    @Override
150    public int getAspectRatio() {
151        return mAspectRatio;
152    }
153
154    /**
155     * This method will adjust the duration of bounding transitions, effects
156     * and overlays if the current duration of the transactions become greater
157     * than the maximum allowable duration.
158     *
159     * @param durationMs The duration of the image in the storyboard timeline
160     */
161    public void setDuration(long durationMs) {
162        mDurationMs = durationMs;
163
164        adjustElementsDuration();
165    }
166
167    /*
168     * {@inheritDoc}
169     */
170    @Override
171    public long getTimelineDuration() {
172        return mDurationMs;
173    }
174
175    /*
176     * {@inheritDoc}
177     */
178    @Override
179    public Bitmap getThumbnail(int width, int height, long timeMs) throws IOException {
180        return scaleImage(mFilename, width, height);
181    }
182
183    /*
184     * {@inheritDoc}
185     */
186    @Override
187    public Bitmap[] getThumbnailList(int width, int height, long startMs, long endMs,
188            int thumbnailCount) throws IOException {
189        final Bitmap thumbnail = scaleImage(mFilename, width, height);
190        final Bitmap[] thumbnailArray = new Bitmap[thumbnailCount];
191        for (int i = 0; i < thumbnailCount; i++) {
192            thumbnailArray[i] = thumbnail;
193        }
194        return thumbnailArray;
195    }
196
197    /**
198     * Resize a bitmap to the specified width and height
199     *
200     * @param filename The filename
201     * @param width The thumbnail width
202     * @param height The thumbnail height
203     *
204     * @return The resized bitmap
205     */
206    private Bitmap scaleImage(String filename, int width, int height)
207            throws IOException {
208        final BitmapFactory.Options dbo = new BitmapFactory.Options();
209        dbo.inJustDecodeBounds = true;
210        BitmapFactory.decodeFile(filename, dbo);
211
212        final int nativeWidth = dbo.outWidth;
213        final int nativeHeight = dbo.outHeight;
214        if (Log.isLoggable(TAG, Log.DEBUG)) {
215            Log.d(TAG, "generateThumbnail: Input: " + nativeWidth + "x" + nativeHeight
216                    + ", resize to: " + width + "x" + height);
217        }
218
219        final Bitmap srcBitmap;
220        float bitmapWidth, bitmapHeight;
221        if (nativeWidth > width || nativeHeight > height) {
222            float dx = ((float)nativeWidth) / ((float)width);
223            float dy = ((float)nativeHeight) / ((float)height);
224            if (dx > dy) {
225                bitmapWidth = width;
226                bitmapHeight = nativeHeight / dx;
227            } else {
228                bitmapWidth = nativeWidth / dy;
229                bitmapHeight = height;
230            }
231            // Create the bitmap from file
232            if (nativeWidth / bitmapWidth > 1) {
233                final BitmapFactory.Options options = new BitmapFactory.Options();
234                options.inSampleSize = nativeWidth / (int)bitmapWidth;
235                srcBitmap = BitmapFactory.decodeFile(filename, options);
236            } else {
237                srcBitmap = BitmapFactory.decodeFile(filename);
238            }
239        } else {
240            bitmapWidth = width;
241            bitmapHeight = height;
242            srcBitmap = BitmapFactory.decodeFile(filename);
243        }
244
245        if (srcBitmap == null) {
246            Log.e(TAG, "generateThumbnail: Cannot decode image bytes");
247            throw new IOException("Cannot decode file: " + mFilename);
248        }
249
250        // Create the canvas bitmap
251        final Bitmap bitmap = Bitmap.createBitmap((int)bitmapWidth, (int)bitmapHeight,
252                Bitmap.Config.ARGB_8888);
253        final Canvas canvas = new Canvas(bitmap);
254        canvas.drawBitmap(srcBitmap, new Rect(0, 0, srcBitmap.getWidth(), srcBitmap.getHeight()),
255                new Rect(0, 0, (int)bitmapWidth, (int)bitmapHeight), sResizePaint);
256        // Release the source bitmap
257        srcBitmap.recycle();
258        return bitmap;
259    }
260}
261