如何存储和检索图像到localStorage?

时间:2013-09-26 00:31:31

标签: javascript cordova jquery-mobile canvas html5-canvas

以为我有这个,但没有。目标:拍摄照片(保险卡),在本地保存,然后再检索。

// Get a reference to the image element
var elephant = document.getElementById("SnapIt_mobileimage_5");

var imgCanvas = document.createElement("canvas"),
imgContext = imgCanvas.getContext("2d");

// Make sure canvas is as big as the picture
imgCanvas.width = elephant.width;
imgCanvas.height = elephant.height;

// Draw image into canvas element

imgContext.drawImage(elephant, 0, 0, elephant.width, elephant.height );
 console.log( 'Did that' );
// Get canvas contents as a data URL
var imgAsDataURL = imgCanvas.toDataURL("data:image/jpg;base64,");

// Save image into localStorage
try {
localStorage.setItem("elephant", imgAsDataURL);
}
catch (e) {
console.log("Storage failed: " + e);
}; 

//Did it work?
var pic = localStorage.getItem("elephant");

console.log( elephant );
console.log( pic );

每一步都成功,最终输出为:

<img id="SnapIt_mobileimage_5" class=" SnapIt_mobileimage_5" name="mobileimage_5" dsid="mobileimage_5" src="files/views/assets/image/IMG_0590.JPG">
 data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA

在新页面上,当我问

var policy_shot = localStorage.getItem( 'elephant' );
console.log( policy_shot );

$('#TestScreen_mobileimage_1').src = policy_shot ;

记录二进制文件:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUg ....

但图像没有出现。

  1. 有更简单的方法吗?
  2. 为什么getItem(二进制)前面有数据:image / png;而不是数据:image / jpg?
  3. 这就是为什么它没有显示,或者我做错了什么?

2 个答案:

答案 0 :(得分:12)

1)这是您可以在本地将图像转换为字符串的唯一方法(使用FileReader加载文件的拼写,见下文)。您可以选择使用服务器来执行此操作。

2)要获取JPEG图像,您需要使用如下参数:

var datauri = imgCanvas.toDataURL("image/jpeg", 0.5); //0.5 = optional quality

不要在参数中使用data:...,因为它将无效,并且会产生您在结果中看到的默认PNG。 toDataURL()只能采用一种类型,即。 image/pngimage/jpeg等。

第3)

外部文件

如果您的图片是从不同的来源(方案,服务器......)加载的,或者是使用本地引用的文件(file:///my/path/等等),则CORS会启动并阻止您创建数据uri,即:图像将为空(因此不可见)。

对于外部服务器,您可以通过提供crossOrigin属性来请求使用来自跨源的图像的权限:

<img src="http://extrernalserver/...." crossOrigin="anonymous" />
在设置img.crossOrigin = 'anonymous';之前

或通过代码(src)。

然而,服务器可以允许或拒绝请求。

如果它仍然不起作用,则需要通过代理加载图像(例如,服务器上的一个页面可以从外部加载图像并从您自己的服务器提供图像)。

或者,如果您有权访问服务器的配置,则可以添加特殊访问权限标头(Access-Control-Allow-Origin: *,有关详细信息,请参阅下面的链接)。

CORS(Cross-Origin Resource Sharing)是一种安全机制,除了这些方式之外无法解决。

本地文件

对于本地文件,您需要使用FileReader - 这可能会带来一个优势,因为FileReader附带了一个方便的方法:readAsDataURL()。这允许您直接“上传”图像文件作为数据uri而不用画布。

见这里的例子:
https://developer.mozilla.org/en-US/docs/Web/API/FileReader

不幸的是,您无法从代码中选择文件 - 您需要提供输入元素或放置区域,以便用户可以选择要存储的文件。

结论

如果所有这些步骤都达到了您实际获得图像的程度,问题可能在另一端,则截断的字符串太长而无法存储。

您可以通过检查存储字符串之前和之后的长度来验证它是否已被剪切:

console.log(imgAsDataURL.length);
... set / get ...
console.log(pic.length);

其他可能性:

  • 未正确定义图像元素。
  • 浏览器中的错误
  • 框架中的错误

(我认为我涵盖了大部分典型的陷阱?)

更新(错过了一个,有点......; - p)

OP在框架中找到了一个特定的内容,我将在此处包含以供将来参考:

  

最后,问题出在$('#TestScreen_mobileimage_1').src = policy_shot ;我使用的是Appery.io,他们不支持.src

     

这是$('#TestScreen_mobileimage_1').attr("src", policy_shot ) ;

最后一点:localStorage在存储图像方面非常有限。典型存储空间为2.5 - 5 mb。存储的每个字符需要2个字节,并且存储编码为base-64的数据uri比原始字符大33% - 因此空间将很少。查看索引数据库,Web SQL或文件API以获得更好的替代方案。

答案 1 :(得分:2)

这里是使用File Api

的完整解决方案

    <html>
    <body>
    <input type="file" id="image-input" />
    <img id="image-container" />
    <script type="text/javascript">
    (function(){
          /** @type {Node} */
      var imgInput = document.getElementById( "image-input" ),
          /** @type {Node} */
          imgContainer = document.getElementById( "image-container" ),
          /** Restore image src from local storage */
          updateUi = function() {
            imgContainer.src = window.localStorage.getItem( "image-base64" );
          },
          /** Register event listeners */
          bindUi = function(){
            imgInput.addEventListener( "change", function(){
              if ( this.files.length ) {
                var reader = new FileReader();
                reader.onload = function( e ){
                  window.localStorage.setItem( "image-base64", e.target.result );
                  updateUi();
                };
                reader.readAsDataURL( this.files[ 0 ] );
              }
            }, false );
          };

    updateUi();
    bindUi();
    }());
    </script>
    </body>
    </html>