I would appreciate any and all wisdom you can give me. Thank you in advance.
Assumptions
I wrote a Javascript game using a game engine called Phaser.js.
Issue.
- [ ] When accessing the URL in the response, an image that is only black is displayed.
Response content from imgurAPI
{"id":"dwdGkep","title":null,"description":null,"datetime":1672621440,"type":"image/png","animated":false,"width":800,"height":800,"size":12914,"views":0,"bandwidth":0,"vote":null,"favorite":false,"nsfw":null,"section":null,"account_url":null,"account_id":0,"is_ad":false,"in_most_viral":false,"has_sound":false,"tags":[],"ad_type":0,"ad_url":"","edited":"0","in_gallery":false,"deletehash":"445HisfrUgBgogT","name":"","link":"https://i.imgur.com/dwdGkep.png"},"success":true,"status":200}
Since “success”:true, “status”:200, the upload process itself seems to be OK.
Relevant source code
Image sending process
function dataURLtoBlob(dataURL) { const bin = atob(dataURL.split(',')[1]); const buffer = new Uint8Array(bin.length); for (let i = 0; i < bin.length; i++) { buffer[i] = bin.charCodeAt(i); } return new Blob([buffer], { type: 'image/png' }); } function canvasToImage() { //get image data from canvas element //const canvas = document.getElementsByTagName("canvas")[0]; var gl = game.canvas.getContext("webgl", { preserveDrawingBuffer: true }); const imageData = game.canvas.toDataURL("image/png"); // convert image data to Blob format const blob = dataURLtoBlob(imageData); const xhr = new XMLHttpRequest(); xhr.open("POST", "https://api.imgur.com/3/image"); xhr.setRequestHeader('Authorization', 'Client-ID XXXXXXXXXXXXXXXX'); xhr.onload = function() { if (xhr.status === 200) { console.log(xhr.response); } else { console.error(xhr.response.data); } } }; xhr.send(blob); }
The calling part of the above process (excerpt) Like setting up an event in the create function.
tweetButton.on("pointerdown", () => { // Put what happens when the button is clicked here canvasToImage(); });
Here is the entire code create function
var tweetButton; // create a game object function create() { // display the tweetButton tweetButton = this.add.image(400, 500, "tweetButton"); tweetButton.setDepth(10); tweetButton.setVisible(false); tweetButton; tweetButton.setInteractive(); tweetButton.on("pointerdown", () => { // Write the process to be executed when the button is clicked here canvasToImage(); }); var startScreenImage = this.add.image(400, 400, "startScreen"); startScreenImage.setInteractive(); // Create text to display the timer this.gameTitle = this.add.text(200, 155, "Endless Chase", { fontSize: "70px", fill: "#000000" // make the text color black }); this.startMessage = this.add.text(200, 250, "Click to start game", { fontSize: "40px", fill: "#000000" // set text color to black }); this.Notion = this.add.text(200, 600, "*The game is only for play on a computer", { fontSize: "30px", fill: "#DC143C" // set text color to black }); startScreenImage.on("pointerdown", () => { // delete startScreenImage when clicked this.gameTitle.destroy(); this.startMessage.destroy(); this.Notion.destroy(); this.startMessage.destroy(); this.startScreenImage.destroy() startScreenImage.destroy(); startScreenImage_flg = true; // Write the process to start the game here // Create a cursor this.cursor = this.add.circle(400, 400, 17, 0x0000ff); // create red circles this.redCircles = []; var redCircle = this.add.circle( Phaser.Math.Between( this.cursor.x - clearance, // coordinates 300px left from cursor this.cursor.x + clearance // coordinates 300px right of cursor ), Phaser.Math.Between( this.cursor.y - clearance, // coordinates 300px above the cursor this.cursor.y + clearance // coordinates 300px below cursor ), 50, // radius 0xff0000 // color ); this.redCircles.push(redCircle); // start the process of adding a red circle every 5 seconds this.intervalId = setInterval(() => { // create a red circle var redCircle = this.add.circle( Phaser.Math.Between(this.cursor.x - clearance, this.cursor.x + clearance), Phaser.Math.Between(this.cursor.y - clearance, this.cursor.y + clearance), 50, // radius 0xff0000 // color ); redCircle.speed = Math.random() * 0.09 + 0.01; this.redCircles.push(redCircle); }, 5000); // Create text to display the timer this.timerText = this.add.text(10, 10, "0 seconds", { fontSize: "32px", fill: "#000000" // make the text color black }); // initialize the timer this.elapsedTime = 0; this.prevTime = this.time.now; this.gameOverText = this.add.text(200, 300, "", { fontSize: "32px", fill: "#000000" // set text color to black }); this.gameOverText.setDepth(10); }); // Register a process to end the game when the tab becomes inactive document.addEventListener("visibilitychange", () => { this.gameOver = true; startScreenImage_flg = true; clearInterval(this.intervalId); }); }
What I tried
I tried the following for the same event, but it didn’t work.
var gl = game.canvas.getContext("webgl", { preserveDrawingBuffer: true });
Current Processing
- [ ] Clicking an element in the Canvas on the Result screen will perform the following series of processes.
- [ ] Convert the WebGL canvas to an image using toDataURL().
- [ ] Convert the image data to Blob format.
- [ ] Upload the data in Blob format with XMLHttpRequest using imgur’s API
- [ ] Obtain the URL in the response`
Advertisement
Answer
The easy solution is to use phaser’s builtin function snapshot
(link to the documentation), the resulting image should display in the correct fashion (no special configuration needed).
This function creates an snapshot-image of the current canvas and passes the taken image as a HTMLImageElement
to a given callback function.
You would just have to change your code to look something like this:
function canvasToImage() { game.renderer.snapshot(function (image) { const blob = dataURLtoBlob(image.src); const xhr = new XMLHttpRequest(); ... xhr.send(blob); }); }
(I tested it, on one of my local projects, and it works)
If this solution doesn’t work for you, you could open an issue on the phaser github or mention it on the discourse page, and fix might be made for the next version.