Skip to content

Commit

Permalink
timob-10080: Added methods to manipulate images in TiBlob class for p…
Browse files Browse the repository at this point in the history
…arity with iOS.Reset image when width or height is changed in TiUIImageView class.
  • Loading branch information
pingwang2011 committed Aug 24, 2012
1 parent 06d905c commit 44d71ff
Show file tree
Hide file tree
Showing 4 changed files with 326 additions and 13 deletions.
Expand Up @@ -936,6 +936,25 @@ public void propertyChanged(String key, Object oldValue, Object newValue, KrollP
} else {
super.propertyChanged(key, oldValue, newValue, proxy);
}

View parentView = getParentView();
if (key.equals(TiC.PROPERTY_WIDTH)) {
if (TiC.LAYOUT_FILL.equals(TiConvert.toString(newValue)) && parentView != null) {
// Use the parent's width when it's fill
requestedWidth = TiConvert.toTiDimension(parentView.getMeasuredWidth(), TiDimension.TYPE_WIDTH);
} else {
requestedWidth = TiConvert.toTiDimension(newValue, TiDimension.TYPE_WIDTH);
}
setImage(true);
} else if (key.equals(TiC.PROPERTY_HEIGHT)) {
// Use the parent's height when it's fill
if (TiC.LAYOUT_FILL.equals(TiConvert.toString(newValue)) && parentView != null) {
requestedHeight = TiConvert.toTiDimension(parentView.getMeasuredHeight(), TiDimension.TYPE_HEIGHT);
} else {
requestedHeight = TiConvert.toTiDimension(newValue, TiDimension.TYPE_HEIGHT);
}
setImage(true);
}
}

public void onDestroy(Activity activity)
Expand Down
177 changes: 170 additions & 7 deletions android/titanium/src/java/org/appcelerator/titanium/TiBlob.java
Expand Up @@ -12,18 +12,28 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;

import org.apache.commons.codec.binary.Base64;
import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.KrollProxy;
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.kroll.common.Log;
import org.appcelerator.kroll.util.KrollStreamHelper;
import org.appcelerator.titanium.io.TiBaseFile;
import org.appcelerator.titanium.io.TitaniumBlob;
import org.appcelerator.titanium.util.TiImageHelper;
import org.appcelerator.titanium.util.TiMimeTypeHelper;

import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.RectF;
import android.media.ThumbnailUtils;

