Bitmaps in Android

What is the difference between Bitmap and Drawable in Android?

A Bitmap is a representation of a bitmap image (something like java.awt.Image). A Drawable is an abstraction of "something that can be drawn". It could be a Bitmap (wrapped up as a BitmapDrawable), but it could also be a solid color, a collection of other Drawable objects, or any number of other structures.

Most of the Android UI framework likes to work with Drawable objects, not Bitmap objects. A View can accept any Drawable as a background. An ImageView can display a foreground Drawable. Images stored as resources are loaded as Drawable objects.

How to merge bitmaps in android?

I've figured it out:

public static Bitmap mergeToPin(Bitmap back, Bitmap front) {
Bitmap result = Bitmap.createBitmap(back.getWidth(), back.getHeight(), back.getConfig());
Canvas canvas = new Canvas(result);
int widthBack = back.getWidth();
int widthFront = front.getWidth();
float move = (widthBack - widthFront) / 2;
canvas.drawBitmap(back, 0f, 0f, null);
canvas.drawBitmap(front, move, move, null);
return result;
}

The trick that front image has equal height and width, and that that height/width matches the width of the back image (or scaled - I've resized it to 90% of the original pin width).

It doesn't matter if you put circled or squared pin, as long as the position for image (circle or square) has equal width and height.
Of course, you need to create circular bitmap if you wish to add it to the circled pin :)

Android - Save 2 bitmap into just one Image file

If you wish, you can use this library I've made that can handle large image files via JNI :

https://github.com/AndroidDeveloperLB/AndroidJniBitmapOperations

But, it doesn't have this functionality that you wish. You will have to add it on your own:

  1. create function/s for storing bitmaps from Java world to JNI world.
  2. create a function for merging the images and getting the result.

You could even have just a single Java Bitmap object at the same time, instead of having 3 in the Java solution above (2 of input + 1 of output).

Some notes:

  1. Using JNI can be slower, as it needs to convert from Java Bitmap object to JNI and back. This is especially true for large bitmaps.

  2. In the end, you will still have to hold the output Java Bitmap object. If it's 10000x10000 pixels, it will take 10000*10000*4 bytes, which is 400,000,000 bytes, which is ~400MB . If the input images do not have transparency, you can use a different bitmap config (RGB_565) , which will take ~200MB of RAM.

    In both cases, this is a lot. You could add a flag in the manifest to tell the OS that you need a lot of heap memory (largeHeap) , but it isn't a safe way to get it, as you still might not get enough heap memory. You should check the amount of available heap memory before trying to create the output bitmap.

  3. Another way to solve this, is to avoid showing the entire bitmap, because there is no screen on Android device that has this resolution. You could instead just show a part of the bitmap to be shown on screen, and the calculation stuff you could leave in JNI.

  4. If my library isn't enough, there are other libraries that use JNI. I'm sure one of them can help.

Android - Imageview with multiple bitmaps

Considered 3 layouts side by side and wrap the top layout into circular shape.

<?xml version="1.0" encoding="utf-8"?>
<nz.co.example.components.CircleLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="@dimen/messaging_profile_pic_size"
android:layout_height="@dimen/messaging_profile_pic_size"
android:orientation="horizontal"
custom:diameter="@dimen/messaging_profile_pic_size"
>
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/iv_left"
android:scaleType="centerCrop"
/>

<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:paddingStart="@dimen/line_spacing"
android:paddingEnd="0dp"
>
<ImageView
android:layout_width="@dimen/messaging_profile_pic_half_size"
android:layout_height="@dimen/messaging_profile_pic_half_size"
android:id="@+id/iv_top_right"
android:scaleType="centerCrop"
/>
<ImageView
android:layout_width="@dimen/messaging_profile_pic_half_size"
android:layout_height="@dimen/messaging_profile_pic_half_size"
android:id="@+id/iv_bottom_right"
android:paddingTop="@dimen/line_spacing"
android:scaleType="centerCrop"
/>
</LinearLayout>

</nz.co.example.components.CircleLinearLayout>

And my Circular linearlayout code goes like this

public class CircleLinearLayout extends LinearLayout {

private Bitmap maskBitmap;
private Paint paint, maskPaint;
private float radius;

public CircleLinearLayout(Context context) {
super(context);
init(context, null, 0);
}

public CircleLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}

public CircleLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}

private void init(Context context, AttributeSet attrs, int defStyle) {

paint = new Paint(Paint.ANTI_ALIAS_FLAG);

maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
if(attrs != null)
{
TypedArray a = context.getTheme().obtainStyledAttributes( attrs,R.styleable.CircleLinearLayout, defStyle , 0);

try {
radius = a.getDimension(R.styleable.CircleLinearLayout_diameter, getResources().getDimension(R.dimen.messaging_profile_pic_size)) / 2;
} finally {
a.recycle();
}
}

setWillNotDraw(false);
}

@Override
public void draw(Canvas canvas) {
Bitmap offscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas offscreenCanvas = new Canvas(offscreenBitmap);

super.draw(offscreenCanvas);

if (maskBitmap == null) {
maskBitmap = createMask(canvas.getWidth(), canvas.getHeight());
}

offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint);
canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint);
}

private Bitmap createMask(int width, int height) {
Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
Canvas canvas = new Canvas(mask);

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);

canvas.drawRect(0, 0, width, height, paint);

paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

canvas.drawCircle(radius , radius , radius , paint);

