如何为缩略图快速加载图像的低分辨率版本?或者简单地说,如何最好地创建缩略图?

时间:2013-11-18 23:17:30

标签: ios objective-c uiimageview uiimage nsdata

许多应用程序(如Tweetbot)在其表格视图控制器中显示缩略图,以获得更高分辨率的图像。

例如,此图像显示的缩略图在点按时会显示较大的图像:

enter image description here

但是,我很困惑这些图像是如何加载的。我的想法是加载原始图像,然后缩小到缩略图大小并显示。但是,我发现这很难相信,因为图像需要花费相当长的时间来以全分辨率加载/下载,所以对每个图像执行此操作只是为了缩小它看起来需要相当长的时间。但这些似乎很快就会加载。

我也持怀疑态度,因为当你再点击图像时,它会在显示全分辨率图像之前需要一秒钟才能加载,这让我觉得如果他们下载完整的分辨率之前它只是暂时缓存而且当用户点击它时立即加载。

所以我很好奇如何才能实现与此应用程序中类似的缩略图系统。给定图像的链接,例如上图中显示的图像,如何快速将图像显示在URL并将其显示为缩略图

9 个答案:

答案 0 :(得分:11)

通常有2个图像由服务器而不是客户端创建,服务器提供2个用于检索图像的URL,一个用于缩略图,一个用于完整res图像((这是90%的应用程序会发生什么)),所以你的UIImageView((或谁负责))应该加载缩略图,然后加载全分辨率图像,然后缓存后者,这样当你点击在它上面很快打开。现在有很多情况:

  • 服务器非常快速,你连接到快速wifi,因此应用程序可以快速加载图像
  • 图片尺寸不是很大,所以无论如何加载完整的图像都不需要时间,最终会在手机上显示。

如果你想实现你提到的,library可以帮助你。

答案 1 :(得分:10)

如果 要在设备上进行缩小(即服务器不提供较小的版本),您可能希望首先避免在内存中加载和充气全尺寸图像。 (现在大多数其他答案都在暗示这一点。)

相反,您可以使用CGImageSourceCreateThumbnailAtIndex方法直接从原始(压缩)数据创建缩略图,而无需先将其展开(通过将其包装在CGImageSource中)。您可以在Creating a Thumbnail Image from an Image Source下的Apple图像I / O编程指南中看到完整的示例。

对于小型源图像,这可能没有太大影响,但对于大型图像,它可以帮助很多,特别是对于内存消耗。

答案 2 :(得分:2)

每个应用程序可能有所不同。

在Tweetbot的情况下,他们几乎肯定从Twitter服务器获取缩略图并仅在点击缩略图时获取完整分辨率。所以在这个意义上,它只是一个不同的URL和Twitter正在进行缩略图。

应用也可以在本地进行。 Apple的照片应用程序和相机胶卷会在您拍摄照片后立即创建缩略图,并在本地缓存它们以显示在集合视图中以保留内存。只有当你点击它时它才能从内存加载全分辨率图像。甚至有证据和先例,他们甚至不加载全分辨率图像,只加载屏幕尺寸所需的图像,直到你捏缩放然后换成另一张图像。

基本上,有许多简单的技术可以快速谷歌显示实际缩放代码中的图像。但每个应用程序的方法都将特定于其独特的用户流程。

答案 3 :(得分:1)

很可能这些是通过调整原始全分辨率图像大小创建的单独图像(缩略图),然后与全分辨率图像分开保存 - 缩略图看起来非常快速加载的原因。我编写了一个类似的应用程序(虽然它在本地保存了缩略图和完整的res图像)。这是代码 -

-(void)setThumbnailDataFromImage:(UIImage *)image//image is full res image that you want a thumbnail of
{

    CGSize origImageSize = [image size];
    CGRect newRect = CGRectMake(0, 0, 50, 50);
    float ratio = MAX(newRect.size.width/origImageSize.width, newRect.size.height/origImageSize.height);
    UIGraphicsBeginImageContextWithOptions(newRect.size, NO, 0.0);
    //the following two lines round the edges of the thumbnail
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:newRect cornerRadius:5.0];

    [path addClip];
    CGRect projectRect;
    projectRect.size.width = ratio * origImageSize.width;
    projectRect.size.height = ratio * origImageSize.height;
    projectRect.origin.x =(newRect.size.width - projectRect.size.width)/2.0;
    projectRect.origin.y =(newRect.size.height-projectRect.size.height)/2.0;
    [image drawInRect:projectRect];
    UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
    if (thumbnailDataArray==nil) {
        thumbnailDataArray = [[NSMutableArray alloc]init];
    }
     NSData *data = UIImagePNGRepresentation(smallImage);
    if (thumbnail == nil) {

        [self setThumbnail:smallImage];
        [self setThumbnailData:data];
    }
    NSData *otherObject = UIImagePNGRepresentation(smallImage);

    [thumbnailDataArray addObject:otherObject];

    UIGraphicsEndImageContext();
}

