Basic Image Scaling and Rotating

We'll start our exploration of image editing and processing with learning how we can perform spatial transformations such as changing scale and rotating images.

Enter the Matrix

The Android API has a Matrix class, which can be used when drawing on existing Bitmap objects or creating a Bitmap object from another Bitmap object. This class allows us to apply a spatial transformation to an image. A transformation of this type would be rotating, cropping, scaling, or otherwise altering the coordinate space of the image.

The Matrix class represents transformations with an array of nine numbers. In many cases, these can be generated by a formula that mathematically represents the transformation that should occur. For instance, the formula for rotation involves using sine and cosine to generate the number in the matrix.

The numbers in the Matrix can also be input manually. In order to understand how the Matrix works, we'll start by doing some manual transforms.

Each number in the Matrix applies to one of the three (x, y, or z) coordinates for each point in the image.

For instance, here is a Matrix of nine floats:

1 0 0
0 1 0
0 0 1

The top row (1, 0, 0) specifies that the source x coordinate will be transformed according the following formula: x = 1x + 0y + 0z. As you can see, the placement of the values in the matrix determines how that number will affect the outcome. The top row will always affect the x coordinate but can operate with the source x, y, and z coordinate.

The second row (0, 1, 0) means that the y coordinate will be determined as y = 0x + 1y + 0z, and the third row (0, 0, 1) means that the z coordinate will be determined by z = 0x + 0y + 1z.

In other words, this Matrix won't do any transformation; everything will be placed as it is in the source image.

To implement this in code, we would create the Matrix object and then explicitly set the values through its setValues method.

Matrix matrix = new Matrix();
matrix.setValues(new float[] {
    1, 0, 0,
    0, 1, 0,
    0, 0, 1
});

We can use the Matrix object when drawing a bitmap onto a canvas.

canvas.drawBitmap(bmp, matrix, paint);

This would be in place of the drawBitmap method that we are using in our previous example.

To have this Matrix change the image in some manner, we can replace any of the existing numbers with a different value. If we change the first number from a 1 to a .5, we would squish the image on the x axis by 50% as illustrated in Figure 3–5. This first number operates on the x coordinate in the source to influence the x coordinate in the resulting image.

.5 0 0
0 1 0
0 0 1

Matrix matrix = new Matrix();
matrix.setValues(new float[] {
    .5f, 0, 0,
    0, 1, 0,
    0, 0, 1
});
canvas.drawBitmap(bmp, matrix, paint);
Image

Figure 3–5. The second image displayed with the custom matrix applied, scaling the x axis by 50%

If we altered the matrix to have the x coordinate also be affected by the source y coordinate, we can alter the second number.

Matrix matrix = new Matrix();
matrix.setValues(new float[] {
    1, .5f, 0,
    0, 1, 0,
    0, 0, 1
});
canvas.drawBitmap(bmp, matrix, paint);
Image

Figure 3–6. The second image displayed with the custom matrix applied, skewing the image

As you can see in Figure 3–6, it causes the image to skew. It skews because the first row, which operates on the x value of each pixel, is being altered by the y value of each pixel. As the y value increases, as we move down the image, the x value increases, causing the image to skew. If we used a negative value, it would skew in the opposite direction. You'll also notice that the image gets cut off due to the coordinates changing. We need to increase the size of the resulting bitmap as shown in Figure 3–7 if we are going to perform operations like this.

alteredBitmap = Bitmap.createBitmap(bmp.getWidth()*2,bmp.getHeight(),bmp.getConfig());
Image

Figure 3–7. The second image displayed with the same custom matrix but with a larger width so the image isn't cropped

As you can see, these Matrix transformations are very powerful. Also, you can see that doing them by hand can be cumbersome. Unfortunately, the formulas to accomplish much of what you would want to do with the Matrix by hand require math that is out of the scope of this book. There are plenty of resources online, though, if you are interested in learning more. A good place to start is the Wikipedia Transformation Matrix article: http://en.wikipedia.org/wiki/Transformation_matrix.

Matrix Methods

What we will do now, though, is explore the other methods of the Matrix class, as they help us accomplish much of what we would want without having to resort to relearning our high school and college math lessons.

Instead of creating our own Matrix numbers, we can simply call corresponding methods for the transformations that we would like to use.

Each of the snippets presented next can take the place of the canvas.drawBitmap line in the “Drawing a Bitmap onto a Bitmap” example.

Rotate

