Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drawing images stored in the app cache #187

Closed
denislepage opened this issue Jul 6, 2020 · 5 comments
Closed

drawing images stored in the app cache #187

denislepage opened this issue Jul 6, 2020 · 5 comments
Labels

Comments

@denislepage
Copy link

I have been looking for a way to display images stored in the app cache downloaded from the Internet, which I saved using the Expo FileSystem.createDownloadResumable package.

Partial code:


        let url = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ee/Catedral_de_Mar%C3%ADa_Reina_del_Mundo%2C_Montreal%2C_Canad%C3%A1%2C_2017-08-12%2C_DD_61-63_HDR.jpg/1280px-Catedral_de_Mar%C3%ADa_Reina_del_Mundo%2C_Montreal%2C_Canad%C3%A1%2C_2017-08-12%2C_DD_61-63_HDR.jpg";

        let localSRC = FileSystem.cacheDirectory + 
            Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) +
            '.jpg';

           const downloadResumable = FileSystem.createDownloadResumable(
                url, localSRC, {}, downloadProgress => {
                    const progress = downloadProgress.totalBytesWritten / downloadProgress.totalBytesExpectedToWrite;
                    console.log(progress);
                }
            );

            const { uri } = await downloadResumable.downloadAsync();

            const image = new Image(canvas);
           // my code works here if I replace uri by url
            image.src = uri;

            image.addEventListener('load', () => {
               context.drawImage(image, 0, 0, 100, 100);
            }); 

The path to the file in Android looks like this:
file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540user%252Fappname/g0ibtcg4zag2kcxoxvozr9.jpg

Question 1: is it in theory possible to load images on the canvas from a local image? The issue #60 and the example in your repo seems to suggest that it should work.

Question 2: is the path not correctly build, or are there permissions issues preventing the canvas package from accessing the cache folder above? The load event never gets fired with the local path. Should I replace the FileSystem.cacheDirectory to something else to make it work? If so, what?

I'd appreciate some guidance. I have been spending a fair bit of time trying to resolve this, but the issue above is the closest clue that I have seen.

thanks!

@iddan iddan added the question label Jul 6, 2020
@saisilinus
Copy link

Hey @denislepage were you able to solve this problem?

@denislepage
Copy link
Author

denislepage commented Dec 3, 2020 via email

@denislepage
Copy link
Author

Back at this. I had initially discarded the idea of passing base64 encoded data to the canvas, as people commented it was too slow for larger files, but I have managed to get this working with it, using FileSystem.readAsStringAsync(). My files are around 250 Kb, and it may not be a solution for larger files. I am not encountering any noticeable issues for simply drawing the image onto the canvas.

I have not managed to resolve my initial problem, which was being able to provide the local URI directly to the canvas using the file:/// path, but this workaround is fine for me.

@saisilinus

let url = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ee/Catedral_de_Mar%C3%ADa_Reina_del_Mundo%2C_Montreal%2C_Canad%C3%A1%2C_2017-08-12%2C_DD_61-63_HDR.jpg/1280px-Catedral_de_Mar%C3%ADa_Reina_del_Mundo%2C_Montreal%2C_Canad%C3%A1%2C_2017-08-12%2C_DD_61-63_HDR.jpg";

let localSRC = FileSystem.cacheDirectory + 
Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) +
'.jpg';

const downloadResumable = FileSystem.createDownloadResumable(
	url, localSRC, {}, downloadProgress => {
		const progress = downloadProgress.totalBytesWritten / downloadProgress.totalBytesExpectedToWrite;
		console.log(progress);
	}
);

const { uri } = await downloadResumable.downloadAsync();
const { base64 } = await FileSystem.readAsStringAsync(uri, {"encoding": FileSystem.EncodingType.Base64});

const image = new Image(canvas);
image.src = "data:image/png;base64," + base64;

image.addEventListener('load', () => {
   context.drawImage(image, 0, 0, 100, 100);
}); 

@VityaSchel
Copy link

readAsStringAsync

Docs says FileSystem.readAsStringAsync returns "A Promise that resolves to a string containing the entire contents of the file." so correct code would be

  const ctx = canvasRef.current.getContext('2d')
  const path = "file:///data/.../...png"

  let canvasImage = new CanvasImage(canvasRef.current)
  await new Promise(async resolve => {
    canvasImage.addEventListener('load', resolve)
    const base64 = await FileSystem.readAsStringAsync(path, { encoding: FileSystem.EncodingType.Base64 })
    canvasImage.src = 'data:image/png;base64,' + base64
  })

  ctx.drawImage(canvasImage, 0, 0, 100, 100)

@Leslie-Wong-H
Copy link

jpg compatible version:

          const image = new CanvasImage(canvas.current);

          const mimeMap = {
            jpeg: "image/jpeg",
            jpg: "image/jpeg",
            png: "image/png"
          };
          const ext = url.split(".").slice(-1)[0];
          console.log({ ext });
          const base64 = await FileSystem.readAsStringAsync(url, {
            encoding: FileSystem.EncodingType.Base64
          });
          image.src = `data:${mimeMap[ext]};base64,` + base64;

          image.addEventListener("load", () => {
            console.log("res");
            ctx.drawImage(image, 0, 0, 100, 100);
          });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants