Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul resource handling #85

Merged
merged 10 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Continuous integration
on: [push, pull_request]


env:
KRILLA_THRESHOLD: "200"
VISREG: ""
Expand Down Expand Up @@ -40,20 +41,20 @@ jobs:
uses: actions/cache@v4
with:
path: mutool
key: mupdf-binary-v1
key: mupdf-binary-v2
- name: Download MuPDF
if: steps.cache-mupdf.outputs.cache-hit != 'true'
run: |
curl -LO https://mupdf.com/downloads/archive/mupdf-1.24.8-source.tar.gz
tar -xvzf ./mupdf-1.24.8-source.tar.gz
curl -LO https://mupdf.com/downloads/archive/mupdf-1.25.1-source.tar.gz
tar -xvzf ./mupdf-1.25.1-source.tar.gz
- name: Build MuPDF
if: steps.cache-mupdf.outputs.cache-hit != 'true'
run: |
cd mupdf-1.24.8-source
cd mupdf-1.25.1-source
make HAVE_X11=no HAVE_GLUT=no
- name: Finish
if: steps.cache-mupdf.outputs.cache-hit != 'true'
run: mv mupdf-1.24.8-source/build/release/mutool mutool
run: mv mupdf-1.25.1-source/build/release/mutool mutool

gs:
name: gs
Expand Down Expand Up @@ -114,7 +115,7 @@ jobs:
- uses: actions/cache@v4
with:
path: mutool
key: mupdf-binary-v1
key: mupdf-binary-v2

- uses: actions/cache@v4
with:
Expand Down
67 changes: 29 additions & 38 deletions crates/krilla/src/content.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
//! A low-level abstraction over a single content stream.

