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);
Related
I want to reuse size of bitmap when I send to server as base64. For example, original image size is 1.2 MB so I have to resize it to 50KB (server limit side). The way make image distort sometimes. I have read [1] and [2], but it didn't help.
The problem is some image become distort after resize.
Here is my code:
private String RescaleImage(String bitmap, int size) {
try {
if ((float) bitmap.getBytes().length / 1000 <= Constants.PROFILE_IMAGE_LIMITED_SIZE) {
return bitmap;
} else {
//Rescale
Log.d("msg", "rescale size : " + size);
size -= 1;
bitmap = BitmapBase64Util.encodeToBase64(Bitmap.createScaledBitmap(decodeBase64(bitmap), size, size, false));
return RescaleImage(bitmap, size);
}
} catch (Exception e) {
return bitmap;
}
}
encodingToBase64:
public static String encodeToBase64(Bitmap image) {
Log.d(TAG, "encoding image");
String result = "";
if (image != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
result = Base64.encodeToString(b, Base64.DEFAULT);
Log.d(TAG, result);
return result;
}
return result;
}
Image is cropped before resize. Size after cropped is 300 x 300
My question is:
How to reuse image size to 50KB, keep same ratio and avoid distort?
You pass the the same width and height in Bitmap.createScaledBitmap(decodeBase64(bitmap), size, size, false). Unless your bitmaps are squares you have to specify the right widht and height, otherwise your image gets distorted based on the original aspect ratio. I think something like this would work:
Bitmap scaledBitmap = Bitmap.createScaledBitmap(decodeBase64(bitmap);
bitmap = BitmapBase64Util.encodeToBase64(scaledBitmap, scaledBitmap.getWidth(), size.getHeight(), false);
If you need compression to reduce the size use this [Edit: You have done this]:
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
I update my code and it work better now.
-- FixED --
Instead of resize the bitmap string continuously, I use the orignal bitmap that is used before resize.
private String RescaleImage(String bitmap, Bitmap origin_bitmap, int size) {
try {
if ((float) bitmap.getBytes().length / 1000 <= Constants.PROFILE_IMAGE_LIMITED_SIZE) {
return bitmap;
} else {
//Rescale
Log.d("msg", "rescale size : " + size);
size -= 1;
bitmap = BitmapBase64Util.encodeToBase64(Bitmap.createScaledBitmap(origin_bitmap, size, size, false));
return RescaleImage(bitmap, origin_bitmap, size);
}
} catch (Exception e) {
return bitmap;
}
}
Also, use this code when decode to reuse distortion. Bad image quality after resizing/scaling bitmap.
If there are better fix, I always welcome in order to improve.
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 have PDF files that contains 1 single icon.
I need to render this icons in GridView.
On Android 5 I'm using PdfRenderer system class and it works amazing:
On Android 4, I'm using "Android-Pdf-Viewer-Library".
https://github.com/jblough/Android-Pdf-Viewer-Library
It works, but the quality is poor:
Can you please suggest any alternatives for rendering PDF as Bitmap?
Or maybe there is a way to increase quality of rendering for that library?
Here is my code:
private static Bitmap renderToBitmap(Context context, InputStream inStream) {
Bitmap bitmap = null;
try {
byte[] decode = IOUtils.toByteArray(inStream);
ByteBuffer buf = ByteBuffer.wrap(decode);
PDFPage mPdfPage = new PDFFile(buf).getPage(0, true);
float width = mPdfPage.getWidth();
float height = mPdfPage.getHeight();
bitmap = mPdfPage.getImage((int) (width), (int) (height), null, true,
true);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inStream.close();
} catch (IOException e) {
}
}
return bitmap;
}
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.
i have a problem when i'm trying to save a bitmap to the external picture directory. When i use the Bitmap.compress function to save it, the bitmap loses its transparency and makes the background black. But when i pass the bitmap to a imageview and show it in the activity it looks fine and has transparency. Only when i try to save it, then transparency turns black.
I have to say, that im using two bitmaps and porterduff mode the draw a path on a bitmap and show only the picture in the drawn path, and all other pixels should be cut off or transparent.
So here's the function for creating a path bitmap:
private void createPathBitmap(RectF rect, Bitmap bitmap, Path path) {
RectF tmpRect = new RectF(rect);
Bitmap src = Bitmap.createBitmap(bitmap, (int) tmpRect.left, (int) tmpRect.top, (int) tmpRect.width(), (int) tmpRect.height());
Bitmap dst = Bitmap.createBitmap(src.getWidth(), src.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(dst);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(mDisplayDensity * SnippetLayer.PATH_DIAMETER);
path.offset(-rect.left, -rect.top);
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
RectF srcRect = new RectF(0, 0, rect.width(), rect.height());
canvas.drawBitmap(src, null, srcRect, paint);
BitmapManager.sBitmapSnippet = dst;
}
And here's the method for saving that bitmap to external storage:
SimpleDateFormat dateFormat = new SimpleDateFormat("HH_mm_ss_dd_MM_yyyy");
File snippetFile = new File(picDir, fileName+"_"+dateFormat.format(new Date())+".png");
try {
FileOutputStream fileOutputStream = new FileOutputStream(snippetFile);
BitmapManager.sBitmapSnippet.setHasAlpha(true);
BitmapManager.sBitmapSnippet.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The picture is shown only in the path, and the rest of the bounding box is black and not transparent.
I appreciate any help.
I'm using compress() method to write bitmap into output stream:
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
It is important to use PNG format. JPEG transforms my transparent background into black color.
I don't know why exactly does it lose transparency, but I had the same problem. All you have to do is to change
BitmapManager.sBitmapSnippet.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
to
BitmapManager.sBitmapSnippet.compress(Bitmap.CompressFormat.PNG, 0, fileOutputStream);.
This will compress the bitmap with full quality, but containing transparent regions.
Don't loose transparency by this small snippet
Here Problem is you save image in .JPEG so JPEG take black background as transparent so we will save in .PNG so definitely get transparent Image
private void saveImage(Bitmap data, View view) {
File createFolder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Magic PhotoShoot");
if (!createFolder.exists())
createFolder.mkdir();
Calendar c = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strDate = sdf.format(c.getTime());
File saveImage = new File(createFolder, "Photoshoot_" + strDate + ".png");
try {
OutputStream outputStream = new FileOutputStream(saveImage);
data.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
outputStream.flush();
outputStream.close();
Snackbar.make(view, "Saved to PhotoShoot successfully", Snackbar.LENGTH_SHORT).show();
isSave = true;
Glob.savedImage = saveImage.getAbsolutePath();
MediaStore.Images.Media.insertImage(getContentResolver(), saveImage.getAbsolutePath(), saveImage.getName(), saveImage.getName());
} catch (FileNotFoundException e) {
Snackbar.make(view, "File not found", Snackbar.LENGTH_SHORT).show();
e.printStackTrace();
} catch (IOException e) {
Snackbar.make(view, "Error while saving image", Snackbar.LENGTH_SHORT).show();
e.printStackTrace();
}
}
JPEG does not support transparency. JPEG's lossy compression also suffers from generation loss, where repeatedly decoding and re-encoding an image to save it
Use PNG extension file format for storing images in storage
In Kotlin:
Here is bitmap which is used for compression and saving into storage using file path
val file=File(outputImagePath)
var fout: OutputStream? = null
fout = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fout)
fout.flush()
fout.close()`
In Java:
Here is bitmap which is used for compression and saving into storage using file path
File imageFile = new File(outputImagePath);
OutputStream fout = null;
fout = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fout);
fout.flush();
fout.close();
You should use Bitmap.CompressFormat.PNG or Bitmap.CompressFormat.WEBP. If you want to get less size image. you should use Bitmap.CompressFormat.WEBP like me.