My App have a feature that let's the user capture photo and add drawing on that photo.
All the photo's are re-sized to exactly 900 x 900.
To allow the user add drawing to the image. I keep a transparent image over the original image and do the drawing on the transparent image. Drawing is done using canvas.
But when drawing in a device that has 720 x 480 (height x width). If i create a 900 x 900 transparent image and draw a line from 0,0 to 900,900, canvas only draws line from 0,0 to 480,480.
Below is the respective portion of the code:
Preparing Canvas:
holder = getHolder();
if (holder.getSurface().isValid()) {
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
/* original image is 900 x 900 */
overlayBitmap = Bitmap.createBitmap(originalImage.getWidth(), originalImage.getHeight(), originalImage.getConfig());
canvas.setBitmap(overlayBitmap);
}
Drawing Line:
canvas.drawLine(0, 0, 900, 900, paint);
I have no idea why i am having this issue. It is because of using canvas?? Is there any work around? Any help is highly appreciated :-)
After some more reading about canvas and also help from this post i was able to fix the issue.
The issue was in the canvas clip rectangle. It was (0,0,480,480) by default as device display was 720 x 480 i guess? So whatever was on the bitmap was always clipped down to 480 x 480.
Later i modified my code like this:
holder = getHolder();
if (holder.getSurface().isValid()) {
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
/* original image is 900 x 900 */
overlayBitmap = Bitmap.createBitmap(originalImage.getWidth(), originalImage.getHeight(), originalImage.getConfig());
canvas.setBitmap(overlayBitmap);
/* set extended clip rectangle for the larger target bitmap */
Rect clipRect = canvas.getClipBounds();
clipRect.set(0, 0, image.getWidth(), image.getHeight());
canvas.clipRect(clipRect, Region.Op.REPLACE);
}
After replacing clip rectangle size with image size everything worked just fine.
Just because a photo is 900x900, that doesn't mean that it's exactly those many pixels when displayed on the device screen. Device screens can have very different sizes, and when an image (or any view for that matter) is told to expand its with to fit the screen, or measured in dp (device independent pixels), the actual number of device pixels will vary depending on the device screen.
Your code needs to be sensitive to these differences. When you do your drawing, don't assume the size of the Canvas of a view. Instead, ask the view how big it is, and perform all the drawing based on the actual measured size.
Related
I have an Image View which displays an image (e.g 2000x1000 pixels) and I have a coordinate (X,Y) on that image (not the image view). The canvas of my Image View is 600x800 for example. How can I convert the point (X,Y) to screen coordinate so that I can draw a path with them on the OnDraw(...) method of Image View. Any help is appreciated! Thank you.
Update: If I use matrix to draw the path between coordinates, it works but the path and objects i draw become really small. Here is the code i used.
final Matrix matrix = canvas.getMatrix();
matrix.preConcat( _view.getImageMatrix() );
matrix.preScale( 1.0f /_inSampleSize, 1.0f / _inSampleSize);
canvas.setMatrix( matrix );
//I draw the path here
Update: I add a picture to show the effect when using matrix to draw the path. I would like to have the 4 line and the 4 corner balls to be in normal size. The red color is the boundary of the Image View which holds the picture.
I think that might depend on how exactly you are displaying your image. Your ImageView (600x800) is not the same aspect ratio as your bitmap (2000x1000).
You are keeping the bitmap's aspect ratio stable as you scale it down? If so, which part (height or width) takes up the full screen and which has black (or whatever else) as padding? This will help you determine your scale factor.
scale_factor = goal_height/height1; //if height is what you are scaling by
scale_factor = goal_width/width1; //if width is what you are scaling by.
I would try:
x_goal = x1 * scale_factor;
y_goal = y1 * scale_factor;
That is, if you have a point (1333, 900) in your image, and your image takes up the full width, you would multiply both x and y by 600/2000 to get (399.9, 270). (you might want to round that decimal).
If you are NOT keeping the bitmaps aspect ratio stable (that is, you're squeezing it to fit), then you'd have a height_scale_factor and a width_scale factor. So you'd take (1333,900) and multiply x by 600/2000 and y by 800/1000 to get (399.9,720).
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()
I'm making a game that is Pixel-based in Android. I have several 8x8 sprites that need to be resized to fit on a 100x100 area. As a test to see if it would work, I tried to just make the image fill the entire canvas. It kind of worked, but it made the 8x8 sprite turn into a 12x12 sprite, making the pixels look really odd and distorted. Here's what I have so far:
Bitmap grass = BitmapFactory.decodeResource(getResources(), R.drawable.small);
Paint configuration = new Paint();
configuration.setDither(false);
configuration.setAntiAlias(false);
Matrix myMatrix = new Matrix();
myMatrix.postScale(canvas.getWidth() / grass.getWidth(), canvas.getWidth() / grass.getHeight());
Bitmap resizedBitmap = Bitmap.createBitmap(grass, 0, 0, grass.getWidth(), grass.getHeight(), myMatrix, false);
canvas.drawBitmap(resizedBitmap, 0, 0, null);
If you work on bitmaps then you simply can't. You'd minimize the distortion by scaling up by non-fractional factor so each pixed would be repeated same number of times (i.e. image 10x10 to 20x20 is scaled by factor of two, but 8x8 to 12x12 is 1,5 so no luck). The solution would be to have all assets in vector form (i.e. SVG) and then render them on run-time according to device density and other specs or prepare separate assets for various type of devices (which would blow application size up a bit)
I am trying to make an app using canvas and a surfaceview, and I am worrying that in the future I would have many problems with it because I am not sure if the canvas is proportional with every device. currently I can only use my emulator since my phone's usb cable doesn't work(I know.. I have to get a new one..).
anyways, i would like to know if the canvas would transfer my coordinates and make everything proportional, what I mean by that is that if i have something in point a, lets say (10, 10) on a device that the screen of it is 100 X 100 (this is just an example for easy calculation) it would be on point (1, 1) on a 10 X 10 device.
This is really bothering me...
Thanks!
No, this wouldn't be the case. If you have a coordinate (10,10), it would be the same on all devices. I'd suggest you scale your drawings.
To scale your drawings you simply define a bitmap (that will stay the same) you'd like to draw to (when screen sizes change, that bitmap will be stretched).
Define a constant bitmap:
Bitmap gameScreen = Bitmap.createBitmap(getGameScreenWidth(),
getGameScreenHeight(), Config.RGB_565);
Get the scale for both x and y
width = game.getWindowManager().getDefaultDisplay().getWidth();
height = game.getWindowManager().getDefaultDisplay().getHeight();
scaleXFromVirtualToReal = (float) width/this.gameScreenWidth;
scaleYFromVirtualToreal = (float) height/this.gameScreenHeight;
Define a canvas object based on the bitmap you defined earlier on (allowing you to draw to it eg. canvas.drawRect() [...]):
Canvas canvasGameScreen = new Canvas(gameScreen);
In your rendering Thread you'll have to have a Canvas called frameBuffer, which will render the virtual framebuffer:
frameBuffer.drawBitmap(this.gameScreen, null, new Rect(0, 0, width,
height), null);
No, the unit on the screen (whether you are using canvas or OpenGL) is a pixel. You can get the size of your canvas using Canvas.getWidth() and Canvas.getHeight() if you need relative coordinates, but your Canvas drawing methods are also in Pixels, so I guess you will need to convert coordinates in OpenGL only and not while using Canvas.
I have a View-derived class where I draw a 790x500 (yes, this is odd but it has to stay this way) bitmap directly on the canvas in onDraw. This looks ok on my Nexus S, but when I run my app on a device with a smaller screen (e.g. Wildfire) I only see the upper left part of the bitmap. What am I missing here?
This is a game-like app where I draw a number of bitmaps on certain coordinates. I really don't want to have different pixel setups for LDPI, MDPI and HDPI (I have a good reason for this).
Q: How can I properly scale my bitmaps for any screen resolution? (Centering the game screen for large screens may be an option, but is not a must.) E.g. when I draw a 800x600 image on a 320x240 screen, the image is automatically stretched and when I output a pixel at 100x100, it becomes 40x40.
There are many forms of the drawbitmap() method. Choose the one that allows you to specify the source and destination rectangle. The source rectangle will be the size of your bitmap and the destination rectangle will be scaled to fit on the device display. Android will scale your bitmap when it draws it.
Rect rs = new Rect();
Rect rd = new Rect();
rs.left = rs.top = 0;
rs.right = 789;
rs.bottom = 499;
<calculate destination rectangle from device size>
canvas.drawBitmap(myBitmap, rs, rd, null);
You can also scale and translate (shift) the entire canvas
canvas.scale(float scaleX, float scaleY);
canvas.translate(float dx, float dy);
Canvas.scale() does the trick.