How to “smart resize” a displayed image to origina

2019-03-10 03:49发布

I have an application in which end-users can size and position images in a designer. Since the spec calls for the image to be "stretched" to the containing control, the end user can end up with an awkwardly stretched image.

To help the user with image sizing I am thinking of implementing a smart resizer function which would allow the the user to easily fix the aspect ratio of the picture so that it no longer appears stretched.

The quick way to solve this is to actually provide two options: 1) scale from width 2) scale from height. The user chooses the method and the algorithm adjusts the size of the picture by using the original aspect ratio. For example: A picture is displayed as 200x200 on the designer but the original image is 1024x768 pixels. The user chooses "Smart Size from width" and the new size becomes ~200x150 since the original aspect ratio is ~1.333

That's OK, but how could I make the algorithm smarter and not bother the user by asking which dimension the recalculation should be based on?

10条回答
够拽才男人
2楼-- · 2019-03-10 04:32

You just need to work out the scale needed for both dimensions and then take the smaller of the 2.

查看更多
在下西门庆
3楼-- · 2019-03-10 04:33

Because you want to maximize showing as much as possible the scaled image (of the original) in your window, i.e. the area in your designer, you would take the larger of either the width or height of the original image, and scale that to 200. Pseudo-code (width, height are dimensions of original):

if (width > height) {
    scaledWidth = 200;
    scaledHeight = (height * 200) / width;
} else {
    scaledHeight = 200;
    scaledWidth = (width * 200) / height;
}
查看更多
贼婆χ
4楼-- · 2019-03-10 04:34

There's no accounting for the amount of copy and pasters out there eh! I also wanted to know this and all I saw were endless examples of scaling width OR height.. who would want the other overflowing?!

  • Resize width AND height without the need for a loop
  • Doesn't exceed the images original dimensions
  • Uses maths that works properly i.e width/aspect for height, and height*aspect for width so images are actually scaled properly up and down :/

//////////////

private void ResizeImage(Image img, double maxWidth, double maxHeight)
{
    double srcWidth = img.Source.Width;
    double srcHeight = img.Source.Height;

    double resizeWidth = srcWidth;
    double resizeHeight = srcHeight;

    double aspect = resizeWidth / resizeHeight;

    if (resizeWidth > maxWidth)
    {
        resizeWidth = maxWidth;
        resizeHeight = resizeWidth / aspect;
    }
    if (resizeHeight > maxHeight)
    {
        aspect = resizeWidth / resizeHeight;
        resizeHeight = maxHeight;
        resizeWidth = resizeHeight * aspect;
    }

    img.Width = resizeWidth;
    img.Height = resizeHeight;
}
查看更多
成全新的幸福
5楼-- · 2019-03-10 04:34

My solution to shrink and grow size in javascript based on https://stackoverflow.com/a/5654847/1055015

var scale =  function (srcWidth, srcHeight, maxWidth, maxHeight) {

      let resizeWidth  = srcWidth;
      let resizeHeight = srcHeight;

      let aspect = resizeWidth / resizeHeight;
      let scaleX = maxWidth / srcWidth;
      let scaleY = maxHeight / srcHeight;
      let scale  = Math.min(scaleX, scaleY);

      resizeWidth *= scale;
      resizeHeight *= scale;

      if (resizeWidth > maxWidth) {
        resizeWidth  = maxWidth;
        resizeHeight = resizeWidth / aspect;
      }

      if (resizeHeight > maxHeight) {
        aspect       = resizeWidth / resizeHeight;
        resizeHeight = maxHeight;
        resizeWidth  = resizeHeight * aspect;
      }

      return {
        width : resizeWidth,
        height: resizeHeight,
      };
    }
查看更多
三岁会撩人
6楼-- · 2019-03-10 04:41

If I'm interpreting your spec correctly, you want a result that is no larger than the one the end-user laid out originally; you want one of the two dimensions to shrink, and the other to stay the same. In other words, the new size should fill the designer space in one direction while shortening the size in the other direction to retain the original aspect ratio.

original_ratio = original_width / original_height
designer_ratio = designer_width / designer_height
if original_ratio > designer_ratio
    designer_height = designer_width / original_ratio
else
    designer_width = designer_height * original_ratio

Often you'll be working with integer coordinates, but the divisions to produce the ratios above need to be floating point. Here's a rearrangement of the formula to be more integer friendly. Make sure your integers have the range to handle the maximum width*height.

if original_width * designer_height > designer_width * original_height
    designer_height = (designer_width * original_height) / original_width
else
    designer_width = (designer_height * original_width) / original_height
查看更多
ゆ 、 Hurt°
7楼-- · 2019-03-10 04:46

Took the suggestion above and made it scale up/down within max height / width. Here the python code for it and also added support for rotating things while keeping within limites:

def _resize(image, dimensions, rotate=None): """ Resizes an image to be as close as possible to specified dimensions. Image is a django image-model-field.

    Will both scale up and down the image to meet this while keeping the proportions
    in width and height

"""

if image and os.path.isfile(image.path):

    im = pil.open(image.path)
    logging.debug('resizing image from %s x %s --> %s x %s ' % (im.size[0], im.size[1], dimensions[0], dimensions[1]))

    if rotate:
        logging.debug('first rotating image %s' % rotate)
        im = im.rotate(90)

    srcWidth = Decimal(im.size[0])
    srcHeight = Decimal(im.size[1])

    resizeWidth = srcWidth
    resizeHeight = srcHeight

    aspect = resizeWidth / resizeHeight # Decimal

    logging.debug('resize aspect is %s' % aspect)

    if resizeWidth > dimensions[0] or resizeHeight > dimensions[1]:
        # if width or height is bigger we need to shrink things
        if resizeWidth > dimensions[0]:
            resizeWidth = Decimal(dimensions[0])
            resizeHeight = resizeWidth / aspect

        if resizeHeight > dimensions[1] :
            aspect = resizeWidth / resizeHeight
            resizeHeight = Decimal(dimensions[1])
            resizeWidth = resizeHeight * aspect

    else:
        # if both width and height are smaller we need to increase size
        if resizeWidth < dimensions[0]:
            resizeWidth = Decimal(dimensions[0])
            resizeHeight = resizeWidth / aspect

        if resizeHeight > dimensions[1] :
            aspect = resizeWidth / resizeHeight
            resizeHeight = Decimal(dimensions[1])
            resizeWidth = resizeHeight * aspect

    im = im.resize((resizeWidth, resizeHeight), pil.ANTIALIAS)

    logging.debug('resized image to %s %s' % im.size)
    im.save(image.path)

else:
    # no action, due to no image or no image in path
    pass

return image
查看更多
登录 后发表回答