use crate::color::{
Color, ColorSpace, ICCBasedColorSpace, LinearRgbColorSpace, DEVICE_CMYK, DEVICE_GRAY,
DEVICE_RGB,
};
use crate::color::Color;
use crate::font::{Font, Glyph, GlyphUnits};
use crate::graphics_state::GraphicsStates;
#[cfg(feature = "raster-images")]
Expand All @@ -19,7 +16,8 @@ use crate::object::tiling_pattern::TilingPattern;
use crate::object::xobject::XObject;
use crate::paint::{InnerPaint, Paint};
use crate::path::{Fill, FillRule, LineCap, LineJoin, Stroke};
use crate::resource::ResourceDictionaryBuilder;
use crate::resource;
use crate::resource::{Resource, ResourceDictionaryBuilder};
use crate::serialize::SerializerContext;
use crate::stream::Stream;
use crate::tagging::ContentTag;
Expand Down Expand Up @@ -362,7 +360,7 @@ impl ContentBuilder {
) {
let font_name = self
.rd_builder
.register_resource(font_identifier.clone(), sc);
.register_resource(sc.add_font_identifier(font_identifier));
self.content.set_font(font_name.to_pdf_name(), size);
self.content.set_text_matrix(
Transform::from_row(1.0, 0.0, 0.0, -1.0, *cur_x, cur_y).to_pdf_transform(),
Expand Down Expand Up @@ -532,7 +530,7 @@ impl ContentBuilder {
sb.expand_bbox(bbox);
},
move |sb, sc| {
let x_object_name = sb.rd_builder.register_resource(x_object, sc);
let x_object_name = sb.rd_builder.register_resource(sc.add_resource(x_object));
sb.content.x_object(x_object_name.to_pdf_name());
},
sc,
Expand Down Expand Up @@ -575,7 +573,9 @@ impl ContentBuilder {
sb.expand_bbox(Rect::from_xywh(0.0, 0.0, 1.0, 1.0).unwrap());
},
move |sb, sc| {
let image_name = sb.rd_builder.register_resource(image, sc);
let image_name = sb
.rd_builder
.register_resource(resource::XObject::new(sc.add_image(image)));

sb.content.x_object(image_name.to_pdf_name());
},
Expand All @@ -587,7 +587,9 @@ impl ContentBuilder {
self.apply_isolated_op(
|_, _| {},
move |sb, sc| {
let sh = sb.rd_builder.register_resource(shading.clone(), sc);
let sh = sb
.rd_builder
.register_resource(sc.add_resource(shading.clone()));
sb.content.shading(sh.to_pdf_name());
},
sc,
Expand Down Expand Up @@ -628,7 +630,9 @@ impl ContentBuilder {
let state = self.graphics_states.cur().ext_g_state().clone();

if !state.empty() {
let ext = self.rd_builder.register_resource(state, sc);
let ext = self
.rd_builder
.register_resource::<resource::ExtGState>(sc.add_resource(state));
self.content.set_parameters(ext.to_pdf_name());
}

Expand All @@ -651,27 +655,6 @@ impl ContentBuilder {
transform.post_concat(self.cur_transform_with_root_transform())
};

let color_to_string =
|color: Color, content_builder: &mut ContentBuilder, sc: &mut SerializerContext| {
match color.color_space(sc) {
ColorSpace::LinearRgb => content_builder
.rd_builder
.register_resource(LinearRgbColorSpace, sc),
ColorSpace::Srgb => content_builder.rd_builder.register_resource(
ICCBasedColorSpace(sc.serialize_settings().pdf_version.rgb_icc()),
sc,
),
ColorSpace::Luma => content_builder.rd_builder.register_resource(
ICCBasedColorSpace(sc.serialize_settings().pdf_version.grey_icc()),
sc,
),
ColorSpace::Cmyk(p) => content_builder.rd_builder.register_resource(p, sc),
ColorSpace::DeviceRgb => DEVICE_RGB.to_string(),
ColorSpace::DeviceGray => DEVICE_GRAY.to_string(),
ColorSpace::DeviceCmyk => DEVICE_CMYK.to_string(),
}
};

let mut write_gradient =
|gradient_props: GradientProperties,
sc: &mut SerializerContext,
Expand All @@ -680,8 +663,11 @@ impl ContentBuilder {
if let Some((color, opacity)) = gradient_props.single_stop_color() {
// Write gradients with one stop as a solid color fill.
content_builder.set_fill_opacity(opacity);
let color_space = color_to_string(color, content_builder, sc);
set_solid_fn(&mut content_builder.content, color_space, color);
let color_space = color.color_space(sc);
let color_space_resource = content_builder
.rd_builder
.register_resource(sc.add_cs(color_space));
set_solid_fn(&mut content_builder.content, color_space_resource, color);
} else {
let shading_mask =
Mask::new_from_shading(gradient_props.clone(), transform, bounds, sc);
Expand All @@ -694,12 +680,14 @@ impl ContentBuilder {
);
let color_space = content_builder
.rd_builder
.register_resource(shading_pattern, sc);
.register_resource::<resource::Pattern>(sc.add_resource(shading_pattern));

if let Some(shading_mask) = shading_mask {
let state = ExtGState::new().mask(shading_mask, sc);

let ext = content_builder.rd_builder.register_resource(state, sc);
let ext = content_builder
.rd_builder
.register_resource::<resource::ExtGState>(sc.add_resource(state));
content_builder.content.set_parameters(ext.to_pdf_name());
}

Expand All @@ -709,8 +697,9 @@ impl ContentBuilder {

match &paint.0 {
InnerPaint::Color(c) => {
let color_space = color_to_string(*c, self, sc);
set_solid_fn(&mut self.content, color_space, *c);
let cs = c.color_space(sc);
let color_space_resource = self.rd_builder.register_resource(sc.add_cs(cs));
set_solid_fn(&mut self.content, color_space_resource, *c);
}
InnerPaint::LinearGradient(lg) => {
let (gradient_props, transform) = lg.clone().gradient_properties(bounds);
Expand All @@ -737,7 +726,9 @@ impl ContentBuilder {
sc,
);

let color_space = self.rd_builder.register_resource(tiling_pattern, sc);
let color_space = self
.rd_builder
.register_resource::<resource::Pattern>(sc.add_resource(tiling_pattern));
set_pattern_fn(&mut self.content, color_space);
}
}
Expand Down
67 changes: 9 additions & 58 deletions crates/krilla/src/object/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
//! was provided to the serialize settings, this will be used for CMYK colors. Otherwise,
//! it will fall back to device CMYK.

use crate::object::{ChunkContainerFn, Object};
use crate::resource::{RegisterableResource, Resource};
use crate::object::{ChunkContainerFn, Object, Resourceable};
use crate::resource;
use crate::serialize::SerializerContext;
use crate::stream::FilterStream;
use crate::util::Prehashed;
use crate::validation::ValidationError;
use pdf_writer::{Buf, Chunk, Finish, Name, Ref};
use pdf_writer::{Chunk, Finish, Name, Ref};
use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
Expand Down Expand Up @@ -389,6 +389,10 @@ impl<const C: u8> Object for ICCBasedColorSpace<C> {
}
}

impl<const C: u8> Resourceable for ICCBasedColorSpace<C> {
type Resource = resource::ColorSpace;
}

#[derive(Clone, Hash, Debug, Eq, PartialEq)]
pub(crate) enum ICCColorSpace {
Xyz,
Expand Down Expand Up @@ -480,61 +484,25 @@ impl ICCMetadata {
}
}

impl RegisterableResource<crate::resource::ColorSpace> for ICCBasedColorSpace<4> {}
impl RegisterableResource<crate::resource::ColorSpace> for ICCBasedColorSpace<3> {}
impl RegisterableResource<crate::resource::ColorSpace> for ICCBasedColorSpace<1> {}

#[derive(Copy, Clone, Hash)]
pub(crate) struct LinearRgbColorSpace;

impl Object for LinearRgbColorSpace {
fn chunk_container(&self) -> ChunkContainerFn {
Box::new(|cc| &mut cc.color_spaces)
}

fn serialize(self, _: &mut SerializerContext, root_ref: Ref) -> Chunk {
let mut chunk = Chunk::new();
chunk.color_space(root_ref).cal_rgb(
[0.9505, 1.0, 1.0888],
None,
Some([1.0, 1.0, 1.0]),
Some([
0.4124, 0.2126, 0.0193, 0.3576, 0.715, 0.1192, 0.1805, 0.0722, 0.9505,
]),
);

chunk
}
}

impl From<LinearRgbColorSpace> for Resource {
fn from(_: LinearRgbColorSpace) -> Self {
Resource::LinearRgb
}
}

impl RegisterableResource<crate::resource::ColorSpace> for LinearRgbColorSpace {}

#[cfg(test)]
mod tests {

use crate::serialize::SerializerContext;

use crate::page::Page;
use crate::path::Fill;
use crate::resource::Resource;
use crate::surface::Surface;
use crate::tests::{cmyk_fill, rect_to_path, red_fill};
use krilla_macros::{snapshot, visreg};

#[snapshot]
fn color_space_sgray(sc: &mut SerializerContext) {
sc.add_resource(Resource::Luma);
sc.add_luma();
}

#[snapshot]
fn color_space_srgb(sc: &mut SerializerContext) {
sc.add_resource(Resource::Srgb);
sc.add_srgb();
}

#[snapshot(single_page, settings_18)]
Expand Down Expand Up @@ -563,20 +531,3 @@ mod tests {
surface.fill_path(&path, cmyk_fill(1.0));
}
}

/// Stores either the name of one of the default color spaces (i.e. DeviceRGB), or
/// a reference to a color space in the PDF.
#[derive(Copy, Clone)]
pub(crate) enum CSWrapper {
Ref(Ref),
Name(Name<'static>),
}

impl pdf_writer::Primitive for CSWrapper {
fn write(self, buf: &mut Buf) {
match self {
CSWrapper::Ref(r) => r.write(buf),
CSWrapper::Name(n) => n.write(buf),
}
}
}
10 changes: 6 additions & 4 deletions crates/krilla/src/object/ext_g_state.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::object::mask::Mask;
use crate::object::{ChunkContainerFn, Object};
use crate::resource::RegisterableResource;
use crate::object::{ChunkContainerFn, Object, Resourceable};
use crate::resource;
use crate::serialize::SerializerContext;
use crate::validation::ValidationError;
use pdf_writer::types::BlendMode;
Expand Down Expand Up @@ -99,8 +99,6 @@ impl ExtGState {
}
}

impl RegisterableResource<crate::resource::ExtGState> for ExtGState {}

impl Object for ExtGState {
fn chunk_container(&self) -> ChunkContainerFn {
Box::new(|cc| &mut cc.ext_g_states)
Expand Down Expand Up @@ -146,6 +144,10 @@ impl Object for ExtGState {
}
}

impl Resourceable for ExtGState {
type Resource = resource::ExtGState;
}

#[cfg(test)]
mod tests {
use crate::object::ext_g_state::ExtGState;
Expand Down
3 changes: 0 additions & 3 deletions crates/krilla/src/object/font/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::font::Font;
use crate::object::font::cid_font::CIDFont;
use crate::object::font::type3_font::{CoveredGlyph, Type3FontMapper, Type3ID};
use crate::path::{Fill, Stroke};
use crate::resource::RegisterableResource;

pub(crate) mod cid_font;
pub(crate) mod type3_font;
Expand Down Expand Up @@ -43,8 +42,6 @@ pub(crate) enum FontIdentifier {
Type3(Type3Identifier),
}

impl RegisterableResource<crate::resource::Font> for FontIdentifier {}

/// The owned version of `PaintMode`.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub(crate) enum OwnedPaintMode {
Expand Down
2 changes: 1 addition & 1 deletion crates/krilla/src/object/font/type3_font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ impl Type3Font {
let x_object = XObject::new(stream, false, false, None);
if !x_object.is_empty() {
font_bbox.expand(&x_object.bbox());
let x_name = rd_builder.register_resource(x_object, sc);
let x_name = rd_builder.register_resource(sc.add_resource(x_object));
content.x_object(x_name.to_pdf_name());
}

Expand Down
3 changes: 0 additions & 3 deletions crates/krilla/src/object/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use crate::color::{ICCBasedColorSpace, ICCProfile, ICCProfileWrapper, DEVICE_CMYK, DEVICE_RGB};
use crate::error::{KrillaError, KrillaResult};
use crate::object::color::DEVICE_GRAY;
use crate::resource::RegisterableResource;
use crate::serialize::SerializerContext;
use crate::stream::FilterStream;
use crate::util::{Deferred, NameExt, SipHashable};
Expand Down Expand Up @@ -516,8 +515,6 @@ fn decode_webp(data: &[u8]) -> Option<Repr> {
}))
}

impl RegisterableResource<crate::resource::XObject> for Image {}

fn handle_u8_image(data: Vec<u8>, cs: ColorSpace) -> (Vec<u8>, Option<Vec<u8>>, BitsPerComponent) {
let mut alphas = if cs.has_alpha() {
Vec::with_capacity(data.len() / cs.num_components())
Expand Down
Loading