In Python, Python Image Library 1.1.6, how can I expand the canvas without resizing?

前端 未结 4 932
北恋
北恋 2020-12-05 18:42

I am probably looking for the wrong thing in the handbook, but I am looking to take an image object and expand it without resizing (stretching/squishing) the original image.

相关标签:
4条回答
  • 2020-12-05 18:42

    You might consider a rather different approach to your image... build it out of tiles of a fixed size. That way, as you need to expand, you just add new image tiles. When you have completed all of your computation, you can determine the final size of the image, create a blank image of that size, and paste the tiles into it. That should reduce the amount of copying you're looking at for completing the task.

    (You'd likely want to encapsulate such a tiled image into an object that hid the tiling aspects from the other layers of code, of course.)

    0 讨论(0)
  • 2020-12-05 18:45

    Based on interjays answer:

    #!/usr/bin/env python
    
    from PIL import Image
    import math
    
    
    def resize_canvas(old_image_path="314.jpg", new_image_path="save.jpg",
                      canvas_width=500, canvas_height=500):
        """
        Resize the canvas of old_image_path.
    
        Store the new image in new_image_path. Center the image on the new canvas.
    
        Parameters
        ----------
        old_image_path : str
        new_image_path : str
        canvas_width : int
        canvas_height : int
        """
        im = Image.open(old_image_path)
        old_width, old_height = im.size
    
        # Center the image
        x1 = int(math.floor((canvas_width - old_width) / 2))
        y1 = int(math.floor((canvas_height - old_height) / 2))
    
        mode = im.mode
        if len(mode) == 1:  # L, 1
            new_background = (255)
        if len(mode) == 3:  # RGB
            new_background = (255, 255, 255)
        if len(mode) == 4:  # RGBA, CMYK
            new_background = (255, 255, 255, 255)
    
        newImage = Image.new(mode, (canvas_width, canvas_height), new_background)
        newImage.paste(im, (x1, y1, x1 + old_width, y1 + old_height))
        newImage.save(new_image_path)
    
    resize_canvas()
    
    0 讨论(0)
  • 2020-12-05 18:57

    The ImageOps.expand function will expand the image, but it adds the same amount of pixels in each direction.

    The best way is simply to make a new image and paste:

    newImage = Image.new(mode, (newWidth,newHeight))
    newImage.paste(srcImage, (x1,y1,x1+oldWidth,y1+oldHeight))
    

    If performance is an issue, make your original image bigger than needed and crop it after the drawing is done.

    0 讨论(0)
  • 2020-12-05 19:07

    This code will enlarge a smaller image, preserving aspect ratio, then center it on a standard sized canvas. Also preserves transparency, or defaults to gray background.

    Tested with P mode PNG files.

    Coded debug final.show() and break for testing. Remove lines and hashtag on final.save(...) to loop and save.

    Could parameterize canvas ratio and improve flexibility, but it served my purpose.

    """
    Resize ... and reconfigures. images in a specified directory
    
    Use case:  Images of varying size, need to be enlarged to exaxtly 1200 x 1200
    """
    import os
    import glob
    
    from PIL import Image
    
    # Source directory plus Glob file reference (Windows)
    source_path = os.path.join('C:', os.sep, 'path', 'to', 'source', '*.png')
    
    # List of UNC Image File paths
    images = glob.glob(source_path)
    
    # Destination directory of modified image (Windows)
    destination_path = os.path.join('C:', os.sep, 'path', 'to', 'destination')
    
    for image in images:
        
        original = Image.open(image)
    
        # Retain original attributes (ancillary chunks)
        info = original.info
        
        # Retain original mode
        mode = original.mode
    
        # Retain original palette
        if original.palette is not None:
            palette = original.palette.getdata()[1]
        else:
            palette = False
    
        # Match original aspect ratio
        dimensions = original.getbbox()
    
        # Identify destination image background color
        if 'transparency' in info.keys():
            background = original.info['transparency']
        else:
            # Image does not have transparency set
            print(image)
            background = (64)
    
        # Get base filename and extension for destination
        filename, extension = os.path.basename(image).split('.')
        
        # Calculate matched aspect ratio
        if dimensions[2] > dimensions[3]:
            width = int(1200)
            modifier = width / dimensions[2]
            length = int(dimensions[3] * modifier)
        elif dimensions[3] > dimensions[2]:
            length = int(1200)
            modifier = length / dimensions[3]
            width = int(dimensions[2] * modifier)
        else:
            width, length = (1200, 1200)
        
        size = (width, length)
    
        # Set desired final image size
        canvas = (1200, 1200)
        
        # Calculate center position
        position = (
            int((1200 - width)/2),
            int((1200 - length)/2),
            int((1200 - width)/2) + width,
            int((1200 - length)/2) + length
        )
    
        # Enlarge original image proportionally
        resized = original.resize(size, Image.LANCZOS)
    
        # Then create sized canvas
        final = Image.new(mode, canvas, background)
    
        # Replicate original properties
        final.info = info
    
        # Replicate original palatte
        if palette:
            final.putpalette(palette)
    
         # Cemter paste resized image to final canvas
        final.paste(resized, position)
    
        # Save final image to destination directory
        final.show()
    
        #final.save("{}\\{}.{}".format(destination_path, filename, extension))
    
        break
    
    0 讨论(0)
提交回复
热议问题