简体   繁体   中英

Why does drawImage from localStorage not work?

Using TypeScript, but I don't think that matters.

StackOverflow new tag needed: localstorage

If you copy an img tag to a canvas through.drawImage, it works fine. If you save and load it from localStorage, you get:

drawImage: Argument 1 could not be converted to any of: HTMLImageElement, SVGImageElement, HTMLCanvasElement, HTMLVideoElement, ImageBitmap.

Setup in Fiddle

HTML:

<div id="app">
  <img id="img0" src='https://ir.ebaystatic.com/rs/v/fxxj3ttftm5ltcqnto1o4baovyl.png' height='100' width='100'>
  <canvas id="img1" height='100' width='100' style='border:1px solid #d3d3d3;'></canvas>
  <canvas id="img2" height='100' width='100' style='border:1px solid #d3d3d3;'></canvas>
</div>

JS:

const img = document.querySelector("#img0");
img.setAttribute('crossOrigin','anonymous'); // mark image as safe for toDataURL

document.querySelector("#img0").onload = () => {
  saveImg('img0');
};

function saveImg(srcImgID) {
    // save img0 to local storage
  var imgSrc = document.getElementById(srcImgID);
  localStorage.setItem('someStorageKey', imgSrc);

    // copy img0 => img2
  var canvas2: HTMLCanvasElement = document.getElementById('img2') as HTMLCanvasElement;
  console.log('cavas2: ' + canvas2);
  var ctx2 = canvas2.getContext('2d');
  ctx2.drawImage(imgSrc, 0, 0);

    // load img0
  var img0: HTMLImageElement = localStorage.getItem('someStorageKey') as HTMLImageElement;
  console.log('Image data loaded: ' + img0);

    // copy img0 => img1
  var canvas1: HTMLCanvasElement = document.getElementById('img1') as HTMLCanvasElement;
  console.log('cavas1: ' + canvas1);
  var ctx1 = canvas1.getContext('2d');
  ctx1.drawImage(img0, 0, 0); //error: Argument 1 could not be converted to any of: HTMLImageElement...
}

If you want to keep the whole element in localStorage , you have to use imgSrc.outerHTML

localStorage.setItem('someStorageKey', imgSrc.outerHTML);

Then get the element a special way: (DOMParser MDN) and SO answer

new DOMParser().parseFromString(localStorage.getItem('someStorageKey') as HTMLImageElement, "text/html").body.childNodes[0];

And wait for the image to load:

img0.onload = () => {
  ctx1.drawImage(img0, 0, 0);
}

And for some reason, I need to append the image to <body> for it to work. If this happens to you as well, you can just remove the image immediately (it might JSFiddle):

document.body.append(img0);img0.remove();

Full code:

const img = document.querySelector("#img0");
img.setAttribute('crossOrigin','anonymous'); // mark image as safe for toDataURL

document.querySelector("#img0").onload = () => {
  saveImg('img0');
};

function saveImg(srcImgID) {
    // save img0 to local storage
  var imgSrc = document.getElementById(srcImgID);
  localStorage.setItem('someStorageKey', imgSrc.outerHTML);

    // copy img0 => img2
  var canvas2: HTMLCanvasElement = document.getElementById('img2') as HTMLCanvasElement;
  console.log('cavas2: ' + canvas2);
  var ctx2 = canvas2.getContext('2d');
  ctx2.drawImage(imgSrc, 0, 0);

    // load img0
  var img0: HTMLImageElement = new DOMParser().parseFromString(localStorage.getItem('someStorageKey') as HTMLImageElement, "text/html").body.childNodes[0];
  console.log('Image data loaded: ' + img0);

    // copy img0 => img1
  var canvas1: HTMLCanvasElement = document.getElementById('img1') as HTMLCanvasElement;
  console.log('cavas1: ' + canvas1);
  var ctx1 = canvas1.getContext('2d');
    img0.onload = () => {
    ctx1.drawImage(img0, 0, 0);
  }document.body.append(img0);img0.remove();
}

