Skip to content

Commit

Permalink
Support DownsampleStrategy in VideoBitmapDecoder
Browse files Browse the repository at this point in the history
  • Loading branch information
sjudd committed Feb 21, 2018
1 parent d939314 commit 97d130d
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package com.bumptech.glide;

import static com.bumptech.glide.test.BitmapSubject.assertThat;
import static org.junit.Assume.assumeTrue;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.test.ConcurrencyHelper;
import com.bumptech.glide.test.GlideApp;
import com.bumptech.glide.test.ResourceIds;
import com.bumptech.glide.test.TearDownGlide;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class DownsampleVideoTest {
// The dimensions of the test video.
private static final int WIDTH = 1080;
private static final int HEIGHT = 1920;

@Rule public final TearDownGlide tearDownGlide = new TearDownGlide();
private final ConcurrencyHelper concurrency = new ConcurrencyHelper();
private final Context context = InstrumentationRegistry.getTargetContext();

@Before
public void setUp() {
assumeTrue(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1);
}

@Test
public void loadVideo_downsampleStrategyNone_returnsOriginalVideoDimensions() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.load(ResourceIds.raw.video)
.downsample(DownsampleStrategy.NONE)
.submit(10, 10));

assertThat(bitmap).hasDimensions(WIDTH, HEIGHT);
}

@Test
public void loadVideo_downsampleStrategyNone_doesNotUpscale() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.load(ResourceIds.raw.video)
.downsample(DownsampleStrategy.NONE)
.submit(WIDTH * 2, HEIGHT * 2));

assertThat(bitmap).hasDimensions(WIDTH, HEIGHT);
}

@Test
public void loadVideo_downsampleDefault_downsamplesVideo() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.load(ResourceIds.raw.video)
.submit(10, 10));

assertThat(bitmap).hasDimensions(10, 18);
}

@Test
public void loadVideo_downsampleAtMost_downsamplesToSmallerSize() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.AT_MOST)
.load(ResourceIds.raw.video)
.submit(540, 959));
assertThat(bitmap).hasDimensions(270, 480);
}

@Test
public void loadVideo_downsampleAtMost_doesNotUpscale() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.AT_MOST)
.load(ResourceIds.raw.video)
.submit(WIDTH * 2, HEIGHT * 2));
assertThat(bitmap).hasDimensions(WIDTH, HEIGHT);
}

@Test
public void loadVideo_downsampleAtLeast_downsamplesToLargerSize() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.AT_LEAST)
.load(ResourceIds.raw.video)
.submit(270, 481));
assertThat(bitmap).hasDimensions(540, 960);
}

@Test
public void loadVideo_downsampleAtLeast_doesNotUpscale() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.AT_LEAST)
.load(ResourceIds.raw.video)
.submit(WIDTH * 2, HEIGHT * 2));
assertThat(bitmap).hasDimensions(WIDTH, HEIGHT);
}

@Test
public void loadVideo_downsampleCenterInside_downsamplesWithinBox() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.CENTER_INSIDE)
.load(ResourceIds.raw.video)
.submit(270, 481));
assertThat(bitmap).hasDimensions(270, 480);
}

@Test
public void loadVideo_downsampleCenterInside_doesNotUpscale() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.CENTER_INSIDE)
.load(ResourceIds.raw.video)
.submit(WIDTH * 2, HEIGHT * 2));
assertThat(bitmap).hasDimensions(WIDTH, HEIGHT);
}

@Test
public void loadVideo_downsampleCenterOutside_downsamplesOutsideBox() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.CENTER_OUTSIDE)
.load(ResourceIds.raw.video)
.submit(270, 481));
assertThat(bitmap).hasDimensions(271, 481);
}

@Test
public void loadVideo_downsampleCenterOutside_upsacles() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.CENTER_OUTSIDE)
.load(ResourceIds.raw.video)
.submit(WIDTH * 2, HEIGHT * 2));
assertThat(bitmap).hasDimensions(WIDTH * 2, HEIGHT * 2);
}

