What Does the Filter Parameter to Createscaledbitmap Do

What does the filter parameter to createScaledBitmap do?

A quick dig through the SKIA source-code indicates that (at least by default) the FILTER flag causes it to do a straightforward bilinear interpolation. Check Wikipedia or your favorite graphics reference to see what the expected consequences are. Traditionally, you want to do bilinear or bicubic interpolation when upsizing images, and area averaging when downsizing images. I get the impression (though I'm glad to be corrected) that Android/Skia does simple subsampling when downsizing without filtering, so you are likely to get better results from filtering even when downsizing. (There's an alternate method for getting high quality downsizing with interpolation, involving doing a series of 50% scale reductions. See http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html for details.)

Bitmap.createScaledBitmap filtering not working as expected

After much fiddling, it seems that the problem is getting bitmaps via getResources(). They will always get filtered, no matter which method of drawing is used.

My workaround was to put all my images in the /assets folder and pull them via getAssets(). (Still not sure how bad of a practice this is...)

Performance difference between drawBitmap and createScaledBitmap

Yes, there is. They do different things. createScaledBitmap takes a bitmap and creates a new scaled copy in memory. It does not place it on a canvas, this is a new bitmap object that can later be drawn to a canvas. drawBitmap draws the bitmap to the canvas (which may be backed by a bitmap, surface, or the screen), scales it, applies effects from the paint object, respects clipping regions, etc.

You should not use drawBitmap unless you actually want to draw it to a canvas- using it just to scale is inefficient. If you need to draw it and scale it- if you'll need to scale it repeatedly and memory isn't an issue, use createScaledBitmap first and then draw that scaled bitmap. If you don't need to draw it again or memory is an issue, use drawBitmap to scale it as you draw it.

Does Bitmap.createScaledBitmap convert an 32 bit image into 24 bit?

I looked up the method createScaledBitmap in the source for the Bitmap class (Link):

public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
int dstHeight, boolean filter) {
Matrix m;
synchronized (Bitmap.class) {
// small pool of just 1 matrix
m = sScaleMatrix;
sScaleMatrix = null;
}

if (m == null) {
m = new Matrix();
}

final int width = src.getWidth();
final int height = src.getHeight();
final float sx = dstWidth / (float)width;
final float sy = dstHeight / (float)height;
m.setScale(sx, sy);
Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);

synchronized (Bitmap.class) {
// do we need to check for null? why not just assign everytime?
if (sScaleMatrix == null) {
sScaleMatrix = m;
}
}

return b;
}

And the call to createBitmap() should return your unchanged source bitmap due to this check in the method body:

    if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
height == source.getHeight() && (m == null || m.isIdentity())) {
return source;
}

Looking at just this it would seem that your original bitmap is returned, But, if your bitmap happens to be mutable, you effectively skip this check and end up here:

    if (m == null || m.isIdentity()) {
bitmap = createBitmap(neww, newh,
source.hasAlpha() ? Config.ARGB_8888 : Config.RGB_565);
paint = null; // not needed
}

As you are not performing any scaling, your matrix will be the identity matrix, and the condition is satisfied. The bitmap created is, as you can see, dependent on the alpha in the source bitmap. If no alpha is present, you end up with a result bitmap with the RGB_565 format rather than the ARGB_8888.

So, to scale and preserve the 32-bit format, your bitmap should either be immutable or use an Alpha channel.

Android: Bitmap resizing using better resampling algorithm than bilinear (like Lanczos3)

The most promising IMO is to use libswscale (from FFmpeg), it offers Lanczos and many other filters. To access Bitmap buffer from native code you can use jnigraphics. This approach guarantees nice performance and reliable results.

EDIT

Here you can find rough demo app, that uses proposed approach. At the moment performance is frustratingly bad, so it should be investigated to decide if we to do something to improve it.



Related Topics



Leave a reply



Submit