Saving bitmap to a file resulting in black image - android

I used the API sample from android for drawing on a view responding to touch events. basically what it does is that everytime I touch the screen, it draws a circle on top of what I have there (so draws a circle with transparent background resulting in looking like as if the contents were preserved)
Now the issue is when I try to save it as an image. I tried both JPG and PNG and I get black picture. Somehow it is making all the transparent stuffs appear black I guess.
Is there ANY way I can have this bitmap saved as an image (preferrebly JPG)? When you look at the image itself it does not have transperency at all.
Thank you
Code added as requested
I initialize the view as follow
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
int curW = mBitmap != null ? mBitmap.getWidth() : 0;
int curH = mBitmap != null ? mBitmap.getHeight() : 0;
if (curW >= w && curH >= h) {
return;
}
if (curW < w) curW = w;
if (curH < h) curH = h;
Bitmap newBitmap = Bitmap.createBitmap(curW, curH, Bitmap.Config.ARGB_8888);
Canvas newCanvas = new Canvas();
newCanvas.setBitmap(newBitmap);
if (mBitmap != null) {
newCanvas.drawBitmap(mBitmap, 0, 0, null);
}
mBitmap = newBitmap;
mCanvas = newCanvas;
}
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap != null) {
canvas.drawBitmap(mBitmap, 0, 0, null);
}
}
I paint the view as follow
void paintmycolor(float x, float y, float major, float minor){
mPaint.setColor(myDrawColor);
mPaint.setAlpha(Math.min((int) (pressure * 128), 255));
canvas.save(Canvas.MATRIX_SAVE_FLAG);
RectF mReusableOvalRect = new RectF();
canvas.rotate((float) (orientation * 180 / Math.PI), x, y);
mReusableOvalRect.left = x - minor / 2;
mReusableOvalRect.right = x + minor / 2;
mReusableOvalRect.top = y - major / 2;
mReusableOvalRect.bottom = y + major / 2;
canvas.drawOval(mReusableOvalRect, paint);
canvas.restore();
}
I save as follows
public File saveBitmap() throws IOException {
File path=Environment.getExternalStoragePublicDirectory(android.os.Environment.DCIM);
File myDirectory = new File(path,mContext.getString(R.string.app_name));
if(!myDirectory.exists()){
myDirectory.mkdirs();
}
File output;
do {
int rand = new Random().nextInt();
output = new File(myDirectory,rand+".jpg");
}while(output.exists());
BufferedOutputStream ous = null;
try {
ous=new BufferedOutputStream(new FileOutputStream(output));
mBitmap.compress(CompressFormat.JPEG, 100, ous);
ous.flush();
ous.close();
return output;
} finally {
if (ous!=null) {
try {
ous.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("closing", e.getMessage());
}
}
}
}

Found the answer. When you create a bitmap, although it shows it as white but it is actually transparent background. That's why I get black

I found a solution for that to retain the Transparency without changing the color to white(may be you would use it with non-white background layout):
When creating a bitmap to save it in the memory, and BEFORE saving it assign the following condition to it:
mBitmap.setHasAlpha(true);
This will make the image retain its transparency while being on the device, and that will result to an image with transparency while retrieving it back from the memory.
After all, don't forget to save it as PNG:
mBitmap.compress(Bitmap.CompressFormat.PNG, 80, ous);

Related

How to scale Canvas and draw thin border around the edge?

I have been struggling to get the preview of a PDF in the Android Print Framework to match the print output. However, I am able to get the output to match as a bitmap. However, if I scale the bitmap and put whitespace around the bitmap, the Print Framework crops out the whitespace. So, to prevent that from happening, I would like to draw a thin border around the edge of the entire Canvas.
This is the code that I have to scale the bitmap:
public static Bitmap captureScreen(View v) {
Bitmap screenshot = null;
Bitmap output = null;
try {
if (v != null) {
screenshot = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
int width = screenshot.getWidth();
int height = screenshot.getHeight();
int scaledWidth = (int) (width * 0.5);
int scaledHeight = (int) (height * 0.5);
output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Bitmap scaled = Bitmap.createScaledBitmap(screenshot, scaledWidth, scaledHeight, false);
Canvas canvas = new Canvas(output);
Paint paint = new Paint();
int distX = (width - scaledWidth) / 2;
int distY = (height - scaledHeight) / 2;
canvas.drawBitmap(scaled, distX, distY, paint);
v.draw(canvas);
}
} catch (Exception e) {
Log.d("ScreenShotActivity", "Failed to capture screenshot because:" + e.getMessage());
}
return output;
}
I would like to draw a thin black border around the entire canvas for I can prevent the whitespace from being cropped out by the Print Framework.
Well, you have the width and height of the canvas, just call Canvas.drawRect(0, 0, width - 1, height - 1, strokePaint)?

From Layout to StaticLayout: How can I use StaticLayout instead of a simple layout to draw multiline texts?

