Handling Image Display Failures in Uniapp Upload Components via Resolution Compression

A frequent issue when working with file upload components in mini-programs is broken image previews—typically indicated by a exclamation mark icon and accompanied by a 404 status. While the root cause can sometimes be an incorrect file format, another subtle culprit is excessive image resolution. Files under 20 MB upload successfully, but previews break once dimensions exceed roughly 3000×3000 pixels. Compressing the resolution before upload resolves this reliably.

1. Replicating the Issue

Test scenarios:

  • File ≤ 2 MB with 1000×500 resolution → previews correctly.
  • File ≥ 10 MB with 2500×1500 resolution → previews correctly.
  • File ≤ 5 MB with 9000×5500 resolution → preview fails with exclamation mark.

Although the network request returns a 200 status, the u-upload component’s @error event fires and detailed error information confirms a 404 response.

2. Implementing Resolution Compression

2.1 Place a Canvas Element

A hidden <canvas> is required for redrawing the image. In this example the canvas lives in the parent page, but it can reside wherever convenient as long as the proper context is referenced.

<canvas style="width:100vw;height:100vw;position:fixed;left:100%;" id="picCanvas" type="2d"></canvas>

2.2 Compress During Upload Callback

Inside the afterRead handler of u-upload, call a compression routine before invoking uni.uploadFile. The compressed temporary file path is stored in data for later use.

afterRead(event) {
  const fileList = [].concat(event.file);
  fileList.forEach((item) => {
    this.formData.files.push({
      ...item,
      status: 'uploading',
      message: 'Uploading'
    });
    
    this.compressImage(item.thumb)
      .then(() => {
        uni.uploadFile({
          url: 'xxxxxx',
          filePath: this.compressedPath,
          name: 'xxxxxx',
          header: { /* custom headers */ },
          success: (res) => { /* handle success */ },
          fail: (err) => { /* handle failure */ }
        });
      })
      .catch((error) => {
        console.error('Compression failed:', error);
      });
  });
}

2.3 Define the Compression Method

A Promise-based function retrieves the original image metadata, calculates whether dimensoins exceed safe thresholds, and redraws the image at a reduced resolution using Canvas API when needed.

methods: {
  compressImage(sourcePath) {
    const self = this;
    return new Promise((resolve, reject) => {
      uni.getImageInfo({
        src: sourcePath,
        success(info) {
          let targetWidth = info.width;
          let targetHeight = info.height;
          let scaleFactor = 1.2;

          // Reduce dimensions while either side exceeds threshold
          while (targetWidth > 2500 || targetHeight > 1500) {
            targetWidth = Math.trunc(info.width / scaleFactor);
            targetHeight = Math.trunc(info.height / scaleFactor);
            scaleFactor += 0.1;
          }

          // No compression needed
          if (info.width === targetWidth && info.height === targetHeight) {
            self.compressedPath = sourcePath;
            resolve();
            return;
          }

          // Redraw using off-screen canvas
          uni.createSelectorQuery()
            .select('#picCanvas')
            .fields({ node: true, size: true })
            .exec((nodes) => {
              try {
                const canvasNode = nodes[0].node;
                const context = canvasNode.getContext('2d');
                const dpr = uni.getSystemInfoSync().pixelRatio;
                canvasNode.width = targetWidth;
                canvasNode.height = targetHeight;
                
                const imageObj = canvasNode.createImage();
                imageObj.src = sourcePath;
                imageObj.onload = () => {
                  context.drawImage(imageObj, 0, 0, targetWidth, targetHeight);
                  // Allow time for rendering
                  setTimeout(() => {
                    uni.canvasToTempFilePath({
                      fileType: 'jpg',
                      canvas: canvasNode,
                      destWidth: targetWidth,
                      destHeight: targetHeight,
                      success(result) {
                        self.compressedPath = result.tempFilePath;
                        resolve();
                      }
                    });
                  }, 200);
                };
              } catch (err) {
                reject(err);
              }
            });
        },
        fail(err) {
          reject(err);
        }
      });
    });
  }
}

Using Canvas-based resolution control, rather than relying solely on file-size compression, prevents the 404 preview error caused by oversized dimensions. This approcah keeps previews functional without limiting acceptable file sizes.

Tags: UniApp image compression Canvas mini-program upload component

Posted on Sat, 16 May 2026 15:48:21 +0000 by stuartc1