Cropping an HTML canvas to the width/height of its visible pixels (content)?
Asked Answered
D

3

8

Can an HTML canvas element be internally cropped to fit its content?

For example, if I have a 500x500 pixel canvas with only a 10x10 pixel square at a random location inside it, is there a function which will crop the entire canvas to 10x10 by scanning for visible pixels and cropping?


Edit: this was marked as a duplicate of Javascript Method to detect area of a PNG that is not transparent but it's not. That question details how to find the bounds of non-transparent content in the canvas, but not how to crop it. The first word of my question is "cropping" so that's what I'd like to focus on.

Donall answered 24/8, 2017 at 16:35 Comment(2)
@K3N Edit explains why it's not a duplicate. Please re-open.Donall
Reopened, however, to crop you simply use the coordinates you get from that method and then use drawImage() to a new canvas to region.Caesarism
C
1

Simple readable version

A two-pass search seems hardly necessary, at least in 2024. Here's my take at a much simpler and more readable version.

Example image

Using the following image of 320x320 pixels with transparent padding:

Example image with transparent padding

Source: myself (feel free to use for any purpose)

Example code

In this example, you'll see the difference between before and after, each image with a red border around it to show where the transparent image padding ends.

The function trimImage iterates over every row and column of pixels to detect the outer boundaries of the painted pixels. It then redraws the pixels within that boundary onto a resized canvas.

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
    />

    <title>Strip transparent padding</title>

    <style>
      img, canvas {
        border: 1px solid red;
        margin: 0 10px;
      }
    </style>
  </head>
  <body>
    <script type="module">
      async function trimImage(image) {
        // Create a canvas
        const canvas = document.createElement('canvas')
        const context = canvas.getContext('2d')
        document.body.appendChild(canvas)

        // Convert the image to a bitmap
        const bitmap = await createImageBitmap(image)
        const { width, height } = bitmap

        // Get pixels
        canvas.width = width
        canvas.height = height
        context.drawImage(bitmap, 0, 0)
        const { data: pixels } = context.getImageData(0, 0, width, height)
        context.clearRect(0, 0, width, height)

        // Find new bounds by ignoring transparent pixels
        const bounds = { top: height, left: width, right: 0, bottom: 0 }

        for (const row of Array(height).keys()) {
          for (const col of Array(width).keys()) {
            if (pixels[row * width * 4 + col * 4 + 3] !== 0) {
              if (row < bounds.top) bounds.top = row
              if (col < bounds.left) bounds.left = col
              if (col > bounds.right) bounds.right = col
              if (row > bounds.bottom) bounds.bottom = row
            }
          }
        }

        const newWidth = bounds.right - bounds.left
        const newHeight = bounds.bottom - bounds.top

        // Draw new image
        canvas.width = newWidth
        canvas.height = newHeight
        context.drawImage(
          bitmap,
          bounds.left,
          bounds.top,
          newWidth,
          newHeight,
          0,
          0,
          newWidth,
          newHeight,
        )
      }

      // Load the image
      const image = new Image()
      // image.src = './images/vector-die-with-transparency.webp'
      image.src = 'data:image/webp;base64,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'
      image.onload = async () => {
        document.body.append('Original:')
        document.body.append(image)
        document.body.append(document.createElement('br'))

        document.body.append('Trimmed:')
        await trimImage(image)
      }
    </script>
  </body>
</html>

Note: I had to paste in the image as base64 in this snippet specifically because I couldn't load an image from cross origin (stack overflow cdn) because getImageData() will error as The canvas has been tainted by cross-origin data.

Under normal circumstances you should be able to use the uploaded blob or imported image that's hosted on the same origin. If not, be sure to check out cross-origin method.

Contradictory answered 26/4 at 22:59 Comment(1)
Thanks. This works well. The previous answer has stopped working for some reason.Donall
M
15

A better trim function.

Though the given answer works it contains a potencial dangerous flaw, creates a new canvas rather than crop the existing canvas and (the linked region search) is somewhat inefficient.

Creating a second canvas can be problematic if you have other references to the canvas, which is common as there are usually two references to the canvas eg canvas and ctx.canvas. Closure could make it difficult to remove the reference and if the closure is over an event you may never get to remove the reference.