return mask;
}
}

Cheers,
Sree

Android: Create image from two bitmaps, bitmap under bitmap

Try this code:

public static Bitmap combineImages(Bitmap c, Bitmap s) {
Bitmap cs;
int width, height;

width = s.getWidth();
height = c.getHeight() + s.getHeight();

cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

Canvas comboImage = new Canvas(cs);

comboImage.drawBitmap(c, 0f, 0f, null);
comboImage.drawBitmap(s, 0f, c.getHeight(), null);

return cs;
}

Draw large bitmaps in Android

I was thinking a lot and came up with an idea to divide input bitmap to small chunks and save them to an array. So now to draw that bitmap all I have to do is to draw visible chunks.

Picture:

Sample Image

Big black rectangle means input bitmap, green rectangle means viewport, red rectangle means visible chunks that are drawn

I've wrote an object that does that all (I didn't check it for bugs yet :/). I've tested it and it draws 3000x3000 bitmap with ~45 fps. I'm considering this way as very effective. The object itself may need to be developed more but I think this functionality is enough for my needs. Hope it'll help someone :)

P.S. https://stackoverflow.com/a/25953122/6121671 - used this for inspiration :)

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;

public final class DividedBitmap {
private final Bitmap[][] mArray; // array where chunks is stored

private final int mWidth; // original (full) width of source image
private final int mHeight; // original (full) height of source image
private final int mChunkWidth; // default width of a chunk
private final int mChunkHeight; // default height of a chunk

/* Init */

public DividedBitmap(Bitmap src) {
this(new Options(src, 100, 100));
}

public DividedBitmap(Options options) {
mArray = divideBitmap(options);

mWidth = options.source.getWidth();
mHeight = options.source.getHeight();
mChunkWidth = options.chunkWidth;
mChunkHeight = options.chunkHeight;
}

/* Getters */

public int getWidth() {
return mWidth;
}

public int getHeight() {
return mHeight;
}

public Bitmap getChunk(int x, int y) {
if (mArray.length < x && x > 0 && mArray[x].length < y && y > 0) {
return mArray[x][y];
}

return null;
}

/* Methods */

/**
* x, y are viewport coords on the image itself;
* w, h are viewport's width and height.
*/
public void draw(Canvas canvas, int x, int y, int w, int h, Paint paint) {
if (x >= getWidth() || y >= getHeight() || x + w <= 0 || y + h <= 0)
return;

int i1 = x / mChunkWidth; // i1 and j1 are indices of visible chunk that is
int j1 = y / mChunkHeight; // on the top-left corner of the screen
int i2 = (x + w) / mChunkWidth; // i2 and j2 are indices of visible chunk that is
int j2 = (y + h) / mChunkHeight; // on the right-bottom corner of the screen

i2 = i2 >= mArray.length ? mArray.length - 1 : i2;
j2 = j2 >= mArray[i2].length ? mArray[i2].length - 1 : j2;

int offsetX = x - i1 * mChunkWidth;
int offsetY = y - j1 * mChunkHeight;

for (int i = i1; i <= i2; i++) {
for (int j = j1; j <= j2; j++) {
canvas.drawBitmap(
mArray[i][j],
(i - i1) * mChunkWidth - offsetX,
(j - j1) * mChunkHeight - offsetY,
paint
);
}
}
}

/* Static */

public static Bitmap[][] divideBitmap(Bitmap bitmap) {
return divideBitmap(new Options(bitmap, 100, 100));
}

public static Bitmap[][] divideBitmap(Options options) {
Bitmap[][] arr = new Bitmap[options.xCount][options.yCount];

for (int x = 0; x < options.xCount; ++x) {
for (int y = 0; y < options.yCount; ++y) {
int w = Math.min(options.chunkWidth, options.source.getWidth() - (x * options.chunkWidth));
int h = Math.min(options.chunkHeight, options.source.getHeight() - (y * options.chunkHeight));
arr[x][y] = Bitmap.createBitmap(options.source, x * options.chunkWidth, y * options.chunkHeight, w, h);
}
}

return arr;
}

public static final class Options {
final int chunkWidth;
final int chunkHeight;
final int xCount;
final int yCount;
final Bitmap source;

public Options(Bitmap src, int chunkW, int chunkH) {
chunkWidth = chunkW;
chunkHeight = chunkH;

xCount = ((src.getWidth() - 1) / chunkW) + 1;
yCount = ((src.getHeight() - 1) / chunkH) + 1;

source = src;
}

public Options(int xc, int yc, Bitmap src) {
xCount = xc;
yCount = yc;

chunkWidth = src.getWidth() / xCount;
chunkHeight = src.getHeight() / yCount;

source = src;
}
}
}

Comparing Bitmap images in Android

Depending on how you define the same. If you mean the exact same file, you can do an md5sum of the files. That will be the same for every type of file I guess.

Because you specifically make the distinction for bitmap files, you might be interested in files that differ in size. That's a bit harder. If they are the same size, but not completely the same (but look really much like eachother) you can compare each separate pixel, and if enough pixels (threshold 1) are close enough to each other in color (threshold 2) you can declare them as being the same.

You can getPixel(int,int) to get the color, see this page

How to Resize a Bitmap in Android?

Change:

profileImage.setImageBitmap(
BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)

To:

Bitmap b = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
profileImage.setImageBitmap(Bitmap.createScaledBitmap(b, 120, 120, false));


Related Topics



Leave a reply



Submit