diff options
author | Ruben Brunk <rubenbrunk@google.com> | 2013-03-15 15:33:38 -0700 |
---|---|---|
committer | Ruben Brunk <rubenbrunk@google.com> | 2013-03-15 18:01:51 -0700 |
commit | f88f1d99563ddcfe15fed8fe98a293c0a5de0d82 (patch) | |
tree | fe03efc0eb2ba7e9cbeb0a0cd35fe879c5e0c532 /src | |
parent | 0fe391a43d0c549fa0effddd21ece4eb4ba86194 (diff) | |
download | android_packages_apps_Snap-f88f1d99563ddcfe15fed8fe98a293c0a5de0d82.tar.gz android_packages_apps_Snap-f88f1d99563ddcfe15fed8fe98a293c0a5de0d82.tar.bz2 android_packages_apps_Snap-f88f1d99563ddcfe15fed8fe98a293c0a5de0d82.zip |
Refactoring iconbutton.
Change-Id: Ie1538d978605ae28bb4fa6779eb2802794a35312
Diffstat (limited to 'src')
4 files changed, 190 insertions, 79 deletions
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java index 2c1a847f8..ef3e3d5ce 100644 --- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java +++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java @@ -255,6 +255,11 @@ public class ImageLoader { try { is = mContext.getContentResolver().openInputStream(uri); BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false); + Rect r = new Rect(0, 0, decoder.getWidth(), decoder.getHeight()); + // return null if bounds are not entirely within the bitmap + if (!r.contains(bounds)) { + return null; + } return decoder.decodeRegion(bounds, options); } catch (FileNotFoundException e) { Log.e(LOGTAG, "FileNotFoundException: " + uri); diff --git a/src/com/android/gallery3d/filtershow/tools/IconFactory.java b/src/com/android/gallery3d/filtershow/tools/IconFactory.java new file mode 100644 index 000000000..ccc49e13d --- /dev/null +++ b/src/com/android/gallery3d/filtershow/tools/IconFactory.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.filtershow.tools; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; + +/** + * A factory class for producing bitmaps to use as UI icons. + */ +public class IconFactory { + + /** + * Builds an icon with the dimensions iconWidth:iconHeight. If scale is set + * the source image is stretched to fit within the given dimensions; + * otherwise, the source image is cropped to the proper aspect ratio. + * + * @param sourceImage image to create an icon from. + * @param iconWidth width of the icon bitmap. + * @param iconHeight height of the icon bitmap. + * @param scale if true, stretch sourceImage to fit the icon dimensions. + * @return an icon bitmap with the dimensions iconWidth:iconHeight. + */ + public static Bitmap createIcon(Bitmap sourceImage, int iconWidth, int iconHeight, + boolean scale) { + if (sourceImage == null) { + throw new IllegalArgumentException("Null argument to buildIcon"); + } + + int sourceWidth = sourceImage.getWidth(); + int sourceHeight = sourceImage.getHeight(); + + if (sourceWidth == 0 || sourceHeight == 0 || iconWidth == 0 || iconHeight == 0) { + throw new IllegalArgumentException("Bitmap with dimension 0 used as input"); + } + + Bitmap icon = Bitmap.createBitmap(iconWidth, iconHeight, + Bitmap.Config.ARGB_8888); + drawIcon(icon, sourceImage, scale); + return icon; + } + + /** + * Draws an icon in the destination bitmap. If scale is set the source image + * is stretched to fit within the destination dimensions; otherwise, the + * source image is cropped to the proper aspect ratio. + * + * @param dest bitmap into which to draw the icon. + * @param sourceImage image to create an icon from. + * @param scale if true, stretch sourceImage to fit the destination. + */ + public static void drawIcon(Bitmap dest, Bitmap sourceImage, boolean scale) { + if (dest == null || sourceImage == null) { + throw new IllegalArgumentException("Null argument to buildIcon"); + } + + int sourceWidth = sourceImage.getWidth(); + int sourceHeight = sourceImage.getHeight(); + int iconWidth = dest.getWidth(); + int iconHeight = dest.getHeight(); + + if (sourceWidth == 0 || sourceHeight == 0 || iconWidth == 0 || iconHeight == 0) { + throw new IllegalArgumentException("Bitmap with dimension 0 used as input"); + } + + Rect destRect = new Rect(0, 0, iconWidth, iconHeight); + Canvas canvas = new Canvas(dest); + + Rect srcRect = null; + if (scale) { + // scale image to fit in icon (stretches if aspect isn't the same) + srcRect = new Rect(0, 0, sourceWidth, sourceHeight); + } else { + // crop image to aspect ratio iconWidth:iconHeight + float wScale = sourceWidth / (float) iconWidth; + float hScale = sourceHeight / (float) iconHeight; + float s = Math.min(hScale, wScale); + + float iw = iconWidth * s; + float ih = iconHeight * s; + + float borderW = (sourceWidth - iw) / 2.0f; + float borderH = (sourceHeight - ih) / 2.0f; + RectF rec = new RectF(borderW, borderH, borderW + iw, borderH + ih); + srcRect = new Rect(); + rec.roundOut(srcRect); + } + + canvas.drawBitmap(sourceImage, srcRect, destRect, new Paint()); + } +} diff --git a/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java b/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java index 59c18e0f4..3e210a0dc 100644 --- a/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java +++ b/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java @@ -20,7 +20,6 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; -import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import android.widget.LinearLayout; @@ -32,6 +31,7 @@ import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.imageshow.GeometryListener; import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.presets.ImagePreset; +import com.android.gallery3d.filtershow.tools.IconFactory; // TODO: merge back IconButton and FilterIconButton? public class FilterIconButton extends IconButton implements View.OnClickListener, @@ -119,8 +119,8 @@ public class FilterIconButton extends IconButton implements View.OnClickListener } else { mIconBitmap = bmap; if (mOverlayBitmap != null) { - Rect destination = new Rect(0, 0, mIconBitmap.getWidth(), mIconBitmap.getHeight()); - drawImage(mIconBitmap, mOverlayBitmap, destination); + // Draw overlay bitmap over icon + IconFactory.drawIcon(mIconBitmap, mOverlayBitmap, false); } setIcon(mIconBitmap); } diff --git a/src/com/android/gallery3d/filtershow/ui/IconButton.java b/src/com/android/gallery3d/filtershow/ui/IconButton.java index 2484d5feb..e7087bdfe 100644 --- a/src/com/android/gallery3d/filtershow/ui/IconButton.java +++ b/src/com/android/gallery3d/filtershow/ui/IconButton.java @@ -19,12 +19,16 @@ package com.android.gallery3d.filtershow.ui; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.widget.Button; +import com.android.gallery3d.filtershow.tools.IconFactory; +import com.android.photos.data.GalleryBitmapPool; + /** * Class of buttons with both an image icon and text. */ @@ -54,8 +58,8 @@ public class IconButton extends Button { /** * Set the image that the button icon will use. The image bitmap will be scaled - * and cropped into the largest square bitmap that will fit cleanly within the - * IconButton's layout. + * and cropped into the largest bitmap with dimensions given by getGoodIconSideSize() + * that will fit cleanly within the IconButton's layout. * * @param image image that icon will be set to before next draw. */ @@ -66,14 +70,63 @@ public class IconButton extends Button { } /** + * Finds a side lengths for the icon that fits within the button. + * Only call after layout. The default implementation returns the best + * side lengths for a square icon. + * <p> + * Override this to make non-square icons or icons with different padding + * constraints. + * + * @return an array of ints representing the icon dimensions [ width, height ] + */ + protected int[] getGoodIconSideSize() { + Paint p = getPaint(); + Rect bounds = new Rect(); + // find text bounds + String s = getText().toString(); + p.getTextBounds(s, 0, s.length(), bounds); + + int inner_padding = 2 * getCompoundDrawablePadding(); + + // find total vertical space available for the icon + int vert = getHeight() - getPaddingTop() - getPaddingBottom() - bounds.height() + - inner_padding; + + // find total horizontal space available for the icon + int horiz = getWidth() - getPaddingLeft() - getPaddingRight() - inner_padding; + + int defaultSize = Math.min(vert, horiz); + return new int[] { defaultSize, defaultSize }; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (w != oldw || h != oldh) { + stale_icon = true; + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (stale_icon && mImageMirror != null && mImageMirror.getHeight() > 0 + && mImageMirror.getWidth() > 0) { + stale_icon = !makeAndSetIcon(mImageMirror); + } + super.onDraw(canvas); + } + + // Internal methods + + /** * Creates and sets button icon. Only call after layout. * * @param image bitmap to use as icon */ private boolean makeAndSetIcon(Bitmap image) { - int size = getGoodIconSideSize(); - if (size > 0) { - return setImageIcon(makeImageIcon(image, size, size)); + int[] sizes = getGoodIconSideSize(); + if (sizes != null && sizes.length >= 2 && sizes[0] > 0 && sizes[1] > 0) { + return setImageIcon(makeImageIcon(image, sizes[0], sizes[1])); } return false; } @@ -87,6 +140,10 @@ public class IconButton extends Button { if (image == null) { return false; } + if(mIcon != null && mIcon.getConfig() == Bitmap.Config.ARGB_8888) { + GalleryBitmapPool.getInstance().put(mIcon); + mIcon = null; + } mIcon = image; this.setCompoundDrawablesWithIntrinsicBounds(null, new BitmapDrawable(getResources(), mIcon), null, null); @@ -102,78 +159,19 @@ public class IconButton extends Button { * @return the scaled/cropped icon bitmap */ private Bitmap makeImageIcon(Bitmap image, int width, int height) { - Rect destination = new Rect(0, 0, width, height); - Bitmap bmap = Bitmap.createBitmap(width, height, - Bitmap.Config.ARGB_8888); - drawImage(bmap, image, destination); - return bmap; - } - - /** - * Finds a side length for the (square) icon that fits within the button. - * Only call after layout. - * - * @return icon side length - */ - private int getGoodIconSideSize() { - Paint p = getPaint(); - Rect bounds = new Rect(); - String s = getText().toString(); - p.getTextBounds(s, 0, s.length(), bounds); - int inner_padding = 2 * getCompoundDrawablePadding(); - int vert = getHeight() - getPaddingTop() - getPaddingBottom() - bounds.height() - - inner_padding; - int horiz = getWidth() - getPaddingLeft() - getPaddingRight() - inner_padding; - return Math.min(vert, horiz); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - if (w != oldw || h != oldh) { - stale_icon = true; - } - } - - @Override - protected void onDraw(Canvas canvas) { - if (stale_icon && mImageMirror != null && mImageMirror.getHeight() > 0 - && mImageMirror.getWidth() > 0) { - stale_icon = !makeAndSetIcon(mImageMirror); + if (image == null || image.getHeight() < 1 || image.getWidth() < 1 || + width < 1 || height < 1) { + throw new IllegalArgumentException("input is null, or has invalid dimensions"); } - super.onDraw(canvas); - } - - /** - * Draws the src image into the destination rectangle within the dst bitmap. - * If src is a non-square image, clips to be a square before drawing into dst. - * - * @param dst bitmap being drawn on. - * @param src bitmap to draw into dst. - * @param destination square in dst in which to draw src. - */ - protected static void drawImage(Bitmap dst, Bitmap src, Rect destination) { - if (src != null && dst != null && src.getWidth() > 0 && dst.getWidth() > 0 - && src.getHeight() > 0 && dst.getHeight() > 0) { - Canvas canvas = new Canvas(dst); - int iw = src.getWidth(); - int ih = src.getHeight(); - int x = 0; - int y = 0; - int size = 0; - Rect source = null; - if (iw > ih) { - size = ih; - x = (int) ((iw - size) / 2.0f); - y = 0; - } else { - size = iw; - x = 0; - y = (int) ((ih - size) / 2.0f); - } - source = new Rect(x, y, x + size, y + size); - canvas.drawBitmap(src, source, destination, new Paint()); + Bitmap icon = null; + icon = GalleryBitmapPool.getInstance().get(width, height); + if (icon == null) { + icon = IconFactory.createIcon(image, width, height, false); + } else { + assert(icon.getWidth() == width && icon.getHeight() == height); + icon.eraseColor(Color.TRANSPARENT); + IconFactory.drawIcon(icon, image, false); } + return icon; } - } |