Ionic2 爱奥尼亚2/cordova插件文件file.writeFile()拒绝正确创建二进制文件(png图像)

Ionic2 爱奥尼亚2/cordova插件文件file.writeFile()拒绝正确创建二进制文件(png图像),ionic2,cordova-plugin-file,Ionic2,Cordova Plugin File,总之 File.writeFile()尝试写入由base64数据生成的Blob时,会创建一个0字节的PNG文件 在我的应用程序中,我试图创建一个由数据库中存储的base64数据组成的文件。数据的渲染等价物是透明背景(不超过300 x 320像素)上的黑色小抗锯齿曲线,该背景先前是从画布元素创建和存储的。我已通过在线提供的各种base64编码器/解码器之一对存储的base64数据进行渲染,独立验证了其确实正确 来自“离子信息”的输出 开发平台是Windows10,到目前为止,我一直在三星Galax

总之

File.writeFile()
尝试写入由base64数据生成的Blob时,会创建一个0字节的PNG文件

在我的应用程序中,我试图创建一个由数据库中存储的base64数据组成的文件。数据的渲染等价物是透明背景(不超过300 x 320像素)上的黑色小抗锯齿曲线,该背景先前是从画布元素创建和存储的。我已通过在线提供的各种base64编码器/解码器之一对存储的base64数据进行渲染,独立验证了其确实正确

来自“离子信息”的输出

开发平台是Windows10,到目前为止,我一直在三星Galaxy S7和S4上直接测试

我知道base64数据必须首先转换为二进制数据(作为Blob),因为文件还不支持将base64直接写入图像文件。我发现了实现这一点的各种技术,并且代码似乎最适合我的需要(并且反映了我在java中实现这一点的类似方式,如下所示):

构造函数的主代码:

this.platform.ready().then(() => {
      this.graphDataService.getDataItem(this.job.id).then((data) =>{
        console.log("getpic:");

        let imgWithMeta = data.split(",") 
        // base64 data
        let imgData = imgWithMeta[1].trim();
        // content type
        let imgType = imgWithMeta[0].trim().split(";")[0].split(":")[1];

        console.log("imgData:",imgData);
        console.log("imgMeta:",imgType);
        console.log("aftergetpic:");

        // this.fs is correctly set to cordova.file.externalDataDirectory
        let folderpath = this.fs;
        let filename = "dotd_test.png";

        File.resolveLocalFilesystemUrl(this.fs).then( (dirEntry) => {
            console.log("resolved dir with:", dirEntry);
            this.savebase64AsImageFile(dirEntry.nativeURL,filename,imgData,imgType);
        });
      });

    });
// convert base64 to Blob
b64toBlob(b64Data, contentType, sliceSize) {

          //console.log("data packet:",b64Data);
          //console.log("content type:",contentType);
          //console.log("slice size:",sliceSize);

          let byteCharacters = atob(b64Data);

          let byteArrays = [];

          for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
              let slice = byteCharacters.slice(offset, offset + sliceSize);

              let byteNumbers = new Array(slice.length);
              for (let i = 0; i < slice.length; i++) {
                  byteNumbers[i] = slice.charCodeAt(i);
              }

              let byteArray = new Uint8Array(byteNumbers);

              byteArrays.push(byteArray);

          }

        console.log("size of bytearray before blobbing:", byteArrays.length);
        console.log("blob content type:", contentType);

        let blob = new Blob(byteArrays, {type: contentType});

        // alternative way WITHOUT chunking the base64 data
        // let blob = new Blob([atob(b64Data)],  {type: contentType});

        return blob;
  }
将base64转换为Blob的助手:

this.platform.ready().then(() => {
      this.graphDataService.getDataItem(this.job.id).then((data) =>{
        console.log("getpic:");

        let imgWithMeta = data.split(",") 
        // base64 data
        let imgData = imgWithMeta[1].trim();
        // content type
        let imgType = imgWithMeta[0].trim().split(";")[0].split(":")[1];

        console.log("imgData:",imgData);
        console.log("imgMeta:",imgType);
        console.log("aftergetpic:");

        // this.fs is correctly set to cordova.file.externalDataDirectory
        let folderpath = this.fs;
        let filename = "dotd_test.png";

        File.resolveLocalFilesystemUrl(this.fs).then( (dirEntry) => {
            console.log("resolved dir with:", dirEntry);
            this.savebase64AsImageFile(dirEntry.nativeURL,filename,imgData,imgType);
        });
      });

    });
// convert base64 to Blob
b64toBlob(b64Data, contentType, sliceSize) {

          //console.log("data packet:",b64Data);
          //console.log("content type:",contentType);
          //console.log("slice size:",sliceSize);

          let byteCharacters = atob(b64Data);

          let byteArrays = [];

          for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
              let slice = byteCharacters.slice(offset, offset + sliceSize);

              let byteNumbers = new Array(slice.length);
              for (let i = 0; i < slice.length; i++) {
                  byteNumbers[i] = slice.charCodeAt(i);
              }

              let byteArray = new Uint8Array(byteNumbers);

              byteArrays.push(byteArray);

          }

        console.log("size of bytearray before blobbing:", byteArrays.length);
        console.log("blob content type:", contentType);

        let blob = new Blob(byteArrays, {type: contentType});

        // alternative way WITHOUT chunking the base64 data
        // let blob = new Blob([atob(b64Data)],  {type: contentType});

        return blob;
  }
我尝试了几十种不同的解码技术,但效果是一样的。但是,如果我将简单文本数据硬编码到
writeFile()
部分,如下所示:

File.writeFile(
        folderpath,
        "test.txt",
        "the quick brown fox jumps over the lazy dog",
        {replace: true}
      )
将在预期位置正确创建文本文件,其中包含上面的文本字符串

但是,我注意到,无论文件是0字节的PNG还是上面的工作文本文件,在这两种情况下,file Promise的“.then()”结果子句都不会触发。

此外,我交换了上述方法,并使用Ionic 2 native Base64 To Gallery库来创建图像,它可以毫无问题地工作。但是,我不希望在整理/打包/传输/删除数据渲染图像时,将图像保存在用户的图片库或相机卷中,因为我不希望冒用户自己的图片的风险。图像应作为应用程序的一部分创建和管理

用户marcus robinson似乎遇到了此处概述的类似问题,但它涉及所有文件类型,而不仅仅是二进制类型。此外,问题似乎已经解决:


有人经历过类似的事情,或者可能发现了我可能造成的错误吗?我已经尝试了几十种替代方案,但似乎都不起作用。

我在您的大部分代码中都找到了这一点:

this.file.writeFile(this.file.cacheDirectory, "currentCached.jpeg", this.b64toBlob(src, "image/jpg", 512) ,{replace: true})
我唯一的不同是:

let byteCharacters = atob(b64Data.replace(/^data:image\/(png|jpeg|jpg);base64,/, ''));
而不是你的

let byteCharacters = atob(b64Data);

注意:我没有使用其他修剪等技术,就像您在构造函数类中使用的那些技术。

我在保存媒体文件时有类似的行为,这些行为在iOS上非常有效。尽管如此,在发布版本中,我还是遇到了在一些Android设备上创建0字节文件的问题(dev build工作得非常好)。经过很长时间的搜索,我遵循以下解决方案

我将
polyfills.js
script标记移到了爱奥尼亚项目中
index.html
的顶部,在
cordova.js
标记之前。通过重新排序,问题得以解决

因此,顺序应该如下所示:

<script src="build/polyfills.js"></script>
<script type="text/javascript" src="cordova.js"></script>

适用于
ionic 3
ionic 4

学分归谁