Created
June 30, 2016 08:20
-
-
Save s1rius/0230994835320e68e9c9aa1b8fd24ad7 to your computer and use it in GitHub Desktop.
Fresco
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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.imagepipeline.producers; | |
import com.facebook.common.internal.Preconditions; | |
import com.facebook.common.internal.VisibleForTesting; | |
import com.facebook.common.logging.FLog; | |
import com.facebook.imageformat.ImageFormat; | |
import com.facebook.imagepipeline.image.EncodedImage; | |
import com.facebook.imagepipeline.common.ResizeOptions; | |
import com.facebook.imagepipeline.request.ImageRequest; | |
public class DownsampleUtil { | |
private static final float MAX_BITMAP_SIZE = 2048f; | |
private static final float MAX_JPEG_BITMAP_SIZE = 4096f; | |
private static final float INTERVAL_ROUNDING = 1.0f/3; | |
private static final int DEFAULT_SAMPLE_SIZE = 1; | |
private DownsampleUtil() {} | |
/** | |
* Get the factor between the dimensions of the encodedImage (actual image) and the ones of the | |
* imageRequest (requested size). | |
* | |
* @param imageRequest the request containing the requested dimensions | |
* @param encodedImage the encoded image with the actual dimensions | |
* @return | |
*/ | |
public static int determineSampleSize(ImageRequest imageRequest, EncodedImage encodedImage) { | |
if (!EncodedImage.isMetaDataAvailable(encodedImage)) { | |
return DEFAULT_SAMPLE_SIZE; | |
} | |
float ratio = determineDownsampleRatio(imageRequest, encodedImage); | |
int sampleSize; | |
if (encodedImage.getImageFormat() == ImageFormat.JPEG) { | |
sampleSize = ratioToSampleSizeJPEG(ratio); | |
} else { | |
sampleSize = ratioToSampleSize(ratio); | |
} | |
// Check the case when the dimension of the downsampled image is still larger than the max | |
// possible dimension for an image. | |
int maxDimension = Math.max(encodedImage.getHeight(), encodedImage.getWidth()); | |
// Make the bitmap not allocate more memory, special with JPEG | |
// TODO to prevent that the newwork image no so small, cant show detail | |
// 为了确保网络上长条形的长微博图片能够正确的显示,降低JPEG图片的压缩比例 | |
// TODO will fix int future | |
if (encodedImage.getImageFormat() == ImageFormat.JPEG) { | |
while (maxDimension / sampleSize > MAX_JPEG_BITMAP_SIZE) { | |
sampleSize++; | |
} | |
} else { | |
while (maxDimension / sampleSize > MAX_BITMAP_SIZE) { | |
sampleSize++; | |
} | |
} | |
return sampleSize; | |
} | |
@VisibleForTesting | |
static float determineDownsampleRatio( | |
ImageRequest imageRequest, EncodedImage encodedImage) { | |
Preconditions.checkArgument(EncodedImage.isMetaDataAvailable(encodedImage)); | |
final ResizeOptions resizeOptions = imageRequest.getResizeOptions(); | |
if (resizeOptions == null || resizeOptions.height <= 0 || resizeOptions.width <= 0 | |
|| encodedImage.getWidth() == 0 || encodedImage.getHeight() == 0) { | |
return 1.0f; | |
} | |
final int rotationAngle = getRotationAngle(imageRequest, encodedImage); | |
final boolean swapDimensions = rotationAngle == 90 || rotationAngle == 270; | |
final int widthAfterRotation = swapDimensions ? | |
encodedImage.getHeight() : encodedImage.getWidth(); | |
final int heightAfterRotation = swapDimensions ? | |
encodedImage.getWidth() : encodedImage.getHeight(); | |
final float widthRatio = ((float) resizeOptions.width) / widthAfterRotation; | |
final float heightRatio = ((float) resizeOptions.height) / heightAfterRotation; | |
float ratio = Math.max(widthRatio, heightRatio); | |
FLog.v( | |
"DownsampleUtil", | |
"Downsample - Specified size: %dx%d, image size: %dx%d " + | |
"ratio: %.1f x %.1f, ratio: %.3f for %s", | |
resizeOptions.width, | |
resizeOptions.height, | |
widthAfterRotation, | |
heightAfterRotation, | |
widthRatio, | |
heightRatio, | |
ratio, | |
imageRequest.getSourceUri().toString()); | |
return ratio; | |
} | |
@VisibleForTesting | |
static int ratioToSampleSize(float ratio) { | |
if (ratio > 0.5f + 0.5f * INTERVAL_ROUNDING) { | |
return 1; // should have resized | |
} | |
int sampleSize = 1; | |
while (true) { | |
double intervalLength = 1.0 / (Math.pow(sampleSize, 2) - sampleSize); | |
double compare = (1.0 / sampleSize) + (intervalLength * INTERVAL_ROUNDING); | |
if (compare <= ratio) { | |
return sampleSize - 1; | |
} | |
sampleSize++; | |
} | |
} | |
@VisibleForTesting | |
static int ratioToSampleSizeJPEG(float ratio) { | |
if (ratio > 0.5f + 0.5f * INTERVAL_ROUNDING) { | |
return 1; // should have resized | |
} | |
int sampleSize = 1; | |
while (true) { | |
double intervalLength = 1.0 / (sampleSize + 1); | |
double compare = (1.0 / (2 * sampleSize)) + (intervalLength * INTERVAL_ROUNDING); | |
if (compare <= ratio) { | |
return sampleSize; | |
} | |
sampleSize++; | |
} | |
} | |
private static int getRotationAngle(ImageRequest imageRequest, EncodedImage encodedImage) { | |
if (!imageRequest.getAutoRotateEnabled()) { | |
return 0; | |
} | |
int rotationAngle = encodedImage.getRotationAngle(); | |
Preconditions.checkArgument(rotationAngle == 0 || rotationAngle == 90 | |
|| rotationAngle == 180 || rotationAngle == 270); | |
return rotationAngle; | |
} | |
@VisibleForTesting | |
static int roundToPowerOfTwo(int sampleSize) { | |
int compare = 1; | |
while (true) { | |
if (compare >= sampleSize) { | |
return compare; | |
} | |
compare++; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment