Combine two dataURIs to form one cohesive image

I need to create images that consist of a label and an icon. The label will have a wide range of variations, around 50-100 different options, while there are only about 10 icons to choose from. To streamline the process, I want to split the final image into two parts: the label image and the icon image. I plan to develop a service that provides dataURIs for the labels, and embed the icon dataURIs directly into the webpage. My goal is to then combine these distinct dataURIs to generate a single dataURI that represents the combined image.

Is there a way to accomplish this on the client side?

Answer №1

Utilizing data URIs to generate images and then incorporating them into a new image using the canvas element is straightforward. Here's a concise example:

var nloaded = 0;
function checkload(event) {
  nloaded++;
  if (nloaded < 2) {
    return;
  }
  
  var canvas = document.querySelector('canvas');
  var context = canvas.getContext('2d');
  context.drawImage(image1, 0, 0, 50, 50);
  context.drawImage(image2, 50, 50, 100, 100);

  var combined = new Image;
  combined.src = canvas.toDataURL('data/gif');
  
  document.body.appendChild(combined);
}

var image1 = new Image;
image1.onload = checkload;
image1.src = 'data:image/gif;base64,R0lGODdhAgACALMAAAAAAP///wAAAAAAAP8AAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAAgACAAAEAxBJFAA7';
 

var image2 = new Image;
image2.onload = checkload;
image2.src = 'data:image/gif;base64,R0lGODdhAgACALMAAAAAAP///wAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAAgACAAAEA5BIEgA7';
canvas {
    display: none;
}
<canvas width=100 height=100></canvas>

.

After loading the images from the data URI and arranging them using the drawImage functions of the canvas context, you can create a new image with the calculated information:

var combined = new Image;
combined.src = canvas.toDataURL('data/gif');

Regrettably, this technique does not function in IE8.

Answer №2

Illustrative example showcasing the utilization of an array comprising image objects with URI src and x, y offsets:

var images = [
   { src: 'data:image/gif;base64,R0lGODdhAgACALMAAAAAAP///wAAAAAAAP8AAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAAgACAAAEAxBJFAA7', x: 0, y: 0 },
   { src: 'data:image/gif;base64,R0lGODdhAgACALMAAAAAAP///wAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAAgACAAAEA5BIEgA7', x: 20, y: 20 },
];

var canvas = document.createElement('canvas');
var destination = document.getElementById('canvas');

Promise.all(images.map(imageObj => add2canvas(canvas, imageObj)))
    .then(() => destination.append(canvas));

function add2canvas(canvas, imageObj) {
   return new Promise( (resolve, reject) => {
      if (!imageObj || typeof imageObj != 'object') return reject();
      var image = new Image();
      image.onload = function () {
          canvas.getContext('2d')
                .drawImage(this, imageObj.x || 0, imageObj.y || 0);
          resolve();
      };

      image.src = imageObj.src;
   });
}

Additionally, a more advanced technique for generating a composite png:

  function mergeImageURIs(images) {
      return new Promise( (resolve, reject) => {
          var canvas = document.createElement('canvas');
          canvas.width = 1000; // desired width of merged images
          canvas.height = 1000; // desired height of merged images
          Promise.all(images.map(imageObj => add2canvas(canvas, imageObj))).then(() => resolve(canvas.toDataURL('image/png'), reject));
      });
  }

  function add2canvas(canvas, imageObj) {
    return new Promise( (resolve, reject) => {
       if (!imageObj || typeof imageObj != 'object') return reject();
       var x = imageObj.x && canvas.width ? (imageObj.x >=0 ? imageObj.x : canvas.width + imageObj.x) : 0;
       var y = imageObj.y && canvas.height ? (imageObj.y >=0 ? imageObj.y : canvas.height + imageObj.y) : 0;
       var image = new Image();
       image.onload = function () {
           canvas.getContext('2d').drawImage(this, x, y);
           resolve();
       };

       image.src = imageObj.src;
    });
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I'm having trouble getting my if statement to function properly with a random number

I'm currently working on creating a natural disaster sequence for my game, and I'm using Math.random to simulate different outbreak scenarios. However, I've encountered an issue at the end of my code where an if statement is supposed to trig ...

Please reset the form fields after the most recent edit

I've created a form that includes multiple select elements. When an option is selected, it activates the next select element and updates it with values using Ajax and PHP. However, I'm facing an issue where changing a previous option only resets ...

I would like for my element to increase and decrease in size while rotating when the button is clicked

I am trying to create an element that changes its size while spinning when a button is clicked. It seems to be working fine on hover, but not onclick. Here is the code I have: <div class="rec">Rec</div> <button id="button&quo ...

Can an arrow be crafted to direct a player towards their final destination?

I'm currently developing a game that utilizes numerical tile maps, such as [1, 0, 0, 1], and I am using JavaScript to display these maps on a canvas. I have been struggling to create an arrow that consistently rotates to point towards an end goal, des ...

How can jQuery determine the amount of line breaks within a div element?

My div wrap size is a percentage of the screen width, containing multiple .item divs that break into new lines as the window size decreases. I attempted to calculate the total number of boxes that could fit based on their widths compared to the container ...

Using only CSS to reverse the order of Bootstrap rows within a forEach statement in a .php file

I am facing a challenge in reversing rows within a forEach statement. For instance, in the first row, the content's div (title, text) should be on the left side and the image on the right side. In the second row, it should be reversed, with the image ...

What is causing myInterval to not be cleared properly?

const homeButton = document.getElementById('home'); window.myInterval = 0; const showHome = () => { console.log('showHome'); window.myInterval = setInterval(wait, 400) } const wait = () => { console.log('wait'); ...

Learn how to create a web application by utilizing HTML5 and REST, and then seamlessly transfer the front-end code to a mobile app using Cordova

Can a mobile application be developed from a web portal using Cordova or similar frameworks? The web portal will consist of: HTML5 for front-end J2EE for back-end with JAX-RS Is it feasible to extract pages from the web portal and integrate them into a ...

Getting the mouse location with three.js: A step-by-step guide

Hey there, I'm currently working with IcosahedronGeometry. I've added CircleGeometry to each of its vertices. My goal now is to allow the circle to sense the mouse movement and follow it when it gets close. To achieve this, I've created a Ri ...

What is the best way to conceal the standard 'X' close button within a magnific popup interface?

I implemented the Magnific-popup plugin in my jsp to show messages to users. Here is the code I used to open Magnific Popup: $.magnificPopup.open({ items: { type: 'inline', src: '#idOfSomeDivInPage' }, focus: '#some ...

Bringing joy to a JS library: Embracing both Node and the Window

I have developed a JS library that I want to convert into a Node module for use with Node.js. This library extends the Canvas context API and relies on the use of getImageData(). Therefore, it begins with a defensive check to ensure compatibility: if (wi ...

Utilize Bootstrap DataTable Sparkline to extract information from a comma-delimited string rather than an array

I have successfully implemented a Bootstrap DataTable component in my Asp.net Core MVC App to display data from my database. However, I am facing a challenge when trying to add a sparkline to a column. The sparkline component requires an array of values, b ...

Sending the appropriate context using "this" to an external function within a class

Imagine a scenario where I have a simple class that extends other classes, and an object of functions that I am passing to class B const actions = { doSomething: (this: B, foo: boolean) => { console.log('from do something', this.text, ...

Attempting to save data to a .txt file using PHP and making an AJAX POST request

I have been facing an issue while trying to save a dynamically created string based on user interaction in my web app. It's just a simple string without anything special. I am using ajax to send this string to the server, and although it reaches the f ...

Navigating using JavaScript dot notation is a powerful way to

Is there a way to implement JavaScript or jQuery code that will assign an active class to a dot when it is clicked, while also removing the active class from any other dots in the sequence? HTML: <div class="dotnav"> <div class="dot active" ...

The fetch API is being restricted, however, AJAX and XHR are still operational

I made an API call to a URL shortener and encountered different responses using Fetch, JQuery, and XHR. Why is Fetch returning a 400 error while the other methods work smoothly? Even after trying mode: 'no-cors' and "crossDomain": true in the re ...

What is the best way to ensure that posts made with Contentlayer stay dynamic for future posts on Vercel?

My issue is that on the webpage I have set up using contentlayer, I display my blog posts from GitHub through Vercel. However, when I publish a new post on GitHub, I am unable to see it because it has not been built yet. What can I do on the Nextjs13 site ...

populating information to compress using Javascript

I am facing an issue with my button. I want to be able to click on it and have the data populate in the collapse using JavaScript, but for some reason it is not working. The collapse functionality is working fine when I click the button, so there is no pr ...

Having a text input that is dependent on choosing a particular item from a list

As someone who is new to VueJs and JS, I have a question regarding my page setup. I want a text input box to only be visible when the user selects the document type 'Write Individual'. However, my current syntax seems to be incorrect as it's ...

Switching over to the latest version of Material-UI, v1.x.x

Currently, my app relies on Material-UI v0.17.0 which is not compatible with React v16.0.0. In order to make it work, I need to upgrade to Material-UI v1.0.0. I came across a migration tool here, but it only updates import statements. Many props have chan ...