1package com.bumptech.glide;
2
3import android.graphics.Bitmap;
4import android.graphics.drawable.Drawable;
5import android.os.ParcelFileDescriptor;
6import android.view.animation.Animation;
7import android.widget.ImageView;
8
9import com.bumptech.glide.load.DecodeFormat;
10import com.bumptech.glide.load.Encoder;
11import com.bumptech.glide.load.Key;
12import com.bumptech.glide.load.ResourceDecoder;
13import com.bumptech.glide.load.ResourceEncoder;
14import com.bumptech.glide.load.Transformation;
15import com.bumptech.glide.load.engine.DiskCacheStrategy;
16import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
17import com.bumptech.glide.load.model.ImageVideoWrapper;
18import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
19import com.bumptech.glide.load.resource.bitmap.Downsampler;
20import com.bumptech.glide.load.resource.bitmap.FileDescriptorBitmapDecoder;
21import com.bumptech.glide.load.resource.bitmap.ImageVideoBitmapDecoder;
22import com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder;
23import com.bumptech.glide.load.resource.bitmap.VideoBitmapDecoder;
24import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
25import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
26import com.bumptech.glide.provider.LoadProvider;
27import com.bumptech.glide.request.RequestListener;
28import com.bumptech.glide.request.animation.ViewPropertyAnimation;
29import com.bumptech.glide.request.target.Target;
30
31import java.io.File;
32import java.io.InputStream;
33
34/**
35 * A class for creating a request to load a bitmap for an image or from a video. Sets a variety of type independent
36 * options including resizing, animations, and placeholders.
37 *
38 * <p>
39 *     Warning - It is <em>not</em> safe to use this builder after calling <code>into()</code>, it may be pooled and
40 *     reused.
41 * </p>
42 *
43 * @param  The type of model that will be loaded into the target.
44 * @param  The type of the transcoded resource that the target will receive
45 */
46public class BitmapRequestBuilder<ModelType, TranscodeType>
47        extends GenericRequestBuilder<ModelType, ImageVideoWrapper, Bitmap, TranscodeType> implements BitmapOptions {
48    private final BitmapPool bitmapPool;
49
50    private Downsampler downsampler = Downsampler.AT_LEAST;
51    private DecodeFormat decodeFormat;
52    private ResourceDecoder<InputStream, Bitmap> imageDecoder;
53    private ResourceDecoder<ParcelFileDescriptor, Bitmap> videoDecoder;
54
55    BitmapRequestBuilder(LoadProvider<ModelType, ImageVideoWrapper, Bitmap, TranscodeType> loadProvider,
56            Class<TranscodeType> transcodeClass, GenericRequestBuilder<ModelType, ?, ?, ?> other) {
57        super(loadProvider, transcodeClass, other);
58        this.bitmapPool = other.glide.getBitmapPool();
59        this.decodeFormat =  other.glide.getDecodeFormat();
60
61        imageDecoder = new StreamBitmapDecoder(bitmapPool, decodeFormat);
62        videoDecoder = new FileDescriptorBitmapDecoder(bitmapPool, decodeFormat);
63    }
64
65    /**
66     * Load images at a size near the size of the target using {@link Downsampler#AT_LEAST}.
67     *
68     * @see #downsample(Downsampler)
69     *
70     * @return This request builder.
71     */
72    public BitmapRequestBuilder<ModelType, TranscodeType> approximate() {
73        return downsample(Downsampler.AT_LEAST);
74    }
75
76    /**
77     * Load images at their original size using {@link Downsampler#NONE}.
78     *
79     * @see #downsample(Downsampler)
80     *
81     * @return This request builder.
82     */
83    public BitmapRequestBuilder<ModelType, TranscodeType> asIs() {
84        return downsample(Downsampler.NONE);
85    }
86
87    /**
88     * Load images at a size that is at most exactly as big as the target using
89     * {@link com.bumptech.glide.load.resource.bitmap.Downsampler#AT_MOST}.
90     *
91     * @see #downsample(com.bumptech.glide.load.resource.bitmap.Downsampler)
92     *
93     * @return This request builder.
94     */
95    public BitmapRequestBuilder<ModelType, TranscodeType> atMost() {
96        return downsample(Downsampler.AT_MOST);
97    }
98
99    /**
100     * Load images using the given {@link Downsampler}. Replaces any existing image decoder. Defaults to
101     * {@link Downsampler#AT_LEAST}. Will be ignored if the data represented by the model is a video. This replaces any
102     * previous calls to {@link #imageDecoder(ResourceDecoder)}  and {@link #decoder(ResourceDecoder)} with default
103     * decoders with the appropriate options set.
104     *
105     * @see #imageDecoder
106     *
107     * @param downsampler The downsampler.
108     * @return This request builder.
109     */
110    private BitmapRequestBuilder<ModelType, TranscodeType> downsample(Downsampler downsampler) {
111        this.downsampler = downsampler;
112        imageDecoder = new StreamBitmapDecoder(downsampler, bitmapPool, decodeFormat);
113        super.decoder(new ImageVideoBitmapDecoder(imageDecoder, videoDecoder));
114        return this;
115    }
116
117    /**
118     * {@inheritDoc}
119     */
120    @Override
121    public BitmapRequestBuilder<ModelType, TranscodeType> thumbnail(float sizeMultiplier) {
122        super.thumbnail(sizeMultiplier);
123        return this;
124    }
125
126    /**
127     * Loads and displays the {@link android.graphics.Bitmap} retrieved by the given thumbnail request if it finishes
128     * before this request. Best used for loading thumbnail {@link Bitmap}s that are smaller and will be loaded more
129     * quickly than the fullsize {@link Bitmap}. There are no guarantees about the order in which the requests will
130     * actually finish. However, if the thumb request completes after the full request, the thumb
131     * {@link android.graphics.Bitmap} will never replace the full image.
132     *
133     * @see #thumbnail(float)
134     *
135     * <p>
136     *     Note - Any options on the main request will not be passed on to the thumbnail request. For example, if
137     *     you want an animation to occur when either the full {@link android.graphics.Bitmap} loads or the thumbnail
138     *     loads, you need to call {@link #animate(int)} on both the thumb and the full request. For a simpler thumbnail
139     *     option where these options are applied to the humbnail as well, see {@link #thumbnail(float)}.
140     * </p>
141     *
142     * <p>
143     *     Only the thumbnail call on the main request will be obeyed, recursive calls to this method are ignored.
144     * </p>
145     *
146     * @param thumbnailRequest The request to use to load the thumbnail.
147     * @return This request builder.
148     */
149    public BitmapRequestBuilder<ModelType, TranscodeType> thumbnail(BitmapRequestBuilder<?, TranscodeType>
150            thumbnailRequest) {
151        super.thumbnail(thumbnailRequest);
152        return this;
153    }
154
155    /**
156     * {@inheritDoc}
157     */
158    @Override
159    public BitmapRequestBuilder<ModelType, TranscodeType> sizeMultiplier(float sizeMultiplier) {
160        super.sizeMultiplier(sizeMultiplier);
161        return this;
162    }
163
164    /**
165     * {@inheritDoc}
166     */
167    @Override
168    public BitmapRequestBuilder<ModelType, TranscodeType> decoder(ResourceDecoder<ImageVideoWrapper, Bitmap> decoder) {
169        super.decoder(decoder);
170        return this;
171    }
172
173    /**
174     * {@inheritDoc}
175     */
176    @Override
177    public BitmapRequestBuilder<ModelType, TranscodeType> cacheDecoder(ResourceDecoder<File, Bitmap> cacheDecoder) {
178        super.cacheDecoder(cacheDecoder);
179        return this;
180    }
181
182    /**
183     * {@inheritDoc}
184     */
185    @Override
186    public BitmapRequestBuilder<ModelType, TranscodeType> encoder(ResourceEncoder<Bitmap> encoder) {
187        super.encoder(encoder);
188        return this;
189    }
190
191    /**
192     * Sets the {@link com.bumptech.glide.load.ResourceDecoder} that will be used to decode {@link Bitmap}s obtained
193     * from an {@link java.io.InputStream}.
194     *
195     * @see #videoDecoder
196     *
197     * @param decoder The decoder to use to decode {@link Bitmap}s.
198     * @return This request builder.
199     */
200    public BitmapRequestBuilder<ModelType, TranscodeType> imageDecoder(ResourceDecoder<InputStream, Bitmap> decoder) {
201        imageDecoder = decoder;
202        super.decoder(new ImageVideoBitmapDecoder(decoder, videoDecoder));
203        return this;
204    }
205
206    /**
207     * Sets the {@link com.bumptech.glide.load.ResourceDecoder} that will be used to decode {@link Bitmap}s obtained
208     * from an {@link android.os.ParcelFileDescriptor}.
209     *
210     * @param decoder The decoder to use to decode {@link Bitmap}s.
211     * @return This request builder.
212     */
213    public BitmapRequestBuilder<ModelType, TranscodeType> videoDecoder(
214            ResourceDecoder<ParcelFileDescriptor, Bitmap> decoder) {
215        videoDecoder = decoder;
216        super.decoder(new ImageVideoBitmapDecoder(imageDecoder, decoder));
217        return this;
218    }
219
220    /**
221     * Sets the preferred format for {@link Bitmap}s decoded in this request. Defaults to
222     * {@link DecodeFormat#PREFER_RGB_565}. This replaces any previous calls to {@link #imageDecoder(ResourceDecoder)},
223     * {@link #videoDecoder(ResourceDecoder)}, {@link #decoder(ResourceDecoder)} and
224     * {@link #cacheDecoder(com.bumptech.glide.load.ResourceDecoder)}} with default decoders with the appropriate
225     * options set.
226     *
227     * <p>
228     *     Note - If using a {@link Transformation} that expect bitmaps to support transparency, this should always be
229     *     set to ALWAYS_ARGB_8888. RGB_565 requires fewer bytes per pixel and is generally preferable, but it does not
230     *     support transparency.
231     * </p>
232     *
233     * @see DecodeFormat
234     *
235     * @param format The format to use.
236     * @return This request builder.
237     */
238    public BitmapRequestBuilder<ModelType, TranscodeType> format(DecodeFormat format) {
239        this.decodeFormat = format;
240        imageDecoder = new StreamBitmapDecoder(downsampler, bitmapPool, format);
241        videoDecoder = new FileDescriptorBitmapDecoder(new VideoBitmapDecoder(), bitmapPool, format);
242        super.cacheDecoder(new FileToStreamDecoder<Bitmap>(new StreamBitmapDecoder(downsampler, bitmapPool, format)));
243        super.decoder(new ImageVideoBitmapDecoder(imageDecoder, videoDecoder));
244        return this;
245    }
246
247    @Override
248    public BitmapRequestBuilder<ModelType, TranscodeType> priority(Priority priority) {
249        super.priority(priority);
250        return this;
251    }
252
253    /**
254     * Transform images using the given {@link com.bumptech.glide.load.resource.bitmap.BitmapTransformation}s.
255     *
256     * @see #centerCrop()
257     * @see #fitCenter()
258     * @see #transform(com.bumptech.glide.load.Transformation[])
259     *
260     * @param transformations The transformations to apply in order.
261     * @return This request builder.
262     */
263    public BitmapRequestBuilder<ModelType, TranscodeType> transform(BitmapTransformation... transformations) {
264        super.transform(transformations);
265        return this;
266    }
267
268    /**
269     * Transform images using {@link com.bumptech.glide.load.resource.bitmap.CenterCrop}.
270     *
271     * @see #fitCenter()
272     * @see #transform(com.bumptech.glide.load.resource.bitmap.BitmapTransformation...)
273     * @see #transform(com.bumptech.glide.load.Transformation[])
274     *
275     * @return This request builder.
276     */
277    public BitmapRequestBuilder<ModelType, TranscodeType> centerCrop() {
278        return transform(glide.getBitmapCenterCrop());
279    }
280
281    /**
282     * Transform images using {@link com.bumptech.glide.load.resource.bitmap.FitCenter}.
283     *
284     * @see #centerCrop()
285     * @see #transform(com.bumptech.glide.load.resource.bitmap.BitmapTransformation...)
286     * @see #transform(com.bumptech.glide.load.Transformation[])
287     *
288     * @return This request builder.
289     */
290    public BitmapRequestBuilder<ModelType, TranscodeType> fitCenter() {
291        return transform(glide.getBitmapFitCenter());
292    }
293
294    /**
295     * {@inheritDoc}
296     *
297     * @see #fitCenter()
298     * @see #centerCrop()
299     */
300    @Override
301    public BitmapRequestBuilder<ModelType, TranscodeType> transform(Transformation<Bitmap>... transformations) {
302        super.transform(transformations);
303        return this;
304    }
305
306    /**
307     * {@inheritDoc}
308     */
309    @Override
310    public BitmapRequestBuilder<ModelType, TranscodeType> transcoder(
311            ResourceTranscoder<Bitmap, TranscodeType> transcoder) {
312        super.transcoder(transcoder);
313        return this;
314    }
315
316    /**
317     * {@inheritDoc}
318     */
319    @Override
320    public BitmapRequestBuilder<ModelType, TranscodeType> dontAnimate() {
321        super.dontAnimate();
322        return this;
323    }
324
325    /**
326     * {@inheritDoc}
327     */
328    @Override
329    public BitmapRequestBuilder<ModelType, TranscodeType> animate(int animationId) {
330        super.animate(animationId);
331        return this;
332    }
333
334    /**
335     * {@inheritDoc}
336     */
337    @Deprecated
338    @SuppressWarnings("deprecation")
339    @Override
340    public BitmapRequestBuilder<ModelType, TranscodeType> animate(Animation animation) {
341        super.animate(animation);
342        return this;
343    }
344
345    /**
346     * {@inheritDoc}
347     */
348    @Override
349    public BitmapRequestBuilder<ModelType, TranscodeType> animate(ViewPropertyAnimation.Animator animator) {
350        super.animate(animator);
351        return this;
352    }
353
354    /**
355     * {@inheritDoc}
356     */
357    @Override
358    public BitmapRequestBuilder<ModelType, TranscodeType> placeholder(int resourceId) {
359        super.placeholder(resourceId);
360        return this;
361    }
362
363    /**
364     * {@inheritDoc}
365     */
366    @Override
367    public BitmapRequestBuilder<ModelType, TranscodeType> placeholder(Drawable drawable) {
368        super.placeholder(drawable);
369        return this;
370    }
371
372    /**
373     * {@inheritDoc}
374     */
375    @Override
376    public BitmapRequestBuilder<ModelType, TranscodeType> error(int resourceId) {
377        super.error(resourceId);
378        return this;
379    }
380
381    /**
382     * {@inheritDoc}
383     */
384    @Override
385    public BitmapRequestBuilder<ModelType, TranscodeType> error(Drawable drawable) {
386        super.error(drawable);
387        return this;
388    }
389
390    /**
391     * {@inheritDoc}
392     */
393    @Override
394    public BitmapRequestBuilder<ModelType, TranscodeType> listener(
395            RequestListener<? super ModelType, TranscodeType> requestListener) {
396        super.listener(requestListener);
397        return this;
398    }
399
400    /**
401     * {@inheritDoc}
402     */
403    @Override
404    public BitmapRequestBuilder<ModelType, TranscodeType> skipMemoryCache(boolean skip) {
405        super.skipMemoryCache(skip);
406        return this;
407    }
408
409    /**
410     * {@inheritDoc}
411     */
412    @Override
413    public BitmapRequestBuilder<ModelType, TranscodeType> diskCacheStrategy(DiskCacheStrategy  strategy) {
414        super.diskCacheStrategy(strategy);
415        return this;
416    }
417
418    /**
419     * {@inheritDoc}
420     */
421    @Override
422    public BitmapRequestBuilder<ModelType, TranscodeType> override(int width, int height) {
423        super.override(width, height);
424        return this;
425    }
426
427    /**
428     * {@inheritDoc}
429     */
430    @Override
431    public BitmapRequestBuilder<ModelType, TranscodeType> thumbnail(
432            GenericRequestBuilder<?, ?, ?, TranscodeType> thumbnailRequest) {
433        super.thumbnail(thumbnailRequest);
434        return this;
435    }
436
437    /**
438     * {@inheritDoc}
439     */
440    @Override
441    public BitmapRequestBuilder<ModelType, TranscodeType> sourceEncoder(Encoder<ImageVideoWrapper> sourceEncoder) {
442        super.sourceEncoder(sourceEncoder);
443        return this;
444    }
445
446    /**
447     * {@inheritDoc}
448     */
449    @Override
450    public BitmapRequestBuilder<ModelType, TranscodeType> dontTransform() {
451        super.dontTransform();
452        return this;
453    }
454
455    @Override
456    public BitmapRequestBuilder<ModelType, TranscodeType> signature(Key signature) {
457        super.signature(signature);
458        return this;
459    }
460
461    @Override
462    public BitmapRequestBuilder<ModelType, TranscodeType> load(ModelType model) {
463        super.load(model);
464        return this;
465    }
466
467    @Override
468    public BitmapRequestBuilder<ModelType, TranscodeType> clone() {
469        return (BitmapRequestBuilder<ModelType, TranscodeType>) super.clone();
470    }
471
472    /**
473     * {@inheritDoc}
474     *
475     * <p>
476     *     Note - If no transformation is set for this load, a default transformation will be applied based on the
477     *     value returned from {@link android.widget.ImageView#getScaleType()}. To avoid this default transformation,
478     *     use {@link #dontTransform()}.
479     * </p>
480     *
481     * @param view {@inheritDoc}
482     * @return {@inheritDoc}
483     */
484    @Override
485    public Target<TranscodeType> into(ImageView view) {
486        return super.into(view);
487    }
488
489    @Override
490    void applyFitCenter() {
491        fitCenter();
492    }
493
494    @Override
495    void applyCenterCrop() {
496        centerCrop();
497    }
498}
499