CreateScaledBitmap returns a blank image in android - android

I have been trying to follow this answer https://stackoverflow.com/a/8527745/1352702
, to create a scaled bitmap instead of just drawing a bitmap on the canvas, to solve some memory issues.
Here is my code,
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
options.inInputShareable = true;
options.inSampleSize = 8;
Bitmap s000 = BitmapFactory.decodeResource(getResources(), getResources().getIdentifier("zoo" + i, "drawable", getPackageName()));
int X = c.getWidth()/2 - s000.getWidth()/2 ;
int Y = c.getHeight()/2 - s000.getHeight()/2 ;
Bitmap.createScaledBitmap(s000, s000.getWidth(), s000.getHeight(), true);
But it just creates a blank screen.
Also how to pass the position parameters of the image (X and Y respectively) in the createScaledBitmap method ?

For the record, I had the same issue when trying to resize certain hi-resolution grayscale PNGs : they were properly loaded by BitmapFactory.decodeResource, then Bitmap.createScaledBitmap turned them into black pictures.
Turns out that, on API 26+, Android doesn't know how to handle bitmaps whose ColorSpace is not properly detected ("Unknown"), and messes up the resizing.
The working solution for my app was to define a preferred ColorSpace at load time :
BitmapFactory.Options options = new BitmapFactory.Options();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
options.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
bitmap = BitmapFactory.decodeXXX(<whatever method you fancy>, options);

Related

Reducing load image time and RAM

i am loading some bitmap from the gallery using the following code:
bitmap = (BitmapFactory.decodeFile(picturePath)).copy(Bitmap.Config.ARGB_8888, true);
bitmap = Bitmap.createScaledBitmap(bitmap, screenWidth, screenHeight, true);
bitmapCanvas = new Canvas(bitmap);
invalidate(); // refresh the screen
Question:
It seems that it takes so long time to load an image by first decode fully and copy, and then making scaling to fit for the screen width and height. It really actually does not need to load the pic with full density because I would not let the user to enlarge the imported image anyway.
In that way, are there any method to reduce the load time and RAM? (directly load a scaled-down image) How to further modify the above coding?
It may be worth trying RGB_565 instead of ARGB_8888 if you don't have transparency.
just have found the answer for this reducing RAM and load time and avoid outofmemory error from other similar questions.
//get importing bitmap dimension
Options op = new Options();
op.inJustDecodeBounds = true;
Bitmap pic_to_be_imported = BitmapFactory.decodeFile(picturePath, op);
final int x_pic = op.outWidth;
final int y_pic = op.outHeight;
//The new size we want to scale to
final int IMAGE_MAX_SIZE= (int) Math.max(DrawViewWidth, DrawViewHeight);
int scale = 1;
if (op.outHeight > IMAGE_MAX_SIZE || op.outWidth > IMAGE_MAX_SIZE)
{
scale = (int)Math.pow(2, (int) Math.round(Math.log(IMAGE_MAX_SIZE /
(double) Math.max(op.outHeight, op.outWidth)) / Math.log(0.5)));
}
final BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
//Import the file using the o2 options: inSampleSized
bitmap = (BitmapFactory.decodeFile(picturePath, o2));
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

Loading a jpeg using BitmapRegionDecoder gives checkerboard distortion

I'm loading a big jpeg file from a url using an InputStream from a URLConnection. The goal is to get an int[] with the image data as this is more efficient than using a Bitmap for further use. There are two options here.
The first is to create a Bitmap object and to copy the results in an int[]. This works in my application but the full image is in memory twice upon loading as the image data is copied into the int[] image.
Bitmap full = BitmapFactory.decodeStream(conn.getInputStream());
full.getPixels(image, 0, width, 0, 0, width, height);
To save memory, I'm trying to perform this process in a tiled fashion using a BitmapRegionDecoder.
int block = 256;
BitmapRegionDecoder decoder = BitmapRegionDecoder.
newInstance(conn.getInputStream(), false);
Rect tileBounds = new Rect();
// loop blocks
for (int i=0; i<height; i+=block) {
// get vertical bounds limited by image height
tileBounds.top = i;
int h = i+block<height ? block : height-i;
tileBounds.bottom = i+h;
for (int j=0; j<width; j+=block) {
// get hotizontal bounds limited by image width
tileBounds.left = j;
int w = j+block<width ? block : width-j;
tileBounds.right = j+w;
// load tile
tile = decoder.decodeRegion(tileBounds, null);
// copy tile in image
int index = i*width + j;
tile.getPixels(image, index, width, 0, 0, w, h);
}
}
Technically this works and I get the full image in the int[] image. Also the tiles are seemlessly inserted into the image.
Now my problem. The second method results in an image which has some kind of strange checkerboard distortion. Pixels seem to alternate between being slightly darker or slightly lighter. BitmapRegionDecoder is supposed to support jpeg, and BitmapFactory.decodeStream has no problems. What is the problem here?
Found it! apparently if you feed null into decoder.decodeRegion(tileBounds, null); it returns a Bitmap with quality Bitmap.Config.RGB_565 (not sure if this is device dependant). Simply feeding it a new options set returns a Bitmap of Bitmap.Config.RGB_ARGB8888 quality. By default this preferred quality is set.
BitmapFactory.Options options = new BitmapFactory.Options();
...
// load tile
tile = decoder.decodeRegion(tileBounds, options);
Thanks for your self-investigation!
Though I would recommend avoid relying on some default and make it clear:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig=Config.ARGB_8888; //explicit setting!
result_bitmap=regionDecoder.decodeRegion(cropBounds, options);
Thanks!