@Test
public void loadVideo_downsampleFitCenter_downsamplesInsideBox() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.FIT_CENTER)
.load(ResourceIds.raw.video)
.submit(270, 481));
assertThat(bitmap).hasDimensions(270, 480);
}

@Test
public void loadVideo_downsampleFitCenter_upscales() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.FIT_CENTER)
.load(ResourceIds.raw.video)
.submit(WIDTH * 2, HEIGHT * 2));
assertThat(bitmap).hasDimensions(WIDTH * 2, HEIGHT * 2);
}

@Test
public void loadVideo_withSizeOriginal_ignoresDownsampleStrategy() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.downsample(DownsampleStrategy.AT_MOST)
.load(ResourceIds.raw.video)
.submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL));

assertThat(bitmap).hasDimensions(WIDTH, HEIGHT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,7 @@ private static String runScaleTest(
Downsampler downsampler = buildDownsampler();

InputStream is = openBitmapStream(format, initialWidth, initialHeight);
Options options = new Options()
.set(Downsampler.DOWNSAMPLE_STRATEGY, strategy);
Options options = new Options().set(DownsampleStrategy.OPTION, strategy);
Bitmap bitmap = downsampler.decode(is, targetWidth, targetHeight, options).get();
try {
if (bitmap.getWidth() != expectedWidth || bitmap.getHeight() != expectedHeight) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,25 @@ public void sameAs(@DrawableRes int resourceId) {
sameAs(drawable);
}

public void hasDimensions(int expectedWidth, int expectedHeight) {
int actualWidth = actual().getWidth();
int actualHeight = actual().getHeight();
String message;
if (expectedWidth != actualWidth && expectedHeight != actualHeight) {
message = "has dimensions of [" + expectedWidth + "x" + expectedHeight + "]";
} else if (expectedWidth != actualWidth) {
message = "has width of " + expectedWidth;
} else if (expectedHeight != actualHeight) {
message = "has height of " + expectedHeight;
} else {
message = null;
}

if (message != null) {
fail(message);
}
}

public void isMutable() {
if (!actual().isMutable()) {
fail("is mutable");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
package com.bumptech.glide.load.resource.bitmap;

import com.bumptech.glide.load.Option;
import com.bumptech.glide.util.Synthetic;

/**
* Indicates the algorithm to use when downsampling images.
*
* <p>{@code DownsampleStrategy} does not provide any guarantees about output sizes. Behavior will
* differ depending on the {@link com.bumptech.glide.load.ResourceDecoder} using the strategy and
* the version of Android the code runs on. Use {@code DownsampleStrategy} as an optimization to
* improve memory efficiency only. If you need a particular size or shape output, use an
* {@link com.bumptech.glide.load.Transformation} either instead or in addition to a
* {@code DownsampleStrategy}.
*
* <p>Some differences between versions of Android and
* {@link com.bumptech.glide.load.ResourceDecoder}s are listed below, but the list is not
* comprehensive because {@link DownsampleStrategy} only controls it's output scale value, not
* how that output value is used.
*/
// Public API.
@SuppressWarnings("WeakerAccess")
Expand All @@ -18,8 +31,8 @@ public abstract class DownsampleStrategy {
* and height. To avoid upscaling, use {@link #AT_LEAST}, {@link #AT_MOST} or
* {@link #CENTER_INSIDE}.
*
* <p>On pre-KitKat devices, this is equivalent to {@link #AT_MOST} because only power of
* two downsampling can be used.
* <p>On pre-KitKat devices, {@link Downsampler} treats this as equivalent to {@link #AT_MOST}
* because only power of two downsampling can be used.
*/
public static final DownsampleStrategy FIT_CENTER = new FitCenter();

Expand All @@ -32,20 +45,24 @@ public abstract class DownsampleStrategy {
* and height. To avoid upscaling, use {@link #AT_LEAST}, {@link #AT_MOST},
* or {@link #CENTER_INSIDE}.
*
* <p>On pre-KitKat devices, this is equivalent to {@link #AT_LEAST} because only power of
* two downsampling can be used.
* <p>On pre-KitKat devices, {@link Downsampler} treats this as equivalent to
* {@link #AT_LEAST} because only power of two downsampling can be used.
*/
public static final DownsampleStrategy CENTER_OUTSIDE = new CenterOutside();

/**
* Downsamples so the image's smallest dimension is between the given dimensions and 2x the given
* dimensions, with no size restrictions on the image's largest dimension.
*
* <p>Does not upscale if the requested dimensions are larger than the original dimensions.
*/
public static final DownsampleStrategy AT_LEAST = new AtLeast();

/**
* Downsamples so the image's largest dimension is between 1/2 the given dimensions and the given
* dimensions, with no restrictions on the image's smallest dimension.
*
* <p>Does not upscale if the requested dimensions are larger than the original dimensions.
*/
public static final DownsampleStrategy AT_MOST = new AtMost();

Expand All @@ -54,7 +71,7 @@ public abstract class DownsampleStrategy {
* 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.
*
* <p>This method will not upscale.</p>
* <p>Does not upscale if the requested dimensions are larger than the original dimensions.
*/
public static final DownsampleStrategy CENTER_INSIDE = new CenterInside();

Expand All @@ -68,6 +85,17 @@ public abstract class DownsampleStrategy {
*/
public static final DownsampleStrategy DEFAULT = CENTER_OUTSIDE;

/**
* Indicates the {@link com.bumptech.glide.load.resource.bitmap.DownsampleStrategy} option that
* will be used to calculate the sample size to use to downsample an image given the original
* and target dimensions of the image.
*/
// The exact String value here is retained to avoid breaking cache keys for images that were
// loaded with older versions of Glide.
public static final Option<DownsampleStrategy> OPTION =
Option.memory(
"com.bumptech.glide.load.resource.bitmap.Downsampler.DownsampleStrategy", DEFAULT);

/**
* Returns a float (0, +infinity) indicating a scale factor to apply to the source
* width and height when displayed in the requested width and height.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ public final class Downsampler {
* Indicates the {@link com.bumptech.glide.load.resource.bitmap.DownsampleStrategy} option that
* will be used to calculate the sample size to use to downsample an image given the original
* and target dimensions of the image.
*
* @deprecated Use {@link DownsampleStrategy#OPTION} directly instead.
*/
public static final Option<DownsampleStrategy> DOWNSAMPLE_STRATEGY =
Option.memory("com.bumptech.glide.load.resource.bitmap.Downsampler.DownsampleStrategy",
DownsampleStrategy.DEFAULT);
@Deprecated
public static final Option<DownsampleStrategy> DOWNSAMPLE_STRATEGY = DownsampleStrategy.OPTION;
/**
* Ensure that the size of the bitmap is fixed to the requested width and height of the
* resource from the caller. The final resource dimensions may differ from the requested
Expand Down Expand Up @@ -195,7 +196,7 @@ public Resource<Bitmap> decode(InputStream is, int requestedWidth, int requested
bitmapFactoryOptions.inTempStorage = bytesForOptions;

DecodeFormat decodeFormat = options.get(DECODE_FORMAT);
DownsampleStrategy downsampleStrategy = options.get(DOWNSAMPLE_STRATEGY);
DownsampleStrategy downsampleStrategy = options.get(DownsampleStrategy.OPTION);
boolean fixBitmapToRequestedDimensions = options.get(FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS);
boolean isHardwareConfigAllowed =
options.get(ALLOW_HARDWARE_CONFIG) != null && options.get(ALLOW_HARDWARE_CONFIG);
Expand Down
Loading

0 comments on commit 97d130d

Please sign in to comment.