android Gallery with arbitrary aspect ratios - android

i wish to have an android gallery that will host images of varying aspect ratios. what i'd like is something like CENTER_CROP for the images in the gallery. however, when i set the image scale type to this, the images overrun the gallery image border.
of course, FIT_XY results in squished / flattened images. CENTER results in horizontal or vertical black space inside the gallery image border.
any ideas how to accomplish this? every example i can find uses FIT_XY with fixed size images. i suppose i could crop the images myself but i'd rather not.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView iv = (ImageView) convertView;
if (iv == null) {
iv = new ImageView(context);
iv.setScaleType(ImageView.ScaleType.FIT_XY);
iv.setBackgroundResource(galleryItemBackground);
iv.setLayoutParams(new Gallery.LayoutParams(200, 200));
}
InputStream is;
try {
is = getInputStream(position);
} catch (IOException ioe) {
// TODO?
throw new RuntimeException(ioe);
}
Bitmap bm = BitmapFactory.decodeStream(is);
iv.setImageBitmap(bm);
/*
* if (bitmaps[position] != null) { bitmaps[position].recycle();
* bitmaps[position] = null; } bitmaps[position] = bm;
*/
return iv;
}

I had the same problem as you and looking at ScaleType documentation I found it could be done using ScaleType.MATRIX, for example:
int w = 1000;
int h = 1000;
Paint p = new Paint();
p.setShader(new LinearGradient(0, 0, w, h, Color.BLACK, Color.RED, Shader.TileMode.CLAMP));
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas g = new Canvas(bmp);
g.drawRect(new Rect(0, 0, w, h), p);
ImageView i3 = new ImageView(context);
i3.setImageBitmap(bmp);
i3.setScaleType(ScaleType.MATRIX);
int viewWidth = 300;
int viewHeight = 300;
Matrix matrix = new Matrix();
matrix.postScale(bmp.getWidth() / viewWidth, bmp.getHeight() / viewHeight, bmp.getWidth() / 2, bmp.getHeight() / 2);
i3.setImageMatrix(matrix);
LayoutParams lp2 = new LayoutParams(viewWidth, viewHeight);
lp2.leftMargin = 100;
lp2.topMargin = 400;
lp2.gravity = 0;
this.addView(i3, lp2);
This solution complicates things a little bit too much though. If you want to scroll and zoom the ImageView you need to use matrix scaling as well. So I'd be interested in knowing any possible alternative.

For this kind of tasks I use this simple class. It fits height or width scaling the image properly (it depends on which is the smaller dimension) . After this operation it centers the image in the ImageView bounds.
public class FixedCenterCrop extends ImageView {
public FixedCenterCrop(Context context) {
super(context);
setScaleType(ScaleType.MATRIX);
}
public FixedCenterCrop(Context context, AttributeSet attrs) {
super(context, attrs);
setScaleType(ScaleType.MATRIX);
}
public FixedCenterCrop(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setScaleType(ScaleType.MATRIX);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
recomputeImgMatrix();
}
#Override
protected boolean setFrame(int l, int t, int r, int b) {
recomputeImgMatrix();
return super.setFrame(l, t, r, b);
}
private void recomputeImgMatrix() {
final Matrix matrix = getImageMatrix();
float scale;
final int viewWidth = getWidth() - getPaddingLeft() - getPaddingRight();
final int viewHeight = getHeight() - getPaddingTop() - getPaddingBottom();
final int drawableWidth = getDrawable().getIntrinsicWidth();
final int drawableHeight = getDrawable().getIntrinsicHeight();
if (drawableWidth * viewHeight > drawableHeight * viewWidth) {
scale = (float) viewHeight / (float) drawableHeight;
} else {
scale = (float) viewWidth / (float) drawableWidth;
}
matrix.setScale(scale, scale);
matrix.postTranslate((viewWidth - drawableWidth * scale) / 2, (viewHeight - drawableHeight*scale)/2);
setImageMatrix(matrix);
}
}

I ended up just trimming the bitmap to a square myself, as,
Bitmap bm = BitmapFactory.decodeStream(is);
// make it square
int w = bm.getWidth();
int h = bm.getHeight();
if (w > h) {
// trim width
bm = Bitmap.createBitmap(bm, (w - h) / 2, 0, h, h);
} else {
bm = Bitmap.createBitmap(bm, 0, (h - w) / 2, w, w);
}

Related

Top crop with ImageLoader - Android

I'm loading images from URLs into my ImageView like so -
ImageLoader.getInstance().displayImage(url, imageview, display-options)
Now I would like to crop the image to the center top. I tried using https://gist.github.com/arriolac/3843346 but I think it expects the image via a drawable and I want to use ImageLoader to set the image.
Can somebody help me understand if I can use https://code.google.com/archive/p/android-query/ (Android Query) in conjunction with ImageLoader?
Is there any way to handle cropping in Android (apart from centerCrop) natively?
Replace your ImageView with ProfileImageView and enjoy the view :)
public class ProfileImageView extends ImageView {
private Bitmap bm;
public ProfileImageView(Context context, AttributeSet attrs) {
super(context, attrs);
bm = null;
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (bm != null) {
setImageBitmap(bm);
bm = null;
}
}
#Override
public void setImageBitmap(Bitmap bm) {
int viewWidth = getWidth();
int viewHeight = getHeight();
if (viewWidth == 0 || viewHeight == 0) {
this.bm = bm;
return;
}
setScaleType(ScaleType.MATRIX);
Matrix m = getImageMatrix();
m.reset();
int min = Math.min(bm.getWidth(), bm.getHeight());
int cut;
if (bm.getWidth() > viewWidth && bm.getWidth() > bm.getHeight()) {
cut = Math.round((bm.getWidth() - viewWidth) / 2.f);
} else {
cut = 0;
}
RectF drawableRect = new RectF(cut, 0, min - cut, min);
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.START);
setImageMatrix(m);
super.setImageBitmap(bm);
}
}

Android ImageView scale bitmap to the width and crop the height

I have a fixed size ImageView. I want to achieve this :
Scale the Bitmap always to the width, if the Bitmap is wider or smaller than Imageview width.
Crop the height if taller than ImageView height else scale it to the height.
I want something like this answer, but the other way around (FitXCropY). I have tried changing this answer with no success.
Thank you.
Based on this answer ImageView to scale to fixed height, but crop excess width
public class FitXCropYImageView extends ImageView {
boolean done = false;
#SuppressWarnings("UnusedDeclaration")
public FitXCropYImageView(Context context) {
super(context);
setScaleType(ScaleType.MATRIX);
}
#SuppressWarnings("UnusedDeclaration")
public FitYCropXImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setScaleType(ScaleType.MATRIX);
}
#SuppressWarnings("UnusedDeclaration")
public FitXCropYImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setScaleType(ScaleType.MATRIX);
}
private final RectF drawableRect = new RectF(0, 0, 0,0);
private final RectF viewRect = new RectF(0, 0, 0,0);
private final Matrix m = new Matrix();
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (done) {
return;//Already fixed drawable scale
}
final Drawable d = getDrawable();
if (d == null) {
return;//No drawable to correct for
}
int viewHeight = getMeasuredHeight();
int viewWidth = getMeasuredWidth();
int drawableWidth = d.getIntrinsicWidth();
int drawableHeight = d.getIntrinsicHeight();
drawableRect.set(0, 0, drawableWidth, drawableHeight);//Represents the original image
//Compute the left and right bounds for the scaled image
float viewHalfHeight = viewHeight / 2;
float scale = (float) viewWidth / (float) drawableWidth;
float scaledHeight = drawableHeight * scale;
float scaledHalfHeight = scaledHeight / 2;
viewRect.set(0, viewHalfHeight-scaledHalfHeight,viewWidth, viewHalfHeight+scaledHalfHeight);
m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER /* This constant doesn't matter? */);
setImageMatrix(m);
done = true;
requestLayout();
}
}
Try like this,
Add inside Oncreate
viewImage = (ImageView) findViewById(R.id.pictureImageview123);
viewImage.setScaleType(ScaleType.FIT_XY);

Android: Draw image on canvas of particular size