I have been working in an app that let the user takes a photo and then let him put a text over it. This is working perfect when the user types a small phrase.
This is my code:
enter code here
private Bitmap ProcessingBitmap(String captionString) {
Bitmap bm1;
Bitmap newBitmap = null;
try {
bm1 = BitmapFactory.decodeStream(getContentResolver().openInputStream(pickedImage));
//create an empty bitmap
newBitmap = Bitmap.createBitmap(bm1.getWidth(), bm1.getHeight(), Bitmap.Config.ARGB_8888);
//create a new Canvas object and pass this bitmap to it
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(bm1, 0, 0, null);
Paint paintText = new Paint(Paint.ANTI_ALIAS_FLAG);
paintText.setColor(Color.RED);
paintText.setTextSize(convertDpToPixel(50,this));
paintText.setTextAlign(Paint.Align.CENTER);
paintText.breakText(captionString,true, canvas.getWidth(),null);
paintText.setStyle(Paint.Style.FILL);
paintText.setTypeface(Typeface.create("Sans", Typeface.BOLD));
Rect textRect = new Rect();
paintText.getTextBounds(captionString, 0, captionString.length(), textRect);
if(textRect.width() >= (canvas.getWidth() - 4))
paintText.setTextSize(convertDpToPixel(25,this));
int xPos = (canvas.getWidth() / 2);
int yPos = (int) ((canvas.getHeight() / 2) - ((paintText.descent() + paintText.ascent()) / 2)) ;
//Draw Canvas
canvas.drawText(captionString, xPos, yPos, paintText);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newBitmap;
}
However, when the user types a long phrase it goes out of the photo area!
I looked online and found a lot of information about StaticLayout. Like this one: http://ivankocijan.xyz/android-drawing-multiline-text-on-canvas/
So I tried to use it in my code but I do not know what I am doing wrong! It is not working when I use a StaticLayout Canvas.
Is there a easy way to convert this code to a staticLayout? Is there another consideration that I am missing?
I lost one week trying to solve it and nothing worked so far. Thx!
I just found a solution, it was easier than I thought! Here it goes! Hopefully it will help someone someday!
private Bitmap ProcessingBitmap(String captionString) {
Bitmap bm1;
Bitmap newBitmap = null;
try {
//Decode image
bm1 = BitmapFactory.decodeStream(getContentResolver().openInputStream(pickedImage));
//create an empty bitmap
newBitmap = Bitmap.createBitmap(bm1.getWidth(), bm1.getHeight(), Bitmap.Config.ARGB_8888);
//create a new Canvas object and pass this bitmap to it
Canvas canvas = new Canvas(newBitmap);
//pass bitmap to canvas
canvas.drawBitmap(bm1, 0, 0, null);
//Create and configure text
TextPaint mTextPaint = new TextPaint();
mTextPaint.setColor(Color.RED);
mTextPaint.setTextSize(convertDpToPixel(100,this));
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setAntiAlias(true);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setTypeface(Typeface.create("Sans", Typeface.BOLD));
//StaticLayout
StaticLayout layout = new StaticLayout(captionString, mTextPaint, canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1, 1, true);
//Draw Canvas
int xPos = (canvas.getWidth() / 2);
int yPos = (int) ((canvas.getHeight() / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)) ;
canvas.translate(xPos, yPos);
//Draw Canvas
layout.draw(canvas);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newBitmap;
}

Android Bitmap Pan / Zoom / Crop

I need a bit of help. I have an ImageView with a touch listener, and I am able to capture all touch inputs into a matrix, and apply that matrix to the ImageView and VOILA! the image pans and zooms appropriately.
Here is the trouble: I'd now like to CROP the image in such a way that it ALWAYS ends up the same size; eg a 300x300 image.
In other words, suppose I have a 300x300 square in the middle of my screen, a user pans and zooms an image until an item of interest fits into that square, and hits "next". I would like to have a resulting image that has cropped the photo to only be the 300x300 portion that was contained in the box.
Make sense?? Please help! Thanks comrades! See a bit of code below for what I have tried thus far.
float[] matrixVals = new float[9];
ImageTouchListener.persistedMatrix.getValues(matrixVals);
model.setCurrentBitmap(Bitmap.createBitmap(model.getOriginalBitmap(), 0, 0, model.getTargetWidth(), model.getTargetHeight(), ImageTouchListener.persistedMatrix, true));
model.setCurrentBitmap(Bitmap.createBitmap(model.getCurrentBitmap(), Math.round(matrixVals[Matrix.MTRANS_X]), Math.round(matrixVals[Matrix.MTRANS_Y]), model.getTargetWidth(), model.getTargetHeight(), null, false));
Finally, I would also like to be able to SHRINK the image into the box, where the edges may actually need to be filled in with black or white or some kind of border... So far, everything I do other than no pan or zoom at all crashes when I hit next.
Thanks again!
see this custom ImageView, the most important part is onTouchEvent where cropped Bitmap is created and saved to /sdcard for verification:
class IV extends ImageView {
Paint paint = new Paint();
Rect crop = new Rect();
public IV(Context context) {
super(context);
paint.setColor(0x660000ff);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
crop.set(w / 2, h / 2, w / 2, h / 2);
crop.inset(-75, -75);
}
#Override
public void setImageResource(int resId) {
super.setImageResource(resId);
setScaleType(ScaleType.MATRIX);
Matrix m = getImageMatrix();
m.postScale(2, 2);
m.postTranslate(40, 30);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
Bitmap croppedBitmap = Bitmap.createBitmap(crop.width(), crop.height(), Config.ARGB_8888);
Canvas c = new Canvas(croppedBitmap);
c.translate(-crop.left, -crop.top);
c.concat(getImageMatrix());
getDrawable().draw(c);
// just save it for test verification
try {
OutputStream stream = new FileOutputStream("/sdcard/test.png");
croppedBitmap.compress(CompressFormat.PNG, 100, stream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return false;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(crop, paint);
}
}
It's not really clear for me what your problem is, a calculation or a drawing problem ... if it is a drawing problem I might have the solution ...
Create a new bitmap, get the canvas and draw the correct rect of the big image into the new smaller one ....
Bitmap bigPicture; //your big picture
Bitmap bitmap = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmap);
Rect source = ...
Rect dest = ...
c.drawBitmap(bigPicture, source, dest, paint);
Now if your problem is a calculation problem I might have a solution too ...

Android Canvas drawBitmap function efficiency

I'm trying to display a bitmap on canvas using the matrix.
canvas.drawBitmap(currentBitmap, m_matrix, tempPaint);
but the result appears, image seems weird. After that I have shown it using bounds
canvas.drawBitmap(currentBitmap, 0, 0, tempPaint);
But here image looks good, in both the cases image is not scaled.
How should I set matrix properties for the initial display?
Does the matrix display uses something else for showing the image because of that image is getting changed?
Please suggest any tutorials for details explanation.
After searching lot a lot i have finally found the solution, some of the threads related to same issue helped me out.
Quality Issue
Quality problems when resizing an image at runtime
I have followed the google's Tutorials for loading the bitmap and written my own function for scaling the bitmap.
public static Bitmap scaleDownBitmap(Bitmap original, boolean recycleOriginal, int newmaxWidth , int newmaxHeight){
if(original == null)
return null;
Bitmap rtr= null;
try{
int origWidth = original.getWidth();
int origHeight = original.getHeight();
if(origWidth <= newmaxWidth && origHeight <= newmaxWidth){
Bitmap b = Bitmap.createBitmap(original);
if (recycleOriginal && (original != b))
original.recycle();
return b;
}
int newWidth = 0;
int newHeight = 0;
float ratio;
if(origWidth > origHeight){
ratio = (float)origWidth/(float)origHeight;
newWidth = newmaxWidth;
newHeight = (int)((float)newWidth/ratio);
}
else{
ratio = (float)origHeight/(float)origWidth;
newHeight = newmaxHeight;
newWidth = (int)((float)newHeight/ratio);
}
rtr = CreateScaledBitmap(original , newWidth , newHeight);
if(recycleOriginal && original != rtr)
original.recycle();
}
catch (Exception e) {
Log.d("Image Compress Error", e.getMessage());
}
return rtr;
}
public static Bitmap CreateScaledBitmap(Bitmap paramBitmap, int paramInt1, int paramInt2)
{
Bitmap localBitmap = Bitmap.createBitmap(paramInt1, paramInt2, paramBitmap.getConfig());
Canvas localCanvas = new Canvas(localBitmap);
localCanvas.setDrawFilter(new PaintFlagsDrawFilter(0, 2));
localCanvas.drawBitmap(paramBitmap, new Rect(0, 0, paramBitmap.getWidth(), paramBitmap.getHeight()),
new Rect(0, 0, paramInt1, paramInt2), null);
return localBitmap;
}
Now after getting the image i have passed the following parameters to the paint.
tempPaint.setFilterBitmap(true); //Line 1
canvas.drawBitmap(currentBitmap, m_matrix, tempPaint);
You have to use Matrix . post scale to scale the image, like in the example below.
private void drawMatrix(){
Matrix matrix = new Matrix();
matrix.postScale(curScale, curScale);
canvas.drawBitmap(currentBitmap, matrix, tempPaint);}
Haven't tried it yet.... But should work...

bitmap on canvas drawing problems

i have several regions.
when i touch each of them they need to change their picture(exacly in some rect)
so, my code below
private void rePaint(Rect rect, int i, int j) {
Canvas canvas = null;
try {
canvas = holder.lockCanvas(rect);
String imageName = cards[i - 1][j - 1].getName();
int id = getResources().getIdentifier(imageName, "drawable", getContext().getPackageName());
Bitmap image = BitmapFactory.decodeResource(getResources(), id);
// Log.d("OLOLO", Integer.toString(id));
// Log.d("OLOLO", imageName + j + i);
Log.d("OLOLO", rect.toString());
canvas.drawBitmap(image, null, rect, null);
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
BUT. on first touch the picture is shown fullscreen. and Log.d("OLOLO", rect.toString()); returns Rect(0, 0 - 800, 404). But this rect checked before rePaint returns Rect(300, 0 - 400, 100)/ How can it change his size?
PS: second touch and other works fine. O_o
PSS: i found the answer. LiveWallpaper with SurfaceHolder.lockCanvas(Rect dirty)
double buffering caused my problem

Categories

Resources