I need to save the content of a webview as image for making it easier for sharing.
I managed to save the content of the webview as image (though I have to goto landscape mode for making the image smaller in height - I can't get it within the portrait!) but I need to attach some text and a watermark image to the bottom of the saved screenshot of webview.
Can any one help me to do so?
My code
if (webContentHeight <= 0) webContentHeight = wbContent.getContentHeight();
Bitmap bitmap = Bitmap.createBitmap(wbContent.getWidth(), (int) (webContentHeight * 1.5), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
wbContent.layout(0, 0, wbContent.getLayoutParams().width, wbContent.getLayoutParams().height);
wbContent.draw(canvas);
File imgDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "imgDir");
if (!imgDir.exists()) imgDir.mkdirs();
File imagePath = new File(imgDir, "Item_" +
new SimpleDateFormat("ddMMyyyy_hhmmss").format(new Date()) + ".png");
FileOutputStream fos;
try {
fos = new FileOutputStream(imagePath);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
startActivity(new Intent(Intent.ACTION_VIEW).setDataAndType(Uri.parse("file://" + imagePath.getAbsolutePath()), "image/*"));
if (Utils.IsNetworkConnected(getApplicationContext()))
new AsyncTsk_GrabContent().execute();
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(context, "Can't save news as image. " + e.getMessage(), Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(context, "Can't save news as image. " + e.getMessage(), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(context, "Can't save news as image. " + e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (Orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
if (pgDialog != null) {
pgDialog.dismiss();
pgDialog = null;
}
}
I tired this but can't meet the requirement :
canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(16);
canvas.drawText("My Text", 10, 10, paint);
wbContent.draw(canvas);
Thanks in Advance.
If you are drawing your text at (10,10), then drawing your wbContent at (0,0), you are drawing over your text. Either move the text down past 2/3 of the height of the canvas (as you seem to be intentionally making your canvas 1.5x the height of wbContent), or simply draw the text after drawing the wbContent.
Related
I am programming a simple drawing application with drawLines:
public void onDraw(Canvas canvas) {
setBackgroundColor(cfgBackground); //background
//canvas.drawColor(ConfigActivity.getCfgBackground(ConfigActivity.cfgBackground)); //to keep background when export to PNG/JPG
//title
paint.setColor(0xbb020a0d);
paint.setTextSize(40);
canvas.drawText(Title, 0, 40, paint);
paint.setColor(color);
paint.setStrokeWidth(thickness);
canvas.drawLines(lines, paint);
}
This is no problem. When export the screen to image file, the image shows normal in the preview screen (with all other photos in the phone), but when open this image, it shows darken, as following:
I have tried Method A/B/C like following, but the result not much different:
File sdCard = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File file = new File(sdCard, imageName);
FileOutputStream fos = null;
try {
// Make sure the Pictures directory exists.
sdCard.mkdirs();
fos = new FileOutputStream(file);
} catch (FileNotFoundException e) {
Toast.makeText(getContext(), file + " open failed: " + e, Toast.LENGTH_SHORT).show();
e.printStackTrace();
return;
}
/* //method A: will get dark image
setDrawingCacheEnabled(true);
Bitmap b = getDrawingCache();
//b.setHasAlpha(true); //to set transparency
//Canvas canvas = new Canvas(b);
//canvas.drawColor(cfgBackground)); //trying to solve darken image
b.compress(Bitmap.CompressFormat.PNG, 100, fos);
setDrawingCacheEnabled(false); //for next screen update
*/
Bitmap b = screenShot(this); //Method B
b.compress(Bitmap.CompressFormat.PNG, 100, fos);
try {
fos.flush();
fos.close();
} catch (IOException e) {
Toast.makeText(getContext(), file + " save failed: " + e, Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
Toast.makeText(getContext(), file + " saved in Albums", Toast.LENGTH_SHORT).show();
//add to gallary
getContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file.toString())));
Two functions:
//Method C
public static Bitmap getBitmapFromView(View view) {
//Define a bitmap with the same size as the view
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
//Get the view's background
Drawable bgDrawable =view.getBackground();
if (bgDrawable!=null)
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
else
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(cfgBackground);
// draw the view on the canvas
view.draw(canvas);
//return the bitmap
return returnedBitmap;
}
//Method B
public Bitmap screenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
Anyone encountered this problem?
I finally found the solution (although not sure why): the background color should be 0xFFrrggbb, eg. 0xffeeee00, though the background looks ugly but just needs more finetune...
If you know why, kindly share here, appreciated!
How to get the bitmap of current layout(For sharing the screen as image) instead of taking screenshot? I'm getting the view of layout using following line,
I can able to get bitmap of this layout but the image is looking as empty(I got blank image). This is my code.
View cardShareView = getLayoutInflater().inflate(R.layout.activity_cad_profile, null);
boolean imageResult=saveImageInLocal(getBitmapFromView(cardShareView), "cad_share.png") == true
public static Bitmap getBitmapFromView(View view) {
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.draw(canvas);
return bitmap;
}
private boolean saveImageInLocal(Bitmap imageData, String filename) {
String iconsStoragePath = Environment.getExternalStorageDirectory() + "/KKMC/";
File sdIconStorageDir = new File(iconsStoragePath);
//create storage directories, if they don't exist
sdIconStorageDir.mkdirs();
try {
filePath = sdIconStorageDir.toString() + filename;
FileOutputStream fileOutputStream = new FileOutputStream(filePath);
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
//choose another format if PNG doesn't suit you
imageData.compress(Bitmap.CompressFormat.PNG, 70, bos);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
Log.w("TAG", "Error saving image file: " + e.getMessage());
return false;
} catch (IOException e) {
Log.w("TAG", "Error saving image file: " + e.getMessage());
return false;
}
return true;
}
Advance Thanks for your response.
Expecting this image
Bit I got this image
Finally, I created duplicate layout(activity_cad_profile.xml) for take the full view as image which is loaded at the time of main layout is loading. I don't know this is correct way or not. But it's working fine for me.
I am writing some text on Image which will be compressed.
Image sie 2048 x 1536 Something px
I first tried to write first
It throws OutOfMemory Exception
then i first compressed it to 1024 x 768
Then Written text on the Image
It increased the Image KB's from 100KB to 640KB
While writing text i can compromise the Image quality but not the text Quality
on Compression quality set to 30 the text also goes downsample
Questions:
is there any process to write then compress or Compress then Write
text without changing the ImageSize(in KB)?
I want Image Size(in KB) as less as Possible?
And also When inSampleSize is set to 3 it does not work and only the image of 2048 , 1024 , 512 using 1 , 2 , 4 is created as output I want image of some size arround 700px maintaining aspect ration.
Codes:.
Method for StampingImage
public void stampMyImage(String filePath, String text, Bitmap bitmap) {
String[] str = text.split("\n");
filePath = "/sdcard/geoTag/1imagelong_001_001_0002_0002_1135_130708144229.jpg";
bitmap = BitmapFactory.decodeFile(filePath);
if (bitmap != null) {
Bitmap dest = null;
try {
dest = bitmap.copy(bitmap.getConfig(), true);
} catch (OutOfMemoryError e1) {
Log.e("Exception", e1.getMessage());
e1.printStackTrace();
} catch (Error e) {
Log.e("Exception", e.getMessage());
e.printStackTrace();
}
Canvas cs = new Canvas(dest);
Typeface tf = Typeface.create("Verdana", Typeface.BOLD);
Paint tPaint = new Paint();
tPaint.setAntiAlias(true);
tPaint.setTextSize(40);
tPaint.setTextAlign(Align.LEFT);
tPaint.setTypeface(tf);
tPaint.setColor(Color.RED);
tPaint.setStyle(Style.FILL_AND_STROKE);
cs.drawBitmap(bitmap, 0f, 0f, null);
float textHeight = tPaint.measureText("yY");
int index = 0;
for (String Oneline : str) {
cs.drawText(Oneline, 20f, (index + 1) * textHeight + 25f,
tPaint);
index++;
}
try {
FileOutputStream fos = new FileOutputStream(
"/sdcard/timeStampedImage.jpg");
dest.compress(Bitmap.CompressFormat.JPEG, 100, fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Method for Regular Compression
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
int quality = 70;
myBitmapClose = BitmapFactory.decodeFile(imgUriClose.getPath(),options);
if (myBitmapClose != null) {
File sdImageMainDirectory = new File(imgUriClose.getPath());
try {
FileOutputStream fileOutputStream = new FileOutputStream(sdImageMainDirectory);
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
myBitmapClose.compress(CompressFormat.JPEG, quality, bos);
if (bos != null) {
bos.flush();
bos.close();
}
if (fileOutputStream != null) {
fileOutputStream.flush();
fileOutputStream.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Image Sample
See Also
Some useful links i followed
How to write text on an image in Java (Android)
Generate a image with custom text in Android
Drawing Text (TimeStamp) Over image captured from Standalone Camera
Your problem is the allowed allocation memory for your app.
When you load images to bitmap variables (decodeFile or bitmap.copy) try to set the options to decrease image quality. For example, when you do bitmap.copy try to set the options like this:
bitmap.copy(Bitmap.Config.ARGB_4444, true);
I am trying to save a canvas on an sdcard. Basically I am drawing two bitmaps (one on top of another) in the onDraw(Canvas canvas) method. But when I save the file, only the bottom layered Bitmap is stored. I am posting the code for the onDraw method here:
Paint paint = new Paint();
paint.setColor(Color.BLACK);
//rectangle for the first image
rct = new Rect(10, 10, canvas.getWidth(), canvas.getHeight());
// rectangle for the second image, the secong image is drawn where the user touches the screen
new_image = new RectF(touchX, touchY, touchX + secondBitmap.getWidth(),
touchY + secondBitmap.getHeight());
//this is the bitmap that is drawn first
canvas.drawBitmap(firstBitmap, null, rct, paint);
//this is the bitmap drawn on top of the first bitmap on user touch
canvas.drawBitmap(secondBitmap, null, new_image, paint);
canvas.save();
the code for saving the canvas on the SDcard written on the MainActivity is:
Bitmap bm = canvas.getDrawingCache() // canvas in an object of the class I extended from View
String path = Environment.getExternalStorageDirectory()
.getAbsolutePath();
boolean exists = (new File(path)).exists();
OutputStream outStream = null;
File file = new File(path, "drawn_image" + ".jpg");
try {
outStream = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
outStream.flush();
outStream.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
The problem is that only the base image(firstBitmap of the onDraw() method) is saved on the SDCard instead of the entire canvas(with both the images). I am new to canvas...So any help would be very appreciated
when getDrawingcache() is called it invalidates the view to get the full cache. so debug your code and check if it is going through each and every line of your onDraw() method in view.
I'm working on application which is drawing on Canvas similar to Finger Paint demo from Android SDK. My problem is when I'm using PorterDuff.Mode.CLEAR. When drawing and Canvas and if I try to erase something, it's working fine. But if I try to save my image as PNG file the strokes of eraser are coloured black, and I'm not sure why is this happening. Here is an example what I'm doing :
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
Eraser :
case ERASE_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
return true;
And how I'm saving the image :
Calendar currentDate = Calendar.getInstance();
SimpleDateFormat formatter= new SimpleDateFormat("yyyyMMMddHmmss");
String dateNow = formatter.format(currentDate.getTime());
File dir = new File(mImagePath);
if(!dir.exists())
dir.mkdirs();
File file = new File(mImagePath + "/" + dateNow +".png");
FileOutputStream fos;
try {
fos = new FileOutputStream(file);
mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
Toast.makeText(getApplicationContext(), "File saved at \n"+mImagePath + "/" + dateNow +".png", Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
Log.e("Panel", "FileNotFoundException", e);
}
catch (IOException e) {
Log.e("Panel", "IOEception", e);
}
return true;
And here is an example of images :
here is what my canvas looks like before saving :
and here is the image after saving it on sd card :
The problem with the fingerpaint code is that what you see is not the same that is compressed into the png. Look at onDraw(). First you draw the screen white. Then you add the Bitmap. Because you used Porter Duff Clear the erased part of the bitmap contains actually transparent black pixels (value 0x00000000). But because you have the white background these black pixels show as white.
To fix this either change your save code to do the same thing as the draw code
try {
fos = new FileOutputStream(file);
Bitmap saveBitmap = Bitmap.createBitmap(mBitmap);
Canvas c = new Canvas(saveBitmap);
c.drawColor(0xFFFFFFFF);
c.drawBitmap(mBitmap,0,0,null);
saveBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
saveBitmap.recycle();
...
or don't use PortDuff.Clear:
case ERASE_MENU_ID:
mPaint.setColor(Color.WHITE);