在 UIImageView 中显示隔行(逐行)图像

Posted

技术标签:

【中文标题】在 UIImageView 中显示隔行(逐行)图像【英文标题】:Displaying interlaced (progressive) Image in UIImageView 【发布时间】:2013-12-15 15:16:22 【问题描述】:

我正在尝试使用部分数据在下载时显示 JPEG 图像,类似于许多网络浏览器或 facebook 应用程序。

有一个低质量版本的图像(只是数据的一部分),然后以全质量显示完整的图像。

这在VIDEO HERE中得到了最好的体现

我关注了这个 SO 问题:

How do I display a progressive JPEG in an UIImageView while it is being downloaded?

但我得到的只是一个图像视图,它随着数据的进入而被渲染,首先没有低质量版本,没有真正的渐进式下载和渲染。

谁能分享一个代码 sn-p 或指出我在哪里可以找到有关如何在 ios 应用中实现此功能的更多信息?

例如尝试显示 JPEG 信息的链接,它将图像识别为渐进式

http://www.webpagetest.org/jpeginfo/jpeginfo.php?url=http://cetus.sakura.ne.jp/softlab/software/spibench/pic_22p.jpg

我使用了正确的代码序列

-(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data

    /// Append the data
    [_dataTemp appendData:data];

    /// Get the total bytes downloaded
    const NSUInteger totalSize = [_dataTemp length];
    /// Update the data source, we must pass ALL the data, not just the new bytes
    CGImageSourceUpdateData(_imageSource, (CFDataRef)_dataTemp, (totalSize == _expectedSize) ? true : false);

    /// We know the expected size of the image
    if (_fullHeight > 0 && _fullWidth > 0)
    
            [_imageView setImage:[UIImage imageWithCGImage:image]];
            CGImageRelease(image);
    

但代码只在加载完成时显示图像,其他图像在下载时会显示,但只是从上到下,没有低质量版本,然后像浏览器一样逐步添加细节。

DEMO PROJECT HERE

【问题讨论】:

【参考方案1】:

这是我有一段时间感兴趣的话题:似乎没有办法使用 Apple 的 API 做你想做的事,但如果你能在这方面投入时间,你可能会成功。

首先,您需要一个 JPEG 解码库:libjpeg 或 libjpeg-turbo。然后,您需要将它集成到您​​可以与 Objective-C 一起使用的东西中。有一个使用这个库的开源项目PhotoScrollerNetwork,它利用 turbo 库在下载时“即时”解码非常大的 jpeg,因此可以平移和缩放它们(PhotoScroller 是一个 Apple 项目平移和缩放,但它需要预先平铺的图像)。

虽然上述项目并不完全符合您的要求,但您应该能够解除大部分 libjpeg-turbo 接口来解码渐进式图像并在收到低质量图像时返回它们。看起来您的图像非常大,否则几乎不需要渐进式图像,因此您可能会发现上述使用项目的平移/缩放功能。

PhotoScrollerNetwork 的一些用户要求支持渐进式图像,但在网络上似乎很少使用它们。

编辑:第二个想法:如果您将使用您的网站来出售渐进式图像(我假设这是因为通常可以找到的图像很少),您可以采取完全不同的策略。

在这种情况下,您将构建一个您自己设计的二进制文件——其中包含 4 个图像。前四个字节将提供其后数据的长度(每个后续图像将使用相同的 4 字节前缀)。然后,在 iOS 端,随着下载的开始,一旦你获得了第一张图片的完整字节,你可以使用这些来构建一个小的低分辨率 UIImage,并在接收下一张图片时显示它。当下一个完全到达时,您将使用较新的高分辨率图像更新低分辨率图像。有可能您可以使用 zip 容器并进行动态解压缩 - 不是 100% 确定的。在任何情况下,以上都是您问题的标准解决方案,并且可以为 libjpeg 提供几乎相同的性能,而且工作量要少得多。

【讨论】:

谢谢,我正在寻找一个现成的解决方案,而不是去开发另一个子任务。我真的希望那里已经准备好了一些东西,我的意思是,网络浏览器已经使用它多年,Facebook 等移动应用程序也在使用它...... 我会在几年前提供基于调制解调器的下载,渐进式图像看起来很有希望。然而,现在“在野外”似乎很少发现。 PNS 的一位用户要求使用该功能,但随后甚至无法显示一个托管主要是渐进式 jpg 的网站。你知道一个吗?【参考方案2】:

我已经为我目前正在开发的应用程序实施了渐进式加载解决方案。它不使用渐进式 Jpeg,因为我需要更大的灵活性来加载不同分辨率的版本,但我得到了相同的结果(而且效果非常好,绝对值得实施)。

这是一个与服务器协同工作的相机应用。因此,图像源自 iPhone 的摄像头并被远程存储。当服务器获取图像时,它会被处理(使用 imageMagick,但可以是任何合适的库)并以 3 种尺寸存储 - 小拇指(~160 x 120)、大拇指(~400x300)和全尺寸(~双视网膜屏幕尺寸)。目标设备是视网膜 iPhone。

我有一个 ImageStore 类,它负责从它们碰巧在的任何地方异步加载图像,首先尝试最快的位置(实时缓存、本地文件系统缓存、资产库、网络服务器)。

  typedef void (^RetrieveImage)(UIImage *image);

- (void)  fullsizeImageFromPath:(NSString*)path
                             completion:(RetrieveImage)completionBlock;
- (void)largeThumbImageFromPath:(NSString*)path
                             completion:(RetrieveImage)completionBlock;
- (void)smallThumbImageFromPath:(NSString*)path
                             completion:(RetrieveImage)completionBlock;

这些方法中的每一个也将尝试加载较低分辨率的版本。完成块实际上将图像加载到它的 imageView 中。

因此fullsizeImageFromPath 将获得完整版,并致电largeThumbImageFromPathlargeThumbImageFromPath 将获得大拇指并致电smallThumbImageFromPathsmallThumbImageFromPath 只会得到小拇指

这些方法调用包装在可取消的 NSOperations 中的调用。如果较大分辨率版本在其任何较低分辨率兄弟姐妹之前到达,则这些相应的较低分辨率调用将被取消。最终结果是fullsizeImageFromPath可能最终应用小拇指,然后是大拇指,最后将全分辨率图像应用到单个 imageView,具体取决于哪个先到达。结果真的很顺利。

这是gist showing the basic idea

这可能不适合您,因为您可能无法控制进程的服务器端。在我实现这个之前,我一直在追求 David H 描述的解决方案。一旦我意识到自己也需要访问低分辨率图像本身,这将是更多的工作,而且用处不大。

解释了另一种可能更接近您的要求的方法here

这已经演变成NYXProgressiveImageView,它是作为NYXImagesKit 的一部分分发的 UIImageView 的子类

最后...对于一个真正 hacky 的解决方案,您可以使用 UIWebView 来显示渐进式 PNG(似乎不支持渐进式 JPeg)。

更新

在推荐NYXProgressiveImageView之后,我意识到这就是你一直在使用的。不幸的是,你在原来的帖子中没有提到这一点,所以我觉得我有点跑题了。其实再看你的帖子,我觉得你有点不诚实。从您帖子的文字来看,“DEMO”似乎是您创建的项目。实际上不是你创建的,是从这里复制的:

http://cocoaintheshell.com/2011/05/progressive-images-download-imageio/ProgressiveImageDownload.zip

伴随着来自 cocoaintheshell 的 this blog entry 您所做的唯一更改是一个 NSLog 行,并更改了 JPG 测试 URL。 您发布的代码 sn-p 不是您的,它是从该项目复制的,没有署名。如果你在帖子中提到了这一点,那会为我节省一大堆时间。

不管怎样,回到帖子上……当您使用此代码时,您可能应该使用当前版本,该版本位于 github:

https://github.com/Nyx0uf/NYXImagesKit

另见this blog entry

为了让您的生活更简单,您只需要项目中的这些文件:

NYXProgressiveImageView.h
NYXProgressiveImageView.m
NYXImagesHelper.h
NYXImagesHelper.m

接下来,您需要确保使用 GOOD 图像进行测试

例如,这个PNG效果很好:

http://www.libpng.org/pub/png/img_png/pnglogo-grr.png

你还需要注意这个神秘的评论:

/// Note: Progressive JPEG are not supported see #32

JPEG tempImage 渲染似乎存在问题,我无法解决 - 也许您可以。这就是为什么你的“Demo”无论如何都不能正常工作的原因。

更新 2 已添加gist

【讨论】:

您好,感谢您的广泛回复,至于您的评论,我很抱歉没有说清楚,但请注意,我没有写它是我的代码,只是这是我找到的一个演示项目这应该有助于说明我遇到的问题。将检查您的链接。在没有找到完整解决方案的情况下关闭这个赏金我有点沮丧,但也许正如大卫所说,没有可用的。 我会在你和大卫之间分配赏金,但我不允许这样做..你能分享你的客户端代码实现吗? @MosheMarciano - 我的实现的完整代码过于详细,并且特定于我正在开发的应用程序。我将尝试简化本质,如果我认为有道理,可能稍后再将其发布在这里。但它对您有用还是需要渐进式 Jpeg 解码器(我的解决方案使用三个单独的 rez 图像,而不是 progressive Jpeg)? @MosheMarciano,请参阅我的要点here - 我已尝试将其缩减为仅显示必需品;-j 谢谢,我不知道能不能按原样使用,因为我真的需要渐进式下载,我得试试看【参考方案3】:

我相信这就是您正在寻找的:

https://github.com/contentful-labs/Concorde

一个用于在 iOS 和 OS X 上下载和解码渐进式 JPEG 的框架,它使用 libjpeg-turbo 作为底层 JPEG 实现。

【讨论】:

【参考方案4】:

试试吧,可能对你有用:

https://github.com/path/FastImageCache

https://github.com/rs/SDWebImage

【讨论】:

这些都是不错的库,但没有一个能像网络浏览器或 facebook 应用那样处理渐进式质量下载。我错了吗? @MosheMarciano 你是对的,他们是基线,而不是进步【参考方案5】:

我有同样的问题,然后我发现了一些棘手的问题,它不是正确的解决方案,但它可以工作。

您必须在加载时加载低分辨率/缩略图图像然后加载 实际图像。

This is example 安卓版希望你能转成ios版。

【讨论】:

以上是关于在 UIImageView 中显示隔行(逐行)图像的主要内容,如果未能解决你的问题,请参考以下文章

播放图像有锯齿_反隔行操作

Progressive Scanning (逐行扫描) vs Interlaced Scanning (隔行扫描)

gifjpegpng的区别

FPGA VGA时序的理解

计算机硬件-显卡

为啥图像路径中的图像不显示在 UIImageView 中?