I have an app with two views - one on top of another. On the top one I use a Bitmap (ARGB_8888) loaded from a PNG resource and I play with its alpha channel to make some parts of it disappear so the one below becomes visible. All works fine if the source image has at least a single transparent pixel to start with. But if the source PNG has no transparent pixels then changing it alpha to 0 makes the pixel I changed black, not transparent.
Any ideas what could be done to fix it? anything like:
aaptOptions {
cruncherEnabled = false
}
but another option?
Currently I modify the source images before compiling by making a tiny area of it "semi-transparent" but would like to avoid that.
Ok. Finally got it.
I had to add one line. Instead of:
mBitmap = BitmapFactory.decodeResource(getResources(), getResourceID()).copy(Bitmap.Config.ARGB_8888, true);
I am now using:
mBitmap = BitmapFactory.decodeResource(getResources(), getResourceID()).copy(Bitmap.Config.ARGB_8888, true);
mBitmap.setHasAlpha(true);
and there is no need to add a transparent pixel on the source image!
Related
I have an image which is monochrome, meaning only white and black pixels. I have made several versions of the image in order to cover all dpi folders. I am using a monochrome image since I want to apply the floodfill algorithm.
The problem is that in some devices, android uses resized versions of the images and while scaling there are some grey pixels. In order to deal with this I tried correcting the pixels and converting the grey to either white or black, but this takes significant time.
Is it possible to force android to generate monochrome images while resizing the imageview or to apply a quick filter to regenerate the monochrome image?
While I haven't tried it, should I generate different versions of the images in the nodpi folder and use them without scaling, perhaps with center crop?
You can load the Drawable as Bitmap.
final BitmapFactory.Options options = new BitmapFactory.Options();
// Load the bitmap as mutable object
options.inMutable = true;
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.my_image, options);
Then you can manipulate it with your algorithm and finally you will set the result to your ImageView
imageView.setImageBitmap(bitmap);
This way you should not get any grey pixels caused by Android Scaling.
For more options:
See here,
And here.
If I have a view with a transparent background and I do bitmap = view.getDrawingCache();, that bitmap is unfortunately no more transparent. A black background is set in background.
I have even tried
view.setDrawingCacheBackgroundColor(Color.TRANSPARENT);
without success.
Actually this method allows to set the background color without any alpha support, Color.TRANSPARENT which is 0x00000000 is actually black if you don't care about the alpha part...
If I use Color.RED, the background is indeed very red.
Any idea to make this work? Is this a limitation of current Android API? Can I use draw() instead? but it's less performant that this view.getDrawingCache() I suppose (no cache)?
Thanks
I also get image with black background by calling getDrawingCache() method. Actually, the image has transparent background. Mistake is saving the image in jpeg format, so the gallery app shows transparent pixels in black color.
If you put it as an overlay, it'll work perfectly. There is no issue here.
Draw caching is somewhat of a relic of pre-HW-accelerated Android, so some stuff might be a bit confusing/not as well documented.
Transparency should work just fine as long as you leave out View#setDrawingCacheBackgroundColor(int) as this might cause the cache to drop down to 16 bit color space (see View#mDrawingCacheBackgroundColor).
This code
view.setDrawingCacheEnabled(true);
// wait for first layout
...
Bitmap b = view.getDrawingCache();
should give you an ARGB_8888 bitmap with transparent background. (You can also this in the Android Studio debugger by settings a breakpoint after the get call and 'View Bitmap' on the variable.
Try this code after setting the layout background color transparent in XML file
layout.setDrawingCacheEnabled(true);
Bitmap bmp = layout.getDrawingCache();
File mFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "smiley1.png");
FileOutputStream outStream;
outStream = new FileOutputStream(mFile);
bmp.compress(Bitmap.CompressFormat.PNG, 100, outStream);
I'm trying to dynamically create images in android by taking an existing Bitmap and removing the centre of it in order to make a "cropped" version. The resulting image's height would naturally be smaller than the original, something like the attached example.
I've got a rough way of doing this by creating two new Bitmaps from the original, one containing the top of the image above the crop section (e.g. the android's head in the example) and the other containing the remaining image below the crop section (the android's feet) using the Bitmap.createBitmap(source, x, y, width, height) method, then drawing both of these bitmaps onto a canvas of a size equal to the original image minus the removed space.
This feels a bit clunky, and as I could be calling this method several times a second, it seems wasteful to create two bitmaps each time.
I was wondering if there was a more efficient way of doing this. Something like drawing the original Bitmap onto a canvas using a Path with it's Paint's xfermode set to a
new PorterDuffXfermode(Mode.DST_OUT) in order to cut out the portion of the image I wish to delete. But this seems to clear that area and not shrink the image down i.e. it leaves a big empty gap in the Android's middle.
Any suggestions greatly appreciated!
Why do you create two bitmaps? You only need to create one bitmap and then do canvas.drawBitmap() twice.
Bitmap bmpOriginal;
Bitmap bmpDerived = Bitmap.create(...);
Canvas canvas = new Canvas(bmpDerived);
canvas.drawBitmap(bmpOriginal, rectTopSrc, rectTopDst, null);
canvas.drawBitmap(bmpOriginal, rectBottomSrc, rectBottomDst, null);
Done.
I have the below image (the white bubble in the image) to draw in a canvas. When I draw the image using the code.., the image 's edge is getting black circle and rounded .. the edge's alpha is 0x00.
image.setBounds(left, top, right, bottom);
image.draw(canvas);
Expected When I draw
How could I remove the black circle??? Is the image wrong?? or Anyone know the clue, Please give me a clue.. Thanks in advance..
^^
Is your expected output taken from an image editor (Photoshop?) If so, that'll be the result of a 32-bit blend, whereas it looks like the alpha-blend on Android is being performed in 16-bits, hence the banding in the background, and halo around your image.
Presuming you're using Bitmap objects, you can check whether this is the case by calling bitmap.getConfig() to find their colour depth (from the Bitmap.Config enum).
Edit: One more thing that may be causing the halo - you say the edges of your sprite have an alpha of 0, but what about the RGB values? Make sure the ARGB is set to full-white (ARGB 0x00ffffff) rather than black (ARGB 0x00000000).
Say I have a somewhat large (i.e. not fit in most phones' memory) bitmap on disk. I want to draw only parts of it on the screen in a way that isn't scaled (i.e. inSampleSize == 1)
Is there a way to load/draw just the part I want given a Rect specifying the area without loading the entire bitmap content?
I'm quite confident this is possible since you can load a really large bitmap file into an ImageView without problems so there must be some sort of a built-in way to handle large bitmaps... and after a few attempts, I've found a solution:
Instead of loading the entire bitmap and manually draw it yourself, load it as a Drawable instead:
InputStream mapInput = getResources().openRawResource(
R.drawable.transit_map);
_map = Drawable.createFromStream(mapInput, "transit_map");
_map.setBounds(0, 0, _mapDimension.width(), _mapDimension.height());
I'm using a resource file but since you can use Drawable.createFromStream to load image from any InputStream, it should works with arbitrary bitmap.
Then, use the Drawable.draw method to draw it onto the desired canvas like so:
int left = -(int) contentOffset.x;
int top = -(int) contentOffset.y;
int right = (int) (zoom * _mapDimension.width() - contentOffset.x);
int bottom = (int) (zoom * _mapDimension.height() - contentOffset.y);
_map.setBounds(left, top, right, bottom);
_map.draw(canvas);
As in the above case, You can also scale and translate the bitmap as well by manipulating the drawable's bounds and only the relevant parts of the bitmap will be loaded and drawn onto the Canvas.
The result is a pinch-zoomable view from just one single 200KB bitmap file. I've also tested this with a 22MB PNG file and it still works without any OutOfMemoryError including when screen orientation changes.
Now it's very relevant: BitmapRegionDecoder.
Note: available since Android SDK 10
It can easily be done by using RapidDecoder.
import rapid.decoder.BitmapDecoder;
Rect bounds = new Rect(10, 20, 30, 40);
Bitmap bitmap = BitmapDecoder.from("your-file.png")
.region(bounds)
.decode();
imageView.setImageBitmap(bitmap);
It supports down to Android 2.2 (API Level 8).
Generally speaking, that isn't possible, particularly since most image formats are compressed, so you don't even know which bytes to read until you've extracted the uncompressed form.
Break your image up into small tiles and load just the tiles you need to cover the region you want to display at runtime. To avoid jittery scrolling, you might also want to preload tiles that are just out of sight (the ones that border the visible tiles) on a background thread.