寻找可靠的长久的存储介质之旅,以及背后制作的三个网页

2023-03-16 11:05:00 浏览数 (2)

其实对于目前的形式来说,虽然像 U 盘、固态硬盘、甚至光盘这些信息储存介质(设备)的容量越来越高,但是不得不说这些设备的可靠性依然像悬着的一块石头,虽然这块石头确实牢牢的粘在天花板上,但是毕竟是粘上去的,总有可能会突然掉下来。

随着现在各种数码信息生成应用的广泛普及,我们每天都会产生大量的数据,以至于我们时常忽视了信息备份的必要性。现在手机内部存储 200 多 GB ,但是依然很快就能被占满,比电脑还要容易占满,很难想象在未来,如果这些海量的数据因为设备的不可靠性而丢失,那将是一个多么可惜的事情?

不是任何数据都值得备份,相比于备份所有数据,备份数据之中的重点等则是很重要的。可能就是其中自己喜欢的照片,然而将它放在手机中,甚至云盘上都不能称之为可靠,手机会坏,比如我之前使用的手机 huawei nove 2s,在我换了新手机后,因为同学的手机被老师没收了我便借给他,但是因为他玩心很大,嘻嘻哈哈中将衣服和我的手机同时甩入天空,然后手机粉身碎骨,其内部数据虽然部分有备份,但终究是损失了很多,尤其是大量的珍贵照片。云盘也不可靠,在七八年前,那时设备很简单,家里有废旧手机若干、几个 GB 的简单内存卡数张、还有一个慢如黄牛的电脑一台,它们带着我走过了很多年,储存了我很多的数据,当然最重要的是那些珍贵的照片。于是我就全存储到了 360 云盘上,因为存储介质在当时及其昂贵,一个蔫蔫数 GB 的内存卡就是好几天的饭钱,所以我几乎没有其他的备份,电脑的硬盘也好像很容易坏,总之我的数据没有备份,但是我未曾想到的是,360 云盘居然嗝屁了。。。然后那些过去的回忆,全都毁于一旦。虽然那时有抢救下载服务,但是终归错过了。

所以我很想找到一个比较可靠的储存方式。我看到了 A4 纸,家里有打印机,也有一个坏掉的喷墨打印机可作为一个扫描仪。于是就想使用打印的方式使用一定方式将二进制数据打印到纸上,进而实现数据的备份,毕竟肉眼可看到数据的细节,心里会很安心。去年末我曾经找到一个叫 PaperBack 的软件来使用该方式打印到纸上,然后使用扫描仪就能还原数据,但是因为需要打印机与扫描仪共同配合使用,所以始终没有完整尝试过。于是想自制一个。

最开始我想到了 vscode 的 hex editor 插件,可以编辑二进制文件,但是由于自己缺乏相关知识,所以无法从得知二进制数据然后制作二进制文件,然后我想到了基于二进制的 base64 ,然后就自制了两个测试网页。

复制图片就能转为 base64 源码:https://www.ccgxk.com/123.html

base64 与文件互转工具:https://www.ccgxk.com/124.html

因为 base64 不仅可以将图片转换为 ASCII 码,而且也能将任何文件转化,并且还能反向进行还原成文件下载。所以问题就简化成在纸上以适当方式转化为一串长长的 ASCII 码。

然而如何能识别纸上的呢?我想到了 github 的南极源代码那个计划,他们使用的 QR 码刻在胶卷上来记录信息,我或许也可以如此?但是在网上找了很久也没找到他们行动的细节,他们报道里的 QR 码是指的日本那个传统上的 QR 码还是通指的 QR 码呢?我不知道。不过在我的测试下,发现 QR 码是为方便扫描而生的,对于简单的数据会产生很巨大的图像,因此并不适用于我的计划。虽然还做了个页面吧。能生成复杂程度级别最低的 QR 码,https://www.ccgxk.com/125.html ,如果用 QR 码来记录信息,那数据量将难以想象。

于是又尝试自己研究识别图像的方式,我知道有个 openvc 库,专门专注于图片领域,但是吧,不会,自己就研究吧,就弄了个,做了一半才知道这个还是有点难度的。

源码在此处,感兴趣的小伙伴可以自己尝试一番

代码语言:javascript复制
<style>
  * { 
    box-sizing: border-box
  }
  table {
    border: red 1px solid;
  }
  td {
    padding: 0;
    border: 0;
    width: 3px;
    height: 3px;
  }
  .the_black{
    background: black;
  }
</style>

  <body>
    <p class="image">
       <img src="./img08.png" width="100px"  id="img" />
    </p>
    <input type="number" value="230" id="blackThreshold" />
    <button onclick="drawTableImg()">点击转换</button>
    <canvas id="myCanvas" width="250"  style="display: none;"></canvas>
    <div id="tableDiv"></div>
  <body>

<script>
const dom = document.getElementById("myCanvas"); // canvas画布
let colorData = new Array;
let canvasWidth = dom.width;  // 获取 canvas 元素上的宽度,以在转 2 维数组时作为分行依据
let imgDom = document.getElementById("img");

function  drawTableImg(){
  let threshold = document.getElementById("blackThreshold").value;  // 获取黑色阈值(0~255)
  getImageData(dom, imgDom.src).then((data)=>{
    let colorData = data;
    let colorData2d = dataTo2d(colorData, canvasWidth, threshold);  // 一维转单色、二维
    // 绘制
    outTable(colorData2d);
  })
}

/**
 * 获取图片源像素信息
*/
function getImageData(dom, url){
  const ctx = dom.getContext("2d");   // 设置在画布上绘图的环境
  const image = new Image();
  image.src = url;

  let imgH = document.getElementById("img").height;
  dom.height = dom.width * (imgH/100);
  //获取画布宽高
  const w = dom.width;
  const h = dom.height ;
  return new Promise((resolve)=>{
      image.onload = function(){
          ctx.drawImage(image, 0, 0 ,w,h);                           // 将图片绘制到画布上
          const imgData = ctx.getImageData(0,0,w,h);    // 获取画布上的图像像素
          resolve(imgData.data)  // 获取到的数据为一维数组,包含图像的 RGBA四个通道数据
          ctx.clearRect(0,0,w,h);
      }     
  }) 
}

/**
 * 把颜色数组改成一维数组
*/
function getColor(array, threshold){
  let result = new Array();
  let nCutTimes = array.length / 4;
  for (let index = 0; index < nCutTimes; index  ) {
    let key = array[index * 4];
    result[index] = (key > threshold) ? 0 : 1;
  }
  return result;
}

/**
 * 改成二维数组(图片平铺)
 * @param array 数组(颜色数据)
 * @param width 图宽(宽度像素值)
*/
function to2dArray(array, width){
  let arrLen = array.length;
  let result = new Array();
  result[0] = new Array();  // 初始化第一行

  for (let index = 0,key = 0,line = 0; index < arrLen; index  ) {
    out("index"   index   "   key"   key   "   line"   line);
    result[line][key] = array[index]; 
    if(key === (width - 1)){  // 如果到每一行的最后一个元素了,就另起一行(申请新数组,行号变量加一,key 清零)
      line  ;
      if(width * (line 1) > arrLen) break;  // 如果新的一行大于图像的高度,则退出循环
      result[line] = new Array();
      key = 0;
    }else{
      key  
    }
  }
  return result;
}

/**
 * 渲染输出成黑白表格
*/
function outTable(array2d){
  out(array2d);
  let outTableData = `<table>`;
  for(let i = 0 ; i < array2d.length; i  ){
    outTableData  = `</tr>`;
    for(let j = 0 ; j < array2d[i].length; j  ){
      if(array2d[i][j] == 1){
        outTableData  = `<td class="the_black"></td>`;
      }else{
        outTableData  = `<td></td>`;
      }

    }
    outTableData  = `</tr>`;
  }
  outTableData  = `</table>`;  // 渲染完毕

  document.getElementById("tableDiv").innerHTML = outTableData;  // 输出
}

/**
 * 将图片源代码数据转化为二维数组 
*/
function dataTo2d(array, width, threshold){
  array = getColor(array, threshold);
  array = to2dArray(array, width);
  return array;
}

最终因为时间不足,暂时放弃了。

0 人点赞