How to save a run-time-created bitmap in Android? - android

In my application a user can upload some pictures and for database size limits I would like to merge these images to create only one image, I do that with:
private Bitmap combineImageIntoOne(ArrayList<Bitmap> bitmap) {
int w = 0, h = 0;
for (int i = 0; i < bitmap.size(); i++) {
if (i < bitmap.size() - 1) {
w = bitmap.get(i).getWidth() > bitmap.get(i + 1).getWidth() ? bitmap.get(i).getWidth() : bitmap.get(i + 1).getWidth();
}
h += bitmap.get(i).getHeight();
}
Bitmap temp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(temp);
int top = 0;
for (int i = 0; i < bitmap.size(); i++) {
Log.d("HTML", "Combine: "+i+"/"+bitmap.size()+1);
top = (i == 0 ? 0 : top+bitmap.get(i).getHeight());
canvas.drawBitmap(bitmap.get(i), 0f, top, null);
}
return temp;
}

Bitmap.compress is the method you are looking for - it allows you to save Bitmap to any OutputStream you want.
bitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(someFile));

Related

Save segmentation result of Selfie segmentation with ML Kit on Android as A Bitmap with transparent background

Save segmentation result of Selfie segmentation with ML Kit on Android as A Bitmap with transparent background
I am following this tutorial and code for Selfie segmentation
Here
I have referred this code from the tutorial
ByteBuffer mask = segmentationMask.getBuffer();
int maskWidth = segmentationMask.getWidth();
int maskHeight = segmentationMask.getHeight();
for (int y = 0; y < maskHeight; y++) {
for (int x = 0; x < maskWidth; x++) {
// Gets the confidence of the (x,y) pixel in the mask being in the foreground.
float foregroundConfidence = mask.getFloat();
}
}
Which generates a Mask
Then I have Referred the Sample app Which generates a purple background Mask
Here
using this code
#ColorInt
private int[] maskColorsFromByteBuffer(ByteBuffer byteBuffer) {
#ColorInt int[] colors = new int[maskWidth * maskHeight];
for (int i = 0; i < maskWidth * maskHeight; i++) {
float backgroundLikelihood = 1 - byteBuffer.getFloat();
if (backgroundLikelihood > 0.9) {
colors[i] = Color.argb(128, 255, 0, 255);
} else if (backgroundLikelihood > 0.2) {
// Linear interpolation to make sure when backgroundLikelihood is 0.2, the alpha is 0 and
// when backgroundLikelihood is 0.9, the alpha is 128.
// +0.5 to round the float value to the nearest int.
int alpha = (int) (182.9 * backgroundLikelihood - 36.6 + 0.5);
colors[i] = Color.argb(alpha, 255, 0, 255);
}
}
return colors;
}
Now I want to generate an Image with the original images detected mask and Overlay it on a Transparent Image and save that bitmap for this I am using this code
public Bitmap generateMaskBgImage(Bitmap image, Bitmap bg) {
//Bg is Transparent Png Image.
Bitmap bgBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), image.getConfig());
for (int y = 0; y < maskHeight; y++) {
for (int x = 0; x < maskWidth; x++) {
int bgConfidence = (int) ((1.0 - maskBuffer.getFloat()) * 255);
int bgPixel = bg.getPixel(x, y);
bgPixel = ColorUtils.setAlphaComponent(bgPixel, bgConfidence);
bgBitmap.setPixel(x, y, bgPixel);
}
}
maskBuffer.rewind();
return bitmapUtils.mergeBitmaps(image, bgBitmap);
}
However it generates an Image with the desired mask but with a Black back ground, How can we save that image with Transparent background.
You can try this (color1 is the color you set in the mask):
private Bitmap performBW(Bitmap originBitmap,Bitmap maskBitmap) {
Bitmap bmOut = Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(),
originBitmap.getConfig());
int w = originBitmap.getWidth();
int h = originBitmap.getHeight();
int[] colors = new int[w * h];
int[] colorsMask=new int[maskBitmap.getWidth() * maskBitmap.getHeight()];
originBitmap.getPixels(colors, 0, w, 0, 0, w, h);
maskBitmap.getPixels(colorsMask, 0, w, 0, 0, w, h);
int pos;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
pos = i * w + j;
if (colorsMask[pos] == color1) colors[pos]=Color.TRANSPARENT;
}
}
bmOut.setPixels(colors, 0, w, 0, 0, w, h);
return bmOut;
}

merge multiple images into one in horizontally android

