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