After capturing a layout screenshot, ImageView is transparent

I have a problem in Android screen capture. The captured image is transparent while the original image is solid JPEG file which is not transparent!
I tested in on many devices with different OS version and problem persists on all phones.
Here is my code for screen capture and also the final output
Code:
final Bitmap rawBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(rawBitmap);
rendererView.layout(0, 0, width, height);
rendererView.draw(canvas);
rawBitmap.compress(CompressFormat.PNG, 100, new FileOutputStream("/sdcard/test" + System.currentTimeMillis() + ".png"));
Result:
The problem was solved. When loading image source to ImageView, I used wrong setting for BitmapFactory Options.
The Code ( Before And After ):
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
//options.inPreferredConfig = Config.ARGB_4444; //WRONG
options.inPreferredConfig = Config.ARGB_8888; //CORRECT
bitmap = BitmapFactory.decodeFile(result.filePath(), options);
Thanks you all.
I would try Bitmap.Config.RGB_565 in createBitmap()

How to use high-quality rendering for an Android resource bitmap loaded into an OpenGL texture?

I know very little about OpenGL so please be gentle.
The app needs to load a bitmap (from resources), resize it, and use it in an OpenGL texture. I have an implementation that works, but there was a bad banding issue on the Wildfire S. So I changed the implementation and fixed the banding issue (by switching to ARGB_8888) but that then broke the functionality on the Galaxy Nexus and the Nexus One.
I am seeing three visual presentations:
The bitmap (a smooth 24-bit gradient) shows correctly, with no banding.
The gradient shows, but with obvious banding
The texture shows as flat white, no bitmap (or issues in logcat)
Here are two versions of the method to load the bitmap, and notes on the results seen with each:
// White on Galaxy Nexus. White on Nexus One. Renders correct image (no banding) on Wildfire S
private Bitmap getBitmap1() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.outWidth = getTextureSize();
options.outHeight = getTextureSize();
final Bitmap bmp;
bmp = BitmapFactory.decodeResource(getResources(), bitmapResourceId, options);
return bmp;
}
// Renders correctly (no banding) on Galaxy Nexus. Renders on Nexus One and Wildfire S but with obvious banding.
private Bitmap getBitmap2() {
int textureSize = getTextureSize();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.outWidth = getTextureSize();
options.outHeight = getTextureSize();
final Bitmap bmp;
bmp = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), bitmapResourceId, options), textureSize, textureSize, true);
return bmp;
}
getTextureSize() returns 1024.
How do I build a single method that shows the bitmap without banding on all devices, and without any devices show a big white box?
getBitmap1
outHeight and outWidth are used in conjunction with inJustDecodeBounds. You cannot use them to load a scaled bitmap. So the reason you are seeing a white texture is that the bitmap is not a power of two.
getBitmap2
you should keep a reference to the bitmap returned by decodeResource so that you can recycle it later.
also use options.inScaled = false;to load an unscaled version of the bitmap. Also take note that createScaledBitmap may change the depth of the bitmap to RGB_565 if the original bitmap contains no alpha channel (Source);
Questions:
is the original Bitmap Resource square? If not your scaling code will change the aspect ratio which could result in artifacts.
EDIT:
so how do you scale a bitmap and preserve the bit depths?
Easiest solution is to pass a bitmap with alpha channel into createScaledBitmap.
You can also scale yourself like so:
Bitmap newBitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
final int width = src.getWidth();
final int height = src.getHeight();
final float sx = 1024 / (float)width;
final float sy = 1024 / (float)height;
Matrix m = new Matrix();
m.setScale(sx, sy);
canvas.drawBitmap(src,m,null );
src.recycle();
ANOTHER EDIT:
take a look at this Question for pointers on how to deal with that.
OpenGL.org has this to say about that error:
GL_INVALID_VALUE​, 0x0501: Given when a value parameter is not a leval
value for that function. This is only given for local problems; if the
spec allows the value in certain circumstances, and other parameters
or state dictate those circumstances, then GL_INVALID_OPERATION is the
result instead.
Step one is to find the exact opengl call that is causing the problem. You'll have to do trial and error to see which line is throwing that error. If you set up the program flow like this:
glSomeCallA()
glGetError() //returns 0
glSomeCallB()
glGetError() //returns 0
glSomeCallC()
glGetError() //returns 0x501
Then you'll know that glSomeCallC was the operation that caused the error. If you look at the man page for that particular call, it will enumerate everything that could cause a specific error to occur.
In your case I'll guess that the error will be after glTexImage call just to save you some time, though I'm not positive.
If you look at the glTexImage man page, at the bottom it will list everything that can cause an invalid value error. My guess will be that your texture is larger than the GL_MAX_TEXTURE_SIZE. You can confirm this by checking glGetIntegerv(GL_MAX_TEXTURE_SIZE);
Color Banding Solved ooooooooooyyyyyyyeaaaaaaaaaa
I solved color banding in two phases
1) * when we use the BitmapFactory to decode resources it decodes the resource in RGB565 which shows color banding, instead of using ARGB_8888, so i used BitmapFactory.Options for setting the decode options to ARGB_8888
second problem was whenever i scaled the bitmap it again got banded
2) This was the tough part and took a lot of searching and finally worked
* the method Bitmap.createScaledBitmap for scaling bitmaps also reduced the images to RGB565 format after scaling i got banded images(the old method for solving this was using at least one transparent pixel in a png but no other format like jpg or bmp worked)so here i created a method CreateScaledBitmap to scale the bitmap with the original bitmaps configurations in the resulting scale bitmap(actually i copied the method from a post by logicnet.dk and translated in java)
BitmapFactory.Options myOptions = new BitmapFactory.Options();
myOptions.inDither = true;
myOptions.inScaled = false;
myOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//important
//myOptions.inDither = false;
myOptions.inPurgeable = true;
Bitmap tempImage =
BitmapFactory.decodeResource(getResources(),R.drawable.defaultart, myOptions);//important
//this is important part new scale method created by someone else
tempImage = CreateScaledBitmap(tempImage,300,300,false);
ImageView v = (ImageView)findViewById(R.id.imageView1);
v.setImageBitmap(tempImage);
// the function
public static Bitmap CreateScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
{
Matrix m = new Matrix();
m.setScale(dstWidth / (float)src.getWidth(), dstHeight / (float)src.getHeight());
Bitmap result = Bitmap.createBitmap(dstWidth, dstHeight, src.getConfig());
Canvas canvas = new Canvas(result);
//using (var canvas = new Canvas(result))
{
Paint paint = new Paint();
paint.setFilterBitmap(filter);
canvas.drawBitmap(src, m, paint);
}
return result;
}
Please correct me if i am wrong.
Also comment if it worked for you.
I am so happy i solved it, Hope it works for you.

The way to calculate Bitmap size?

I'm trying to find the size of my image but not to load into memory. I use the flowing code
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeResource(a.getResources(), R.drawable.icon, o);
int width1 = o.outWidt;
int height1 = o.outHeight;
Now, I make some comparison:
Bitmap icon = BitmapFactory.decodeResource(a.getResources(), R.drawable.icon);
int width = icon.getWidth();
int height = icon.getHeight();
Why width, height is not equal to width1 and height1 ?
I'm almost certain this is because referencing that image from resources with decode the image comes pre scaled for density.
Checkout #1 here on the docs: http://developer.android.com/guide/practices/screens_support.html#DensityConsiderations
I'm not sure what is going on, but it may be that BitmapFactory applies density scaling when actually returning a bitmap (as described here), but not when it is just decoding its size. (If this is what's going on, I'd consider filing a bug report.)
You can test this theory by moving your image from the drawables directory to drawables-nodpi.

Categories

Resources