I am adding 1 layout dynamically. In that adding custom view. now I want to draw image on canvas exactly of same size as the size of that layout.
Below is the code of my custom view which i have tried.
public BlockView(Context context, Bitmap bitmap, int layoutHeight,
int layoutWidth) {
super(context);
this.bitmap = bitmap;
this.width = bitmap.getWidth();
this.height = bitmap.getHeight();
this.layoutHeight = layoutHeight;
this.layoutWidth = layoutWidth;
if (drawableWidth <= viewWidth && drawableHeight <= viewHeight) {
scale = 1.0f;
} else {
scale = Math.min((float) viewWidth / (float) drawableWidth,
(float) viewHeight / (float) drawableHeight);
}
mDrawable = new BitmapDrawable(getResources(), bitmap);
}
private static float getDegreesFromRadians(float angle) {
return (float) (angle * 180.0 / Math.PI);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
drawableWidth = mDrawable.getIntrinsicWidth();
drawableHeight = mDrawable.getIntrinsicHeight();
viewWidth = layoutWidth;
viewHeight = layoutHeight;
setMeasuredDimension(viewWidth, viewHeight);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int saveCount = canvas.save();
matrix.setScale(scale, scale);
matrix.postRotate(getDegreesFromRadians(angle));
matrix.postTranslate(position.getX(), position.getY());
canvas.concat(matrix);
mDrawable.setBounds(0, 0, drawableWidth, drawableHeight);
mDrawable.draw(canvas);
canvas.restoreToCount(saveCount);
}
With above code,I am successfully able to draw image and perform drag,zoom and rotate. But facing problem of not able to draw image of same size as the size of layout. and also need some way to proceed on how to check that image should not be scaled too small than the layout size.
Any help will be really appreciated.

How to set selected area of Image to ImageView

I Was trying to set image to imageimageviewview from external storage and I done with that, but the thing is that it sets the whole image to imageview and I only want to set the selected square area from that image. Just life facebook provided functionality to set profile pic..
Can any one help me to do it??
Following is the sample what i want to do..
Something like this:
public static Bitmap cropBitmapToSquare(Bitmap bmp) {
System.gc();
Bitmap result = null;
int height = bmp.getHeight();
int width = bmp.getWidth();
if (height <= width) {
result = Bitmap.createBitmap(bmp, (width - height) / 2, 0, height,
height);
} else {
result = Bitmap.createBitmap(bmp, 0, (height - width) / 2, width,
width);
}
return result;
}
Here is a sample with crop activity:
http://khurramitdeveloper.blogspot.ru/2013/07/capture-or-select-from-gallery-and-crop.html
actually my comment above about setImageMatrix was not the best solution, try this custom Drawable (no need to allocate any temporary Bitmaps):
class CropDrawable extends BitmapDrawable {
private Rect mSrc;
private RectF mDst;
public CropDrawable(Bitmap b, int left, int top, int right, int bottom) {
super(b);
mSrc = new Rect(left, top, right, bottom);
mDst = new RectF(0, 0, right - left, bottom - top);
}
#Override
public void draw(Canvas canvas) {
canvas.drawBitmap(getBitmap(), mSrc, mDst, null);
}
#Override
public int getIntrinsicWidth() {
return mSrc.width();
}
#Override
public int getIntrinsicHeight() {
return mSrc.height();
}
}
and testing code:
ImageView iv = new ImageView(this);
Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.test);
Drawable d = new CropDrawable(b, 150, 100, 180, 130);
iv.setImageDrawable(d);
setContentView(iv);

ImageView to scale to fixed height, but crop excess width

