summaryrefslogtreecommitdiff
path: root/src/export
diff options
context:
space:
mode:
Diffstat (limited to 'src/export')
-rw-r--r--src/export/pdf/image.rs22
-rw-r--r--src/export/pdf/outline.rs2
-rw-r--r--src/export/pdf/page.rs4
-rw-r--r--src/export/render.rs72
4 files changed, 67 insertions, 33 deletions
diff --git a/src/export/pdf/image.rs b/src/export/pdf/image.rs
index 04d4dcc3..dcd5a45a 100644
--- a/src/export/pdf/image.rs
+++ b/src/export/pdf/image.rs
@@ -11,6 +11,7 @@ use crate::image::{DecodedImage, RasterFormat};
pub fn write_images(ctx: &mut PdfContext) {
for image in ctx.image_map.items() {
let image_ref = ctx.alloc.bump();
+ let icc_ref = ctx.alloc.bump();
ctx.image_refs.push(image_ref);
let width = image.width();
@@ -19,7 +20,7 @@ pub fn write_images(ctx: &mut PdfContext) {
// Add the primary image.
// TODO: Error if image could not be encoded.
match image.decoded() {
- DecodedImage::Raster(dynamic, format) => {
+ DecodedImage::Raster(dynamic, icc, format) => {
// TODO: Error if image could not be encoded.
let (data, filter, has_color) = encode_image(*format, dynamic).unwrap();
let mut image = ctx.writer.image_xobject(image_ref, &data);
@@ -29,7 +30,9 @@ pub fn write_images(ctx: &mut PdfContext) {
image.bits_per_component(8);
let space = image.color_space();
- if has_color {
+ if icc.is_some() {
+ space.icc_based(icc_ref);
+ } else if has_color {
space.device_rgb();
} else {
space.device_gray();
@@ -49,6 +52,21 @@ pub fn write_images(ctx: &mut PdfContext) {
mask.height(height as i32);
mask.color_space().device_gray();
mask.bits_per_component(8);
+ } else {
+ image.finish();
+ }
+
+ if let Some(icc) = icc {
+ let compressed = deflate(&icc.0);
+ let mut stream = ctx.writer.icc_profile(icc_ref, &compressed);
+ stream.filter(Filter::FlateDecode);
+ if has_color {
+ stream.n(3);
+ stream.alternate().srgb();
+ } else {
+ stream.n(1);
+ stream.alternate().d65_gray();
+ }
}
}
DecodedImage::Svg(svg) => {
diff --git a/src/export/pdf/outline.rs b/src/export/pdf/outline.rs
index f8f12d71..c156ecaf 100644
--- a/src/export/pdf/outline.rs
+++ b/src/export/pdf/outline.rs
@@ -118,7 +118,7 @@ fn write_outline_item(
let index = pos.page.get() - 1;
if let Some(&height) = ctx.page_heights.get(index) {
let y = (pos.point.y - Abs::pt(10.0)).max(Abs::zero());
- outline.dest_direct().page(ctx.page_refs[index]).xyz(
+ outline.dest().page(ctx.page_refs[index]).xyz(
pos.point.x.to_f32(),
height - y.to_f32(),
None,
diff --git a/src/export/pdf/page.rs b/src/export/pdf/page.rs
index acf5062e..35a4f5dc 100644
--- a/src/export/pdf/page.rs
+++ b/src/export/pdf/page.rs
@@ -139,7 +139,7 @@ fn write_page(ctx: &mut PdfContext, page: Page) {
annotation
.action()
.action_type(ActionType::GoTo)
- .destination_direct()
+ .destination()
.page(ctx.page_refs[index])
.xyz(pos.point.x.to_f32(), height - y.to_f32(), None);
}
@@ -499,7 +499,7 @@ fn write_image(ctx: &mut PageContext, x: f32, y: f32, image: &Image, size: Size)
if let Some(alt) = image.alt() {
let mut image_span =
ctx.content.begin_marked_content_with_properties(Name(b"Span"));
- let mut image_alt = image_span.properties_direct();
+ let mut image_alt = image_span.properties();
image_alt.pair(Name(b"Alt"), pdf_writer::Str(alt.as_bytes()));
image_alt.finish();
image_span.finish();
diff --git a/src/export/render.rs b/src/export/render.rs
index fa3dc4b5..31e440d1 100644
--- a/src/export/render.rs
+++ b/src/export/render.rs
@@ -5,9 +5,10 @@ use std::sync::Arc;
use image::imageops::FilterType;
use image::{GenericImageView, Rgba};
+use resvg::FitTo;
use tiny_skia as sk;
use ttf_parser::{GlyphId, OutlineBuilder};
-use usvg::{FitTo, NodeExt};
+use usvg::{NodeExt, TreeParsing};
use crate::doc::{Frame, FrameItem, GroupItem, Meta, TextItem};
use crate::geom::{
@@ -38,7 +39,7 @@ pub fn render(frame: &Frame, pixel_per_pt: f32, fill: Color) -> sk::Pixmap {
fn render_frame(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
frame: &Frame,
) {
for (pos, item) in frame.items() {
@@ -73,13 +74,13 @@ fn render_frame(
fn render_group(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
group: &GroupItem,
) {
let ts = ts.pre_concat(group.transform.into());
let mut mask = mask;
- let mut storage;
+ let storage;
if group.clips {
let size = group.frame.size();
let w = size.x.to_f32();
@@ -88,22 +89,33 @@ fn render_group(
.map(sk::PathBuilder::from_rect)
.and_then(|path| path.transform(ts))
{
- let result = if let Some(mask) = mask {
- storage = mask.clone();
- storage.intersect_path(&path, sk::FillRule::default(), false)
+ if let Some(mask) = mask {
+ let mut mask = mask.clone();
+ mask.intersect_path(
+ &path,
+ sk::FillRule::default(),
+ false,
+ sk::Transform::default(),
+ );
+ storage = mask;
} else {
let pxw = canvas.width();
let pxh = canvas.height();
- storage = sk::ClipMask::new();
- storage.set_path(pxw, pxh, &path, sk::FillRule::default(), false)
+ let Some(mut mask) = sk::Mask::new(pxw, pxh) else {
+ // Fails if clipping rect is empty. In that case we just
+ // clip everything by returning.
+ return;
+ };
+
+ mask.fill_path(
+ &path,
+ sk::FillRule::default(),
+ false,
+ sk::Transform::default(),
+ );
+ storage = mask;
};
- // Clipping fails if clipping rect is empty. In that case we just
- // clip everything by returning.
- if result.is_none() {
- return;
- }
-
mask = Some(&storage);
}
}
@@ -115,7 +127,7 @@ fn render_group(
fn render_text(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
text: &TextItem,
) {
let mut x = 0.0;
@@ -136,7 +148,7 @@ fn render_text(
fn render_svg_glyph(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
text: &TextItem,
id: GlyphId,
) -> Option<()> {
@@ -157,8 +169,8 @@ fn render_svg_glyph(
// Parse SVG.
let opts = usvg::Options::default();
- let tree = usvg::Tree::from_xmltree(&document, &opts.to_ref()).ok()?;
- let view_box = tree.svg_node().view_box.rect;
+ let tree = usvg::Tree::from_xmltree(&document, &opts).ok()?;
+ let view_box = tree.view_box.rect;
// If there's no viewbox defined, use the em square for our scale
// transformation ...
@@ -182,7 +194,7 @@ fn render_svg_glyph(
// See https://github.com/RazrFalcon/resvg/issues/602 for why
// using the svg size is problematic here.
let mut bbox = usvg::Rect::new_bbox();
- for node in tree.root().descendants() {
+ for node in tree.root.descendants() {
if let Some(rect) = node.calculate_bbox().and_then(|b| b.to_rect()) {
bbox = bbox.expand(rect);
}
@@ -224,14 +236,16 @@ fn render_svg_glyph(
&sk::PixmapPaint::default(),
sk::Transform::identity(),
mask,
- )
+ );
+
+ Some(())
}
/// Render a bitmap glyph into the canvas.
fn render_bitmap_glyph(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
text: &TextItem,
id: GlyphId,
) -> Option<()> {
@@ -255,7 +269,7 @@ fn render_bitmap_glyph(
fn render_outline_glyph(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
text: &TextItem,
id: GlyphId,
) -> Option<()> {
@@ -278,7 +292,7 @@ fn render_outline_glyph(
// system is Y-up.
let scale = text.size.to_f32() / text.font.units_per_em() as f32;
let ts = ts.pre_scale(scale, -scale);
- canvas.fill_path(&path, &paint, rule, ts, mask)?;
+ canvas.fill_path(&path, &paint, rule, ts, mask);
return Some(());
}
@@ -318,7 +332,9 @@ fn render_outline_glyph(
&sk::PixmapPaint::default(),
sk::Transform::identity(),
mask,
- )
+ );
+
+ Some(())
} else {
let cw = canvas.width() as i32;
let ch = canvas.height() as i32;
@@ -365,7 +381,7 @@ fn render_outline_glyph(
fn render_shape(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
shape: &Shape,
) -> Option<()> {
let path = match shape.geometry {
@@ -465,7 +481,7 @@ fn convert_path(path: &geom::Path) -> Option<sk::Path> {
fn render_image(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
image: &Image,
size: Size,
) -> Option<()> {
@@ -503,7 +519,7 @@ fn render_image(
fn scaled_texture(image: &Image, w: u32, h: u32) -> Option<Arc<sk::Pixmap>> {
let mut pixmap = sk::Pixmap::new(w, h)?;
match image.decoded() {
- DecodedImage::Raster(dynamic, _) => {
+ DecodedImage::Raster(dynamic, _, _) => {
let downscale = w < image.width();
let filter =
if downscale { FilterType::Lanczos3 } else { FilterType::CatmullRom };