在 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
将获得完整版,并致电largeThumbImageFromPath
largeThumbImageFromPath
将获得大拇指并致电smallThumbImageFromPath
smallThumbImageFromPath
只会得到小拇指
这些方法调用包装在可取消的 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 中显示隔行(逐行)图像的主要内容,如果未能解决你的问题,请参考以下文章