I'm writing my first app of any consequence, so I may be going about this the entire wrong way, but...
I have a resource image that is 1600x880. I'd like to fill the entire screen with a subset of that image to my canvas, such that an arbitrary x,y coordinate marks the top-left corner drawn at the top-left corner of the screen. For instance, if I was viewing this image on an N1 and I entered x=100 and y=50, I'd expect to see from 100,50 to 580,850 since it's display area is 480x800.
I think I need to use Canvas.drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint). But, no matter what I plug in to either Rect (even if it's a perfectly sane set of values that shouldn't butt up against any edges of the image), I end up with an unexpected area or a grossly stretched/smooshed output.
I've tried using various combinations of calculations involving display.getWidth() and getHeight(), canvas.getWidth() and getHeight(), and bitmap.getWidth() and getHeight() but nothing seems to be working.
I don't know what I'm doing wrong.
Related
Suppose, we've got a display sized 100x100, an image 100x50, and I want to enlarge that image so that it has the same height as the screen does. So the image will be 200x100. After that I want to make the animation of image movement to the left and to the right. I've found 2 ways of the realization of my task:
To create a new image using Bitmap.createScaledBitmap(). But the
image created this way will occupy twice more RAM.
To use matrix.setScale() in every onDraw(). But this works very
slow. Is there any other better solution?
The second method is slow because you calculate your "matrix" on every frame! Since your matrix is always the same thing and it does not change, you can pre-calculate your matrix and save it as a "field" in you class, then just use this function to draw it on screen:
canvas.drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)
It should be fast enough. The other option is to use:
canvas.drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)
Again, try to pre-calculate stuff as much as possible. In this case, pre-calc src and dst rectangles.
I've created a simple custom control in android and on it I place a background image. I'm having problems when the control is placed on a layout at different sizes (i.e. when it is stretched), specifically:
I wish to overlay a rectangle at a specific position and size, which I know the pixel position for the original image. How can I do this with my control. I suspect something like this is impossible given it's a 9-patch. Is my best bet to work out the percentage from the top/left on the original or is that pointless given some parts stretch and some don't?
In the custom control I set the image like this in the constructor:
setBackgroundResource(R.drawable.buttonbt);
Which is working just fine, however I wanted to originally draw it in the onDraw event as I might want to change it depending on property changes, e.g.
Bitmap b=BitmapFactory.decodeResource(getResources(), R.drawable.buttonbt);
canvas.drawBitmap(b, 0, 0, null);
But this does not resize according to the size of its bounding box, it is simply trying to show it at it's original size without scaling to fit. How would you do this (whether the former method is better or not).
thanks.
You can create a scaled bitmap as below
Bitmap bitmap = Bitmap.createScaledBitmap(b, width, height, true);
Hope it will work for you. Please let me know!
ok when your View is say 100x100 px and your Bitmap is 300x300 you can try the following (pseudo code here) in inDraw method:
# src is a Bitmap 300x300
# dst is a View 100x100
mMatrix.setRectToRect(RectF src, RectF dst, Matrix.ScaleToFit stf)
canvas.save()
canvas.concat(mMatrix)
canvas.drawBitmap(mBitmap, 0, 0, null)
// actually it will draw a rect with left/top edge at (10, 10) and right/bottom at (20, 20)
canvas.drawRect(30, 30, 60, 60, paint)
canvas.restore()
Is the Android documentation for canvas.drawBitmap wrong? It says:
public void drawBitmap (Bitmap bitmap, float left, float top, Paint paint)
Draw the specified bitmap, with its top/left corner at (x,y), using the specified paint, transformed by the current matrix.
Well, x and y don’t seem to be floats, they’re ints; is that correct?
Say I want to overlay the bitmap (which is the size of the available screen, and is bound to a canvas of the same) over the whole available screen. It seems sensible I would:
canvas.drawBitmap(myBitmap, 0, 0, mPaint);
doesn’t it?
But that doesn’t work. What does seem to work is:
canvas.drawBitmap(myBitmap, 2000000, 1000000, mPaint).
Now that statement seems to me to tell the bitmap that it should draw itself a huge distance
Outside the screen! What am I missing here?
In this method x and y are floats, not ints. But like mentioned in the documentation, the x and y coordinates of the bitmaps will be affected by the matrix currently set on the Canvas. In the case of a ScrollView for instance, the matrix could very well contain a very large translation.
What this means is that the coordinates 0, 0 will draw the bitmap at the current origin of the Canvas. That origin is defined by the matrix you can query with getMatrix().
I have a problem that I can not really solve. I have created a graphing app which will contain data with alot of data points. To enable scrolling in the graph i create a bitmap of the graph data, and the shift / move the bitmap to the right or left of the screen depending on the user input. The bitmap is always the graph view height and graph view width. When the user moves the bitmap, i shift the bitmap with:
memoryCanvas.drawBitmap(memoryBitmap, bitmapShift, 0.0f, paint);
where shift is a a float value containing the shifting values.
Now, on most devices i have tried this is, it works very nice. I have tried it on HTC Desire, Galaxy Tab and Galaxy S. When testing this on my own Galaxy S however, i get strange results that i can not explain. Do note that my Galaxy S contains a custom rom (with android 4.0.4), so that is probably the reason why i get this behavior, but i still can not understand it or properly mitigate it.
So in a normal use case behavior, the bitmaps get shifted by bitmapShift number of pixels, and then i fill in the empty space by normal line drawing. But when using my phone, dragging the bitmap either direction slowly, so the bitmapShift values are around 0.5, the bitmap does not move, or only moves sometimes. I have compared the bitmapShift on the other platforms and they are in the same range, 0.5 when dragging slowly. This behavior does of course screw up my drawings a lot. This does also happen when doing fast dragging, but its most visible when doing it slowly.
I can not really figure out what causes this behavior. The bitmap does not move according to my bitmapShift value. It does on all other platforms i have tried. If i skip using bitmaps, and only draw lines according to the shifting values, everything works fine.
Does anyone have any idea on what could cause this behavior? Im kinda running out after sitting some days trying to figure it out. The critical code is below. This code is in my onDraw function.
memoryCanvas.setBitmap(emptyBitmap); //First set another bitmap to clear
memoryCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //Clear it
memoryCanvas.drawBitmap(memoryBitmap, bitmapShift, 0.0f, paint); //Draw shifted bitmap on it
memoryCanvas.drawLines(lineDrawPoints, 0 , cnt, paint); //Draw remaining lines
memoryCanvas.setBitmap(memoryBitmap); //Set the original
memoryCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //Clear original
memoryCanvas.drawBitmap(emptyBitmap, 0.0f, 0.0f, paint); //Draw the final image
canvas.drawBitmap(memoryBitmap, 0, 0.0f, paint); //And finally draw on real canvas
Any help, tips, suggestions are very welcome.
Cheers
Wilhelm
When there is only a simple transform set on Canvas (a simple transform = translate only, no rotate, no scale), Skia, Android's 2D rendering library, aligns bitmaps to the pixel grid. This means that a move by less than 1 pixel might not be visible at all. A silly workaround is to set a very, very small scale or rotate transform on Canvas before drawing your bitmap. This has the side effect of not snapping bitmaps to the pixel grid.
I think I should just add a new API on Paint to let apps do subpixel positioning of bitmaps no matter what transform is set.
I have a canvas-based drawing app that when zoomed in, I draw a miniature of the overall drawing in one corner as a scaled Bitmap. I also have a small RectF that I draw over top of the miniature, which shows you where you are in the drawing. See first attached image.
What I would like to do is to draw the scaled bitmap, then draw a RectF of the same size over top of it, with an alpha value that allows you to see the miniature, and then finally, punch a hole in the RectF that shows you where you are and allows you a clearer view of the miniature. See second attached image.
I've considered using a bitmap for the RectF with the hole already 'built-in', but as the hole will both be moving depending on location, and will change in size depending on scale factor, I need to do it dynamically.
I've looked over the RectF docs but don't see anything that would allow me to clip the RectF with a smaller RectF that would make the 'hole'. Any ideas?
You could use a Path with filling option.
moveTo 0,0 and frame the whole minipic, then moveTo the first corner inside and frame/create the hole. Not sure if it works but you can also add shapes to the path.