My app let the user take a picture with the camera and return a byte array containing the image data (jpeg at the moment but can be modified).
If we know the width and height of the picture, is it possible to use
BitmapFactory.decodeByteArray(data, offset, length)
To decode the picture from specified offset to get a squared picture ?
The image is in high res (portrait) and I only need the squared bottom of this picture still in high res for image processing.
x offset = 0
y offset = height - width
width = width
height = width
I have seen this answer but I still was wondering if this was possible. I could compress image data with another format if needed
My guess was to compute the number of bytes used to store n rows of pixels (using known dimensions), where n = maxRows - pictureWidth
and then start from computed offset
First decode to small size
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inSampleSize = 4; //inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels
BitmapFactory.decodeByteArray(data, offset, length, opt)
ANd Then
bitMap1 = Bitmap.createScaledBitmap(bitMap, width, height, true);
try this
Related
While I try to get image dimensions in pixels in an ImageView, I found that its width is 3 times more than the original jpg file width.
I put a jpg file which dimensions are 800 x 600, but the code below displays 2400 as its width.
Bitmap bitmap = ((BitmapDrawable)imgv.getDrawable()).getBitmap();
float fwidth = bitmap.getWidth();
Log.d("width0", Float.toString(fwidth));
I checked the jpg file size again but it was not changed (800 x 600),
I also searched for a solution but the code above displays the correct dimensions of the bitmap on other user's experience.
What have I done incorrectly?
Can anyone give me some advice?
Thanks for your help.
This is the solution found in a web site.
I needed to change the Option value when I decode the resource not to scale the original image. I had to use the three parameters for the decodeResource function, not two.
Of course, the third parameter was Options specifying the original bitmap not to be scaled. So now I can get 800 when I call bitmap's getWidth() function.
Resources res = getResources();
int id = R.drawable.map10;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
// options.inSampleSize = 3;
Bitmap bb = BitmapFactory.decodeResource(res, id, options);
float fwidth = bb.getWidth();
Make sure, that your ImageView is set to:
height : wrap_content
width : wrap_content
scaleType: none
In my Android application, I need an image with size of width 1029 * height 1029 pixel (image center crop is allowed) . The original image width and height is above than 1029 pixels.
I have tried the following things.
I have placed the image in a image view and capture the bitmap I got the following exception.
Bitmap too large to be uploaded into a texture (2322x4128, max=4096x4096)
This is the layout design of image view.
<ImageView
android:id="#+id/iv_try1"
android:layout_width="425dp"
android:layout_height="425dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:scaleType="centerCrop"
android:contentDescription="#string/icd" />
( I am not sure 425dp gives 1029 pixels, just a try).
I used the following code to capture the bitmap from image view.
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getLayoutParams().width, v.getLayoutParams().height);
v.draw(c);
// resultant bitmap is save into save in SDcard.
How can I get an image with width 1029 * height 1029 pixel resolution as bitmap? Thanks in advance.
as the exceptions states your bitmap is too large. The height exceed the maximum value. What you can do is to downscale the bitmap. The first step would be to load only the meta-info of your bitmap with
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decode*(..., o);
setting inJustDecodeBounds = true, will make the decode* method return a null Bitmap, but the BitmapFactory.Options will contain the width/height of the bitmap in pixels. Knowing those two, you can calculate the value of inSampleSize that you need to scale the bitmap to with/height close to your constraint (1029 px). From the documentation of inSampleSize
If set to a value > 1, requests the decoder to subsample the original
image, returning a smaller image to save memory. The sample size is
the number of pixels in either dimension that correspond to a single
pixel in the decoded bitmap. For example, inSampleSize == 4 returns an
image that is 1/4 the width/height of the original, and 1/16 the
number of pixels. Any value <= 1 is treated the same as 1. Note: the
decoder uses a final value based on powers of 2, any other value will
be rounded down to the nearest power of 2.
In my android application I am working on canvas bitmaps (actually it is SCanvas from Samsung SPen SDK, but it does not matter), as a rule 90-95% of area of such bitmaps is transparent, so I expected to have not too large bitmap size in KB. But seems like bitmap size (in KB) does not depend on whether it is a simple background or complex picture, so for example if I have two images (sorry, I am a new user and I can't post any images):
1) empty frame (1000x700 px, background is transparent, color border)
2) full frame (1000x700 px, background is transparent, color border, a lot of text inside)
the size of both bitmaps are about 1.3MB.
But if I convert these bitmaps in byte arrays, the size of the first array is about 11 times less than the size of the second array.
I have to store a lot of such images as BLOBs in DB and display them as ImageView bitmaps.
Question 1: if I need to display 20 ImageView objects with such 95% transparent images, is there any way to not use 20 * 1.3MB at the same time? To me it seems like it should be only 1 alpha layer + 20 "data" layers.
Question 2: is there any way to reduce size (in KB) of an image with transparency without losing too much quality? The only way I saw is to decode the image byte array with inSampleSize = 2 and then create a scaled bitmap to keep the original image dimensions, something like:
originalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream);
byte[] bitmapBytes = stream.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length, options);
int bWidth = options.outWidth;
int bHeight = options.outHeight;
options.inSampleSize = 2;
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
options.inJustDecodeBounds = false;
Bitmap scaledBitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length, options);
Bitmap finalBitmap = Bitmap.createScaledBitmap(scaledBitmap, bWidth, bHeight, true);
But the finalBitmap quality is unacceptable, no matter what options I used (inPreferredConfig, inDither).
Any other thoughts about the optimal way to handle the images with about 90% of simple transparent background and 10% of one-color "data"?
No matter what format you use, it will always end up as raw uncompressed (decoded) data before displaying, if it weren't decoded, you couldn't see it on the display. If you're worried about memory, try not to have all the images decoded all the time, just decode the one you have to show, and always release the others (don't keep a reference to them).
I am running into a strange issue. I have multiple images in my Android project which I stored as .png files under res\drawable. I was able to easily extract the images at runtime and convert them to a bitmap like this:
Drawable d = getResources().getDrawable(R.drawable.imageId);
Bitmap bitmap = ((BitmapDrawable)d).getBitmap();
This works great and the image gets scaled correctly no matter what screen density the device has. All my images are 200 pixels by 200 pixels and my image layout is configured as 200 dip x 200 dip.
Now, I have stored all images as blobs in an SQlite database due to scalability issues and I am extracting them at runtime and converting to a bitmap like this:
byte[] bb = cursor.getBlob(columnIndex);
Bitmap bitmap = BitmapFactory.decodeByteArray(bb, 0, bb.length);
The image displays fine if the screen density is standard 160 dip. But if the density is any less or more, the image doesn't scale and remains 200 pixels x 200 pixels for 160 dip. So basically, on a smaller screen (120 dip), the image takes more space than it should and on a larger screen (240 dip), it takes less space than it should.
Has anyone else run into this bizarre issue? Any explanation, workaround, solution will be really appreciated.
Thanks much in advance!
Okay, I finally got it to work by using createScaledBitmap().
After creating a bitmap from the blob, I calculate the scaling factor and then calculate the new width and height. I then use those in the createScaledBitmap() function. Here's the code that works:
public static Bitmap getImageFromBlob(byte[] mBlob)
{
byte[] bb = mBlob;
Bitmap b = BitmapFactory.decodeByteArray(bb, 0, bb.length);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int newWidth = b.getWidth()*metrics.densityDpi)/DisplayMetrics.DENSITY_DEFAULT;
int newHeight = b.getHeight()*metrics.densityDpi)/DisplayMetrics.DENSITY_DEFAULT;
return Bitmap.createScaledBitmap(b, newWidth, newHeight, true);
}
This link provided the clue:
difference between methods to scale a bitmap
Use decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts) and in opts set inDesity to let say 160.
Worked for me, see this. But I have to say, I think SQLite is doing it right, and the android drawable is incorrectly sized.
I am trying to reduce the size of images retrieved form the camera (so ~5-8 mega pixels) down to one a a few smaller sizes (the largest being 1024x768). I Tried the following code but I consistently get an OutOfMemoryError.
Bitmap image = BitmapFactory.decodeStream(this.image, null, opt);
int imgWidth = image.getWidth();
int imgHeight = image.getHeight();
// Constrain to given size but keep aspect ratio
float scaleFactor = Math.min(((float) width) / imgWidth, ((float) height) / imgHeight);
Matrix scale = new Matrix();
scale.postScale(scaleFactor, scaleFactor);
final Bitmap scaledImage = Bitmap.createBitmap(image, 0, 0, imgWidth, imgHeight, scale, false);
image.recycle();
It looks like the OOM happens during the createBitmap. Is there a more memory efficient way to do this? Perhaps something that doesn't require me to load the entire original into memory?
When you decode the bitmap with the BitmapFactory, pass in a BitmapFactory.Options object and specify inSampleSize. This is the best way to save memory when decoding an image.
Here's a sample code Strange out of memory issue while loading an image to a Bitmap object
Are you taking the picture with the camera within your application? If so, you should set the picture size to a smaller one in the first place when they're being captured via android.hardware.Camera.Parameters.setPictureSize
Here is a similar question that I answered and show how to go about dynamically loading the proper image size.
out of memory exception + analyzing hprof file dump