localStorage.setItem only takes strings so anything that is not a string will have .toString() ran on it before beeing saved, check out MDN localStorage.setItem .

Have you considerd saving the img src to localStorage and doing something like this to render it https://stackoverflow.com/a/4776378/12523447

Instead of an img html element you should store in localStorage just its src attribute. Then you just need to create an image set its src to value that is stored in localStorage and after it will be loaded draw it on canvas . Like so:

function saveImg(srcImgID) {
    // save img0 to local storage
  var img = document.getElementById(srcImgID);
  var imgSrc = img.getAttribute('src');
  
  localStorage.setItem('someStorageKey', imgSrc);

    // copy img0 => img2
  var canvas2: HTMLCanvasElement = document.getElementById('img2') as HTMLCanvasElement;
  console.log('cavas2: ' + canvas2);
  var ctx2 = canvas2.getContext('2d');
  ctx2.drawImage(img, 0, 0);

  var canvas1: HTMLCanvasElement = document.getElementById('img1') as HTMLCanvasElement;
  console.log('cavas1: ' + canvas1);
  var ctx1 = canvas1.getContext('2d');
  
  // load img0
  var img0Src = localStorage.getItem('someStorageKey') as HTMLImageElement;
  var img0 = new Image(); 
  
  img0.src = img0Src;
  
  img0.onload = function () {
    ctx1.drawImage(img0, 0, 0);
  }
}
 

Found a working solution, at least in JSFiddle: https://jsfiddle.net/Dustin_00/nb1j3fw0/70/

@Rojo's solution works as well. But neither work inside my .NET Core app -- just a blank image.

<div id="app">
  <img id="img0" src='https://ir.ebaystatic.com/rs/v/fxxj3ttftm5ltcqnto1o4baovyl.png' height='100' width='100'>
  <canvas id="canvas1" height='100' width='100' style='border:2px solid #00f;'></canvas>
  <canvas id="canvas2" height='100' width='100' style='border:2px solid #f00;'></canvas>
</div>

TypeScript:

const img = document.querySelector("#img0");
img.setAttribute('crossOrigin','anonymous'); // mark image as safe for toDataURL

document.querySelector("#img0").onload = () => {
  saveImg('img0');
};

function getBase64Image(img) {
  var canvas = document.createElement("canvas");
  canvas.width = img.width;
  canvas.height = img.height;

  var ctx = canvas.getContext("2d");
  ctx.drawImage(img, 0, 0);

  var dataURL = canvas.toDataURL("image/png");

  return dataURL;
}

function saveImg(srcImgID) {
    // save img0 to local storage
  var imgSrc = document.getElementById(srcImgID);
  var imgBase64 = getBase64Image(imgSrc);
  localStorage.setItem('someStorageKey', imgBase64);

    // copy img0 => canvas2 (red border)
  var canvas2: HTMLCanvasElement = document.getElementById('canvas2') as HTMLCanvasElement;
  //console.log('cavas2: ' + canvas2);
  var ctx2 = canvas2.getContext('2d');
  ctx2.drawImage(imgSrc, 0, 0);

  // load img0
  var imgData = localStorage.getItem('someStorageKey');

  // copy img0 => canvas1 (blue border) from storage
  var canvas1: HTMLCanvasElement = document.getElementById('canvas1') as HTMLCanvasElement;
  //console.log('cavas1: ' + canvas1);
  var ctx1 : HTMLCanvasElement = canvas1.getContext('2d');
  //console.log('ctx1: ' + ctx1);
  
  var imgFromStorage = new Image(); 
  imgFromStorage.onload = function () {
    //console.log('imgFromStorage: ' + imgFromStorage);
    //console.log('imgFromStorage.src: ' + imgFromStorage.src);
    ctx1.drawImage(imgFromStorage, 0, 0);
  }
    imgFromStorage.src = imgData;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM