Skip to content

Commit

Permalink
Merge pull request bumptech#727 from josemontiel/master
Browse files Browse the repository at this point in the history
Implemented CENTER_INSIDE support
  • Loading branch information
sjudd committed Nov 24, 2015
2 parents 20aacc5 + 7286c3f commit acc3fe3
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 0 deletions.
3 changes: 3 additions & 0 deletions library/src/main/java/com/bumptech/glide/RequestBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,9 @@ public Target<TranscodeType> into(ImageView view) {
case CENTER_CROP:
requestOptions.optionalCenterCrop(context);
break;
case CENTER_INSIDE:
requestOptions.optionalCenterInside(context);
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.bumptech.glide.load.resource.bitmap;

import android.content.Context;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;

import java.security.MessageDigest;

/**
* Returns the image with its original size if its dimensions match or are smaller
* than the target's, couple with {@link android.widget.ImageView.ScaleType#CENTER_INSIDE}
* in order to center it in Target. If not, then it is scaled so that one of the dimensions of
* the image will be equal to the given dimension and the other will be less than the given
* dimension (maintaining the image's aspect ratio).
*/
public class CenterInside extends BitmapTransformation {
private static final String ID = "com.bumptech.glide.load.resource.bitmap.CenterInside";
private static final byte[] ID_BYTES = ID.getBytes(CHARSET);

public CenterInside(Context context) {
super(context);
}

public CenterInside(BitmapPool bitmapPool) {
super(bitmapPool);
}

@Override
protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth,
int outHeight) {
return TransformationUtils.centerInside(pool, toTransform, outWidth, outHeight);
}

@Override
public boolean equals(Object o) {
return o instanceof CenterInside;
}

@Override
public int hashCode() {
return ID.hashCode();
}

@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
messageDigest.update(ID_BYTES);
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ public abstract class DownsampleStrategy {
*/
public static final DownsampleStrategy AT_MOST = new AtMost();

/**
* Returns the original image if it is smaller than the target, otherwise it will be downscaled
* maintaining its original aspect ratio, so that one of the image's dimensions is exactly equal
* to the requested size and the other is less or equal than the requested size.
*/
public static final DownsampleStrategy DOWNSCALE_ONLY = new DownscaleOnly();

/**
* Performs no downsampling or scaling.
*/
Expand Down Expand Up @@ -168,6 +175,23 @@ public SampleSizeRounding getSampleSizeRounding(int sourceWidth, int sourceHeigh
}
}

private static class DownscaleOnly extends DownsampleStrategy {

@Override
public float getScaleFactor(int sourceWidth, int sourceHeight, int requestedWidth,
int requestedHeight) {

return Math.min(1.f,
CENTER_INSIDE.getScaleFactor(sourceWidth, sourceHeight, requestedWidth, requestedHeight));
}

@Override
public SampleSizeRounding getSampleSizeRounding(int sourceWidth, int sourceHeight,
int requestedWidth, int requestedHeight) {
return SampleSizeRounding.QUALITY;
}
}

/**
* Indicates whether to prefer to prefer downsampling or scaling to prefer lower memory usage
* or higher quality.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,32 @@ public static Bitmap fitCenter(@NonNull BitmapPool pool, @NonNull Bitmap inBitma
return toReuse;
}

/**
* If the Bitmap is smaller or equal to the Target it returns the original size, if not then
* {@link #fitCenter(BitmapPool, Bitmap, int, int)} is called instead.
*
* @param pool The BitmapPool obtain a bitmap from.
* @param inBitmap The Bitmap to center.
* @param width The width in pixels of the target.
* @param height The height in pixels of the target.
* @return returns input Bitmap if smaller or equal to target, or toFit if the Bitmap's width or
* height is larger than the given dimensions
*/
public static Bitmap centerInside(@NonNull BitmapPool pool, @NonNull Bitmap inBitmap, int width,
int height) {
if (inBitmap.getWidth() <= width && inBitmap.getHeight() <= height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "requested target size larger or equal to input, returning input");
}
return inBitmap;
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "requested target size too big for input, fit centering instead");
}
return fitCenter(pool, inBitmap, width, height);
}
}

