+(UIImage *)decodedAndScaledDownImageWithImage:(UIImage *)image limitBytes:(NSUInteger)bytes {#if SD_MACreturn image;#elseif(![self shouldDecodeImage:image]){return image;}if(![self shouldScaleDownImage:image limitBytes:bytes]){return[self decodedImageWithImage:image];}
CGFloat destTotalPixels;
CGFloat tileTotalPixels;if(bytes >0){
destTotalPixels = bytes / kBytesPerPixel;
tileTotalPixels = destTotalPixels /3;}else{
destTotalPixels = kDestTotalPixels;
tileTotalPixels = kTileTotalPixels;}
CGContextRef destContext;// autorelease the bitmap context and all vars to help system to free memory when there are memory warning.// on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory];@autoreleasepool {
CGImageRef sourceImageRef = image.CGImage;
CGSize sourceResolution = CGSizeZero;
sourceResolution.width =CGImageGetWidth(sourceImageRef);
sourceResolution.height =CGImageGetHeight(sourceImageRef);
CGFloat sourceTotalPixels = sourceResolution.width * sourceResolution.height;// Determine the scale ratio to apply to the input image// that results in an output image of the defined size.// see kDestImageSizeMB, and how it relates to destTotalPixels.
CGFloat imageScale =sqrt(destTotalPixels / sourceTotalPixels);
CGSize destResolution = CGSizeZero;
destResolution.width =(int)(sourceResolution.width * imageScale);
destResolution.height =(int)(sourceResolution.height * imageScale);// device color space
CGColorSpaceRef colorspaceRef =[self colorSpaceGetDeviceRGB];
BOOL hasAlpha =[self CGImageContainsAlpha:sourceImageRef];// iOS display alpha info (BGRA8888/BGRX8888)
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;// kCGImageAlphaNone is not supported in CGBitmapContextCreate.// Since the original image here has no alpha info, use kCGImageAlphaNoneSkipFirst// to create bitmap graphics contexts without alpha info.
destContext =CGBitmapContextCreate(NULL,
destResolution.width,
destResolution.height,
kBitsPerComponent,0,
colorspaceRef,
bitmapInfo);if(destContext ==NULL){return image;}CGContextSetInterpolationQuality(destContext, kCGInterpolationHigh);// Now define the size of the rectangle to be used for the// incremental blits from the input image to the output image.// we use a source tile width equal to the width of the source// image due to the way that iOS retrieves image data from disk.// iOS must decode an image from disk in full width 'bands', even// if current graphics context is clipped to a subrect within that// band. Therefore we fully utilize all of the pixel data that results// from a decoding opertion by achnoring our tile size to the full// width of the input image.
CGRect sourceTile = CGRectZero;
sourceTile.size.width = sourceResolution.width;// The source tile height is dynamic. Since we specified the size// of the source tile in MB, see how many rows of pixels high it// can be given the input image width.
sourceTile.size.height =(int)(tileTotalPixels / sourceTile.size.width );//added by yyhif(tileTotalPixels < sourceTile.size.width){
sourceTile.size.height =1;}
sourceTile.origin.x =0.0f;// The output tile is the same proportions as the input tile, but// scaled to image scale.
CGRect destTile;
destTile.size.width = destResolution.width;
destTile.size.height = sourceTile.size.height * imageScale;
destTile.origin.x =0.0f;// The source seem overlap is proportionate to the destination seem overlap.// this is the amount of pixels to overlap each tile as we assemble the ouput image.float sourceSeemOverlap =(int)((kDestSeemOverlap/destResolution.height)*sourceResolution.height);
CGImageRef sourceTileImageRef;// calculate the number of read/write operations required to assemble the// output image.int iterations =(int)( sourceResolution.height / sourceTile.size.height );// If tile height doesn't divide the image height evenly, add another iteration// to account for the remaining pixels.int remainder =(int)sourceResolution.height %(int)sourceTile.size.height;if(remainder){
iterations++;}// Add seem overlaps to the tiles, but save the original tile height for y coordinate calculations.float sourceTileHeightMinusOverlap = sourceTile.size.height;
sourceTile.size.height += sourceSeemOverlap;
destTile.size.height += kDestSeemOverlap;for(int y =0; y < iterations;++y ){@autoreleasepool {
sourceTile.origin.y = y * sourceTileHeightMinusOverlap + sourceSeemOverlap;
destTile.origin.y = destResolution.height -(( y +1)* sourceTileHeightMinusOverlap * imageScale + kDestSeemOverlap);
sourceTileImageRef =CGImageCreateWithImageInRect( sourceImageRef, sourceTile );if( y == iterations -1&& remainder ){float dify = destTile.size.height;
destTile.size.height =CGImageGetHeight( sourceTileImageRef )* imageScale;
dify -= destTile.size.height;
destTile.origin.y += dify;}CGContextDrawImage( destContext, destTile, sourceTileImageRef );CGImageRelease( sourceTileImageRef );}}
CGImageRef destImageRef =CGBitmapContextCreateImage(destContext);CGContextRelease(destContext);if(destImageRef ==NULL){return image;}
UIImage *destImage =[[UIImage alloc] initWithCGImage:destImageRef scale:image.scale orientation:image.imageOrientation];CGImageRelease(destImageRef);if(destImage == nil){return image;}
destImage.sd_isDecoded = YES;
destImage.sd_imageFormat = image.sd_imageFormat;return destImage;}#endif}