why getBounds( ) of Drawable remains the same even after scaling? - android

I used an ImageView to display a jpg file under my project 'assets' folder, the intrinsic dimensions are: 1280x854, which I confirmed by calling myDrawable.getIntrinsicWidth() and myDrawable.getIntrinsicHeight().
My image view implemented pinch zoom so the image was scaled up to 2x for example. Then the following code got executed:
Drawable drawable = getDrawable();
Rect bounds =drawable.getBounds();
Log.i("activity", String.format("drawalbe : top:%d, left: %d, (%d, %d)", bounds.top, bounds.left, bounds.width(), bounds.height()));
the drawable bounds is always 1280x854 no matter what the current scale is, and the top, left is always 0, 0.
Isn't the bounds should be scaled accordingly? Could anyone give me some hints? Thank you.

It's because of this.
Scale matrix only affects how the view is drawn, but does not change its dimensions.
Although you can create a Rect of the size of your image and apply the same scale matrix to Rect with Matrix.mapRect(Rect r) and Rect will have the scaled dimensions.

Related

Android - Set Drawable to Canvas but keep Aspect Ratio

I'm having a small issue with my android code . This is the first time i'm using canvas and i want to set an image to it but keep some type of aspect ratio.
This is what i'm doing right now and this maps the image onto the canvas completely . It sets the image width-height to canvas width-height.
Drawable drawable = image; // gets the image
drawable.SetBounds(0, 0, canvasWidth, canvasHeight);
drawable.Draw(canvas);
This works well on certain devices but when the device is large , the stretching is really bad . I want to set the bounds in such a way that it keeps an aspect ratio . If the canvas width-height is not the same aspect ratio , it will try to fill the canvas with an aspect ratio but might leave some space off in x or y axis .
int imgWidth = 500;
int imgHeight = 800;
I want to map the image on the canvas based on these values and stretch as necessary but keeping this aspect ratio even if part of the canvas is not filled .
What is the best way to do this ?
Thanks
I've already answered a similar question here.
To preserve the aspect ratio I did this:
val drawable = resources.getDrawable(R.drawable.my_vector, null)
val aspectRatio = drawable.intrinsicWidth.toFloat() / drawable.intrinsicHeight
val desiredWidthInPx = 100 // could be your view size or canvas size
val derivedHeightInPx = (desiredWidthInPx / aspectRatio).toInt()
drawable.setBounds(0, 0, desiredWidthInPx, derivedHeightInPx)
drawable.draw(canvas)
The above is for when the drawable width is smaller than its height.
If the drawable height is larger than its width, then first set the height to your desired size and then calculate the width.
Provide correct images in each resource folder. Correct images means correct resolution and screen density. Refer to this link http://developer.android.com/guide/topics/resources/providing-resources.html

How to convert coordinates on Bitmap to real coordiates on Image View displayed on screen

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).

Having some problems with scaling in Android custom view

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()

Scaling Canvas to resize SVG in Android

I'm not having much luck wrapping my head around this, so I'm hoping someone can help me out.
I'm getting a drawable from an SVG using svg-android, but the drawable isn't scaling to the view. Everything that I've been able to find says I should draw directly to canvas and rescale the canvas, but when I try that it only seems to change the bounds but not scale the image.
This is what I've tried so far:
ImageView testview = (ImageView)findViewById(R.id.testview);
//Get SVG and convert to drawable
SVG vector = SVGParser.getSVGFromResource(getResources(),R.drawable.testvector);
Drawable test = vector.createPictureDrawable();
testview.setBackground(test); //displays fine, but won't scale to the dimensions of
//the View
//function that clips the image but doesn't scale:
Drawable testTwo = new CustomPictureDrawable(vector.getPicture(),
(float)0.5, (float)0.5);
testView.setBackground(testTwo);
class CustomPictureDrawable extends PictureDrawable {
private float scalex, scaley;
public CustomPictureDrawable(Picture picture, float scalex, float scaley) {
super(picture);
this.scalex = scalex;
this.scaley = scaley;
}
#Override
public void draw(Canvas canvas) {
Matrix original = canvas.getMatrix();
canvas.scale(scalex, scaley);
super.draw(canvas);
canvas.setMatrix(original);
}
}
//doesn't display anything
Picture testThree = vector.getPicture();
Bitmap b = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_4444);
Canvas c = new Canvas(b);
c.drawPicture(testThree, new Rect(0,0,10,10));
testview.draw(c);
I've also found a function that will create a scaled bitmap, but the image quality is significantly reduced, so I may as well just use scaled PNGs.
Obviously I'm missing something, and my lack of experience is making it really frustrating.
What I'd like to be able to do is have svg-android completely re-scale the SVG before pulling a Picture or PictureDrawable out of it, but I can't figure out how to step through the SVGParser, and running multipliers on every coordinate pair would probably be super resource intensive anyway.
[edit] Is the only way to scale and re-draw the Picture and assign that to a view to create custom Views and override OnDraw?
i.e.
Picture testThree = vector.getPicture();
Bitmap b = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_4444);
Canvas c = new Canvas(b);
c.drawPicture(testThree, new Rect(0,0,10,10));
//CustomView extends ImageView or Button or whatever with OnDraw overridden and no
//other changes
CustomView testview = (CustomView)findViewById(R.id.testview);
testview.OnDraw(c);
Am I on the right track? Canvas c would overwrite the default canvas (which is what I want), wouldn't it?
I figured it out. Or at least figured out a method that works. The answer was staring me in the face in that scaled bitmap function that I didn't like. I fundamentally misunderstood how the Picture class and Draw calls work.
Code that seems to have pulled it off:
//Get a Picture from the SVG
SVG vector = SVGParser.getSVGfromResource(getResources(), R.raw.testvector);
Picture test = vector.getPicture();
//Redraw the picture to a new size
Bitmap bitmap = Bitmap.createBitmap(desired width, desired height, config);
Canvas canvas = new Canvas(bitmap);
Picture resizePicture = new Picture();
canvas = resizePicture.beginRecording(desiredWidth, desiredGeight);
canvas.drawPicture(test, new Rect(0,0,desiredWidth, desiredHeight);
resizePicture.endRecording();
//get a drawable from resizePicture
Drawable vectorDrawing = new PictureDrawable(resizePicture);
I can size it to whatever View I want by getting desiredWidth and desiredHeight from getWidth() and getHeight() calls, and setBackground(vectorDrawing) at the end to put it on the View.
I had a similar problem and this is what I learned and how I solved it.
First I tried to render my svg directly into a canvas
svg.renderToCanvas(canv);
which didn't have the size I wanted. Then I tried to resize the image using
svg.renderToCanvas(canv,new RectF(0,0,200,200));
and
svg.setDocumentWidth(200);
svg.renderToCanvas(canv);
but both didn't work, so I started to look at my SVG. The problem was that my SVG started like this
<svg width="66.3679625" height="100.4148375" xmlns="http://www.w3.org/2000/svg">
and it seems impossible, once width and height are set in the svg, to change this in code afterwards. There is also an answer in the AndroidSvgFAQ where they recommend to remove those attributes. So I changed this to
<svg version="1.1" viewBox="0 0 1280 696" xmlns="http://www.w3.org/2000/svg">
The viewBox attribute is the frame of my SVG picture, so if now I use the code above
svg.setDocumentWidth(200);
svg.renderToCanvas(canv);
I get the content of the box with upper left angle at (0,0) and lower right angle at (1200,696) resized such that the width is 200. You can change the behaviour for the ratio initialy it keeps ratios. Note that one can omit width, heigth and ViewBox in SVG and set the ViewBox programmatically
svg.setDocumentViewBox(0,0,width,height);
To get to know more about the ViewBox attribute see W3ViewBox.

Is there a way to find the on-screen coordinates of an ImageView's drawable?

I have an activity which consists of just an ImageView. The drawable contained in the ImageView is a Bitmap that was captured from the camera. The image is automatically scaled (maintaining the Bitmap's aspect ratio) so that the scaled width matches the width of the ImageView, and the image is centered on the screen vertically.
I need to figure out the coordinates of the top-left pixel of the actual drawable (not of the ImageView itself), but the ImageView class doesn't seem to give me a way of doing that.
I feel like I could potentially calculate it based on the dimensions of the original bitmap and the dimensions of the ImageView, but that would involve a lot of math that should be unnecessary, and would be prone to floating point errors.
Does anyone know of a way to find the coordinates of the top-left pixel of the Drawable relative to the ImageView?
Thanks.
Looking at the ImageView source code, it translates a Matrix halfway the vertical size (i.e., center it vertically), so you could retrieve it with the ImageView getImageMatrix() method and check the vertical translation by Matrix#getValues(float[]). If I read it right, it will be the sixth value.
I can't test it right now, but it would be something like:
Matrix matrix = iv.getImageMatrix ();
float[] values = new float[];
matrix.getValues(values);
float startY = values[5];

Categories

Resources