Merge pull request #144 from presenton/fix/presentation-export

fix/presentation export
This commit is contained in:
Saurav Niraula 2025-07-26 20:26:25 +05:45 committed by GitHub
commit 0b8d0ba812
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 39 additions and 55 deletions

View file

@ -133,7 +133,7 @@ class PptxPictureBoxModel(PptxShapeModel):
margin: Optional[PptxSpacingModel] = None
clip: bool = True
opacity: Optional[float] = None
overlay: Optional[str] = None
invert: bool = False
border_radius: Optional[List[int]] = None
shape: Optional[PptxBoxShapeEnum] = None
object_fit: Optional[PptxObjectFitModel] = None

View file

@ -34,10 +34,10 @@ from models.pptx_models import (
)
from utils.download_helpers import download_files
from utils.image_utils import (
change_image_color,
clip_image,
create_circle_image,
fit_image,
invert_image,
round_image_corners,
set_image_opacity,
)
@ -174,7 +174,7 @@ class PptxPresentationCreator:
if (
picture_model.clip
or picture_model.border_radius
or picture_model.overlay
or picture_model.invert
or picture_model.opacity
or picture_model.object_fit
or picture_model.shape
@ -206,8 +206,8 @@ class PptxPresentationCreator:
image = round_image_corners(image, picture_model.border_radius)
if picture_model.shape == PptxBoxShapeEnum.CIRCLE:
image = create_circle_image(image)
if picture_model.overlay:
image = change_image_color(image, picture_model.overlay)
if picture_model.invert:
image = invert_image(image)
if picture_model.opacity:
image = set_image_opacity(image, picture_model.opacity)
image_path = os.path.join(self._temp_dir, f"{str(uuid.uuid4())}.png")

View file

@ -116,17 +116,7 @@ def round_image_corners(image: Image.Image, radii: List[int]) -> Image.Image:
return result
def change_image_color(img: Image.Image, color: str) -> Image.Image:
# r, g, b, alpha = img.split()
# color_overlay = Image.new("RGBA", img.size, color=f"#{color}")
# return Image.composite(color_overlay, img, alpha)
if color.startswith("#"):
color = color[1:]
r_new = int(color[:2], 16)
g_new = int(color[2:4], 16)
b_new = int(color[4:], 16)
def invert_image(img: Image.Image) -> Image.Image:
# Get image data
data = img.getdata()
@ -136,9 +126,9 @@ def change_image_color(img: Image.Image, color: str) -> Image.Image:
# Get current pixel values
r, g, b, a = item
# Apply new color while preserving transparency
# Invert RGB values while preserving transparency
if a != 0: # Skip fully transparent pixels
new_data.append((r_new, g_new, b_new, a))
new_data.append((255 - r, 255 - g, 255 - b, a))
else:
new_data.append((0, 0, 0, 0))

View file

@ -38,7 +38,7 @@ export const Schema = z.object({
}),
trendIcon: IconSchema.default({
__icon_url__: "https://example.com/trend-up.svg",
__icon_url__: "/static/icons/placeholder.png",
__icon_query__: "upward trend arrow icon"
}).meta({
description: "Trend indicator icon",

View file

@ -37,7 +37,7 @@ const type10SlideSchema = z.object({
})).min(2).max(3).default(() => [
{
icon: {
__icon_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'A beautiful road in the mountains'
},
heading: 'First Key Point',
@ -45,7 +45,7 @@ const type10SlideSchema = z.object({
},
{
icon: {
__icon_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'A beautiful road in the mountains'
},
heading: 'Second Key Point',

View file

@ -23,7 +23,7 @@ const type6SlideSchema = z.object({
heading: 'Professional Service',
description: 'High-quality professional services tailored to your specific needs and requirements',
icon: {
__icon_url__: 'https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Professional Service'
}
},
@ -31,7 +31,7 @@ const type6SlideSchema = z.object({
heading: 'Expert Consultation',
description: 'Expert advice and consultation from experienced professionals in the field',
icon: {
__icon_url__: 'https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Expert Consultation'
}
},
@ -39,7 +39,7 @@ const type6SlideSchema = z.object({
heading: 'Quality Assurance',
description: 'Comprehensive quality assurance processes to ensure excellent results',
icon: {
__icon_url__: 'https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Quality Assurance'
}
},
@ -47,7 +47,7 @@ const type6SlideSchema = z.object({
heading: 'Customer Support',
description: 'Dedicated customer support available to assist you throughout the process',
icon: {
__icon_url__: 'https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Customer Support'
}
}

View file

@ -18,7 +18,7 @@ const type7SlideSchema = z.object({
description: "Item description",
}),
icon: IconSchema.default({
__icon_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Default icon'
}).meta({
description: "Icon for the item",
@ -28,7 +28,7 @@ const type7SlideSchema = z.object({
heading: 'Professional Service',
description: 'High-quality professional services tailored to your specific needs and requirements',
icon: {
__icon_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Professional service icon'
}
},
@ -36,7 +36,7 @@ const type7SlideSchema = z.object({
heading: 'Expert Consultation',
description: 'Expert advice and consultation from experienced professionals in the field',
icon: {
__icon_url__: 'https://cdn.pixabay.com/photo/2016/02/19/11/19/office-1209640_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Expert consultation icon'
}
},
@ -44,7 +44,7 @@ const type7SlideSchema = z.object({
heading: 'Quality Assurance',
description: 'Comprehensive quality assurance processes to ensure excellent results',
icon: {
__icon_url__: 'https://cdn.pixabay.com/photo/2017/08/10/08/47/laptop-2619235_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Quality assurance icon'
}
},
@ -52,7 +52,7 @@ const type7SlideSchema = z.object({
heading: 'Customer Support',
description: 'Dedicated customer support available to assist you throughout the process',
icon: {
__icon_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Customer support icon'
}
}

View file

@ -21,7 +21,7 @@ const type8SlideSchema = z.object({
description: "Item description",
}),
icon: IconSchema.default({
__icon_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Default icon'
}).meta({
description: "Icon for the item",
@ -31,7 +31,7 @@ const type8SlideSchema = z.object({
heading: 'Advanced Features',
description: 'Cutting-edge functionality designed to enhance productivity and user experience',
icon: {
__icon_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Advanced features icon'
}
},
@ -39,7 +39,7 @@ const type8SlideSchema = z.object({
heading: 'Reliable Performance',
description: 'Consistent and dependable performance across all platforms and devices',
icon: {
__icon_url__: 'https://cdn.pixabay.com/photo/2016/02/19/11/19/office-1209640_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Reliable performance icon'
}
},
@ -47,7 +47,7 @@ const type8SlideSchema = z.object({
heading: 'Secure Environment',
description: 'Enterprise-grade security measures to protect your data and privacy',
icon: {
__icon_url__: 'https://cdn.pixabay.com/photo/2017/08/10/08/47/laptop-2619235_1280.jpg',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Secure environment icon'
}
}

View file

@ -32,7 +32,7 @@ const bulletWithIconsSlideSchema = z.object({
title: 'Inefficiency',
description: 'Businesses struggle to find digital tools that meet their needs, causing operational slowdowns.',
icon: {
__icon_url__: 'https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/alert-triangle.js',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'warning alert inefficiency'
}
},
@ -40,7 +40,7 @@ const bulletWithIconsSlideSchema = z.object({
title: 'High Costs',
description: 'Outdated systems increase expenses, while small businesses struggle to expand their market reach.',
icon: {
__icon_url__: 'https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/trending-up.js',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'trending up costs chart'
}
}

View file

@ -64,7 +64,7 @@ const chartWithBulletsSlideSchema = z.object({
title: 'Total Addressable Market',
description: 'Companies can use TAM to plan future expansion and investment.',
icon: {
__icon_url__: 'https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/target.js',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'target market scope'
}
},
@ -72,7 +72,7 @@ const chartWithBulletsSlideSchema = z.object({
title: 'Serviceable Available Market',
description: 'Indicates more measurable market segments for sales efforts.',
icon: {
__icon_url__: 'https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/pie-chart.js',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'pie chart analysis'
}
},
@ -80,7 +80,7 @@ const chartWithBulletsSlideSchema = z.object({
title: 'Serviceable Obtainable Market',
description: 'Help companies plan development strategies according to the market.',
icon: {
__icon_url__: 'https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/trending-up.js',
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'trending up growth'
}
}

View file

@ -44,7 +44,7 @@ const problemStatementSlideSchema = z.object({
"Businesses struggle to find digital tools that meet their needs, causing operational slowdowns.",
icon: {
__icon_url__:
"https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/alert-triangle.js",
"/static/icons/placeholder.png",
__icon_query__: "warning alert inefficiency",
},
},
@ -54,7 +54,7 @@ const problemStatementSlideSchema = z.object({
"Outdated systems increase expenses, while small businesses struggle to expand their market reach.",
icon: {
__icon_url__:
"https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/trending-up.js",
"/static/icons/placeholder.png",
__icon_query__: "trending up costs chart",
},
},
@ -64,7 +64,7 @@ const problemStatementSlideSchema = z.object({
"Businesses struggle to find digital tools that meet their needs, causing operational slowdowns.",
icon: {
__icon_url__:
"https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/alert-triangle.js",
"/static/icons/placeholder.png",
__icon_query__: "warning alert inefficiency",
},
},
@ -74,7 +74,7 @@ const problemStatementSlideSchema = z.object({
"Businesses struggle to find digital tools that meet their needs, causing operational slowdowns.",
icon: {
__icon_url__:
"https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/alert-triangle.js",
"/static/icons/placeholder.png",
__icon_query__: "warning alert inefficiency",
},
},

View file

@ -51,7 +51,7 @@ const solutionSlideSchema = z.object({
icon: {
__icon_query__: "market innovation",
__icon_url__:
"https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/globe.js",
"/static/icons/placeholder.png",
},
},
{
@ -60,7 +60,7 @@ const solutionSlideSchema = z.object({
icon: {
__icon_query__: "industry building",
__icon_url__:
"https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/building.js",
"/static/icons/placeholder.png",
},
},
{
@ -69,7 +69,7 @@ const solutionSlideSchema = z.object({
icon: {
__icon_query__: "SEM data analysis",
__icon_url__:
"https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/chart-bar.js",
"/static/icons/placeholder.png",
},
},
{
@ -78,7 +78,7 @@ const solutionSlideSchema = z.object({
icon: {
__icon_query__: "end user impact",
__icon_url__:
"https://cdn.jsdelivr.net/npm/lucide@latest/dist/esm/icons/user.js",
"/static/icons/placeholder.png",
},
},
])

View file

@ -304,8 +304,8 @@ export interface PptxPictureBoxModel extends PptxShapeModel {
position: PptxPositionModel;
margin?: PptxSpacingModel;
clip: boolean;
overlay?: string;
opacity?: number;
invert?: boolean;
border_radius?: number[];
shape?: PptxBoxShapeEnum;
object_fit?: PptxObjectFitModel;

View file

@ -219,17 +219,11 @@ function convertToPictureBox(element: ElementAttributes): PptxPictureBoxModel {
path: element.imageSrc || ''
};
// Set overlay to white if invert is 1 and brightness is 0
let overlay = element.overlay;
if (element.filters?.invert === 1 && element.filters?.brightness === 0) {
overlay = 'FFFFFF';
}
return {
position,
margin: undefined,
clip: element.clip ?? true,
overlay,
invert: element.filters?.invert === 1,
opacity: element.opacity,
border_radius: element.borderRadius ? element.borderRadius.map(r => Math.round(r)) : undefined,
shape: element.shape ? (element.shape as PptxBoxShapeEnum) : PptxBoxShapeEnum.RECTANGLE,