File size: 6,547 Bytes
dccd1b0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import io
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx.enum.text import PP_ALIGN
from PIL import Image, ImageDraw, ImageFont
import skia

def transfer_textbox_content_in_group(group_shape):
    """Edit the content of text boxes within a group shape."""
    group_shape_item = {}
    for l, shape in enumerate(group_shape.shapes):
        shape_item = {}
        if shape.has_text_frame:
            shape_item['type'] = "text"
            shape_item['location'] = (shape.left, shape.top)
            text_frame = shape.text_frame
            for r, paragraph in enumerate(text_frame.paragraphs):
                original_run = paragraph.runs[0]
                paragraph_item = {}
                paragraph_item['text'] = paragraph.text
                paragraph_item['align'] = paragraph.alignment
                font_item = {}
                font_item['name'] = original_run.font.name
                font_item['size'] = original_run.font.size
                font_item['bold'] = original_run.font.bold
                font_item['italic'] = original_run.font.italic
                font_item['underline'] = original_run.font.underline
                font_item['color'] = original_run.font.color.rgb
                font_item['language_id'] = original_run.font.language_id
                paragraph_item['font'] = font_item
                shape_item[f'paragraph_{r}'] = paragraph_item
        group_shape_item[f"shape_{l}"] = shape_item
    return group_shape_item

def pptx_to_images(pptx_path):
    # Load the PowerPoint presentation
    prs = Presentation(pptx_path)
    
    # List to hold the images
    images = []
    
    # Conversion factor from EMUs to pixels
    EMU_TO_PIXELS = 914400 / 96
    
    # Conversion factor from EMUs to points
    EMU_TO_POINTS = 12700
    
    # Load a default font
    default_font = ImageFont.load_default()
    
    # Iterate through each slide in the presentation
    for slide in prs.slides:
        # Convert slide dimensions from EMUs to pixels
        slide_width = int(prs.slide_width / EMU_TO_PIXELS)
        slide_height = int(prs.slide_height / EMU_TO_PIXELS)
        
        # Create a blank image with the same dimensions as the slide
        img = Image.new('RGB', (slide_width, slide_height), color='white')
        draw = ImageDraw.Draw(img)
        
        # Draw the slide content onto the image
        for shape in slide.shapes:
            if shape.has_text_frame:
                # Convert shape position from EMUs to pixels
                shape_left = int(shape.left / EMU_TO_PIXELS)
                shape_top = int(shape.top / EMU_TO_PIXELS)
                text_frame = shape.text_frame
                for paragraph in text_frame.paragraphs:
                    original_run = paragraph.runs[0]
                    font = ImageFont.truetype(original_run.font.name, original_run.font.size)
                    draw.text((shape_left, shape_top), paragraph.text, fill=original_run.font.color.rgb, font=font)
            elif isinstance(shape, GroupShape):
                group_content = transfer_textbox_content_in_group(shape)
                for shape_key, shape_item in group_content.items():
                    if shape_item['type'] == "text":
                        text_location = shape_item['location']
                        text_left = int(text_location[0] / EMU_TO_PIXELS)
                        text_top = int(text_location[1] / EMU_TO_PIXELS)
                        for paragraph_key, paragraph_item in shape_item.items():
                            if paragraph_key.startswith('paragraph_'):
                                font_info = paragraph_item['font']
                                # font = ImageFont.load_default()
                                print(font_info['size'])
                                font_size = int(font_info['size'] / EMU_TO_POINTS)  # Convert EMUs to points
                                font = ImageFont.truetype("fonts/FXZK-FANXMLT.ttf", font_size)
                                # font = ImageFont.truetype(font_info['name'], font_info['size'])
                                draw.text((text_left, text_top), paragraph_item['text'], fill=font_info['color'], font=font)
            elif shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
                # Convert shape position and size from EMUs to pixels
                picture_left = int(shape.left / EMU_TO_PIXELS)
                picture_top = int(shape.top / EMU_TO_PIXELS)
                picture_width = int(shape.width / EMU_TO_PIXELS)
                picture_height = int(shape.height / EMU_TO_PIXELS)
                
                # Load the picture and resize it to the correct dimensions
                picture = shape.image.blob
                picture_img = Image.open(io.BytesIO(picture))
                picture_img = picture_img.resize((picture_width, picture_height), Image.Resampling.LANCZOS)
                
                # Paste the picture onto the image
                img.paste(picture_img, (picture_left, picture_top))
        
        # Convert the PIL image to a byte stream
        img_byte_arr = io.BytesIO()
        img.save(img_byte_arr, format='PNG')
        img_byte_arr.seek(0)
        
        # Append the image byte stream to the list
        images.append(img_byte_arr)
    
    return images, (slide_width, slide_height)

def render_images_with_skia(images, slide_dimensions, output_dir):
    # Create the output directory if it doesn't exist
    import os
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    
    # Create a Skia surface
    slide_width, slide_height = slide_dimensions
    surface = skia.Surface(slide_width, slide_height)
    
    with surface as canvas:
        for i, img_byte_arr in enumerate(images):
            # Load the image into a Skia image
            skia_image = skia.Image.MakeFromEncoded(img_byte_arr.getvalue())
            
            # Draw the image onto the canvas
            canvas.drawImage(skia_image, 0, 0)
            
            # Save the canvas to a file
            output_path = os.path.join(output_dir, f'slide_{i+1}.png')
            surface.makeImageSnapshot().save(output_path, skia.kPNG)

if __name__ == "__main__":
    pptx_path = 'templates_from_gaoding/ppt/1.pptx'  # Replace with your .pptx file path
    output_dir = 'output_slides'  # Directory to save the rendered images
    images, slide_dimensions = pptx_to_images(pptx_path)
    render_images_with_skia(images, slide_dimensions, output_dir)