在javascript中创建图像的缩略图方块(不丢失纵横比)

发布于 2024-12-07 16:59:34 字数 512 浏览 0 评论 0原文

我正在制作一个客户端拖放文件上传脚本作为书签。在上传之前,我使用 File API 将图像读取为 base64 格式并将其显示为缩略图。

这就是我的缩略图的样子。我希望它们看起来更方形,但又不会失去纵横比。 (请忽略进度条) widethumbnails

这就是我想要的缩略图的样子,它们居中并根据 min(height,width )。 squarethumbnails

我可以仅使用 javascript 来执行此操作(通过脚本更改样式即可)吗?请尝试确保您的解决方案适合 base64 图像(在通过文件 API 作为数据 URL 读取图像之后)。

我已在此处上传了这些确切的图像集。

感谢您的帮助。

I am making a client side Drag and Drop file upload script as a bookmarklet. Before uploading I am using the File API to read the images into base64 format and display them as thumbnails.

This is how my thumbnails look like. I want them to look more square but without loosing their aspect ratio. (please ignore progress bar)
wide thumbnails

This is how I want the thumbnails to be like, they are centered and being cropped based on min(height,width).
square thumbnails

Can I do this using javascript only (changing styles via script will do)? Please try to make sure that your solution will fit with base64 images (after the images are read via file API as DATA URL).

I have uploaded these exact set of images here.

Thanks for the help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

扮仙女 2024-12-14 16:59:34

只是想分享我如何解决我的问题。
因为我想要一个纯粹的 javascript 解决方案,所以我使用一次性画布元素来完成肮脏的工作。

这是我的代码:

function resizeImage(url, width, height, callback, file) {
  console.log("In_resizeImage");
  var sourceImage = new Image();

  sourceImage.onload = (function (f) {
      return function (evt) {
        console.log("In_sourceImage_onload");
        console.log("sourceImage.width:" + sourceImage.width);
        console.log("sourceImage.height:" + sourceImage.height);
        var canvas = document.createElement("canvas");
        canvas.width = width;
        canvas.height = height;

        if (sourceImage.width == sourceImage.height) {
          canvas.getContext("2d").drawImage(sourceImage, 0, 0, width, height);
        } else {
          minVal = Math.min(sourceImage.width, sourceImage.height);
          if (sourceImage.width > sourceImage.height) {
            canvas.getContext("2d").drawImage(sourceImage, (sourceImage.width - minVal) / 2, 0, minVal, minVal, 0, 0, width, height);
          } else {
            canvas.getContext("2d").drawImage(sourceImage, 0, (sourceImage.height - minVal) / 2, minVal, minVal, 0, 0, width, height);
          }
        }
        callback(canvas.toDataURL(), f);
      }
    })(file);

  sourceImage.src = url;
}

我直接处理图像文件,因此我能够使用 Image 对象。对于其他人来说,可能需要进行一些调整。

Just wanted to share how I resolved my issue.
Since I wanted a purely javascript only solution, I used throwaway canvas elements to do the dirty work.

Here is my code for the same:

function resizeImage(url, width, height, callback, file) {
  console.log("In_resizeImage");
  var sourceImage = new Image();

  sourceImage.onload = (function (f) {
      return function (evt) {
        console.log("In_sourceImage_onload");
        console.log("sourceImage.width:" + sourceImage.width);
        console.log("sourceImage.height:" + sourceImage.height);
        var canvas = document.createElement("canvas");
        canvas.width = width;
        canvas.height = height;

        if (sourceImage.width == sourceImage.height) {
          canvas.getContext("2d").drawImage(sourceImage, 0, 0, width, height);
        } else {
          minVal = Math.min(sourceImage.width, sourceImage.height);
          if (sourceImage.width > sourceImage.height) {
            canvas.getContext("2d").drawImage(sourceImage, (sourceImage.width - minVal) / 2, 0, minVal, minVal, 0, 0, width, height);
          } else {
            canvas.getContext("2d").drawImage(sourceImage, 0, (sourceImage.height - minVal) / 2, minVal, minVal, 0, 0, width, height);
          }
        }
        callback(canvas.toDataURL(), f);
      }
    })(file);

  sourceImage.src = url;
}

I was directly dealing with image files so I was able to use Image object. For others to use, little bit tweaking might be required.

傲性难收 2024-12-14 16:59:34

实例化另一个 html 元素(我会选择一个表格,但我已经过时了)并使用 CSS 将图片对齐为背景图片,例如

thetable { 背景: url('planets.jpg') 0px -150px no-repeat;
宽度:60 像素;高度 60 像素}

我从这里偷了一切:如何创建 CSS-sprites

Instanciate another html-element (I would chose a table, but I'm old and outdated) and align the picture as a background picture with CSS, something like

thetable { background: url('planets.jpg') 0px -150px no-repeat;
width: 60 px; height 60 px}

I stole it all from here: How to create CSS-sprites

饭团 2024-12-14 16:59:34

这应该支持图像和视频。它将为媒体创建缩略图,但也会保持媒体纵横比。

这也应该会自行清理,这样事件泄漏就不会持续存在。它还将使缩略图图像变得平滑。

/* example to resize an image to 300px width 
and keep the aspect */ 
resizeMedia('/images/logo.jpg', 300, function(data)
{
    console.log(data); // the new thumbnail data uri 
});  


/* this will create a thumbnail of an image or video 
and keep the aspect. 
@param (string | object) media = the image string or video object 
@param (int) width = the new width to contain the media 
@param (function) callBack = the callBack to handle the 
image data uri */ 
function resizeMedia(media, width, callBack) 
{
    var self = this; 

    /* this will get the type by checking ifthe media 
    is a string (e.g. img src or dataUri) */ 
    var type = typeof media === 'string'? 'image' : 'video'; 

    /* this will get the height and width of the resized 
    media and keep the aspect. 
    @param (int) udateSize = the width the modify 
    @param (int) width = the old width 
    @param (int) height = the old height 
    @return (object) the width and height to modify the 
    media */ 
    var getModifySize = function(updateSize, width, height) 
    { 
        var getModifyAspect = function(max, min, value)
        {
            var ratio = max / min;
            return value * ratio;
        };   

        return { 
            width: updateSize,
            height: getModifyAspect(updateSize, width, height) 
        }; 
    }; 

    /* this will create a canvas and draw the media 
    on the canvas. 
    @param (object) media = the image or video 
    object 
    @param (int) width = the canvas width
    @param (int) height = the canvas height 
    @return (object) the new canvas */ 
    var createCanvas = function(media, width, height)
    { 
        var canvas = document.createElement("canvas");
        var ctx = canvas.getContext("2d"); 

        canvas.width = width;
        canvas.height = height;

        ctx.mozImageSmoothingEnabled = true;
        ctx.webkitImageSmoothingEnabled = true;
        ctx.msImageSmoothingEnabled = true;
        ctx.imageSmoothingEnabled = true;

        /* we need to draw on load to make sure
        the image is ready to be used */
        ctx.drawImage(media, 0, 0, width, height);

        /* this will convert the canvas to a data uri
        using jpeg to speed up the process. if you need 
        to keep transparency remove the mime type 
        and it will default to png */ 
        callBack(canvas.toDataURL('image/jpeg'));

        return canvas; 
    }; 

    if(type === 'image') 
    { 
        var img = new window.Image();
        img.crossOrigin = "anonymous";
        img.addEventListener('load', function loadImage() 
        {
            var modify = getModifySize(width, img.width, img.height);

            createCanvas(img, modify.width, modify.height); 
            img.removeEventListener('load', loadImage);
        });

        img.src = media;
    } 
    else if(type === 'video') 
    { 
        var modify = getModifySize(width, media.videoWidth, media.videoHeight);
        createCanvas(media, modify.width, modify.height);
    }
}; 

This should support both image and video. It will create a thumbnail for the media but will also keep the media aspect ratio.

This should also clean up after itself so no event leaks should persist. It will also smooth the thumbnail image.

/* example to resize an image to 300px width 
and keep the aspect */ 
resizeMedia('/images/logo.jpg', 300, function(data)
{
    console.log(data); // the new thumbnail data uri 
});  


/* this will create a thumbnail of an image or video 
and keep the aspect. 
@param (string | object) media = the image string or video object 
@param (int) width = the new width to contain the media 
@param (function) callBack = the callBack to handle the 
image data uri */ 
function resizeMedia(media, width, callBack) 
{
    var self = this; 

    /* this will get the type by checking ifthe media 
    is a string (e.g. img src or dataUri) */ 
    var type = typeof media === 'string'? 'image' : 'video'; 

    /* this will get the height and width of the resized 
    media and keep the aspect. 
    @param (int) udateSize = the width the modify 
    @param (int) width = the old width 
    @param (int) height = the old height 
    @return (object) the width and height to modify the 
    media */ 
    var getModifySize = function(updateSize, width, height) 
    { 
        var getModifyAspect = function(max, min, value)
        {
            var ratio = max / min;
            return value * ratio;
        };   

        return { 
            width: updateSize,
            height: getModifyAspect(updateSize, width, height) 
        }; 
    }; 

    /* this will create a canvas and draw the media 
    on the canvas. 
    @param (object) media = the image or video 
    object 
    @param (int) width = the canvas width
    @param (int) height = the canvas height 
    @return (object) the new canvas */ 
    var createCanvas = function(media, width, height)
    { 
        var canvas = document.createElement("canvas");
        var ctx = canvas.getContext("2d"); 

        canvas.width = width;
        canvas.height = height;

        ctx.mozImageSmoothingEnabled = true;
        ctx.webkitImageSmoothingEnabled = true;
        ctx.msImageSmoothingEnabled = true;
        ctx.imageSmoothingEnabled = true;

        /* we need to draw on load to make sure
        the image is ready to be used */
        ctx.drawImage(media, 0, 0, width, height);

        /* this will convert the canvas to a data uri
        using jpeg to speed up the process. if you need 
        to keep transparency remove the mime type 
        and it will default to png */ 
        callBack(canvas.toDataURL('image/jpeg'));

        return canvas; 
    }; 

    if(type === 'image') 
    { 
        var img = new window.Image();
        img.crossOrigin = "anonymous";
        img.addEventListener('load', function loadImage() 
        {
            var modify = getModifySize(width, img.width, img.height);

            createCanvas(img, modify.width, modify.height); 
            img.removeEventListener('load', loadImage);
        });

        img.src = media;
    } 
    else if(type === 'video') 
    { 
        var modify = getModifySize(width, media.videoWidth, media.videoHeight);
        createCanvas(media, modify.width, modify.height);
    }
}; 
浅忆流年 2024-12-14 16:59:34

您还可以使用drawImage()直接将图像中的中心正方形“剪辑”到画布上,您只需输入这些参数:

canvas.getContext(“2d”).drawImage(img,sx,sy,swidth,sheight, x,y,宽度,高度);

sx 可选。开始裁剪的 x 坐标

sy 可选。开始裁剪的 y 坐标

swidth 可选。裁剪图像的宽度

可选。剪切图像的高度

x 将图像放置在画布上的 x 坐标

y 将图像放置在画布上的 y 坐标

width 可选。要使用的图像的宽度(拉伸或缩小图像)

height 可选。要使用的图像的高度(拉伸或缩小图像)

问候,

Pierrick

You can also "clip" directly a centered square in the image onto the canvas with drawImage(), you simply have to put theses parameters :

canvas.getContext("2d").drawImage(img,sx,sy,swidth,sheight,x,y,width,height);

sx Optional. The x coordinate where to start clipping

sy Optional. The y coordinate where to start clipping

swidth Optional. The width of the clipped image

sheight Optional. The height of the clipped image

x The x coordinate where to place the image on the canvas

y The y coordinate where to place the image on the canvas

width Optional. The width of the image to use (stretch or reduce the image)

height Optional. The height of the image to use (stretch or reduce the image)

Regards,

Pierrick

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文