Search code examples
pythonpython-pptxwand

Is there any way to fit an image in pptx without changing the aspect ratio of an image using python pptx package


I have a task to create water mark in images and create pptx using these images and i should not change the aspect ratio of an image as per the rules

Image ratio = 4000x6016

Without changing the ratio, images are not fitting inside the pptx Is there any way to fit an image in pptx without changing the aspect ratio of an image using python pptx package

Expected ouput: enter image description here

current ouput enter image description here

Code:

from wand.image import Image
from pptx import Presentation
from pptx.util import Inches
prs = Presentation()
blankSideLayout = prs.slide_layouts[4]

def makePPTX(path):
   slide = prs.slides.add_slide(blankSideLayout)
   slide.shapes.title.text = "sample title"
   slide.placeholders[2].text = "Sample Sub Title" 
   slide.shapes.add_picture(path, Inches(1), Inches(3))
   prs.save("slides.pptx")

logoImg = Image(filename='logo.jpg')
logoImg.transparentize(0.33)
  
img = Image(filename='img.jpg')

img.composite_channel("all_channels",logoImg,"dissolve",20,20)
    
img.save(filename='imgwatermark.jpg')

makePPTX('imgwatermark.jpg')
    

Solution

  • Yes. In my project (md2pptx) I do this.

    Essentially you

    1. Work out the dimensions of the graphic and the space you want to fit it in.
    2. You figure out which dimension you need to scale by and by how much. Answers to 1. guide you in this.
    3. You create the graphic scaling according to 2.

    Here's code from the md2pptx repo:

    def scalePicture(maxPicWidth, maxPicHeight, imageWidth, imageHeight):
        heightIfWidthUsed = maxPicWidth * imageHeight / imageWidth
        widthIfHeightUsed = maxPicHeight * imageWidth / imageHeight
    
        if heightIfWidthUsed > maxPicHeight:
            # Use the height to scale
            usingHeightToScale = True
    
            picWidth = widthIfHeightUsed
            picHeight = maxPicHeight
    
        else:
            # Use the width to scale
            usingHeightToScale = False
    
            picWidth = maxPicWidth
            picHeight = heightIfWidthUsed
        return (picWidth, picHeight, usingHeightToScale)
    

    The main difficulty is going to be figuring out the dimensions of the source graphic.

    Here is some code I borrowed for that:

    import imghdr, struct
    
    def get_image_size(fname):
        """Determine the image type of fhandle and return its size.
        from draco"""
        try:
            with open(fname, "rb") as fhandle:
                head = fhandle.read(24)
                if len(head) != 24:
                    return -1, -1
                if imghdr.what(fname) == "png":
                    check = struct.unpack(">i", head[4:8])[0]
                    if check != 0x0D0A1A0A:
                        return
                    width, height = struct.unpack(">ii", head[16:24])
                elif imghdr.what(fname) == "gif":
                    width, height = struct.unpack("<HH", head[6:10])
                elif imghdr.what(fname) == "jpeg":
                    try:
                        fhandle.seek(0)  # Read 0xff next
                        size = 2
                        ftype = 0
                        while not 0xC0 <= ftype <= 0xCF:
                            fhandle.seek(size, 1)
                            byte = fhandle.read(1)
                            while ord(byte) == 0xFF:
                                byte = fhandle.read(1)
                            ftype = ord(byte)
                            size = struct.unpack(">H", fhandle.read(2))[0] - 2
                        # We are at a SOFn block
                        fhandle.seek(1, 1)  # Skip 'precision' byte.
                        height, width = struct.unpack(">HH", fhandle.read(4))
                    except Exception:  # IGNORE:W0703
                        return
                else:
                    return
                return width, height
        except EnvironmentError:
            return -1, -1