I am trying to convert an image to a canvas, and than add a text to the image and convert it back to an image, but I am having issues doing it. The text is NEVER added to the final picture.
At the end of the function I upload the image to the server but the picture uploaded doen't have the text on it, just the picture.
I have tried many different ways and the result is the same, can someone tell me what am I doing wrong please?
async function saveConfiguration() {
try {
const {
left: caseLeft,
top: caseTop,
width,
height,
} = phoneCaseRef.current!.getBoundingClientRect();
const { left: containerLeft, top: containerTop } =
containerRef.current!.getBoundingClientRect();
const leftOffset = caseLeft - containerLeft;
const topOffset = caseTop - containerTop;
const actualX = renderedPosition.x - leftOffset;
const actualY = renderedPosition.y - topOffset;
//create canvas
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
const userImage = new Image();
userImage.crossOrigin = "anonymous";
userImage.src = imageUrl;
await new Promise((resolve) => (userImage.onload = resolve));
//add image
ctx?.drawImage(
userImage,
actualX,
actualY,
renderedDimension.width,
renderedDimension.height
);
// add text
ctx.font = `${fontSizeCustom}px Arial`;
ctx.fillStyle = "rgba(255,255,255,.5)";
ctx.textBaseline = "top";
ctx.fillStyle = "red"; //
ctx.fillText(customText, fontPosition.x, fontPosition.y);
const base64 = canvas.toDataURL();
const base64Data = base64.split(",")[1];
//function convert base64 to blob
const blob = base64ToBlob(base64Data, "image/png");
const file = new File([blob], "filename.png", { type: "image/png" });
//upload iamge to server UPLOADTHINGS
await startUpload([file], { configId });
} catch (err) {
console.log("error al subir imagen");
}
}
Function
function base64ToBlob(base64: string, mimeType: string) {
const byteCharacters = atob(base64);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
return new Blob([byteArray], { type: mimeType });
}
I tried using the function but doent work. Just want to add the text to the final image.
After faking the data for some of the variable that you did not include, writing an upload function, and removing the base64 code, your code seemed to work just fine.
The only reason I can think of that it did not work for you, is that your canvas had a 0 height or width.
I would recommend that you append the canvas to the DOM for debugging purposes. i.e. You can see if the text is actually being drawn to the canvas (it was).
You can get a blob directly from the canvas, which is a file like object (files are based on blobs). So no need to get a Data URL and no need to for the base64 conversion.
You may not even need to convert the blob to a File.
Stackoverflow will not let the save dialog box pop up in this code snippet, but if you run it, you can see that the text is added. Also if you run the code locally on your computer, you can see it save the image WITH the text overlaid.
saveConfiguration()
async function saveConfiguration() {
const fontSizeCustom = 20
const fontPosition = {x:30, y:40}
let customText = "Something to say!"
let imageUrl = "https://images.dog.ceo/breeds/beagle/1271553739_Milo.jpg"
let phoneCaseRef = {}
let containerRef = {}
let renderedPosition = {x:0, y:0} // NO idea what this is suppose to be
let renderedDimension = {width:140, height:100} // NO idea what this is suppose to be
phoneCaseRef.current = document.querySelector("#PhoneCaseID")
containerRef.current = document.querySelector("#ContainerID")
try {
const {
left: caseLeft,
top: caseTop,
width,
height,
} = phoneCaseRef.current.getBoundingClientRect();
const { left: containerLeft, top: containerTop } =
containerRef.current.getBoundingClientRect();
const leftOffset = caseLeft - containerLeft;
const topOffset = caseTop - containerTop;
const actualX = renderedPosition.x - leftOffset;
const actualY = renderedPosition.y - topOffset;
//create canvas
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
// For testing purposes, show the canvas on the screen
containerRef.current.appendChild( canvas )
// ctx.fillRect(20,20,100,100)
const userImage = new Image();
userImage.crossOrigin = "anonymous";
userImage.src = imageUrl;
await new Promise((resolve) => (userImage.onload = resolve));
//add image
ctx.drawImage(
userImage,
actualX,
actualY,
renderedDimension.width,
renderedDimension.height
);
// add text
ctx.font = `${fontSizeCustom}px Arial`;
ctx.fillStyle = "rgba(255,255,255,.5)";
ctx.textBaseline = "top";
ctx.fillStyle = "red"; //
ctx.fillText(customText, fontPosition.x, fontPosition.y);
const blob = canvas.toBlob( blob => {
if( blob ) {
// Convert blob to a File if needed
// const file = new File([blob], "filename.png", { type: "image/png" });
//upload iamge to server UPLOADTHINGS
// await startUpload([file], { configId });
saveBlob( "filename.png", blob )
}
else console.error( `canvas.toBlob() failed` );
});
} catch (err) {
console.log("error al subir imagen");
}
}
function saveBlob( defaultFileName, blob ) {
let objectURL = URL.createObjectURL( blob );
let aElement = document.createElement( "a" ); // Create a <a> tag (hyperlink)
console.log(`Saving blob --- Save Dialog box would pop up here if run locally.` )
aElement.download = defaultFileName;
aElement.href = objectURL;
aElement.click( ); // Trigger the save dialog
URL.revokeObjectURL( objectURL );
}
#PhoneCaseID {
border: solid 2px purple;
padding: 20px;
}
#ContainerID {
border: solid 2px grey;
width: 200px;
height: 150px;
}
<div id="PhoneCaseID">
<div id="ContainerID">
<!-- canvas will get appended here -->
</div>
</div>