Bitmap compress PNG -> JPEG and vice versa in Android - android

I have problem with size of picture when I'm doing conversion from PNG to JPEG, and then JPEG to PNG.
public void onClick(View v) {
String imageFileName = "/sdcard/Penguins2.png";
File imageFile = new File(imageFileName);
if (imageFile.exists()) {
// Load the image from file
myBitmap = BitmapFactory.decodeFile(imageFileName);
// Display the image in the image viewer
myImageView = (ImageView) findViewById(R.id.my_image_view);
if (myImageView != null) {
myImageView.setImageBitmap(myBitmap);
}
}
}
Conversion:
private void processImage() {
try {
String outputPath = "/sdcard/Penguins2.jpg";
int quality = 100;
FileOutputStream fileOutStr = new FileOutputStream(outputPath);
BufferedOutputStream bufOutStr = new BufferedOutputStream(
fileOutStr);
myBitmap.compress(CompressFormat.JPEG, quality, bufOutStr);
bufOutStr.flush();
bufOutStr.close();
} catch (FileNotFoundException exception) {
Log.e("debug_log", exception.toString());
} catch (IOException exception) {
Log.e("debug_log", exception.toString());
}
myImageView.setImageBitmap(myBitmap);
After processing this operation I just change these lines:
String imageFileName = "/sdcard/Penguins2.png";
to
String imageFileName = "/sdcard/Penguins2.jpg";
and
String outputPath = "/sdcard/Penguins2.jpg";
(...)
myBitmap.compress(CompressFormat.JPEG, quality, bufOutStr);
to
String outputPath = "/sdcard/Penguins2.png";
(...)
myBitmap.compress(CompressFormat.PNG, quality, bufOutStr);
Size of image changed from 585847 to 531409 (in DDMS)
I want to do such thing because I'd like to use PNG which is lossless for some image processing.
Then converse image to jpeg and send as MMS, I'm not sure but I think JPEG is only format which is support by all devices in MMS. Receiver would open image and converse it back to png without losing data.

In addition to the #Sherif elKhatib answer, if you check the documentation: http://developer.android.com/reference/android/graphics/Bitmap.html#compress%28android.graphics.Bitmap.CompressFormat,%20int,%20java.io.OutputStream%29
You can see that the PNG images don't use the quality paremeter:
quality: Hint to the compressor, 0-100. 0 meaning compress for small size, 100 meaning compress for max quality. Some formats, like PNG which is lossless, will ignore the quality setting

This is not doable! Once you convert to JPG you lost the "lossless state of PNG".
Anyway png is supported by everyone.
+In your case, you want the receiver to change it back to PNG to retrieve the lossless image. This means that the receiver also supports PNG. What is the point of changing it to JPG before sending and then changing it back to PNG when received. Just some extra computations?

Related

Android bitmap compress webp to jpg not change mime type

when I use compress(CompressFormat format, int quality, OutputStream stream) function to compress webp to jpg, it's suffix change to .jpg.
But it's mimeType doesn't change, still "image/webp".
So there is a problem which phone dosen't support webp will not preview it.
Could anyone give me the answer?
webpBitmap.compress(Bitmap.CompressFormat.JPEG, 45, fos)
//get mime type from bitmap file
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.absolutePath, options)
return options.outMimeType
// it return "image/webp" not "image/jpg"
the question is why bitmap.compress will not change file mime type

Is it possible to capture a screenshot of a widget while the device screen is off?

For an app I'm trying to make I need to periodically capture screenshots of a widget (which my app would be the host of). But I want these screenshots to be captured without waking up the screen.
Essentially I want to refresh the widget, capture screenshot and then send it over the Internet while the phone screen is off.
Edit: Is it possible to load a widget, and then access its view (in order to generate a screenshot of the view) all while the phone's screen is off / locked?
You should be able to so long as you have an instance of the view. I'm not 100% sure the view's canvas remains drawn with the screen off though. Worth a shot. Here's some code I use to grab view screenshots over the web (note the compression differences for different view sizes)
public static byte[] captureScreenshot(View view) throws JSONException {
//maybe do something with filename
String fileName = null;
try {
// create bitmap screen capture
Bitmap bitmap;
view.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Bitmap.CompressFormat compressionFormat;
int filename = view.getId();
if (filename == -1) {
filename = 1010;
}
if (getBitMapSize(bitmap) > 750000) {
compressionFormat = Bitmap.CompressFormat.JPEG;
fileName = String.valueOf(filename) + ".jpg";
} else {
compressionFormat = Bitmap.CompressFormat.PNG;
fileName = String.valueOf(filename) + ".png";
}
bitmap.compress(compressionFormat, 60, outputStream);
byte[] imageBytes = outputStream.toByteArray();
} catch (Exception e) {
Log.e("Error creating screenshot: ");
}
return byte[];

OutOfMemoryError with emodo/cropper library when using getCroppedImage

I am using edmodo/cropper library to crop the image after the user has taken the image from camera.
Link: https://github.com/edmodo/cropper/wiki
I got this issue on device GT-N7000 and some other android phones.
java.lang.OutOfMemoryError
1 at android.graphics.Bitmap.nativeCreate(Native Method)
2 at android.graphics.Bitmap.createBitmap(Bitmap.java:669)
3 at android.graphics.Bitmap.createBitmap(Bitmap.java:604)
4 at android.graphics.Bitmap.createBitmap(Bitmap.java:530)
5 at com.edmodo.cropper.CropImageView.getCroppedImage(CropImageView.java:357)
Does anyone know how to solve this issue. Please help me ,the device keep getting crashes.
I solved it by subsampling the captured image before storing it in cropView using BitmapFactory.Options.
Here is the code:
// setting path to the clicked image and cropped image
path_click = "sdcard/Pictures/Candice/Clicked.jpg";
path_crop = "sdcard/Pictures/Candice/Cropped.jpg";
final BitmapFactory.Options options = new BitmapFactory.Options();
//If set to a value > 1,requests the decoder to subsample the
//original image, returning a smaller image to save memory.
options.inSampleSize = 2;
clickedImage = BitmapFactory.decodeFile(path_click, options);
cropImageView.setImageBitmap(clickedImage);
// Sets initial aspect ratio to 10/10, for demonstration purposes
cropImageView.setAspectRatio(DEFAULT_ASPECT_RATIO_VALUES,
DEFAULT_ASPECT_RATIO_VALUES);
cropButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Here we save the cropped image and then call the next
// activity
// To retrieve the image contained within the Cropper window,
// use the provided method, getCroppedImage() to retrieve a
// Bitmap of the cropped image.
croppedImageBitmap = cropImageView.getCroppedImage();
/** Save cropped image to SD card using output streams **/
// An output stream that writes bytes to a file.
// If it does not exist, a new file will be created.
FileOutputStream out = null;
try {
out = new FileOutputStream(path_crop);
// Writing a compressed version of bitmap to outputstream.
croppedImageBitmap.compress(Bitmap.CompressFormat.JPEG, 90,
out);
// Just after compression,add
croppedImageBitmap.recycle();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
startActivity(chooseIntent);
}
});
I don't know how big is your image, but have you tried adding android:largeHeap="true" to your <application> tag in the AndroidManifest.xml?