I would like my ImageView to scale in a particular fashion:
Scale so that the height of the image always fits the height of the ImageView
Crop any excess width
A picture speaks louder than a 1000 words, so here is a representation of how I want my ImageView to behave. Suppose it has a fixed height of say 100dp and suppose its width is match_parent.
Note that
on the phone layout, the image height is stretched, but the sides are cropped, akin to CROP_CENTER.
on the tablet layout, the image is also stretched to fit the ImageView height, behaving like FIT_CENTER
I suspect I need scaleType:matrix, but after that I'm lost. How can I make sure an image fits Y, but crops X?
In xml, use:
android:scaleType="centerCrop"
android:adjustViewBounds="true"
from & thanks to: https://stackoverflow.com/a/15600295/2162226
With a little help from my friends Carlos Robles and pskink, came up with the following custom ImageView:
public class FitYCropXImageView extends ImageView {
boolean done = false;
#SuppressWarnings("UnusedDeclaration")
public FitYCropXImageView(Context context) {
super(context);
setScaleType(ScaleType.MATRIX);
}
#SuppressWarnings("UnusedDeclaration")
public FitYCropXImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setScaleType(ScaleType.MATRIX);
}
#SuppressWarnings("UnusedDeclaration")
public FitYCropXImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setScaleType(ScaleType.MATRIX);
}
private final RectF drawableRect = new RectF(0, 0, 0,0);
private final RectF viewRect = new RectF(0, 0, 0,0);
private final Matrix m = new Matrix();
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (done) {
return;//Already fixed drawable scale
}
final Drawable d = getDrawable();
if (d == null) {
return;//No drawable to correct for
}
int viewHeight = getMeasuredHeight();
int viewWidth = getMeasuredWidth();
int drawableWidth = d.getIntrinsicWidth();
int drawableHeight = d.getIntrinsicHeight();
drawableRect.set(0, 0, drawableWidth, drawableHeight);//Represents the original image
//Compute the left and right bounds for the scaled image
float viewHalfWidth = viewWidth / 2;
float scale = (float) viewHeight / (float) drawableHeight;
float scaledWidth = drawableWidth * scale;
float scaledHalfWidth = scaledWidth / 2;
viewRect.set(viewHalfWidth - scaledHalfWidth, 0, viewHalfWidth + scaledHalfWidth, viewHeight);
m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER /* This constant doesn't matter? */);
setImageMatrix(m);
done = true;
requestLayout();
}
}
If you use scaleType:matrix you will need to create your own Matrix and asign it to the view by means of setImageMatrix(Matrix) or manually modify the matrix at hen onMEasure method of a customImageView.
public class MyImageView extends ImageView {
boolean done=false;
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (done)
return;
final Drawable d = getDrawable();
final int drawableW = d.getIntrinsicWidth();
final int drawableH = d.getIntrinsicHeight();
float ratio = drawableW / drawableH;
//int width = getMeasuredWidth();
int height = getMeasuredHeight();
float scale=height/drawableH;
Matrix m = getImageMatrix();
float[] f = new float[9];
m.getValues(f);
f[Matrix.MSCALE_X]=scale;
f[Matrix.MSCALE_Y]=scale;
m.setValues(f);
done = true;
requestLayout();
}
}
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
LayoutParams params;
final ImageView iv0 = new ImageView(this);
//iv0.setBackgroundColor(0xffff0000);
params = new LayoutParams(LayoutParams.MATCH_PARENT, 100);
ll.addView(iv0, params);
final ImageView iv1 = new ImageView(this);
//iv1.setBackgroundColor(0xff00ff00);
params = new LayoutParams(60, 100);
ll.addView(iv1, params);
setContentView(ll);
Runnable action = new Runnable() {
#Override
public void run() {
Drawable d = getResources().getDrawable(R.drawable.layer0);
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
RectF src = new RectF(0, 0, dw, dh);
ImageView[] iviews = {iv0, iv1};
for (int i = 0; i < iviews.length; i++) {
ImageView iv = iviews[i];
iv.setImageDrawable(d);
iv.setScaleType(ScaleType.MATRIX);
float h = iv.getHeight();
float w = iv.getWidth();
float cx = w / 2;
float scale = h / dh;
float deltaw = dw * scale / 2;
RectF dst = new RectF(cx - deltaw, 0, cx + deltaw, h);
Matrix m = new Matrix();
m.setRectToRect(src, dst, ScaleToFit.FILL);
iv.setImageMatrix(m);
}
}
};
iv1.post(action);
If you want to display the center of the image, use:
android:scaleType="centerCrop"
android:adjustViewBounds="true"
If you want to show the edge of the image instead of the center, use:
android:scaleType="matrix"
android:adjustViewBounds="true"

Categories

Resources