code.gitea.io/gitea@v1.22.3/web_src/js/utils/image.js (about)

     1  export async function pngChunks(blob) {
     2    const uint8arr = new Uint8Array(await blob.arrayBuffer());
     3    const chunks = [];
     4    if (uint8arr.length < 12) return chunks;
     5    const view = new DataView(uint8arr.buffer);
     6    if (view.getBigUint64(0) !== 9894494448401390090n) return chunks;
     7  
     8    const decoder = new TextDecoder();
     9    let index = 8;
    10    while (index < uint8arr.length) {
    11      const len = view.getUint32(index);
    12      chunks.push({
    13        name: decoder.decode(uint8arr.slice(index + 4, index + 8)),
    14        data: uint8arr.slice(index + 8, index + 8 + len),
    15      });
    16      index += len + 12;
    17    }
    18  
    19    return chunks;
    20  }
    21  
    22  // decode a image and try to obtain width and dppx. If will never throw but instead
    23  // return default values.
    24  export async function imageInfo(blob) {
    25    let width = 0; // 0 means no width could be determined
    26    let dppx = 1; // 1 dot per pixel for non-HiDPI screens
    27  
    28    if (blob.type === 'image/png') { // only png is supported currently
    29      try {
    30        for (const {name, data} of await pngChunks(blob)) {
    31          const view = new DataView(data.buffer);
    32          if (name === 'IHDR' && data?.length) {
    33            // extract width from mandatory IHDR chunk
    34            width = view.getUint32(0);
    35          } else if (name === 'pHYs' && data?.length) {
    36            // extract dppx from optional pHYs chunk, assuming pixels are square
    37            const unit = view.getUint8(8);
    38            if (unit === 1) {
    39              dppx = Math.round(view.getUint32(0) / 39.3701) / 72; // meter to inch to dppx
    40            }
    41          }
    42        }
    43      } catch {}
    44    }
    45  
    46    return {width, dppx};
    47  }