/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.react.views.imagehelper; import javax.annotation.Nullable; import java.util.List; import com.facebook.imagepipeline.core.ImagePipeline; import com.facebook.imagepipeline.core.ImagePipelineFactory; import com.facebook.react.views.imagehelper.ImageSource; /** * Helper class for dealing with multisource images. */ public class MultiSourceHelper { public static class MultiSourceResult { private final @Nullable ImageSource bestResult; private final @Nullable ImageSource bestResultInCache; private MultiSourceResult( @Nullable ImageSource bestResult, @Nullable ImageSource bestResultInCache) { this.bestResult = bestResult; this.bestResultInCache = bestResultInCache; } /** * Get the best result overall (closest in size to the view's size). Can be null if there were * no sources to choose from, or if there were more than 1 sources but width/height were 0. */ public @Nullable ImageSource getBestResult() { return bestResult; } /** * Get the best result (closest in size to the view's size) that is also in cache. If this would * be the same as the source from {@link #getBestResult()}, this will return {@code null} * instead. */ public @Nullable ImageSource getBestResultInCache() { return bestResultInCache; } } public static MultiSourceResult getBestSourceForSize( int width, int height, List<ImageSource> sources) { return getBestSourceForSize(width, height, sources, 1.0d); } /** * Chooses the image source with the size closest to the target image size. * * @param width the width of the view that will be used to display this image * @param height the height of the view that will be used to display this image * @param sources the list of potential image sources to choose from * @param multiplier the area of the view will be multiplied by this number before calculating the * best source; this is useful if the image will be displayed bigger than the view * (e.g. zoomed) */ public static MultiSourceResult getBestSourceForSize( int width, int height, List<ImageSource> sources, double multiplier) { // no sources if (sources.isEmpty()) { return new MultiSourceResult(null, null); } // single source if (sources.size() == 1) { return new MultiSourceResult(sources.get(0), null); } // For multiple sources, we first need the view's size in order to determine the best source to // load. If we haven't been measured yet, return null and wait for onSizeChanged. if (width <= 0 || height <= 0) { return new MultiSourceResult(null, null); } ImagePipeline imagePipeline = ImagePipelineFactory.getInstance().getImagePipeline(); ImageSource best = null; ImageSource bestCached = null; final double viewArea = width * height * multiplier; double bestPrecision = Double.MAX_VALUE; double bestCachePrecision = Double.MAX_VALUE; for (ImageSource source : sources) { double precision = Math.abs(1.0 - source.getSize() / viewArea); if (precision < bestPrecision) { bestPrecision = precision; best = source; } if (precision < bestCachePrecision && (imagePipeline.isInBitmapMemoryCache(source.getUri()) || imagePipeline.isInDiskCacheSync(source.getUri()))) { bestCachePrecision = precision; bestCached = source; } } if (bestCached != null && best != null && bestCached.getSource().equals(best.getSource())) { bestCached = null; } return new MultiSourceResult(best, bestCached); } }