Android Rotate and Scale Bitmap Example
Join the DZone community and get the full member experience.
Join For Freei built an android demo app so i could test my understanding of displaying bitmaps on a canvas. i had done scaling of bitmaps, rotation of bitmaps, and translation from one origin to another, but i had not done more than one of those transformations at a time.
the demo app is shown in the figures above. there are two images in the center of the screen. each image is scaled to fit within the light blue region. when you press the rotate button, each of the images is rotated around its center, while maintaining its position in the center of the region on the screen. the scale button resizes the images. there are three different sizes. each time you touch scale, it switches to the next size. the offset cycles you through four different offsets.
in the app mainactivity, two instances of starshipview are in the layout. in the oncreate method, each view is assigned a bitmap.
sv.setbitmapfromresource (r.drawable.starship1); sv.setscale (1.0f); sv.invalidate ();
the onclick method in mainactivity gets called whenever a button is clicked. the code in onclick finds the two views in its layout and sets properties that control the amount of rotation, size of the bitmap, and x and y offsets.
sv.setscale (newscale1); sv.setdegrees (degrees1); sv.setoffsetx (newoffset1); sv.setoffsety (newoffset1); sv.invalidate ();
inside class starshipview, in the ondraw method, the bitmap assigned to the view is written to the canvas. the code is actually very simple, once you get comfortable with using matrix objects to do the work. here’s what goes on in the ondraw method of class starshipview.
first, the matrix object is set so it will fit the bitmap into the rectangle for the view. for this demo app, i chose some interesting sizes to test this part of the code. the starship image is 512 x 512. it is scaled to fit into the 96 dp area on the left. the star field image on the right is 96 x 96 is displayed in the 120 dp square on the right.
the second step is to translate the view up and left by half the width and half the height. that is done because rotation is around the top left point (the origin) of the view. rotation follows that step. it is very simple: “matrix.postrotate (rotation)”.
/** * draw the bitmap onto the canvas. * * the following transformations are done using a matrix object: * (1) the bitmap is scaled to fit within the view; * (2) the bitmap is translated up and left half the width and height, to support rotation around the center; * (3) the bitmap is rotated n degrees; * (4) the bitmap is translated to the specified offset valuess. */ @override public void ondraw(canvas canvas) { if (pbitmap == null) return; // use the same matrix over and over again to minimize // allocation in ondraw. matrix matrix = mmatrix; matrix.reset (); float vw = this.getwidth (); float vh = this.getheight (); float hvw = vw / 2; float hvh = vh / 2; float bw = (float) pbitmap.getwidth (); float bh = (float) pbitmap.getheight (); // first scale the bitmap to fit into the view. // use either scale factor for width and height, // whichever is the smallest. float s1x = vw / bw; float s1y = vh / bh; float s1 = (s1x < s1y) ? s1x : s1y; matrix.postscale (s1, s1); // translate the image up and left half the height // and width so rotation (below) is around the center. matrix.posttranslate(-hvw, -hvh); // rotate the bitmap the specified number of degrees. int rotation = getdegrees (); matrix.postrotate(rotation); // if the bitmap is to be scaled, do so. // also figure out the x and y offset values, which start // with the values assigned to the view // and are adjusted based on the scale. float offsetx = getoffsetx (), offsety = getoffsety (); if (pscale != 1.0f) { matrix.postscale (pscale, pscale); float sx = (0.0f + pscale) * vw / 2; float sy = (0.0f + pscale) * vh / 2; offsetx += sx; offsety+= sy; } else { offsetx += hvw; offsety += hvh; } // the last translation moves the bitmap to where it has to be to have its top left point be // where it should be following the rotation and scaling. matrix.posttranslate (offsetx, offsety); // finally, draw the bitmap using the matrix as a guide. canvas.drawbitmap (pbitmap, matrix, null); }
once the bitmap is rotated, it needs to have its location translated to the place where it should display in the view. that is specified in the offsetx and offsety values. so you see one more matrix.posttranslate call in the method.
the final action in the ondraw method is the drawing of the bitmap. notice that the drawbitmap method uses the matrix with the various transformations encoded in it.
source code
you can download the source code for this demo from the wglxy.com website. click here: download zip file from wglxy.com . the zip is attached at the bottom of that page. after you import the project into eclipse, it’s a good idea to use the project – clean menu item to rebuild the project.
this demo app was compiled with android 4.4 (api 19). it works in all api levels from api 10 on up.
references
as with many other problems, i found very good advice on stackoverflow. a stackoverflow post on rotating images around the center of the image helped me.
Published at DZone with permission of Bill Lahti. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments