圖片壓縮問題

最近做論壇功能,發帖的時候需要用到從相冊中選取圖片然後上傳,由於每次上傳圖片的最大數量爲9張,所以需要對圖片進行壓縮。開始時用了以前經常用的壓縮的方法:

[objc] view plain copy

//壓縮圖片質量

+(UIImage *)reduceImage:(UIImage *)image percent:(float)percent

{

    NSData *imageData = UIImageJPEGRepresentation(image, percent);

    UIImage *newImage = [UIImage imageWithData:imageData];

    return newImage;

}

//壓縮成指定大小

+ (UIImage*)imageWithImageSimple:(UIImage*)image scaledToSize:(CGSize)newSize

{

    // Create a graphics image context

    UIGraphicsBeginImageContext(newSize);

    // new size

    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];

    // Get the new image from the context

    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();

    

    // End the context

    UIGraphicsEndImageContext();

    // Return the new image.

    return newImage;

}

//等比壓縮

- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize

{

    UIImage *sourceImage = self;

    UIImage *newImage = nil;

    CGSize imageSize = sourceImage.size;

    CGFloat width = imageSize.width;

    CGFloat height = imageSize.height;

    CGFloat targetWidth = targetSize.width;

    CGFloat targetHeight = targetSize.height;

    CGFloat scaleFactor = 0.0;

    CGFloat scaledWidth = targetWidth;

    CGFloat scaledHeight = targetHeight;

    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

    

    if (CGSizeEqualToSize(imageSize, targetSize) == NO)

    {

        CGFloat widthFactor = targetWidth / width;

        CGFloat heightFactor = targetHeight / height;

        

        if (widthFactor > heightFactor)

            scaleFactor = widthFactor; // scale to fit height

        else

            scaleFactor = heightFactor; // scale to fit width

        scaledWidth  = width * scaleFactor;

        scaledHeight = height * scaleFactor;

        

        // center the image

        if (widthFactor > heightFactor)

        {

            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;

        }

        else

            if (widthFactor < heightFactor)

            {

                thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;

            }

    }

    

    UIGraphicsBeginImageContext(targetSize); // this will crop

    

    CGRect thumbnailRect = CGRectZero;

    thumbnailRect.origin = thumbnailPoint;

    thumbnailRect.size.width  = scaledWidth;

    thumbnailRect.size.height = scaledHeight;

    

    [sourceImage drawInRect:thumbnailRect];

    

    newImage = UIGraphicsGetImageFromCurrentImageContext();

    if(newImage == nil)

        NSLog(@"could not scale image");

        

        //pop the context to get back to the default

        UIGraphicsEndImageContext();

        return newImage;

}


@end



上面的方法比較常見,可是需要加載到內存中來處理圖片,當圖片數量多了的時候就會收到內存警告,程序崩潰。研究半天終於在一篇博客中找到了解決方法:

[objc] view plain copy

static size_t getAssetBytesCallback(voidvoid *info, voidvoid *buffer, off_t position, size_t count) {

    ALAssetRepresentation *rep = (__bridge id)info;

    

    NSError *error = nil;

    size_t countRead = [rep getBytes:(uint8_t *)buffer fromOffset:position length:count error:&error];

    

    if (countRead == 0 && error) {

        // We have no way of passing this info back to the caller, so we log it, at least.

        NDDebug(@"thumbnailForAsset:maxPixelSize: got an error reading an asset: %@", error);

    }

    

    return countRead;

}


static void releaseAssetCallback(voidvoid *info) {

    // The info here is an ALAssetRepresentation which we CFRetain in thumbnailForAsset:maxPixelSize:.

    // This release balances that retain.

    CFRelease(info);

}


// Returns a UIImage for the given asset, with size length at most the passed size.

// The resulting UIImage will be already rotated to UIImageOrientationUp, so its CGImageRef

// can be used directly without additional rotation handling.

// This is done synchronously, so you should call this method on a background queue/thread.

- (UIImage *)thumbnailForAsset:(ALAsset *)asset maxPixelSize:(NSUInteger)size {

    NSParameterAssert(asset != nil);

    NSParameterAssert(size > 0);

    

    ALAssetRepresentation *rep = [asset defaultRepresentation];

    

    CGDataProviderDirectCallbacks callbacks = {

        .version = 0,

        .getBytePointer = NULL,

        .releaseBytePointer = NULL,

        .getBytesAtPosition = getAssetBytesCallback,

        .releaseInfo = releaseAssetCallback,

    };

    

    CGDataProviderRef provider = CGDataProviderCreateDirect((voidvoid *)CFBridgingRetain(rep), [rep size], &callbacks);

    CGImageSourceRef source = CGImageSourceCreateWithDataProvider(provider, NULL);

    

    CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(source, 0, (__bridge CFDictionaryRef) @{

                                                                                                      (NSString *)kCGImageSourceCreateThumbnailFromImageAlways : @YES,

                                                                                                      (NSString *)kCGImageSourceThumbnailMaxPixelSize : [NSNumber numberWithInt:size],

                                                                                                      (NSString *)kCGImageSourceCreateThumbnailWithTransform : @YES,

                                                                                                      });

    CFRelease(source);

    CFRelease(provider);

    

    if (!imageRef) {

        return nil;

    }

    

    UIImage *toReturn = [UIImage imageWithCGImage:imageRef];

    

    CFRelease(imageRef);

    

    return toReturn;

}


採用上面的方法之後內存佔用率很低!


發佈了40 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章