Cropp Image to fit ImageView based on X axis - android

As you can see in image, we have two type of ImageView, one type Horizontal and another Vertical. We want to load image to them in the way that bitmap fill the ImageView, images can be smaller ( like image #1 ) or bigger and taller ( like image #2 ).
Our goal is something like shown in image, we want to scale images on their X-Axis and crop overfllow of drawable in Y-Axis
We tried almost all scale-type, but results does not satisfy us, unfortunately

If you want to make width of drawable match with ImageView's width you can use Matrix:
public Matrix scaleWidthMatrix(int imageWidth, int viewWidth) {
Matrix scaleMatrix = new Matrix();
float scale = (float) viewWidth / imageWidth;
scaleMatrix.setScale(scale, scale);
return scaleMatrix;
}
This method returns a scale Matrix to scale image so that its width matches with ImageView and it does not consider height factor, Therefore parts of scaled drawable that is out of ImageView's boundary (in this case lower part of drawable) will be cropped.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView iv = (ImageView) findViewById(R.id.iv);
iv.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
int imageWidth = iv.getDrawable().getIntrinsicWidth();
Matrix matrix = scaleWidthMatrix(imageWidth, iv.getWidth());
//we should setScaleType to Matrix in order to use image matrix
iv.setScaleType(ImageView.ScaleType.MATRIX);
iv.setImageMatrix(matrix);
//No need to call again so remove it
iv.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
});
PS:
OnPreDrawListener gets called just before onDraw method gets invoked. At this point, all views in the tree have been measured so you can pass valid arguments to scaleWidthMatrix method.

Related

Resizing an image to fit on a imageview

I am developing an application in which I need to fit an Bitmap into Imageview with specific dimensions(let's suppose 350dpx50dp - height*width).
I wanted to do something similar like this: http://gyazo.com/d739d03684e46411feb58d66acea1002
I have looked here for solutions. I found this code for scale the bitmap and fit it into imageview, but the problem is that imageview becomes greater when I add the bitmap into him:
private void scaleImage(Bitmap bitmap, ImageView view)
{
// Get current dimensions AND the desired bounding box
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int bounding = dpToPx(350);
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) bounding) / width;
float yScale = ((float) bounding) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
// Create a matrix for the scaling and add the scaling data
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// Create a new bitmap and convert it to a format understood by the ImageView
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
// Apply the scaled bitmap
view.setImageBitmap(scaledBitmap);
}
Using this code I can get this : http://gyazo.com/e9871db2130ac33668156fc0cf773594
But that's not what I wanted, I want to keep the dimensions of imageview and add the bitmap into imageview without modifying the dimensions of imageview and occupying all the imageview's surface. Like the first image.
Why don't you just add android:scaleType="fitXY" to your ImageView in xml?

Get image dimensions after it draws in screen

I have an ImageView with MathParent height and width
In my activity it loads a pic from resource to ImageView. How can i get width and height of the picture inside the ImageView AFTER it has been scaled.
I have not set the android:scaleType in XML
these dimensions i mean!
You can do a lot with the matrix the view uses to display the image.
Here I calculate the scale the image is drawn at:
private float scaleOfImageView(ImageView image) {
float[] coords = new float[]{0, 0, 1, 1};
Matrix matrix = image.getImageMatrix();
matrix.mapPoints(coords);
return coords[2] - coords[0]; //xscale, method assumes maintaining aspect ratio
}
Applying the scale to the image dimensions gives the displayed image size:
private void logImageDisplaySize(ImageView image) {
Drawable drawable = image.getDrawable();
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
float scale = scaleOfImageView(image);
float displayedWidth = scale * width;
float displayedHeight = scale * height;
Log.d(TAG, String.format("Image drawn at scale: %.2f => %.2f x %.2f",
scale, displayedWidth, displayedHeight));
}
I suspect you don't really care about the image size, I suspect you want to map touch points back to a coordinate on the image, this answer shows how to do this (also using the image matrix): https://stackoverflow.com/a/9945896/360211

how to scale a image to imageview in onCreate when i need to use scaleType matrix

I'm trying to create a ImageView with zoom functions.
I got the zoom function ready, but now I want the image to scale to the ImageView
when starting the Activity. Normally I would use the ScaleType in the xml layout,
but it needs to be Matrix for the zoom function. How can I do this?
I tried the solution from this question: Android image view matrix scale + translate
Matrix m = imageView.getImageMatrix();
RectF drawableRect = new RectF(0, 0, imageWidth, imageHeight);
RectF viewRect = new RectF(0, 0, imageView.getWidth(), imageView.getHeight());
m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER);
imageView.setImageMatrix(m);
But the problem is I can't use getWidth() and getHeight() because its to early (it only returns 0). Is there a work around? Or how can I fix this?
You need to a add an observer to the ImageView, that will be called when the object is layouted:
imageView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int width = imageView.getWidth();
int height = imageView.getHeight();
// do your stuff
}
});
I had the same problem with matrix, zoom and imageview and the easiest solution I found is to render the image twice, one with scaleType fitcenter and Matrix.
After many (really many..) tempts with setRectToRect and the solution mentioned before (and so on..), I finally find a solution (at least for my case, similar to the post):
In the imageview in your activity xml set fitcenter:
<ImageView
...
android:scaleType="fitCenter"
Then in your java file define a init function on focus changed
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
init();
}
}
private void init() {
maxZoom = 10;
minZoom = 1f;
height = viewHeight;
width = viewWidth;
**Matrix m = imageSWT.getImageMatrix();
imageSWT.setScaleType(ScaleType.MATRIX);
matrix.set(m);**
}
So I'm using the property of fitcenter and then I get his matrix, after that I switch to Matrix mode (for the zoom functionality) and I save the fitcentered-matrix into the matrix-zoom object for keeping the changes when the zoom is used.
I hope this solution could help someone ;)
The only way to be sure of a views width and height is to subclass the view and override onSizeChanged() and use the given width/height or onLayout() and used getMeasuredHeight() and getMeasuredWidth().
This means you're matrix won't be setup until way after onCreate() (until the view is about to be rendered for the first time), but at least the code you've posted could go entirely into the subclassed view.

rotate bitmap and maintain size

I am creating a tile board game.
I want to rotate a bitmap tile piece by a few pre-determined degrees.
When I rotate my bitmap, the size changes.
For example, if I want a 75x75 triangle tile piece, on rotation I get a 68x68 back from this code. How can I keep things the same size so everything remains the size for the board?
Here's what I'm using to rotate:
public class RotatebitmapActivity extends Activity {
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
LinearLayout linLayout = new LinearLayout(this);
// load the origial BitMap (500 x 500 px)
Bitmap bitmapOrg = BitmapFactory.decodeResource(getResources(),
R.drawable.t123);
int width = bitmapOrg.getWidth();
int height = bitmapOrg.getHeight();
int newWidth = 75;
int newHeight = 75;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// createa matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// rotate the Bitmap
matrix.postRotate(120);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
width, height, matrix, true);
// make a Drawable from Bitmap to allow to set the BitMap
// to the ImageView, ImageButton or what ever
BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
ImageView imageView = new ImageView(this);
// set the Drawable on the ImageView
imageView.setImageDrawable(bmd);
// center the Image
imageView.setScaleType(ScaleType.CENTER);
// add ImageView to the Layout
linLayout.addView(imageView,
new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT
)
);
// set LinearLayout as ContentView
setContentView(linLayout);
}
What is happening in your code, is that the bitmap that is created is the correct size. However, all Bitmaps are automatically scaled to fit the density of the screen that is currently in use.
There are two ways (that I know of) to get the result you desire.
You can set the density of a bitmap after creating it and before wrapping it in a drawable. To do this, add code similar to:
resizedBitmap.setDensity(DisplayMetric.DENSITY_HIGH);
This code sets the density that the bitmap is designed for, and can prevent Android from auto-scaling the image.
The second solution is more of a methodology than a specific solution to this particular problem. I won't go into detail, for that see Supporting Multiple Screens | Android Developers
Hopefully someone will happen along that can answer your question better than I can.

ImageView bitmap scale dimensions

I have a Bitmap that is larger than the ImageView that I'm putting it in. I have the ScaleType set to center_inside. How do I get the dimensions of the scaled down image?
Ok. I probably should have been clearer. I needed the height and width of the scaled Bitmap before it's ever drawn to the screen so that I could draw some overlays in the correct position. I knew the position of the overlays in the original Bitmap but not the scaled. I figured out some simple formulas to calculate where they should go on the scaled Bitmap.
I'll explain what I did in case someone else may one day need this.
I got the original width and height of the Bitmap. The ImageView's height and width are hard-coded in the xml file at 335.
int bitmap_width = bmp.getWidth();
int bitmap_height = bmp.getHeight();
I determined which one was larger so that I could correctly figure out which one to base the calculations off of. For my current example, width is larger. Since the width was scaled down to the the width of the ImageView, I have to find the scaled down height. I just multiplied the ratio of the ImageView's width to the Bitmap's width times the Bitmap's height. Division is done last because Integer division first would have resulted in an answer of 0.
int scaled_height = image_view_width * bitmap_height / bitmap_width;
With the scaled height I can determine the amount of blank space on either side of the scaled Bitmap by using:
int blank_space_buffer = (image_view_height - scaled_height) / 2;
To determine the x and y coordinates of where the overlay should go on the scaled Bitmap I have to use the original coordinates and these calculated numbers. The x coordinate in this example is easy. Since the scaled width is the width of the ImageView, I just have to multiply the ratio of the ImageView's width to the Bitmap's width with the original x coordinate.
int new_x_coord = image_view_width * start_x / bitmap_width;
The y coordinate is a bit trickier. Take the ratio of the Bitmap's scaled height to the Bitmap's original height. Multiply that value with the original y coordinate. Then add the blank area buffer.
int new_y_coord = scaled_height * start_y / bitmap_height + blank_space_buffer;
This works for what I need. If the height is greater than the width, just reverse the width and height variables.
Here's how I do it:
ImageView iv = (ImageView)findViewById(R.id.imageview);
Rect bounds = iv.getDrawable().getBounds();
int scaledHeight = bounds.height();
int scaledWidth = bounds.width();
You can use Drawable's getIntrinsicWidth() or height method if you want to get the original size.
EDIT: Okay, if you're trying to access these bounds at the time onCreate runs, you'll have to wait and retrieve them till after the layout pass. While I don't know that this is the best way, this is how I've been able to accomplish it. Basically, add a listener to the ImageView, and get your dimensions just before it's drawn to the screen. If you need to make any layout changes from the dimensions you retrieve, you should do it within onPreDraw().
ImageView iv = (ImageView)findViewById(R.id.imageview);
int scaledHeight, scaledWidth;
iv.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
Rect rect = iv.getDrawable().getBounds();
scaledHeight = rect.height();
scaledWidth = rect.width();
iv.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
});
Try this code:
final ImageView iv = (ImageView) findViewById(R.id.myImageView);
ViewTreeObserver vto = iv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Toast.makeText(MyActivity.this, iv.getWidth() + " x " + iv.getHeight(), Toast.LENGTH_LONG).show();
iv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
Otherwise you can use onSizeChange() by making this view a custom one.

Categories

Resources