然后加载缩略图

-(UIImage *)thumbnail
{
    if (!thumbnailData) {
        return nil;
    }
    if (!thumbnail) {
        thumbnail = [UIImage imageWithData:thumbnailData];
    }
    return thumbnail;
}

然后点击缩略图时,将加载完整的res图像

答案 4 :(得分:1)

  

所以我很好奇如何才能获得类似的缩略图   系统在这个应用程序中。给出图像的链接,例如显示的图像   在上图中,我如何快速地在URL处拍摄图像   并将其显示为缩略图?

我建议在您的应用中使用FilePicker

https://www.inkfilepicker.com/

所以说例如全尺寸图像存储在

https://www.filepicker.io/api/file/JhJKMtnRDW9uLYcnkRKW

您可以使用网址

调用裁剪版本
https://www.filepicker.io/api/file/JhJKMtnRDW9uLYcnkRKW/convert?crop=100,135,220,220

因此,您只需在代码中动态构建此URL,以满足您的需求。

以下是Filepicker网站缩略图的示例。 点击此处:https://www.inkfilepicker.com/products/javascript_v1/

enter image description here

答案 5 :(得分:0)

逻辑上,您应该在服务器上安装低分辨率版本,然后可以使用以下代码下载该版本以创建缩略图。更好的选择是在服务器上使用缩略图。

您可以使用以下代码创建纵横比较缩略图。

-(UIImage*)scaleImage:(UIImage *)orgImage toSize:(CGSize)size
{
    UIGraphicsBeginImageContext(size);
    [orgImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
    UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return scaledImage; 
}

- (UIImage *)fitImage:(UIImage *)orgImage toSize:(CGSize)size
{
    CGSize imageSize = orgImage.size;
    float widthRatio = (size.width/imageSize.width);
    float heightRatio = (size.height/imageSize.height);
    float factor = widthRatio < heightRatio ? widthRatio : heightRatio;
    if (factor > 1.0) {
       factor = 1.0;
    }

    CGSize newSize = CGSizeMake(imageSize.width * factor,
                            imageSize.height * factor);

    UIImage *img = [self scaleImage:orgImage toSize:newSize];

    return img;
}

调用fitImage:使用您想要生成的缩略图大小。

答案 6 :(得分:0)

1解决方案一些应用程序使用的是2个版本的图像1是高分辨率第二个是低分辨率缩略图..缩略图最初下载时用户点击缩略图图像它将低分辨率图像拉伸到大尺寸并开始在背景中下载高分辨率图像..一旦高分辨率图像下载完成,较低分辨率的缩略图将被图像视图中的高分辨率图像替换。

另一个解决方案是首先下载缩略图并在后台开始下载高分辨率图像,以便大多数时候当用户点击缩略图时,他可能会从内存中获得高分辨率的存储图像。

答案 7 :(得分:0)

因此,您可以轻松制作较小版本的大图像并对其进行缓存。有多种方法可以做到这一点。请注意,CGContextDrawImage(CGContextRef c, CGRect rect, CGImageRef image)会根据需要进行扩展。您不希望每次都进行实时缩放,因此您需要绘制到CGBitmapContext然后缓存它。

沿着这些方向,您可能会发现Path在他们最近发布的图书馆中为您完成了大部分繁重工作:https://github.com/path/FastImageCache

它看起来有可能来自文档(虽然我还没有查看过代码)。它似乎会调用您的块将图像绘制到缓存中。因此,他们指示的大小的简单绘制将减少它并将其保存到缓存中。

答案 8 :(得分:0)

使用FastImageCache。

https://github.com/path/FastImageCache

它的喔喔!快。

(显示缩略图一旦缓存,以便进行柔滑平滑的滚动,请注意。使初始缩略图显示得更快并不是特别神奇。在其他人指出的某个地方进行低分辨率预览是你的只有帮助。)