DEV Community

haiyun wang
haiyun wang

Posted on Fully Autonomous

Resize an image to a square PNG without stretching it

A rectangular source image and a square output do not have the same aspect ratio. Setting both output dimensions to the same number can distort the artwork. A better workflow makes the sizing decision explicit, then exports a new file.

Fit the image before exporting

Let the source be w × h and the destination be s × s. To preserve the whole image, use:

scale = Math.min(s / w, s / h)

The drawn size is w × scale by h × scale. Center it with x = (s - drawnWidth) / 2 and y = (s - drawnHeight) / 2.

For example, a 1200 × 800 source fitted into a 512 × 512 square becomes approximately 512 × 341.3. The remaining space stays transparent. If the design needs a solid background, fill the canvas before drawing.

Using Math.max instead fills the square and crops the edges. That can suit a photo, but it can cut off a logo or text. Make the choice deliberately.

A small browser implementation

This function takes a File or Blob, decodes it, draws it onto a square canvas, and returns a PNG Blob. The size limit is a guard for this example, rather than a promise about every browser's memory capacity.

async function squarePng(file, size = 512) {
  if (!(file instanceof Blob)) {
    throw new TypeError('Choose an image file.');
  }
  if (!Number.isInteger(size) || size < 1 || size > 2048) {
    throw new RangeError('Choose an integer size from 1 to 2048.');
  }

  const image = await createImageBitmap(file);
  try {
    const canvas = document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;
    const ctx = canvas.getContext('2d');
    if (!ctx) throw new Error('Canvas 2D is unavailable.');

    const scale = Math.min(size / image.width, size / image.height);
    const width = image.width * scale;
    const height = image.height * scale;
    ctx.drawImage(image, (size - width) / 2, (size - height) / 2,
                  width, height);

    return await new Promise((resolve, reject) => {
      canvas.toBlob(blob => {
        if (blob) resolve(blob);
        else reject(new Error('PNG export failed.'));
      }, 'image/png');
    });
  } finally {
    image.close();
  }
}
Enter fullscreen mode Exit fullscreen mode

Use await squarePng(input.files[0], 512) inside an async file-input handler, catch errors, and show them beside the input. The function does not upload the file. Decode support depends on the browser, so a file picker should not promise support for every image format.

The canvas bitmap dimensions control the exported pixel size. CSS width and height only change how a canvas is displayed. Also, enlarging a small source does not recreate missing detail.

Check the output

Open the exported PNG and check its pixel dimensions, transparent padding, and artwork at small display sizes. Preserve the original file so that later exports can start from it. A square PNG alone is not a complete platform-specific app icon package; check the destination platform's requirements before release.

For a ready-made workflow, ConvertAny's app icon tools provide iOS, Android and macOS entry points. This guide is published for ConvertAny and was prepared with AI assistance.

API references

Top comments (0)