The flaw is when canvas contains no pixels. Setting the canvas to zero size is allowed (canvas.width = 0; canvas.height = 0; will not throw an error), but some functions can not accept zero as an argument and will throw an error (eg ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height); is common practice but will throw an error if the canvas has no size). As this is not directly associated with the resize this potencial crash can be overlooked and make its way into production code.

The linked search checks all pixels for each search, the inclusion of a simple break when an edge is found would improve the search, there is still an on average quicker search. Searching in both directions at the same time, top and bottom then left and right will reduce the number of iterations. And rather than calculate the address of each pixel for each pixel test you can improve the performance by stepping through the index. eg data[idx++] is much quicker than data[x + y * w]

A more robust solution.

The following function will crop the transparent edges from a canvas in place using a two pass search, taking in account the results of the first pass to reduce the search area of the second.

It will not crop the canvas if there are no pixels, but will return false so that action can be taken. It will return true if the canvas contains pixels.

There is no need to change any references to the canvas as it is cropped in place.

// ctx is the 2d context of the canvas to be trimmed
// This function will return false if the canvas contains no or no non transparent pixels.
// Returns true if the canvas contains non transparent pixels
function trimCanvas(ctx) { // removes transparent edges
    var x, y, w, h, top, left, right, bottom, data, idx1, idx2, found, imgData;
    w = ctx.canvas.width;
    h = ctx.canvas.height;
    if (!w && !h) { return false } 
    imgData = ctx.getImageData(0, 0, w, h);
    data = new Uint32Array(imgData.data.buffer);
    idx1 = 0;
    idx2 = w * h - 1;
    found = false; 
    // search from top and bottom to find first rows containing a non transparent pixel.
    for (y = 0; y < h && !found; y += 1) {
        for (x = 0; x < w; x += 1) {
            if (data[idx1++] && !top) {  
                top = y + 1;
                if (bottom) { // top and bottom found then stop the search
                    found = true; 
                    break; 
                }
            }
            if (data[idx2--] && !bottom) { 
                bottom = h - y - 1; 
                if (top) { // top and bottom found then stop the search
                    found = true; 
                    break;
                }
            }
        }
        if (y > h - y && !top && !bottom) { return false } // image is completely blank so do nothing
    }
    top -= 1; // correct top 
    found = false;
    // search from left and right to find first column containing a non transparent pixel.
    for (x = 0; x < w && !found; x += 1) {
        idx1 = top * w + x;
        idx2 = top * w + (w - x - 1);
        for (y = top; y <= bottom; y += 1) {
            if (data[idx1] && !left) {  
                left = x + 1;
                if (right) { // if left and right found then stop the search
                    found = true; 
                    break;
                }
            }
            if (data[idx2] && !right) { 
                right = w - x - 1; 
                if (left) { // if left and right found then stop the search
                    found = true; 
                    break;
                }
            }
            idx1 += w;
            idx2 += w;
        }
    }
    left -= 1; // correct left
    if(w === right - left + 1 && h === bottom - top + 1) { return true } // no need to crop if no change in size
    w = right - left + 1;
    h = bottom - top + 1;
    ctx.canvas.width = w;
    ctx.canvas.height = h;
    ctx.putImageData(imgData, -left, -top);
    return true;            
}
Merthiolate answered 25/8, 2017 at 2:44 Comment(6)
Wow, this worked straight away even with fillText which I experienced problems with using the other method (see my comment on the other answer). Here is a working demo: jsfiddle.net/umasz04w Thank you.Donall
Ok but why are you calling twice getImageData? Put the one you analysed with the cropping arguments of putImageDataMillenarianism
@Millenarianism Sorry missed that. Will fixMerthiolate
omg it is 2022 and this still works!!Nidus
And now it is 2023. I know my x,y,w,h. You inspired me to do imgdata = ctx.getImageData(x,y,w,h); , canvas.width = w; canvas.height = h; , ctx.putImageData(imgdata, 0,0); Thanks!Porras
I modified the final return from 'return true' to 'return [left, top]' because my click events need offsetting after canvas crop...Sonja
C
2

Can an HTML canvas element be internally cropped to fit its content?

