图片压缩问题

    xiaoxiao2021-03-25  127

    最近做论坛功能,发帖的时候需要用到从相册中选取图片然后上传,由于每次上传图片的最大数量为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;

    }

    采用上面的方法之后内存占用率很低!

    转载请注明原文地址: https://ju.6miu.com/read-19875.html

    最新回复(0)