mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-10-05 00:21:15 +03:00
Have Image objects "render themselves" on a cairo Context.
This commit is contained in:
parent
e36006ea21
commit
0faaceb44f
@ -24,14 +24,6 @@ from .stacking import StackingContext
|
||||
from .text import show_first_line
|
||||
from .compat import xrange
|
||||
|
||||
# Map values of the image-rendering property to cairo FILTER values:
|
||||
# Values are normalized to lower case.
|
||||
IMAGE_RENDERING_TO_FILTER = dict(
|
||||
optimizespeed=cairo.FILTER_FAST,
|
||||
auto=cairo.FILTER_GOOD,
|
||||
optimizequality=cairo.FILTER_BEST,
|
||||
)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def stacked(context):
|
||||
@ -304,12 +296,9 @@ def draw_background_image(context, layer):
|
||||
sub_surface = cairo.PDFSurface(None, repeat_width, repeat_height)
|
||||
sub_context = cairo.Context(sub_surface)
|
||||
sub_context.rectangle(0, 0, image_width, image_height)
|
||||
sub_context.scale(image_width / intrinsic_width,
|
||||
image_height / intrinsic_height)
|
||||
sub_pattern = layer.image.get_pattern()
|
||||
sub_pattern.set_filter(IMAGE_RENDERING_TO_FILTER[layer.image_rendering])
|
||||
sub_context.set_source(sub_pattern)
|
||||
sub_context.fill()
|
||||
sub_context.clip()
|
||||
layer.image.draw(
|
||||
sub_context, image_width, image_height, layer.image_rendering)
|
||||
pattern = cairo.SurfacePattern(sub_surface)
|
||||
pattern.set_extend(cairo.EXTEND_REPEAT)
|
||||
|
||||
@ -637,27 +626,15 @@ def draw_collapsed_borders(context, table, enable_hinting):
|
||||
|
||||
def draw_replacedbox(context, box):
|
||||
"""Draw the given :class:`boxes.ReplacedBox` to a ``cairo.context``."""
|
||||
if box.style.visibility == 'hidden':
|
||||
if box.style.visibility == 'hidden' or box.width == 0 or box.height == 0:
|
||||
return
|
||||
|
||||
x, y = box.content_box_x(), box.content_box_y()
|
||||
width, height = box.width, box.height
|
||||
scale_width = width / box.replacement.intrinsic_width
|
||||
scale_height = height / box.replacement.intrinsic_height
|
||||
# Draw nothing for width:0 or height:0
|
||||
if scale_width != 0 and scale_height != 0:
|
||||
with stacked(context):
|
||||
context.translate(x, y)
|
||||
context.rectangle(0, 0, width, height)
|
||||
context.translate(box.content_box_x(), box.content_box_y())
|
||||
context.rectangle(0, 0, box.width, box.height)
|
||||
context.clip()
|
||||
context.scale(scale_width, scale_height)
|
||||
pattern = box.replacement.get_pattern()
|
||||
# We might get a shared Pattern that was previously used
|
||||
# in a repeating background.
|
||||
pattern.set_filter(IMAGE_RENDERING_TO_FILTER[
|
||||
box.style.image_rendering])
|
||||
context.set_source(pattern)
|
||||
context.paint()
|
||||
box.replacement.draw(
|
||||
context, box.width, box.height, box.style.image_rendering)
|
||||
|
||||
|
||||
def draw_inline_level(context, page, box, enable_hinting):
|
||||
|
@ -31,6 +31,15 @@ except OSError:
|
||||
from .logger import LOGGER
|
||||
|
||||
|
||||
# Map values of the image-rendering property to cairo FILTER values:
|
||||
# Values are normalized to lower case.
|
||||
IMAGE_RENDERING_TO_FILTER = dict(
|
||||
optimizespeed=cairocffi.FILTER_FAST,
|
||||
auto=cairocffi.FILTER_GOOD,
|
||||
optimizequality=cairocffi.FILTER_BEST,
|
||||
)
|
||||
|
||||
|
||||
class RasterImage(object):
|
||||
def __init__(self, image_surface):
|
||||
self.image_surface = image_surface
|
||||
@ -38,8 +47,14 @@ class RasterImage(object):
|
||||
self.intrinsic_height = image_surface.get_height()
|
||||
self.intrinsic_ratio = self.intrinsic_width / self.intrinsic_height
|
||||
|
||||
def get_pattern(self):
|
||||
return cairocffi.SurfacePattern(self.image_surface)
|
||||
def draw(self, context, concrete_width, concrete_height, image_rendering):
|
||||
if self.intrinsic_width > 0 and self.intrinsic_height > 0:
|
||||
context.scale(concrete_width / self.intrinsic_width,
|
||||
concrete_height / self.intrinsic_height)
|
||||
context.set_source_surface(self.image_surface)
|
||||
context.get_source().set_filter(
|
||||
IMAGE_RENDERING_TO_FILTER[image_rendering])
|
||||
context.paint()
|
||||
|
||||
|
||||
class ScaledSVGSurface(cairosvg.surface.SVGSurface):
|
||||
@ -62,14 +77,14 @@ class SVGImage(object):
|
||||
self._svg_data = svg_data
|
||||
|
||||
# TODO: find a way of not doing twice the whole rendering.
|
||||
cairosvg_result = self._render()
|
||||
svg = self._render()
|
||||
# TODO: support SVG images with none or only one of intrinsic
|
||||
# width, height and ratio.
|
||||
if not (cairosvg_result.width > 0 and cairosvg_result.height > 0):
|
||||
if not (svg.width > 0 and svg.height > 0):
|
||||
raise ValueError(
|
||||
'SVG Images without an intrinsic size are not supported.')
|
||||
self.intrinsic_width = cairosvg_result.width
|
||||
self.intrinsic_height = cairosvg_result.height
|
||||
self.intrinsic_width = svg.width
|
||||
self.intrinsic_height = svg.height
|
||||
self.intrinsic_ratio = self.intrinsic_width / self.intrinsic_height
|
||||
|
||||
def _render(self):
|
||||
@ -79,11 +94,14 @@ class SVGImage(object):
|
||||
cairosvg.parser.Tree(bytestring=self._svg_data, url=self._base_url),
|
||||
output=None, dpi=96)
|
||||
|
||||
def get_pattern(self):
|
||||
# Do not re-use the Surface object, but regenerate it as needed.
|
||||
def draw(self, context, concrete_width, concrete_height, image_rendering):
|
||||
# Do not re-use the rendered Surface object, but regenerate it as needed.
|
||||
# If a surface for a SVG image is still alive by the time we call
|
||||
# show_page(), cairo will rasterize the image instead writing vectors.
|
||||
return cairocffi.SurfacePattern(self._render().cairo)
|
||||
svg = self._render()
|
||||
context.scale(concrete_width / svg.width, concrete_height / svg.height)
|
||||
context.set_source_surface(svg.cairo)
|
||||
context.paint()
|
||||
|
||||
|
||||
def get_image_from_uri(cache, url_fetcher, uri, forced_mime_type=None):
|
||||
|
Loading…
Reference in New Issue
Block a user