One of the built-in methods is the setRotation method. It takes in a float representing the degrees of rotation. Positive values rotate the image clockwise and negative values rotate it counter-clockwise around the default point (0,0), which is the top left corner of the image as illustrated in Figure 3–8.

Matrix matrix = new Matrix();
matrix.setRotate(15);
canvas.drawBitmap(bmp, matrix, paint);
Image

Figure 3–8. Rotation around the default point (0,0)

Alternatively, the setRotation method can be called with the degrees of rotation and the points around which to rotate. Choosing the center point on the image might yield results more in line with what we are looking for as shown in Figure 3–9.

matrix.setRotate(15,bmp.getWidth()/2,bmp.getHeight()/2);
Image

Figure 3–9. Rotation around the mid-point of the image

Scale

Another useful method of Matrix is the setScale method. It takes in two floats representing the amount of scaling to occur on each axis. The first argument is the x-axis scale, and the second is the y-axis scaling. Figure 3–10 shows the result of the following setScale method call.

matrix.setScale(1.5f,1);
Image

Figure 3–10. 1.5 scale applied on the x axis

Translate

One of the most useful methods of Matrix is the setTranslate method. A translate simply moves the image on the x and y axes. The setTranslate method takes in two floats representing the amount to move on each axis. The first argument is the amount the image will move on the x axis, and the second argument is the amount the image will move on the y axis. Translating with positive values on the x axis will move the image to the right, while using negative values will move the image to the left. Translating with positive values on the y –axis will move the image downward and using negative values will move the image upward.matrix.

setTranslate(1.5f,-10);.
Pre and Post

Of course, these are just the tip of the iceberg. There are several more that may prove to be useful to you. Each of them also has a pre and a post version. These enable you to do more than one transformation at a time in sequence. For instance, you could do a preScale and then setRotate or a setScale and then postRotate. Changing the order of when they occur could yield vastly different results depending on the operations performed.  Figure 3–11 shows the results of the following two method calls.

matrix.setScale(1.5f, 1);
matrix.postRotate(15,bmp.getWidth()/2,bmp.getHeight()/2);
Image

Figure 3–11. Scaled and rotated

Mirroring

One particularly useful pair is setScale and postTranslate, which allow you to flip the image across a single axis (or both if you desire). If you scale by a negative number, the image will draw in the negative space of the coordinate system. Since the 0, 0 point is the top left, using a negative number on the x axis would cause the image to draw to the left. Therefore we need to use the postTranslate method to move it over to the right as displayed in Figure 3–12.

matrix.setScale(-1, 1);
matrix.postTranslate(bmp.getWidth(),0);
Image

Figure 3–12. Mirrored

Flipping

We could do the same thing, but on the y axis, to flip the image upside-down. We could have achieved the same effect by rotating the image 180 degrees around the midpoint on both axes as shown in Figure 3–13.

matrix.setScale(1, -1);
matrix.postTranslate(0, bmp.getHeight());
Image

Figure 3–13. Flipped

Alternative to Drawing

One of the drawbacks to the methods we are using in the foregoing sections is that the images get cut off, as we aren't calculating the resulting size after the transformation and just drawing into a Bitmap with a predetermined size.

One way that we can overcome this issue is to apply the Matrix as we are creating the Bitmap in the first place, rather than drawing into an empty Bitmap.

Going about things this way removes the need for us to have a Canvas and a Paint object. The drawback is that we cannot continually change the Bitmap object and have to recreate it if we want to do any more transformations on it.

The static createBitmap method available in the Bitmap class allows this. The first argument is the source Bitmap, the next arguments are the start x, y, width, and height values to use from the source, followed by the Matrix to apply, and last a Boolean representing whether to apply any filtering to the image. Since we are not applying a matrix that contains a filter, which we'll discuss later in the chapter, we set that to be false.

Matrix matrix = new Matrix();
matrix.setRotate(15,bmp.getWidth()/2,bmp.getHeight()/2);
alteredBitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(),Image
 matrix, false);
alteredImageView.setImageBitmap(alteredBitmap);

As you can see, we deal with the matrix in the same way, but we instantiate our second Bitmap (alteredBitmap) using the original (bmp) as the source and pass in the Matrix object. This creates a Bitmap from the source with the translation and scaled to the size of the Bitmap object as shown in Figure 3–14.

Image

Figure 3–14. Matrix applied when Bitmap created; the dimensions of the Bitmap are adjusted to match the actual image data.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.74.25