MediaImageItem.java revision fdacc8be92cd36f712cfdb0fcf9b0e847f8eeb58
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;
27
28/**
29 * This class represents an image item on the storyboard.
30 * {@hide}
31 */
32public class MediaImageItem extends MediaItem {
33    // Logging
34    private static final String TAG = "MediaImageItem";
35
36    // The resize paint
37    private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
38
39    // Instance variables
40    private final int mWidth;
41    private final int mHeight;
42    private final int mAspectRatio;
43    private long mDurationMs;
44
45    /**
46     * This class cannot be instantiated by using the default constructor
47     */
48    @SuppressWarnings("unused")
49    private MediaImageItem() throws IOException {
50        this(null, null, 0, RENDERING_MODE_BLACK_BORDER);
51    }
52
53    /**
54     * Constructor
55     *
56     * @param mediaItemId The MediaItem id
57     * @param filename The image file name
58     * @param durationMs The duration of the image on the storyboard
59     * @param renderingMode The rendering mode
60     *
61     * @throws IOException
62     */
63    public MediaImageItem(String mediaItemId, String filename, long durationMs, int renderingMode)
64            throws IOException {
65        super(mediaItemId, filename, renderingMode);
66
67        // Determine the size of the image
68        final BitmapFactory.Options dbo = new BitmapFactory.Options();
69        dbo.inJustDecodeBounds = true;
70        BitmapFactory.decodeFile(filename, dbo);
71
72        mWidth = dbo.outWidth;
73        mHeight = dbo.outHeight;
74        mDurationMs = durationMs;
75
76        // TODO: Determine the aspect ratio from the width and height
77        mAspectRatio = MediaProperties.ASPECT_RATIO_4_3;
78    }
79
80    /*
81     * {@inheritDoc}
82     */
83    @Override
84    public int getFileType() {
85        if (mFilename.endsWith(".jpg") || mFilename.endsWith(".jpeg")) {
86            return MediaProperties.FILE_JPEG;
87        } else if (mFilename.endsWith(".png")) {
88            return MediaProperties.FILE_PNG;
89        } else {
90            return MediaProperties.FILE_UNSUPPORTED;
91        }
92    }
93
94    /*
95     * {@inheritDoc}
96     */
97    @Override
98    public int getWidth() {
99        return mWidth;
100    }
101
102    /*
103     * {@inheritDoc}
104     */
105    @Override
106    public int getHeight() {
107        return mHeight;
108    }
109
110    /*
111     * {@inheritDoc}
112     */
113    @Override
114    public int getAspectRatio() {
115        return mAspectRatio;
116    }
117
118    /**
119     * @param durationMs The duration of the image in the storyboard timeline
120     */
121    public void setDuration(long durationMs) {
122        mDurationMs = durationMs;
123        // TODO: Validate/modify the start and the end time of effects and overlays
124    }
125
126    /*
127     * {@inheritDoc}
128     */
129    @Override
130    public long getDuration() {
131        return mDurationMs;
132    }
133
134    /*
135     * {@inheritDoc}
136     */
137    @Override
138    public long getTimelineDuration() {
139        return mDurationMs;
140    }
141
142    /*
143     * {@inheritDoc}
144     */
145    @Override
146    public Bitmap getThumbnail(int width, int height, long timeMs) throws IOException {
147        return generateImageThumbnail(mFilename, width, height);
148    }
149
150    /*
151     * {@inheritDoc}
152     */
153    @Override
154    public Bitmap[] getThumbnailList(int width, int height, long startMs, long endMs,
155            int thumbnailCount) throws IOException {
156        final Bitmap thumbnail = generateImageThumbnail(mFilename, width, height);
157        final Bitmap[] thumbnailArray = new Bitmap[thumbnailCount];
158        for (int i = 0; i < thumbnailCount; i++) {
159            thumbnailArray[i] = thumbnail;
160        }
161        return thumbnailArray;
162    }
163
164    /**
165     * Resize a bitmap within an input stream
166     *
167     * @param filename The filename
168     * @param width The thumbnail width
169     * @param height The thumbnail height
170     *
171     * @return The resized bitmap
172     */
173    private Bitmap generateImageThumbnail(String filename, int width, int height)
174            throws IOException {
175        final BitmapFactory.Options dbo = new BitmapFactory.Options();
176        dbo.inJustDecodeBounds = true;
177        BitmapFactory.decodeFile(filename, dbo);
178
179        final int nativeWidth = dbo.outWidth;
180        final int nativeHeight = dbo.outHeight;
181        if (Log.isLoggable(TAG, Log.DEBUG)) {
182            Log.d(TAG, "generateThumbnail: Input: " + nativeWidth + "x" + nativeHeight
183                    + ", resize to: " + width + "x" + height);
184        }
185
186        final Bitmap srcBitmap;
187        float bitmapWidth, bitmapHeight;
188        if (nativeWidth > width || nativeHeight > height) {
189            float dx = ((float)nativeWidth) / ((float)width);
190            float dy = ((float)nativeHeight) / ((float)height);
191            if (dx > dy) {
192                bitmapWidth = width;
193                bitmapHeight = nativeHeight / dx;
194            } else {
195                bitmapWidth = nativeWidth / dy;
196                bitmapHeight = height;
197            }
198            // Create the bitmap from file
199            if (nativeWidth / bitmapWidth > 1) {
200                final BitmapFactory.Options options = new BitmapFactory.Options();
201                options.inSampleSize = nativeWidth / (int)bitmapWidth;
202                srcBitmap = BitmapFactory.decodeFile(filename, options);
203            } else {
204                srcBitmap = BitmapFactory.decodeFile(filename);
205            }
206        } else {
207            bitmapWidth = width;
208            bitmapHeight = height;
209            srcBitmap = BitmapFactory.decodeFile(filename);
210        }
211
212        if (srcBitmap == null) {
213            Log.e(TAG, "generateThumbnail: Cannot decode image bytes");
214            throw new IOException("Cannot decode file: " + mFilename);
215        }
216
217        // Create the canvas bitmap
218        final Bitmap bitmap = Bitmap.createBitmap((int)bitmapWidth, (int)bitmapHeight,
219                Bitmap.Config.ARGB_8888);
220        final Canvas canvas = new Canvas(bitmap);
221        canvas.drawBitmap(srcBitmap, new Rect(0, 0, srcBitmap.getWidth(), srcBitmap.getHeight()),
222                new Rect(0, 0, (int)bitmapWidth, (int)bitmapHeight), sResizePaint);
223        // Release the source bitmap
224        srcBitmap.recycle();
225        return bitmap;
226    }
227}
228