Titanium Community Questions & Answer Archive

We felt that 6+ years of knowledge should not die so this is the Titanium Community Questions & Answer Archive

Please post working code for Android image resize

I've tried just about everything I could find on the forums to resize an image (from the device camera, for uploading to a server) without luck. If you have code that you know works with Appcelerator 1.4.1 on an Android device I'd be most appreciative if you'd post it.

Here's my latest attempt. It seems to do nothing - the returned image has the same dimensions as the input image.

function resize_image(image, max_width){
    var reducedImageView = Titanium.UI.createImageView({
        width: max_width
        height: 'auto',
        canScale: true,
        image: image
    });
    return reducedImageView.toBlob();
}

Other things I've tried: toImage instead of toBlob crashes when I try to use the returned image:

09-24 14:02:14.197: ERROR/TiUncaughtHandler(16495): (main) [724,20151] Sending event: exception on thread: main msg:java.lang.IllegalArgumentException: width and height must be > 0
— asked September 24th 2010 by Parand Darugar
  • image
  • mobile
  • resize
0 Comments

5 Answers

  • The argument image should be a UI.ImageView object.

    function resizeImage(image, maxWidth) {
        var tmp = image.toImage();
        var wid = tmp.width;
        var ht = tmp.height;
        var reduction;
        if(wid > ht) {
            reduction = maxWidth / wid;
            wid = maxWidth;
            ht = Math.round(ht * reduction);
        } else {
            reduction = maxWidth / ht;
            ht = maxWidth;
            wid = Math.round(wid * reduction);
        }
        image = Ti.UI.createImageView({
            image: tmp,
            width: wid,
            height: ht
        });
        return image;
    };
    
    — answered October 20th 2010 by Dan Satterfield
    permalink
    0 Comments
  • I also tried using backgroundImage instead of image in the view. It crashes with both of toBlob and toImage.

    — answered September 24th 2010 by Parand Darugar
    permalink
    0 Comments
  • Hi Parand,

    my android app doesn't work in 1.4.1 for some reason so I'm still using 1.3 for android.

    I've posted the full code here http://pastie.org/1180130 Its hard to remember what I did but I think I have 2 versions of the image. One that's displayed on screen for the user to see and another slightly larger one that gets uploaded to the server. I've included the rescale and upload functions, the upload function sends the data to a php script which returns a JSON stream indicating success.

    Just gave it a quick test and they still work :) I hope they help you out.

    — answered September 24th 2010 by Leigh Kayley
    permalink
    4 Comments
    • Thanks very much Leigh, really appreciate it. Will give it a try.

      — commented September 24th 2010 by Parand Darugar
    • You mention this doesn't work in 1.4.1 . I need to use 1.4.1 (since I need selectors to work in Android). Did you by chance figure out why it failed in 1.4.1?

      — commented September 29th 2010 by Parand Darugar
    • Thank you so much! To make a long story short, what you actually do on Android is setting "canScale" to true and "enableZoomControls" to false, then assign the image and the image scales without showing zoom controls.
      It's a very simple combination and works on most versions (I confess, I thought about it before, but decided it wont work without event trying it… now I cant explain why).

      — commented October 4th 2010 by Ganna Kozynenko
    • It works on 1.4.1, no worries :)

      — commented October 4th 2010 by Ganna Kozynenko
  • There is a built in function to do this for iOS only but you'll need to make your own module, but here are two functions to perform the resize in a custom android module. Appcelerator folks, here's your prompt to just pull code into your repo for android users wanting the same functionality.

    To future people reading this… sorry I can't share any more source than this. Good luck everyone!

    ... (Appcelerator module) ...
    
        //private utility function to create an image (in Ti) from a bitmap
        public KrollDict createDictForImage(Bitmap bmpInput)
        {
            KrollDict d = new KrollDict();
            d.put("x", 0);
            d.put("y", 0);
            d.put("width", bmpInput.getWidth());
            d.put("height", bmpInput.getHeight());
    
            KrollDict cropRect = new KrollDict();
            cropRect.put("x", 0);
            cropRect.put("y", 0);
            cropRect.put("width", bmpInput.getWidth());
            cropRect.put("height", bmpInput.getHeight());
            d.put("cropRect", cropRect);
            d.put("media", TiBlob.blobFromImage(getTiContext(), bmpInput));
    
            return d;
        }
    
        //Methods
        @Kroll.method
        public KrollDict imageAsResized(@Kroll.argument(optional=false) KrollDict objImage, int iWidth, int iHeight) 
            throws IOException, IllegalStateException    
        {
            //decode the blob
            //if (blobInput.getType() != TiBlob.TYPE_IMAGE)   {
            //    throw new IOException("imageAsCropped::Input type of blob is not image");
            //}
            if (!objImage.containsKeyAndNotNull("media") 
                || !objImage.containsKeyAndNotNull("width") 
                || !objImage.containsKeyAndNotNull("height"))
            {
                throw new IllegalStateException("imageAsCropped::Failed, unknown image type!");
            }
            TiBlob blobInput = null;
            if (objImage.containsKey("media")) {
                Object media = objImage.get("media");
                if (media instanceof TiBlob) {
                    blobInput = (TiBlob) media;
                }
            }
    
            //decode the blob input
            byte[] byImage = blobInput.getBytes();
            Bitmap bmpInput = BitmapFactory.decodeByteArray(byImage, 0, byImage.length);
            Log.d(LCAT, "imageAsResized::Decoded "+byImage.length+" bytes from input blob");
            if (byImage.length==0 || bmpInput==null) {
                throw new IllegalStateException("imageAsCropped::Could not parse the input image in bytes");
            }
    
            //otherwise scale the bitmap with some java code...
            Bitmap bmpScaled = Bitmap.createScaledBitmap(bmpInput, iWidth, iHeight, false);
            //convert the scaled version back into a blob
            return createDictForImage(bmpScaled);
        }
    
        //config is a set of floats (x,y,width,height)
        @Kroll.method
        public KrollDict imageAsCropped(@Kroll.argument(optional=false) KrollDict objImage, 
                                     @Kroll.argument(optional=false) KrollDict config) 
            throws IOException, IllegalStateException 
        {
            double dX=0, dY=0, dWidth=0, dHeight=0;
    
            if (!objImage.containsKeyAndNotNull("media") 
                || !objImage.containsKeyAndNotNull("width") 
                || !objImage.containsKeyAndNotNull("height"))
            {
                throw new IllegalStateException("imageAsCropped::Failed, unknown image type!");
            }
            TiBlob blobInput = null;
            if (objImage.containsKey("media")) {
                Object media = objImage.get("media");
                if (media instanceof TiBlob) {
                    blobInput = (TiBlob) media;
                }
            }
    
            //decode the blob
            //if (blobInput.getType() != TiBlob.TYPE_IMAGE) {
            //    throw new IOException("imageAsCropped::Input type of blob is not image");
            //}
            if (!config.containsKeyAndNotNull("x") 
                || !config.containsKeyAndNotNull("y") 
                || !config.containsKeyAndNotNull("width") 
                || !config.containsKeyAndNotNull("height"))
            {
                throw new IllegalStateException("imageAsCropped::Failed, missing one parameter (x,y,width,height)");
            }
            dX = config.getDouble("x");
            dY = config.getDouble("y");
            dWidth = config.getDouble("width");
            dHeight = config.getDouble("height");
    
            //parse input into a regular image...
            byte[] byImage = blobInput.getBytes();
            Bitmap bmpInput = BitmapFactory.decodeByteArray(byImage, 0, byImage.length);
            Log.d(LCAT, "imageAsResized::Decoded "+byImage.length+" bytes from input blob");
            if (byImage.length==0 || bmpInput==null) {
                throw new IllegalStateException("imageAsCropped::Could not parse the input image in bytes");
            }
    
            // recreate the new Bitmap
            Bitmap bmpCropped = Bitmap.createBitmap(bmpInput, (int)dX, (int)dY,
                                                    (int)dWidth, (int)dHeight);
            //convert the scaled version back into a blob
            return createDictForImage(bmpCropped);
        }
    
    ...
    
    — answered September 1st 2011 by Eric Z
    permalink
    0 Comments
  • just had the same problem. try giving a different height, 'auto' doesn't work

    — answered December 22nd 2011 by mo joe
    permalink
    0 Comments
The ownership of individual contributions to this community generated content is retained by the authors of their contributions.
All trademarks remain the property of the respective owner.