In Android, is there a clean way to display only a given part of a bitmap in an ImageView (for example a single sprite of a sprite sheet), without having to :
Manually split the bitmap png into small pngs (=> more drawables embedded in the app, tedious manual operation possibly leading to bugs, or loose the spritesheet).
Have small pngs used in the ImageViews, with the sprite sheet being generated (=> complicated)
Create "dirty" subclasses for ImageView, Drawable, etc (=> the more we use Android API "ASIS" the better)
Programmatically create sub-bitmaps of the big bitmap (=> We have to do all the work programmatically)
For instance I have tried creating an ImageView of width/height of 40dp, and setting its drawable as a ClipDrawable displaying only the part of the bitmap I wanted, but it did not go well :
the clipped part did not fill the parent when using Gravity.CENTER when creating the ClipDrawable.
The whole "big" PNG was displayed when using Gravity.FILL.
Furthermore this solution is feasable with a simple sprite sheet (for example 2*2 sprites), but I do not think it is possible when using something like a 4*4 sprite sheet. I think ClipDrawable is not meant for such a use.
Isn't there something "clean and easy" like in OpenGL where you can set a texture Id, and set the texture coordinates to display only part of the texture? Considering my researchs I think the best solution is to manually split the big bitmap with Bitmap.createBitmap, when I'd rather ask before starting something like that.
PS : I consider using SpriteSheets because of OpenGl, although my "menus" are developed using Android APIs, hence using ImageView.
Are you familiar with Canvas at all? I think that is another way that would work for you.
You create one bitmap in memory, then use drawBitmap to draw just the current chunk you want.
Here is a snippet from the manual:
public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)
This function ignores the density associated with the bitmap. This is because the source and destination rectangle coordinate spaces are in their respective densities, so must already have the appropriate scaling factor applied.
Parameters
bitmap The bitmap to be drawn
src May be null. The subset of the bitmap to be drawn
dst The rectangle that the bitmap will be scaled/translated to fit into
paint May be null. The paint used to draw the bitmap
Related
I have two images one over other. Uppper image is having some transparent portion, I want to cut that portion and place it in sd card.
Also the below image can be zoomed in/out/scaled.
Can any one help me in this ?
I appreciate if anyone even can provide me some idea.
Create a Bitmap object to draw to that is the same size as the Upper image.
Create a Canvas object and pass this bitmap to its constructor so that you are drawing into the bitmap.
Draw the Lower image on the canvas with a transformation Matrix that represents your zoom/pan etc.
Then iterate over the pixels in the upper bitmap and the one you just drew into and set the alpha value of the pixels in the new bitmap to that in the upper image. Maybe there is another way of applying an alpha mask but I did not see one after a quick skim of the Canvas class interface - maybe looking a bit closer would reveal something.
Alternatively for better performance, use OpenGL and write a shader to do it using your two images. You can render to texture and pull the data back from the render texture. More complicated to do than the other method.
I am working on a project for android devices. I want to split a bitmap image by a line into 2 bitmaps. How do I do this?
If resulting bitmaps are rectangular, i. e. line is either horizontal or vetical - you need to use this method of a canvas:
drawBitmap
You just create new bitmaps and use this methods for partial drawing of original bitmaps on its Canvas.
Otherwise - more tricky, I suppose you will need using masks and color blending using PorterDuff alghorithm (all is available through Canvas API) or just clip with a Path.
I would like to show a zoomable and scrollable map-like SVG in my app. The only way to do this without writing your own library etc. is to use an existing library all of which seem to render the SVG to a Bitmap, which can be assigned to an ImageView, for example.
The underlying bitmap quickly gets very large which may result in an out-of-memory exception. How do I draw only part of a possibly large and/or zoomed SVG to a Bitmap? Scaling up a small bitmap looks bad and is not an option.
I am going to answer this question myself because i have been looking for an answer for a while, found it scattered all over the web (but not here) and think that it may be helpful for others.
Can you not use Google's svg-android library? You can scale the Canvas to the correct size before rendering.
Would this be like how Google maps works? They appear to tile and increase/decrease detail as you zoom in and out.
I have done something similar in the past, not sure if it is how Google did it but my scheme worked exceptionally well for me. What I did was break my map into rectangular regions, I would then calculate which regions had any portion that was visible and pull in data only from those regions. Each rectangular region was sub-divided to provide more detail if the user zoomed in. I kept subdividing down to the level I wanted, I stopped at three, because I used a 10 X 10 grid so each level was effectively a magnification of 10 - at level three I was viewing 100 times the detail I was viewing at level one which was sufficient for my needs.
I was even able to animate this so that when you zoomed in you appeared to smoothly "fly" closer to the terrain.
First of all, I am using libsvg-android which requires the NDK but which seems to be very fast, especially if you have to redraw your SVG frequently. Actually, I am using this modified version of the library which enables you to query the width and height of the SVG as specified in the SVG document.
My first approach was this:
long svgID = SvgRaster.svgAndroidCreate();
SvgRaster.svgAndroidParseBuffer(svgID, svgString);
SvgRaster.svgAndroidSetAntialiasing(svgID, true);
Bitmap bitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.RGB_565);
SvgRaster.svgAndroidRenderToAreaUniform(svgID, new Canvas(bitmap), -300, -200, 1500, 1500);
First, the SVG source is parsed. Then, a Bitmap is created that will be assigned to an ImageView later on. Next, the SVG is rendered (zoomed to 1500x1500 pixels in size) to the bitmap. Note the translation (-300, -200) applied because the user has scrolled the image view.
This does not work. It seems that negative offsets are not supported.
Instead, the canvas has to be translated like this:
Canvas canvas = new Canvas(bitmap);
canvas.translate(-300, -200);
SvgRaster.svgAndroidRenderToAreaUniform(svgID, canvas, 0, 0, 1500, 1500);
This works as expected. The translation of the SVG is applied to the canvas; the scale is applied by adjusting the size of the rendered SVG. In this way, you can have a large SVG document and render the proportion you are interested in to a much smaller bitmap.
I've written an ImageView subclass which is scrollable in both the x and the y directions and zoomable. Its image resource is a low resolution raster image of the SVG. When the user scrolls or zooms the image, this version of the SVG is shown. When the user stops interacting with the image, I render the currently visible part of the SVG to a Bitmap the size of my image view and draw this instead of the low resolution image.
I am creating an Android app and in my app I have a canvas which I draw numerous bitmaps to the canvas via the canvas.drawBitmap () function. From my understanding the z-index on these bitmaps are set based on the order in which they are being drawn to the canvas. What I am trying to figure out is after drawing these bitmaps if I can dynamically change the z-index on a bitmap to push it to the top? This seems like a very simple problem, but I have had not luck in finding a solution yet.
Not really possible: after you call drawBitmap the contents of the bitmap are rendered onto the canvas, but the canvas does not store any references to the original bitmap, it only stores the results of applying the bitmap's contents to the canvas. There is no way to dynamically say that bitmap you drew 1st out of 50, I want you to make that the 50th bitmap and automatically redraw every single other bitmap to reflect the change.
So you'll need to order your drawing operations before hand.
How can you blit a non-rectangular (e.g. oval) part of a bitmap into a canvas on Android?
Consider how you'd blit a rectangular part of a bitmap:
canvas.DrawBitmap(src,src_rect,dest_rect,paint). Sadly there is no corresponding methods for non-rectangular regions.
Four approaches present themselves (maybe you know a fifth?):
copy the rectangular bounds you want to blit into an intermediate bitmap, and go setting the pixels you don't want to blit to be transparent, then draw that bitmap
make a mask bitmap - there are ways to blit with a separate mask?
use a BitmapShader with drawArc()/drawCircle(); however, I can't work out how to get the matrix to be properly aligned; how would you initialize the matrix for this operation?
use a very very complicated clipping region
Of these, option 3 is the one that I would most like to work; however, I cannot work out how to do so; can you?
You can use option number #3, it's probably the easiest. Another way is to draw the shape you want to clip with in an intermediate Bitmap (ARGB8888), then draw your original Bitmap using a DstIn or DstOut xfermode.