Skip to content

Commit

Permalink
Merge pull request Kozea#1881 from Kozea/images
Browse files Browse the repository at this point in the history
Improve management of images
  • Loading branch information
liZe committed Aug 24, 2023
2 parents 2326bcc + 33892cd commit 211978a
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 24 deletions.
24 changes: 18 additions & 6 deletions weasyprint/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ def draw(self, stream, concrete_width, concrete_height, image_rendering):
if self.width <= 0 or self.height <= 0:
return

width, height = self.width, self.height
interpolate = 'true' if image_rendering == 'auto' else 'false'
interpolate = image_rendering == 'auto'
ratio = 1
if self._dpi:
pt_to_in = 4 / 3 / 96
Expand All @@ -103,7 +102,7 @@ def draw(self, stream, concrete_width, concrete_height, image_rendering):
dpi = max(self.width / width_inches, self.height / height_inches)
if dpi > self._dpi:
ratio = self._dpi / dpi
image_name = stream.add_image(self, width, height, interpolate, ratio)
image_name = stream.add_image(self, interpolate, ratio)

stream.transform(
concrete_width, 0, 0, -concrete_height, 0, concrete_height)
Expand All @@ -116,7 +115,20 @@ def cache_image_data(self, data, filename=None, alpha=False):
key = f'{self.id}{int(alpha)}{self._dpi or ""}'
return LazyImage(self._cache, key, data)

def get_xobject(self, width, height, interpolate):
def get_x_object(self, interpolate, dpi_ratio):
if dpi_ratio == 1:
width, height = self.width, self.height
else:
thumbnail = Image.open(io.BytesIO(self.image_data.data))
width = max(1, int(round(self.width * dpi_ratio)))
height = max(1, int(round(self.height * dpi_ratio)))
thumbnail.thumbnail((width, height))
image_file = io.BytesIO()
thumbnail.save(
image_file, format=thumbnail.format, optimize=self.optimize)
width, height = thumbnail.width, thumbnail.height
self.image_data = self.cache_image_data(image_file.getvalue())

if self.mode in ('RGB', 'RGBA'):
color_space = '/DeviceRGB'
elif self.mode in ('L', 'LA'):
Expand All @@ -134,7 +146,7 @@ def get_xobject(self, width, height, interpolate):
'Height': height,
'ColorSpace': color_space,
'BitsPerComponent': 8,
'Interpolate': interpolate,
'Interpolate': 'true' if interpolate else 'false',
})

if self.format == 'JPEG':
Expand Down Expand Up @@ -176,7 +188,7 @@ def get_xobject(self, width, height, interpolate):
'Height': height,
'ColorSpace': '/DeviceGray',
'BitsPerComponent': 8,
'Interpolate': interpolate,
'Interpolate': 'true' if interpolate else 'false',
})
else:
png_data = self._get_png_data(
Expand Down
11 changes: 9 additions & 2 deletions weasyprint/pdf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,19 @@ def _use_references(pdf, resources, images):
for key, x_object in resources.get('XObject', {}).items():
# Images
if x_object is None:
x_object = images[key]
if x_object.number is not None:
image_data = images[key]
x_object = image_data['x_object']

if x_object is not None:
# Image already added to PDF
resources['XObject'][key] = x_object.reference
continue

image = image_data['image']
dpi_ratio = max(image_data['dpi_ratios'])
x_object = image.get_x_object(image_data['interpolate'], dpi_ratio)
image_data['x_object'] = x_object

pdf.add_object(x_object)
resources['XObject'][key] = x_object.reference

Expand Down
25 changes: 9 additions & 16 deletions weasyprint/pdf/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from fontTools import subset
from fontTools.ttLib import TTFont, TTLibError, ttFont
from fontTools.varLib.mutator import instantiateVariableFont
from PIL import Image

from ..logger import LOGGER
from ..matrix import Matrix
Expand Down Expand Up @@ -362,26 +361,20 @@ def add_group(self, x, y, width, height):
self._x_objects[group.id] = group
return group

def add_image(self, image, width, height, interpolate, ratio):
image_name = f'i{image.id}{width}{height}{interpolate}{ratio}'
def add_image(self, image, interpolate, ratio):
image_name = f'i{image.id}{int(interpolate)}'
self._x_objects[image_name] = None # Set by write_pdf
if image_name in self._images:
# Reuse image already stored in document
self._images[image_name]['dpi_ratios'].add(ratio)
return image_name

if ratio != 1:
thumbnail = Image.open(io.BytesIO(image.image_data.data))
width = int(round(image.width * ratio))
height = int(round(image.height * ratio))
thumbnail.thumbnail((max(1, width), max(1, height)))
image_file = io.BytesIO()
thumbnail.save(
image_file, format=thumbnail.format, optimize=image.optimize)
width, height = thumbnail.width, thumbnail.height
image.image_data = image.cache_image_data(image_file.getvalue())

xobject = image.get_xobject(width, height, interpolate)
self._images[image_name] = xobject
self._images[image_name] = {
'image': image,
'interpolate': interpolate,
'dpi_ratios': {ratio},
'x_object': None, # Set by write_pdf
}
return image_name

def add_pattern(self, x, y, width, height, repeat_width, repeat_height,
Expand Down

0 comments on commit 211978a

Please sign in to comment.