Edit and modify the image size and DPI with JS (modify the 1-inch photo into a 2-inch photo)

Various registrations have size restrictions on photos. In view of this situation, I searched online and pieced together the following code, which is used to change the 1-inch photo into a 2-inch photo, and at the same time change the DPI to 300. Of course, you can also change it according to your own requirements. Situation modification code:

HTML

<input type="file" id="input" accept="image/*">
<div style="display: grid;grid-template-columns: 1fr 5px 1fr;">
    <div>
        <p>before fixing:</p>
        <img id="before-image" src="" style="display: block; max-width:100%;" >
    </div>
    <div></div>
    <div>
        <p>After modification (click on the image to download):</p>
        <a href="javascript:;" download><img id="after-image" src="" style="display: block;"></a>
    </div>
</div>

JS

<script type="text/javascript">
    const after_image = document.getElementById('before-image');
    document.getElementById('input').addEventListener('change', (e) => {<!-- -->
        const reader = new FileReader();
        reader.readAsDataURL(e.target.files[0]);
        reader.onload = (e) => {<!-- -->
            b64 = e.target.result;
            after_image.src = b64;
            //Set the target image size
            var target_width = 413;
            var target_height = 626;
            //Calculate the width and height ratio of the target image
            var target_wh_scale = target_width / target_height;

            //Define an Image object
            var bitmap = new Image();
            bitmap.src = b64;
            bitmap.onload = function () {<!-- -->
                //
                var cut_width = 0;
                var cut_height = 0;
                //
                var bitmap_wh_scale = bitmap.width / bitmap.height;
                if (bitmap_wh_scale > target_wh_scale) {<!-- -->
                    cut_width = bitmap.width - bitmap.width / (bitmap_wh_scale / target_wh_scale);
                }//Crop width
                else if (bitmap_wh_scale < target_wh_scale) {<!-- -->
                    cut_height = bitmap.height - bitmap.height * (bitmap_wh_scale / target_wh_scale);

                } else {<!-- -->
                    Console.log("The proportions are consistent without cropping");
                }
                console.log("Picture cropping width:" + cut_width + " px");
                console.log("Picture cropping height:" + cut_height + " px");



                const canvas = document.createElement('canvas');
                const ctx = canvas.getContext('2d');
                canvas.width = target_width;
                canvas.height = target_height;
                ctx.drawImage(this, cut_width / 2, cut_height / 2, bitmap.width - cut_width, bitmap.height - cut_height, 0, 0, target_width, target_height);

                var after_img = document.getElementById('after-image');
                after_img.src = canvas.toDataURL('image/jpg');

                var dataUrl = canvas.toDataURL('image/jpeg', 0.9);
                //Modify DPI to 300
                downloadBase64Img(after_img.parentElement, changeDpiDataUrl(dataUrl, 300), "t.jpg");
            }

        };
    })

    function downloadBase64Img(a, base64URL, fileName) {<!-- -->
        //Set the download attribute of the a tag to the name of the file to be downloaded
        a.download = fileName || 'image';
        //Create a Blob object and get the MIME type of base64 data
        const mimeType = base64URL.match(/:(.*?);/)[1];
        //Convert base64 data to byte array
        const byteCharacters = atob(base64URL.split(',')[1]);
        const byteNumbers = new Array(byteCharacters.length);
        // Fill the byte array into Uint8Array
        for (let i = 0; i < byteCharacters.length; i + + ) {<!-- -->
            byteNumbers[i] = byteCharacters.charCodeAt(i);
        }
        const byteArray = new Uint8Array(byteNumbers);
        //Create Blob object
        const blob = new Blob([byteArray], {<!-- --> type: mimeType });
        //Assign the URL of the Blob object to the href attribute of the a tag
        a.href = URL.createObjectURL(blob);
    }

    function changeDpiDataUrl(base64Image, dpi) {<!-- -->
        const PNG = 'image/png';
        const JPEG = 'image/jpeg';
        const dataSplitted = base64Image.split(',');
        const format = dataSplitted[0];
        const body = dataSplitted[1];
        let type;
        let headerLength;
        let overwritepHYs = false;
        if (format.indexOf(PNG) !== -1) {<!-- -->
            type = PNG;
            const b64Index = detectPhysChunkFromDataUrl(body);
            // 28 bytes in dataUrl are 21bytes, length of phys chunk with everything inside.
            if (b64Index >= 0) {<!-- -->
                headerLength = Math.ceil((b64Index + 28) / 3) * 4;
                overwritepHYs = true;
            } else {<!-- -->
                headerLength = 33 / 3 * 4;
            }
        }
        if (format.indexOf(JPEG) !== -1) {<!-- -->
            type = JPEG;
            headerLength = 18 / 3 * 4;
        }
        // 33 bytes are ok for pngs and jpegs
        // to contain the information.
        const stringHeader = body.substring(0, headerLength);
        const restOfData = body.substring(headerLength);
        const headerBytes = atob(stringHeader);
        const dataArray = new Uint8Array(headerBytes.length);
        for (let i = 0; i < dataArray.length; i + + ) {<!-- -->
            dataArray[i] = headerBytes.charCodeAt(i);
        }
        const finalArray = changeDpiOnArray(dataArray, dpi, type, overwritepHYs);
        const base64Header = btoa(String.fromCharCode(...finalArray));
        return [format, ',', base64Header, restOfData].join('');
    }

    function changeDpiOnArray(dataArray, dpi, format, overwritepHYs) {<!-- -->
        const PNG = 'image/png';
        const JPEG = 'image/jpeg';

        if (format === JPEG) {<!-- -->
            dataArray[13] = 1; // 1 pixel per inch or 2 pixel per cm
            dataArray[14] = dpi >> 8; // dpiX high byte
            dataArray[15] = dpi & 0xff; // dpiX low byte
            dataArray[16] = dpi >> 8; // dpiY high byte
            dataArray[17] = dpi & amp; 0xff; // dpiY low byte
            return dataArray;
        }
        if (format === PNG) {<!-- -->
            const physChunk = new Uint8Array(13);
            // chunk header pHYs
            // 9 bytes of data
            // 4 bytes of crc
            // this multiplication is because the standard is dpi per meter.

            const _P = 'p'.charCodeAt(0);
            const _H = 'H'.charCodeAt(0);
            const _Y = 'Y'.charCodeAt(0);
            const _S = 's'.charCodeAt(0);
            dpi *= 39.3701;
            physChunk[0] = _P;
            physChunk[1] = _H;
            physChunk[2] = _Y;
            physChunk[3] = _S;
            physChunk[4] = dpi >>> 24; // dpiX highest byte
            physChunk[5] = dpi >>> 16; // dpiX veryhigh byte
            physChunk[6] = dpi >>> 8; // dpiX high byte
            physChunk[7] = dpi & amp; 0xff; // dpiX low byte
            physChunk[8] = physChunk[4]; // dpiY highest byte
            physChunk[9] = physChunk[5]; // dpiY veryhigh byte
            physChunk[10] = physChunk[6]; // dpiY high byte
            physChunk[11] = physChunk[7]; // dpiY low byte
            physChunk[12] = 1; // dot per meter....

            const crc = calcCrc(physChunk);

            const crcChunk = new Uint8Array(4);
            crcChunk[0] = crc >>> 24;
            crcChunk[1] = crc >>> 16;
            crcChunk[2] = crc >>> 8;
            crcChunk[3] = crc & 0xff;

            if (overwritepHYs) {<!-- -->
                const startingIndex = searchStartOfPhys(dataArray);
                dataArray.set(physChunk, startingIndex);
                dataArray.set(crcChunk, startingIndex + 13);
                return dataArray;
            } else {<!-- -->
                // i need to give back an array of data that is divisible by 3 so that
                // dataurl encoding gives me integers, for luck this chunk is 17 + 4 = 21
                // if it was we could add a text chunk contaning some info, untill desired
                // length is met.

                // chunk structur 4 bytes for length is 9
                const chunkLength = new Uint8Array(4);
                chunkLength[0] = 0;
                chunkLength[1] = 0;
                chunkLength[2] = 0;
                chunkLength[3] = 9;

                const finalHeader = new Uint8Array(54);
                finalHeader.set(dataArray, 0);
                finalHeader.set(chunkLength, 33);
                finalHeader.set(physChunk, 37);
                finalHeader.set(crcChunk, 50);
                return finalHeader;
            }
        }
    }
</script>

The two functions changeDpiDataUrl() and changeDpiOnArray() in the above code come from the open source project changeDPI.