Yes, using this method (or a similar one) will give you the needed coordinates. The background don't have to be transparent, but uniform (modify code to fit background instead) for any practical use.

When the coordinates are obtained simply use drawImage() to render out that region:

Example (since no code is provided in question, adopt as needed):

// obtain region here (from linked method)
var region = {
  x: x1, 
  y: y1, 
  width: x2-x1, 
  height: y2-y1
};

var croppedCanvas = document.createElement("canvas");
croppedCanvas.width = region.width;
croppedCanvas.height = region.height;

var cCtx = croppedCanvas.getContext("2d");
cCtx.drawImage(sourceCanvas, region.x, region.y, region.width, region.height, 
                             0, 0, region.width, region.height);

Now croppedCanvas contains only the cropped part of the original canvas.

Caesarism answered 24/8, 2017 at 19:34 Comment(2)
Thank you. The related question certainly helps but I wasn't aware of how to actually extract the region.Donall
I'm having trouble using your linked method for finding boundaries when using fillText. The "right edge" is incorrect if I use 0,0 as the fillText co-ordinates. If I change them to e.g. 1,0 then the right edge is correct. See this fiddle: jsfiddle.net/9jj7o5az/2Donall
C
1

Simple readable version

A two-pass search seems hardly necessary, at least in 2024. Here's my take at a much simpler and more readable version.

Example image

Using the following image of 320x320 pixels with transparent padding:

Example image with transparent padding

Source: myself (feel free to use for any purpose)

Example code

In this example, you'll see the difference between before and after, each image with a red border around it to show where the transparent image padding ends.

The function trimImage iterates over every row and column of pixels to detect the outer boundaries of the painted pixels. It then redraws the pixels within that boundary onto a resized canvas.

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
    />

    <title>Strip transparent padding</title>

    <style>
      img, canvas {
        border: 1px solid red;
        margin: 0 10px;
      }
    </style>
  </head>
  <body>
    <script type="module">
      async function trimImage(image) {
        // Create a canvas
        const canvas = document.createElement('canvas')
        const context = canvas.getContext('2d')
        document.body.appendChild(canvas)

        // Convert the image to a bitmap
        const bitmap = await createImageBitmap(image)
        const { width, height } = bitmap

        // Get pixels
        canvas.width = width
        canvas.height = height
        context.drawImage(bitmap, 0, 0)
        const { data: pixels } = context.getImageData(0, 0, width, height)
        context.clearRect(0, 0, width, height)

        // Find new bounds by ignoring transparent pixels
        const bounds = { top: height, left: width, right: 0, bottom: 0 }

        for (const row of Array(height).keys()) {
          for (const col of Array(width).keys()) {
            if (pixels[row * width * 4 + col * 4 + 3] !== 0) {
              if (row < bounds.top) bounds.top = row
              if (col < bounds.left) bounds.left = col
              if (col > bounds.right) bounds.right = col
              if (row > bounds.bottom) bounds.bottom = row
            }
          }
        }

        const newWidth = bounds.right - bounds.left
        const newHeight = bounds.bottom - bounds.top

        // Draw new image
        canvas.width = newWidth
        canvas.height = newHeight
        context.drawImage(
          bitmap,
          bounds.left,
          bounds.top,
          newWidth,
          newHeight,
          0,
          0,
          newWidth,
          newHeight,
        )
      }

      // Load the image
      const image = new Image()
      // image.src = './images/vector-die-with-transparency.webp'
      image.src = 'data:image/webp;base64,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'
      image.onload = async () => {
        document.body.append('Original:')
        document.body.append(image)
        document.body.append(document.createElement('br'))

        document.body.append('Trimmed:')
        await trimImage(image)
      }
    </script>
  </body>
</html>

Note: I had to paste in the image as base64 in this snippet specifically because I couldn't load an image from cross origin (stack overflow cdn) because getImageData() will error as The canvas has been tainted by cross-origin data.

Under normal circumstances you should be able to use the uploaded blob or imported image that's hosted on the same origin. If not, be sure to check out cross-origin method.

Contradictory answered 26/4 at 22:59 Comment(1)
Thanks. This works well. The previous answer has stopped working for some reason.Donall

© 2022 - 2024 — McMap. All rights reserved.