/**
* A Titanium Blob object. A Blob can represent any opaque data or input stream.
Expand Down Expand Up @@ -60,16 +70,15 @@ public class TiBlob extends KrollProxy
private int type;
private Object data;
private String mimetype;
private int width, height;
private Bitmap image;

private TiBlob(int type, Object data, String mimetype)
{
super();
this.type = type;
this.data = data;
this.mimetype = mimetype;
this.width = 0;
this.height = 0;
this.image = null;
}

/**
Expand Down Expand Up @@ -125,8 +134,7 @@ public static TiBlob blobFromImage(Bitmap image)
}

TiBlob blob = new TiBlob(TYPE_IMAGE, data, "image/bitmap");
blob.width = image.getWidth();
blob.height = image.getHeight();
blob.image = image;
return blob;
}

Expand Down Expand Up @@ -332,13 +340,47 @@ public int getType()
@Kroll.getProperty @Kroll.method
public int getWidth()
{
return width;
if (image != null) {
return image.getWidth();
}

// Query the dimensions of a bitmap without allocating the memory for its pixels
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
switch (type) {
case TYPE_FILE:
BitmapFactory.decodeStream(getInputStream(), null, opts);
return opts.outWidth;
case TYPE_DATA:
byte[] byteArray = (byte[]) data;
BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length, opts);
return opts.outWidth;
}

return 0;
}

@Kroll.getProperty @Kroll.method
public int getHeight()
{
return height;
if (image != null) {
return image.getHeight();
}

// Query the dimensions of a bitmap without allocating the memory for its pixels
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
switch (type) {
case TYPE_FILE:
BitmapFactory.decodeStream(getInputStream(), null, opts);
return opts.outHeight;
case TYPE_DATA:
byte[] byteArray = (byte[]) data;
BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length, opts);
return opts.outHeight;
}

return 0;
}

@Kroll.method
Expand Down Expand Up @@ -402,4 +444,125 @@ public String toBase64()
{
return new String(Base64.encodeBase64(getBytes()));
}

public Bitmap getImage()
{
switch(type) {
case TYPE_FILE:
return BitmapFactory.decodeStream(getInputStream());
case TYPE_DATA:
byte[] byteArray = (byte[])data;
return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
}
return image;
}

@Kroll.method
public TiBlob imageAsCropped(Object params)
{
Bitmap img = getImage();
if (img == null) {
return null;
}
if (!(params instanceof HashMap)) {
Log.e(TAG, "Argument for imageAsCropped must be a dictionary");
return null;
}

KrollDict options = new KrollDict((HashMap) params);
int width = img.getWidth();
int height = img.getHeight();
int widthCropped = options.optInt(TiC.PROPERTY_WIDTH, width);
int heightCropped = options.optInt(TiC.PROPERTY_HEIGHT, height);
int x = options.optInt(TiC.PROPERTY_X, (width - widthCropped) / 2);
int y = options.optInt(TiC.PROPERTY_Y, (height - heightCropped) / 2);
Bitmap imageCropped = Bitmap.createBitmap(img, x, y, widthCropped, heightCropped);
return blobFromImage(imageCropped);
}

@Kroll.method
public TiBlob imageAsResized(Number width, Number height)
{
Bitmap img = getImage();
if (img == null) {
return null;
}

int dstWidth = width.intValue();
int dstHeight = height.intValue();
Bitmap imageResized = Bitmap.createScaledBitmap(img, dstWidth, dstHeight, true);
return blobFromImage(imageResized);
}

@Kroll.method
public TiBlob imageAsThumbnail(Number size, @Kroll.argument(optional = true) Number borderSize,
@Kroll.argument(optional = true) Number cornerRadius)
{
Bitmap img = getImage();
if (img == null) {
return null;
}

int thumbnailSize = size.intValue();
Bitmap imageThumbnail = ThumbnailUtils.extractThumbnail(img, thumbnailSize, thumbnailSize);

float border = 1f;
if (borderSize != null) {
border = borderSize.floatValue();
}
float radius = 0f;
if (cornerRadius != null) {
radius = cornerRadius.floatValue();
}

if (border == 0 && radius == 0) {
return blobFromImage(imageThumbnail);
}

Bitmap imageThumbnailBorder = TiImageHelper.imageWithRoundedCorner(imageThumbnail, radius, border);
return blobFromImage(imageThumbnailBorder);
}

@Kroll.method
public TiBlob imageWithAlpha()
{
Bitmap img = getImage();
if (img == null) {
return null;
}

Bitmap imageWithAlpha = TiImageHelper.imageWithAlpha(img);
return blobFromImage(imageWithAlpha);
}

@Kroll.method
public TiBlob imageWithRoundedCorner(Number cornerRadius, @Kroll.argument(optional = true) Number borderSize)
{
Bitmap img = getImage();
if (img == null) {
return null;
}

float radius = cornerRadius.floatValue();
float border = 1f;
if (borderSize != null) {
border = borderSize.floatValue();
}

Bitmap imageRoundedCorner = TiImageHelper.imageWithRoundedCorner(img, radius, border);
return blobFromImage(imageRoundedCorner);
}

@Kroll.method
public TiBlob imageWithTransparentBorder(Number size)
{
Bitmap img = getImage();
if (img == null) {
return null;
}

int borderSize = size.intValue();
Bitmap imageWithBorder = TiImageHelper.imageWithTransparentBorder(img, borderSize);
return blobFromImage(imageWithBorder);
}
}
@@ -0,0 +1,125 @@
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2009-2012 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/

package org.appcelerator.titanium.util;

import java.util.Arrays;

import org.appcelerator.kroll.common.Log;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.RectF;

/**
* Utility class for image manipulations.
*/
public class TiImageHelper
{
private static final String TAG = "TiImageHelper";

/**
* Add an alpha channel to the given image if it does not already have one.
*
* @param image
* the image to add an alpha channel to.
* @return a copy of the given image with an alpha channel.
*/
public static Bitmap imageWithAlpha(Bitmap image)
{
if (image == null) {
return null;
}
if (image.hasAlpha()) {
return image;
}
return image.copy(Bitmap.Config.ARGB_8888, true);
}

/**
* Create a copy of the given image with rounded corners and a transparent border around its edges.
*
* @param image
* the image to add rounded corners to.
* @param cornerRadius
* the radius of the rounded corners.
* @param borderSize
* the size of the border to be added.
* @return a copy of the given image with rounded corners and a transparent border.
*/
public static Bitmap imageWithRoundedCorner(Bitmap image, float cornerRadius, float borderSize)
{
if (image == null) {
return null;
}
if (cornerRadius < 0 || borderSize < 0) {
Log.e(TAG, "Invalid corner radius or border size for imageWithRoundedCorner");
return image;
}

if (cornerRadius == 0) {
return imageWithTransparentBorder(image, (int) borderSize);
}

int width = image.getWidth();
int height = image.getHeight();
Bitmap imageRoundedCorner = Bitmap.createBitmap(width + (int) (borderSize * 2), height + (int) (borderSize * 2),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageRoundedCorner);

Path clipPath = new Path();
RectF imgRect = new RectF(borderSize, borderSize, width + borderSize, height + borderSize);

float radii[] = new float[8];
Arrays.fill(radii, cornerRadius);
clipPath.addRoundRect(imgRect, radii, Direction.CW);

// This still happens sometimes when hw accelerated so, catch and warn
try {
canvas.clipPath(clipPath);
} catch (Exception e) {
Log.e(TAG, "Unable to create the image with rounded corners. clipPath failed on canvas: " + e.getMessage());
canvas.clipRect(imgRect);
}

canvas.drawBitmap(imageWithAlpha(image), borderSize, borderSize, null);
return imageRoundedCorner;
}

/**
* Add a transparent border to the given image around its edges.
*
* @param image
* the image to add a transparent border to.
* @param borderSize
* the size of the border to be added.
* @return a copy of the given image with a transparent border.
*/
public static Bitmap imageWithTransparentBorder(Bitmap image, int borderSize)
{
if (image == null) {
return null;
}
if (borderSize < 0) {
Log.e(TAG, "Invalid border size for imageWithTransparentBorder");
return image;
}

if (borderSize == 0) {
return image;
}

int width = image.getWidth();
int height = image.getHeight();
Bitmap imageBorder = Bitmap.createBitmap(width + borderSize * 2, height + borderSize * 2, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageBorder);
canvas.drawBitmap(imageWithAlpha(image), borderSize, borderSize, null);
return imageBorder;
}
}

0 comments on commit 44d71ff

Please sign in to comment.