使用JavaScript将图像裁剪为特定的长宽比

在这3分钟的教程中,我们将编写一个微型JavaScript函数,该函数可以帮助我们将图像裁剪为各种纵横比。超级有用,可用于在将照片发布到社交媒体时间轴之前上传照片或上传个人资料照片,因为这些照片通常需要具有一定的长宽比。

在本教程中,我们将通过修改图像数据。例如,当用户要上传图像时,我们会将其裁剪为特定的宽高比。如果我们只想以特定的长宽比显示图像,则可以使用仅CSS的解决方案

加载图像数据

首先,我们需要一个源图像。让我们使用通用图像URL作为源。

const imageURL = 'path/to/our/image.jpeg';

要裁剪图像,我们需要访问实际的图像数据。我们可以通过将URL加载到<img>元素中来获取这些数据。

const inputImage = new Image();
inputImage.src = imageURL;

下一步是将图像绘制到<canvas>,画布将允许我们修改图像数据。我们将onload在设置之前添加回调,src这样我们就可以捕获加载图像的那一刻。

// this image will hold our source image data
const inputImage = new Image();

// we want to wait for our image to load
inputImage.onload = () => {

    // create a canvas that will present the output image
    const outputImage = document.createElement('canvas');

    // set it to the same size as the image
    outputImage.width = inputImage.naturalWidth;
    outputImage.height = inputImage.naturalHeight;

    // draw our image at position 0, 0 on the canvas
    const ctx = outputImage.getContext('2d');
    ctx.drawImage(inputImage, 0, 0);

    // show both the image and the canvas
    document.body.appendChild(inputImage);
    document.body.appendChild(outputImage);
};

// start loading our image
inputImage.src = imageURL;

运行此代码会导致<canvas>呈现与位于的图片相同的图片imageURL

将图像裁切成正方形的长宽比

现在我们已经可以访问图像数据了,我们可以开始对其进行操作了。

让我们从方形作物开始。方形作物的纵横比为1:1。这意味着输出图像的每一侧都具有相同的长度。我们可以用数值的长宽比表示它1。200×200图像1的宽高比为,可以通过将宽度和高度除以等于1.333(400/300)的方式来计算400×300图像的宽高比。

让我们编辑代码并查看结果。

// the desired aspect ratio of our output image (width / height)
const outputImageAspectRatio = 1;

// this image will hold our source image data
const inputImage = new Image();

// we want to wait for our image to load
inputImage.onload = () => {
    // let's store the width and height of our image
    const inputWidth = inputImage.naturalWidth;
    const inputHeight = inputImage.naturalHeight;
    
    // get the aspect ratio of the input image
    const inputImageAspectRatio = inputWidth / inputHeight;
    
    // if it's bigger than our target aspect ratio
    let outputWidth = inputWidth;
    let outputHeight = inputHeight;
    if (inputImageAspectRatio > outputImageAspectRatio) {
        outputWidth = inputHeight * outputImageAspectRatio;
    } else if (inputImageAspectRatio < outputImageAspectRatio) {
        outputHeight = inputHeight / outputImageAspectRatio;
    }

    // create a canvas that will present the output image
    const outputImage = document.createElement('canvas');

    // set it to the same size as the image
    outputImage.width = outputWidth;
    outputImage.height = outputHeight;
    
    // draw our image at position 0, 0 on the canvas
    const ctx = outputImage.getContext('2d');
    ctx.drawImage(inputImage, 0, 0);

    // show both the image and the canvas
    document.body.appendChild(inputImage);
    document.body.appendChild(outputImage);
};

// start loading our image
inputImage.src = imageURL;

结果是正方形图像,太好了!但是,让我们仔细看看。看来我们的作物没有位于输入图像的中心。这是因为我们尚未更新drawImage呼叫。该drawImage调用需要3个(或更多)参数inputImage,,和xy位置来绘制图像。

我们的输入图像仍在位置绘制00我们需要对其进行调整,以便获得中心裁剪而不是左上方裁剪。

为此,我们需要将图像稍微向左移动。假设我们的输入图像为400像素宽,而我们的输出图像为300像素宽,为了使其居中,我们需要将输入图像50像素向左移动(负50像素)。-50像素300减去后400除以2。这将导致以下代码片段。

const outputX = (outputWidth - inputWidth) * .5

让我们更新的代码片段中,我们可以使用相同的代码,都xy偏移。

// the desired aspect ratio of our output image (width / height)
const outputImageAspectRatio = 1;

// this image will hold our source image data
const inputImage = new Image();