am using camera2 api to capture multiple images as one and after that i save the image and creating a panorama images
private Bitmap combineImageIntoOne(ArrayList<Bitmap> bitmap) {
int w = 0, h = 0;
for (int i = 0; i < bitmap.size(); i++) {
if(i < bitmap.size() - 1){
h = bitmap.get(i).getHeight() > bitmap.get(i + 1).getHeight() ? bitmap.get(i).getHeight() : bitmap.get(i + 1).getHeight();
}
w += bitmap.get(i).getWidth();
}
Bitmap temp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(temp);
float aspectRatio = 0;
int side = 0;
int width = 0;
for (int i = 0; i < bitmap.size(); i++) {
Log.d("HTML", "Combine: "+i+"/"+bitmap.size()+1);
side = (i == 0 ? 0 : side+bitmap.get(i).getWidth());
canvas.drawBitmap(bitmap.get(i), 0f, side, null);
}
return temp;
}
scaling it down become more difficult does any one have an idea how I can dealt with horizontal image merge with 20 items?What code did you use to resolve this problem?
private Bitmap mergeMultiple(ArrayList<Bitmap> parts) {
int w = 0, h = 0;
for (int i = 0; i < parts.size(); i++) {
if (i < parts.size() - 1) {
w = parts.get(i).getWidth() > parts.get(i + 1).getWidth() ? parts.get(i).getWidth() : parts.get(i + 1).getWidth();
}
h += parts.get(i).getHeight();
}
Bitmap temp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(temp);
Paint paint = new Paint();
paint.setColor(Color.WHITE);
int top = 0;
for (int i = 0; i < parts.size(); i++) {
top = (i == 0 ? 0 : top + parts.get(i).getHeight() + 100);
canvas.drawBitmap(parts.get(i), 0f, top,paint );
}
return temp;
}

Create a QR Code and show it in ImageView

I am creating an app which will be able to scan QR code and create QR code. The scanning part is done and its working fine. But when I try to create the QR code and show it in an ImageView the QR code created is not containing correct text. I am using ZXING library.
Hashtable<EncodeHintType, ErrorCorrectionLevel> hintMap = new Hashtable<>();
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
QRCodeWriter qrCodeEncoder = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeEncoder.encode(myText, BarcodeFormat.QR_CODE,
200, 200, hintMap);
height = bitMatrix.getHeight();
width = bitMatrix.getWidth();
final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
for (x = 0; x < width; x++){
bmp.setPixel(x, y, bitMatrix.get(x,y) ? Color.BLACK : Color.WHITE);
}
ImageView myImage = (ImageView) findViewById(R.id.qr_code);
myImage.setImageBitmap(bmp);
The error is in the for loop. You missed a inner for loop. But how come you were getting a blank image!
Use below snippet.
for (x = 0; x < width; x++){
for (y = 0; y < height; y++){
bmp.setPixel(x, y, bitMatrix.get(x,y) ? Color.BLACK : Color.WHITE);
}
}
This should work.
Try out full code:
com.google.zxing.Writer writer = new QRCodeWriter();
// String finaldata = Uri.encode(data, "utf-8");
int width = 250;
int height = 250;
BitMatrix bm = writer
.encode(data, BarcodeFormat.QR_CODE, width, height);
Bitmap ImageBitmap = Bitmap.createBitmap(width, height,
Config.ARGB_8888);
for (int i = 0; i < width; i++) {// width
for (int j = 0; j < height; j++) {// height
ImageBitmap.setPixel(i, j, bm.get(i, j) ? Color.BLACK
: Color.WHITE);
}
}
Works !!

A bitmap from many of them

