HTML5 iPhone动态缓存图像

8
我们正在为iPhone构建离线工作的Web应用程序。但我们在缓存动态图片方面遇到了困难。请继续阅读,我将通过实例准确地展示我的意思以及我们迄今为止所做的事情。
例如,让我们说我们正在构建一个简单的列表应用程序,只有1个页面。该应用程序的唯一目的是列出5个项目,每个项目包含一些文本和1个图像。
该应用程序具有简单的标志、一些独立的JavaScript和CSS代码。这些静态资源使用缓存清单文件进行缓存。
有2种情况:
情况1:我在线并打开Web应用程序
当我在Safari中加载列表应用程序时,它会从包含数千个项的数据库中获取5个新的随机项。所有这些都是通过AJAX调用(JSON格式)由简单的后端提供的。
整个包含5个项目的JSON对象立即存储在HTML5本地存储中,并缓存以供离线使用。
JSON对象的结构有点像这样:
{
    "0" : {
        id: "3",
        text: "Some text about item #3",
        image_url: "http://www.domain.com/image22341.png"
    },
    "1" : {
        id: "23",
        text: "Some text about item #23",
        image_url: "http://www.domain.com/image442321.png"
    },
    "2" : {
        id: "4",
        text: "Some text about item #4",
        image_url: "http://www.domain.com/image2321.png"
    },
    "3" : {
        id: "432",
        text: "Some text about item #432",
        image_url: "http://www.domain.com/image2441.png"
    },
    "4" : {
        id: "43",
        text: "Some text about item #43",
        image_url: "http://www.domain.com/image221.png"
    }
}

如您所见,非常简单(JSON 中可能存在一些错误),整个 JSON 对象存储在本地存储中。现在,使用 JavaScript 注入的 HTML 渲染 5 个项目(使用 CSS 进行样式设置),没有什么花哨的东西。创建包含文本的 span 标签和指向图像资源的 image 标签等。在线模式下,一切都很顺利。第二种情况:我离线并打开 Web 应用程序。页面加载(显示标志,因为其作为静态资源使用缓存清单进行了缓存),一些 JavaScript 检测到我们确实离线,并且应用程序因此不会尝试联系后端。而是从本地存储中读取先前存储的 JSON 对象并开始渲染 5 个项目。所有都符合预期。文本显示得很好,但是这次,图像没有显示,原因很简单,图像标签指向不可用的图像资源。因此,它显示了那个小图像不可用图标。现在我的问题是,有没有办法以某种方式缓存这些图像资源?这是我尝试过的:对图像进行 Base64 编码并通过 JSON 提供它们。这有效,但它会大大增加获取和呈现时间(我们谈论的是增加 30 秒,非常慢)。一些缓存清单黑客/试错。。找不到任何有效的东西(理想情况下需要一个策略,即'当它们被请求时,缓存域上的所有资源',但据我所知,这种策略不存在)。我已经花了几个小时在这上面,找不到解决办法...有人有线索吗?我知道这是可能的,因为如果您查看 iPhone 的 Google Mail HTML5 应用程序,它们可以以某种方式缓存附件,即使在离线状态下也可以检索它们。我们没有尝试过的一件事是使用 Safari 支持的 SQLite 数据库...也许我可以将图像作为 BLOB 存储(仍然意味着从 feed 中获取它,因此很慢?)然后在屏幕上以某种神奇的方式将其转换为图像....但我不知道如何做到这一点。感谢任何帮助。
2个回答

2

这里有一段代码,可以从AJAX下载图像并将其转换为base64字符串。使用此字符串,您可以将其保存到本地存储中,并将其分配给离线的src属性。

function _arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
}


var xhr = new XMLHttpRequest();
xhr.open('GET', 'an_image.png', true);
xhr.responseType = 'arraybuffer';

xhr.onload = function(e) {
        if (this.status == 200) {
          var string_with_bas64_image = _arrayBufferToBase64(this.response);

          // You can save this string to local storag or set it to an img elemment this way

          document.getElementById("img").src = "data:image/png;base64," + string_with_bas64_image;
        }
};

xhr.send();

你可以在这里测试:http://jsbin.com/ivifiy/1/edit 通过这种技术,你可以编写一个localStorage缓存。
_arrayBufferToBase64是从这里提取的: ArrayBuffer转换为base64编码字符串

三年前主要的网络浏览器中并不存在 Uint8Array,但对于现代的网络浏览器来说它是一个不错的解决方案 :) - Waleed Amjad

1
我建议您查看一下是否可以使用画布来容纳您的图像,因为它们具有某些属性来获取/插入图像像素数据,例如像素值(0-255)的CSV。
来源:https://developer.apple.com/library/content/documentation/AudioVideo/Conceptual/HTML-canvas-guide/PixelManipulation/PixelManipulation.html 我不确定您是否可以动态地将图像源用于画布,但如果可以,您应该能够将CSVV数据从图像传输到数据库,反之亦然。
引用

Safari 4.0及更高版本支持直接操作画布的像素。您可以使用getImageData()函数获取画布的原始像素数据,并使用createImageData()函数创建一个新的缓冲区以处理像素。

存档网站上的来源

更新:

我找到了这些链接,你可能也会感兴趣。

http://wecreategames.com/blog/?p=210

http://wecreategames.com/blog/?p=219 //还要注意使用画布序列化的想法 :)


谢谢您的回复 - 您提出了一个我没有考虑到的好观点。我熟悉画布元素,所以我应该很快就能尝试这个方法。现在让我们希望多个画布在iPhone上表现良好。稍后我会在这里报告结果。 - Waleed Amjad
谢谢,第二个链接正是我想要的...看起来他们通过生成base64表示来存储序列化的画布元素。为了显示缓存的图像,他们创建一个指向以"data:base64,"为前缀的base64字符串(来自数据库)的Image对象,然后将该Image对象绘制到画布上。再次感谢您的帮助。 - Waleed Amjad
太好了!那是我的博客,很高兴能帮到你。我很快就会发布另一个资源,它可以将图像包装到画布中并保存到本地缓存...所以请继续关注。顺便说一句,我也很想看看你编写的代码。 - JayCrossler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接