// we want to wait for our image to load
inputImage.onload = () => {
    // let's store the width and height of our image
    const inputWidth = inputImage.naturalWidth;
    const inputHeight = inputImage.naturalHeight;
    
    // get the aspect ratio of the input image
    const inputImageAspectRatio = inputWidth / inputHeight;
    
    // if it's bigger than our target aspect ratio
    let outputWidth = inputWidth;
    let outputHeight = inputHeight;
    if (inputImageAspectRatio > outputImageAspectRatio) {
        outputWidth = inputHeight * outputImageAspectRatio;
    } else if (inputImageAspectRatio < outputImageAspectRatio) {
        outputHeight = inputHeight / outputImageAspectRatio;
    }
    
    // calculate the position to draw the image at
    const outputX = (outputWidth - inputWidth) * .5;
    const outputY = (outputHeight - inputHeight) * .5;

    // create a canvas that will present the output image
    const outputImage = document.createElement('canvas');

    // set it to the same size as the image
    outputImage.width = outputWidth;
    outputImage.height = outputHeight;
    
    // draw our image at position 0, 0 on the canvas
    const ctx = outputImage.getContext('2d');
    ctx.drawImage(inputImage, outputX, outputY);

    // show both the image and the canvas
    document.body.appendChild(inputImage);
    document.body.appendChild(outputImage);
};

// start loading our image
inputImage.src = imageURL;

通过此更新,我们的裁剪现在位于输入图像的中心。

创建可重用的JavaScript裁剪功能

最后,我们将代码转换为可重用的函数,以便我们可以快速裁剪具有各种裁剪纵横比的图像。我们的JavaScript代码段已经适合用于任何长宽比,而不仅仅是正方形。

/**
 * @param {string} url - The source image
 * @param {number} aspectRatio - The aspect ratio
 * @return {Promise<HTMLCanvasElement>} A Promise that resolves with the resulting image as a canvas element
 */
function crop(url, aspectRatio) {
    
    // we return a Promise that gets resolved with our canvas element
    return new Promise(resolve => {

        // this image will hold our source image data
        const inputImage = new Image();

        // we want to wait for our image to load
        inputImage.onload = () => {

            // let's store the width and height of our image
            const inputWidth = inputImage.naturalWidth;
            const inputHeight = inputImage.naturalHeight;

            // get the aspect ratio of the input image
            const inputImageAspectRatio = inputWidth / inputHeight;

            // if it's bigger than our target aspect ratio
            let outputWidth = inputWidth;
            let outputHeight = inputHeight;
            if (inputImageAspectRatio > aspectRatio) {
                outputWidth = inputHeight * aspectRatio;
            } else if (inputImageAspectRatio < aspectRatio) {
                outputHeight = inputHeight / aspectRatio;
            }

            // calculate the position to draw the image at
            const outputX = (outputWidth - inputWidth) * .5;
            const outputY = (outputHeight - inputHeight) * .5;

            // create a canvas that will present the output image
            const outputImage = document.createElement('canvas');

            // set it to the same size as the image
            outputImage.width = outputWidth;
            outputImage.height = outputHeight;

            // draw our image at position 0, 0 on the canvas
            const ctx = outputImage.getContext('2d');
            ctx.drawImage(inputImage, outputX, outputY);
            resolve(outputImage);
        };

        // start loading our image
        inputImage.src = url;
    })
    
}

我们新的闪亮crop函数可以这样调用:

crop('path/to/our/image.jpeg', 1)

或者,要获得“ 16:9”的收成:

crop('path/to/our/image.jpeg', 16/9)

当函数返回a时,Promise我们可以得到如下结果:

crop('path/to/our/image.jpeg', 16/9).then(canvas => {
  // `canvas` is the resulting image
})

或者,使用async / await:

const canvas = await crop('path/to/our/image.jpeg', 16/9)

在CodePen上查看最终结果的演示

结论

通过使用HTML canvas API和一些基本数学运算,我们构建了一个微小的裁切助手功能,使您可以轻松快速地裁切各种纵横比的图像。这有助于我们为社交媒体帖子,个人资料图片,熟悉的文档尺寸或其他流行的媒体格式准备图像。

为了使文章简洁,我们当前的解决方案未涵盖以下情况:

  • 浏览器被移动照片EXIF方向标头所迷惑。
  • 移动设备上的画布内存溢出,以获取非常大的图像。
  • 缩小图像时图像质量差。

如果您需要针对这些问题的解决方案,则可以探索Doka,它是一种易于使用的图像编辑器,可以解决这些极端情况,并具有多种附加功能。

免责声明: 本站提供的资源,都来自网络,版权争议与本站无关,所有内容及软件的文章仅限用于学习和研究目的。不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负,我们不保证内容的长久可用性,通过使用本站内容随之而来的风险与本站无关,您必须在下载后的24个小时之内,从您的电脑/手机中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
侵删请致信站长

西楼网 » 使用JavaScript将图像裁剪为特定的长宽比