Guys I have a solution to crate a bitmap from 5 different another ones. However, I want this solution to be faster. I could not find another easy and fast way to do same.
private void createImage() {
// Magic numbers from image files
int numberOfImages = 5;
int imgWidth = 125;
int imgHeight = 300;
int totalwidth = imgWidth * numberOfImages;
int totalheight = imgHeight;
img = Bitmap.createBitmap(totalwidth, totalheight, Bitmap.Config.ARGB_8888);
for (int i = 0; i < numberOfImages; i++) {
Bitmap imgFile = BitmapFactory.decodeResource(context.getResources(), context.getResources().getIdentifier(
"f" + i, "drawable", context.getPackageName()));
for (int x = 0; x < imgWidth; x++) {
for (int y = 0; y < imgHeight; y++) {
int targetX = x + (i * imgWidth);
int targetY = y;
int color = imgFile.getPixel(x, targetY);
img.setPixel(targetX, targetY, color);
}
}
}
img = Bitmap.createScaledBitmap(img, screenWidth, screenHeight, true);
}
You are mostly there. You've created a bitmap that is wide enough for them all.
What you then need to do is draw the bitmaps directly onto it one at a time, but the whole bitmap at once, not pixel by pixel.
You can do this using something call Canvas. Which aids in drawing things onto bitmaps.
img = Bitmap.createBitmap(totalwidth, totalheight, Bitmap.Config.ARGB_8888);
Canvas drawCanvas = new Canvas(img);
for (int i = 0; i < numberOfImages; i++) {
Bitmap imgFile = BitmapFactory.decodeResource(context.getResources(), context.getResources().getIdentifier(
"f" + i, "drawable", context.getPackageName()));
// Draw bitmap onto combo bitmap, at offset x, y.
drawCanvas.drawBitmap(imgFile, i * imgWidth, 0, null);
}
I imagine the Bitmap.getPixels() and Bitmap.setPixels() methods might help.
private void createImage() {
// Magic numbers from image files
int numberOfImages = 5;
int imgWidth = 125;
int imgHeight = 300;
int totalwidth = imgWidth * numberOfImages;
int totalheight = imgHeight;
img = Bitmap.createBitmap(totalwidth, totalheight, Bitmap.Config.ARGB_8888);
int buf[] = new int[totalwidth * totalheight];
for (int i = 0; i < numberOfImages; ++i) {
Bitmap imgFile = BitmapFactory.decodeResource(context.getResources(),
context.getResources().getIdentifier(
"f" + i, "drawable", context.getPackageName()));
imgFile.getPixels(buf, i*imgWidth, totalwidth, 0, 0, imgWidth, imgHeight);
}
img.setPixels(buf, 0, totalwidth, 0, 0, totalwidth, totalheight);
img = Bitmap.createScaledBitmap(img, screenWidth, screenHeight, true);
}
I have not tried it, but based on the documentation, I think it should work. I imagine it will hopefully be considerably faster since we do all the work with only 6 function calls, assuming that under the covers those functions do something much more clever than just looping over the array (such as direct memory copy).
The Doomsknight's answer seems correct to me but you should not do this kind of processes on the main thread for Android. Too many images might hit the 16ms barrier.
You can do this in background handler thread and update the UI Thread after finished.
HandlerThread cropperHandlerThread = new HandlerThread("background_cropper");
cropperHandlerThread.start();
// Do not call getLooper before start handler thread.
Handler cropperHandler = new Handler(cropperHandlerThread.getLooper());
cropperHandler.post(new Runnable() {
#Override
public void run() {
// Create Bitmap Here
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// Update ImageView here
}
});
}
});

How to convert 2d int array to bitmap in android

I need to convert a 2d integer array (subSrc) to a bitmap. Any solutions?
private Bitmap decimation(Bitmap src){
Bitmap dest = Bitmap.createBitmap(
src.getWidth(), src.getHeight(), src.getConfig());
int bmWidth = src.getWidth();
int bmHeight = src.getHeight();`enter code here`
int[][] subSrc = new int[bmWidth/2][bmWidth/2];
for(int k = 0; k < bmWidth-2; k++){
for(int l = 0; l < bmHeight-2; l++){
subSrc[k][l] = src.getPixel(2*k, 2*l); <---- ??
I looked for a method that received an 2d array (int[][]) and created a Bitmap, and found none, so I wrote one myself:
public static Bitmap bitmapFromArray(int[][] pixels2d){
int width = pixels2d.length;
int height = pixels2d[0].length;
int[] pixels = new int[width * height];
int pixelsIndex = 0;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
pixels[pixelsIndex] = pixels2d[i][j];
pixelsIndex ++;
}
}
return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
}
I also wrote a reverse method:
public static int[][] arrayFromBitmap(Bitmap source){
int width = source.getWidth();
int height = source.getHeight();
int[][] result = new int[width][height];
int[] pixels = new int[width*height];
source.getPixels(pixels, 0, width, 0, 0, width, height);
int pixelsIndex = 0;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
result[i][j] = pixels[pixelsIndex];
pixelsIndex++;
}
}
return result;
}
I hope you find it useful!
you can use
setPixel(int, int, int) or setPixels (int[] pixels, int offset, int stride, int x, int y, int width, int height) methos od bitmap class.
Bitmap dest = Bitmap.createBitmap(
src.getWidth()/2, src.getHeight()/2, src.getConfig());
int bmWidth = src.getWidth();
int bmHeight = src.getHeight();
for(int k = 0; k < bmWidth/2; k++){
for(int l = 0; l < bmHeight/2; l++){
dest.setPixel(k,l,src.getPixel(2*k, 2*l));
But this will be slower i think.
for the 2nd method you uhave to do something like this
int subSrc = new int[(bmWidth/2*)(bmHeight/2)];
for(int k = 0; k < bmWidth-2; k++){
subSrc[k] = src.getPixel(2*(k/bmWidth), 2*(k%bmHeight)); <---- ??
So, you are essentially trying to pull pixels out, do something to them, then make a Bitmap as a result?
The routines expect the pixels to be in a single-dimensional array, so you'll want to put them into the array more like this:
int data[] = new int[size];
data[x + width*y] = pixel(x,y);
...
Then use Bitmap.createBitmap() that accepts the single-dimensional array. You'll want to use the Bitmap.Config for ARGB in your example, since you're using b.getPixel(x,y) which always returns a color in ARGB format.
Bitmap result = Bitmap.createBitmap(data, width, height, Bitmap.Config.ARGB_8888);

Categories

Resources