/**
* Sets the alpha of the Bitmap we're going to re-use to the alpha of the Bitmap we're going to
* transform. This keeps {@link android.graphics.Bitmap#hasAlpha()}} consistent before and after
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.bumptech.glide.load.resource.bitmap.BitmapDrawableTransformation;
import com.bumptech.glide.load.resource.bitmap.BitmapEncoder;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.CenterInside;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy;
import com.bumptech.glide.load.resource.bitmap.Downsampler;
Expand Down Expand Up @@ -528,6 +529,34 @@ public CHILD fitCenter(Context context) {
return transform(context, DownsampleStrategy.CENTER_INSIDE, new FitCenter(context));
}

/**
* Applies {@link com.bumptech.glide.load.resource.bitmap.CenterInside} to all default types, and
* ignores unknown types.
*
* <p>This will override previous calls to {@link #dontTransform()}.
*
* @param context Any {@link android.content.Context}.
* @see #optionalTransform(Class, com.bumptech.glide.load.Transformation)
* @see #centerInside(Context) (android.content.Context)
*/
public CHILD optionalCenterInside(Context context) {
return optionalTransform(context, DownsampleStrategy.DOWNSCALE_ONLY, new CenterInside(context));
}

/**
* Applies {@link com.bumptech.glide.load.resource.bitmap.CenterInside} to all default types and
* throws an exception if asked to transform an unknown type.
*
* <p>This will override previous calls to {@link #dontTransform()}.
*
* @param context Any {@link android.content.Context}.
* @see #transform(Class, com.bumptech.glide.load.Transformation)
* @see #optionalCenterInside(Context) (android.content.Context)
*/
public CHILD centerInside(Context context) {
return transform(context, DownsampleStrategy.DOWNSCALE_ONLY, new CenterInside(context));
}

/**
* Applies {@link CircleCrop} to all default types, and ignores unknown types.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public final class RequestOptions extends BaseRequestOptions<RequestOptions> {
private static RequestOptions skipMemoryCacheTrueOptions;
private static RequestOptions skipMemoryCacheFalseOptions;
private static RequestOptions fitCenterOptions;
private static RequestOptions centerInsideOptions;
private static RequestOptions centerCropOptions;
private static RequestOptions circleCropOptions;
private static RequestOptions noTransformOptions;
Expand Down Expand Up @@ -131,6 +132,18 @@ public static RequestOptions fitCenterTransform(Context context) {
return fitCenterOptions;
}

/**
* Returns a {@link RequestOptions} object with {@link #centerInside(Context)} set.
*/
public static RequestOptions centerInsideTransform(Context context) {
if (centerInsideOptions == null) {
centerInsideOptions = new RequestOptions()
.centerInside(context.getApplicationContext())
.autoLock();
}
return centerInsideOptions;
}

/**
* Returns a {@link RequestOptions} object with {@link #circleCrop(Context)} set.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.bumptech.glide.load.resource.bitmap;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;

import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPoolAdapter;
import com.bumptech.glide.tests.KeyAssertions;
import com.bumptech.glide.tests.Util;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowCanvas;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE, sdk = 18, shadows = { CenterInsideTest.DrawNothingCanvas.class })
public class CenterInsideTest {

@Mock Resource<Bitmap> resource;
@Mock Transformation<Bitmap> transformation;
private BitmapPool pool;
private CenterInside centerInside;
private int bitmapWidth;
private int bitmapHeight;

@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
bitmapWidth = 100;
bitmapHeight = 100;
Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
when(resource.get()).thenReturn(bitmap);

pool = new BitmapPoolAdapter();

centerInside = new CenterInside(pool);
}

@Test
public void testReturnsGivenResourceIfMatchesSizeExactly() {
Resource<Bitmap> result =
centerInside.transform(resource, bitmapWidth, bitmapHeight);

assertEquals(resource, result);
}

@Test
public void testReturnsGivenResourceIfSmallerThanTarget() {
Resource<Bitmap> result =
centerInside.transform(resource, 150, 150);

assertEquals(resource, result);
}

@Test
public void testReturnsNewResourceIfLargerThanTarget() {
Resource<Bitmap> result =
centerInside.transform(resource, 50, 50);

assertNotEquals(resource, result);
}


@Test
public void testDoesNotRecycleGivenResourceIfMatchesSizeExactly() {
centerInside.transform(resource, bitmapWidth, bitmapHeight);

verify(resource, never()).recycle();
}

@Test
public void testDoesNotRecycleGivenResource() {
centerInside.transform(resource, 50, 50);

verify(resource, never()).recycle();
}

@Test
public void testEquals() throws NoSuchAlgorithmException {
KeyAssertions.assertSame(centerInside, new CenterInside(pool));

doAnswer(new Util.WriteDigest("other")).when(transformation)
.updateDiskCacheKey(any(MessageDigest.class));
KeyAssertions.assertDifferent(centerInside, transformation);
}

@Implements(Canvas.class)
public static final class DrawNothingCanvas extends ShadowCanvas {

@Implementation
@Override
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
// Do nothing.
}
}
}

0 comments on commit acc3fe3

Please sign in to comment.