Compress image file to specified size

I have a requirement to make sure that all pictures my users take from ACTION_IMAGE_CAPTURE Intent in my app are under 4 MB due to server restrictions. What would be the best way to go about doing this? The files are JPEG if that matters.
So far I'm using a brute force method below but this doesn't work. (Edit: It works now with suggestions given below, but takes a while) I'm wondering if there is some more efficient method, perhaps using BitmapFactory.Options.inJustDecodeBounds, that could maybe map pixel count to number of bytes so I wouldn't need so many IO operations.
private final int MAX_IMAGE_SIZE = 4194304;
private void shrinkImageFile(File file) throws IOException
{
Bitmap bitmap = BitmapFactory.decodeFile(file.getPath());
int quality = 90;
while (file.length() > MAX_IMAGE_SIZE )
{
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, out);
quality -= 10;
}
}

Some Androids Uploading Scrambled Images

First I use this code to save the photo to the Android's SD Card:
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
currentFilename = String.format("%d", System.currentTimeMillis());
outStream = new FileOutputStream("/sdcard/" + currentFilename + ".jpg");
outStream.write(data);
outStream.close();
}
};
Then I am using this code to upload photos on Android devices:
public void uploadPhoto() {
try {
// Create HttpPost
HttpPost post = new HttpPost("http://www.example.com/upload.php");
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
MultipartEntity entity = new MultipartEntity( HttpMultipartMode.BROWSER_COMPATIBLE );
// Add the Picture as "userfile"
entity.addPart( "userfile", new FileBody(
new File( "/sdcard/", currentFilename + ".jpg" ),
"image/jpeg")
);
// Send the data to the server
post.setEntity( entity );
client.execute( post );
} catch (Exception e) {
// catch
} finally {
// finally
}
}
This works on my LG Optimus V running Android 2.2.2 and Droid X running Android 2.3.4
However - a user who has an HTC Evo running 2.3.4 (Same as my Droid X) is experiencing that all of her uploaded photos are scrambled when they are saved to her phone (and when they get to the server). The image looks like an array of jagged colored lines.
Any ideas about what might be going on here and what could be done to remedy the problem?
Update:
I was able to access this phone and when I pull the jpg files off of the sdcard, it says that the files are 3.5 - 4.0 MB in size, but they cannot be opened and may be corrupted... but the files on the other phones work normally.
It looks like problem with picture sizes. Decoding data from array to picture when width and heigh are wrong results with scrambled image.
Pictures might be taken with supported screen sizes:
Parameters params = camera.getParameters();
List<Camera.Size> sizes = params.getSupportedPictureSizes();
try to set one of them, for example the biggest, as picture size:
List<Size> sizes = params.getSupportedPictureSizes();
Size theBiggest=null;
int maxWidth = 0;
for (Size s : sizes) {
if (s.width > maxWidth) {
maxWidth = s.width;
theBiggest = s;
}
}
params.setPictureSize(theBiggest.width, theBiggest.height);
camera.setParameters(params);
Images need to be cached to sdcard in order to achieve full (non-compressed) size. Steps are easy
capture image
save captured image to sdcard
load saved image from sdcard
convert it to byte array and add as a ByteArrayBody, or as you o you might skip step 3 and create a file body with cached file.
Note: Currently i am away from my pc. I will post an detailed answer if there is no detailed post. Good luck.
Compress the bitmap in JPEG format into the output stream.. Assuming data is a Bitmap type
currentFilename = String.format("%d", System.currentTimeMillis());
outStream = new FileOutputStream("/sdcard/" + currentFilename + ".jpg");
data.compress(Bitmap.CompressFormat.JPEG, 90, outStream );
outStream.close();
You can change the compression ratio parameter to the compress api.. for example, pass 80 to get 80% compression.
This post may have some relation to your problem.

Categories

Resources