Merge pull request #144 from presenton/fix/presentation-export
fix/presentation export
This commit is contained in:
commit
0b8d0ba812
14 changed files with 39 additions and 55 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
},
|
||||
},
|
||||
])
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue