Skip to content
Open
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ And more importantly, we do not plan to support many feature at all.
- GPU rendering.
- Text rendering (maybe someday).
- PDF generation.
- Non-RGBA8888 images.
- Non-RGBA images.
- Non-PNG image formats.
- Advanced Bézier path operations.
- Conic path segments.
Expand Down
10 changes: 10 additions & 0 deletions src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ impl PremultipliedColorU8 {
)
}
}

/// Converts into `PremultipliedColor`.
pub fn to_color(&self) -> PremultipliedColor {
PremultipliedColor {
r: NormalizedF32::new_clamped(f32::from(self.red()) / 255.0),
g: NormalizedF32::new_clamped(f32::from(self.green()) / 255.0),
b: NormalizedF32::new_clamped(f32::from(self.blue()) / 255.0),
a: NormalizedF32::new_clamped(f32::from(self.alpha()) / 255.0),
}
}
}

impl core::fmt::Debug for PremultipliedColorU8 {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub use color::{Color, ColorSpace, ColorU8, PremultipliedColor, PremultipliedCol
pub use color::{ALPHA_OPAQUE, ALPHA_TRANSPARENT, ALPHA_U8_OPAQUE, ALPHA_U8_TRANSPARENT};
pub use mask::{Mask, MaskType};
pub use painter::{FillRule, Paint};
pub use pixmap::{Pixmap, PixmapMut, PixmapRef, BYTES_PER_PIXEL};
pub use pixmap::{AlignedMemory, PixelType, Pixmap, PixmapMut, PixmapRef};
pub use shaders::{FilterQuality, GradientStop, PixmapPaint, SpreadMode};
pub use shaders::{LinearGradient, Pattern, RadialGradient, Shader, SweepGradient};

Expand Down
91 changes: 58 additions & 33 deletions src/mask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use tiny_skia_path::{IntRect, IntSize, Path, Scalar, Transform};
use crate::geom::IntSizeExt;
use crate::painter::DrawTiler;
use crate::pipeline::RasterPipelineBlitter;
use crate::pixmap::SubPixmapMut;
use crate::scan;
use crate::pixmap::PixelType;
use crate::{scan, PremultipliedColorU8};
use crate::{FillRule, PixmapRef};

/// A mask type.
Expand Down Expand Up @@ -61,30 +61,49 @@ impl Mask {
size: pixmap.size(),
};

// TODO: optimize
match mask_type {
MaskType::Alpha => {
for (p, a) in pixmap.pixels().iter().zip(mask.data.as_mut_slice()) {
*a = p.alpha();
}
}
MaskType::Luminance => {
for (p, ma) in pixmap.pixels().iter().zip(mask.data.as_mut_slice()) {
// Normalize.
let mut r = f32::from(p.red()) / 255.0;
let mut g = f32::from(p.green()) / 255.0;
let mut b = f32::from(p.blue()) / 255.0;
let a = f32::from(p.alpha()) / 255.0;

// Demultiply.
if p.alpha() != 0 {
r /= a;
g /= a;
b /= a;
for y in 0..pixmap.height() {
let pix_bpp = usize::from(pixmap.pixel_type().size());

let width = pixmap.width() as usize;
let pix_row_len = pix_bpp * width;
let row = &pixmap.data()
[y as usize * pixmap.stride()..y as usize * pixmap.stride() + pix_row_len];
let dst = &mut mask.data[y as usize * width..y as usize * width + width];

// TODO: optimize
match mask_type {
MaskType::Alpha => match pixmap.pixel_type() {
PixelType::Rgba8U => {
let pixels: &[PremultipliedColorU8] = bytemuck::cast_slice(row);
for (p, a) in pixels.iter().zip(dst) {
*a = p.alpha();
}
}
},
MaskType::Luminance => {
match pixmap.pixel_type() {
PixelType::Rgba8U => {
let pixels: &[PremultipliedColorU8] = bytemuck::cast_slice(row);

for (p, ma) in pixels.iter().zip(dst) {
// Normalize.
let mut r = f32::from(p.red()) / 255.0;
let mut g = f32::from(p.green()) / 255.0;
let mut b = f32::from(p.blue()) / 255.0;
let a = f32::from(p.alpha()) / 255.0;

// Demultiply.
if p.alpha() != 0 {
r /= a;
g /= a;
b /= a;
}

let luma = r * 0.2126 + g * 0.7152 + b * 0.0722;
*ma = ((luma * a) * 255.0).clamp(0.0, 255.0).ceil() as u8;
}
}
}

let luma = r * 0.2126 + g * 0.7152 + b * 0.0722;
*ma = ((luma * a) * 255.0).clamp(0.0, 255.0).ceil() as u8;
}
}
}
Expand Down Expand Up @@ -157,20 +176,20 @@ impl Mask {
})
}

pub(crate) fn as_subpixmap(&mut self) -> SubPixmapMut<'_> {
SubPixmapMut {
pub(crate) fn as_submask_mut(&mut self) -> SubMaskMut<'_> {
SubMaskMut {
size: self.size,
real_width: self.size.width() as usize,
data: &mut self.data,
}
}

pub(crate) fn subpixmap(&mut self, rect: IntRect) -> Option<SubPixmapMut<'_>> {
pub(crate) fn submask_mut(&mut self, rect: IntRect) -> Option<SubMaskMut<'_>> {
let rect = self.size.to_int_rect(0, 0).intersect(&rect)?;
let row_bytes = self.width() as usize;
let offset = rect.top() as usize * row_bytes + rect.left() as usize;

Some(SubPixmapMut {
Some(SubMaskMut {
size: rect.size(),
real_width: self.size.width() as usize,
data: &mut self.data[offset..],
Expand Down Expand Up @@ -294,12 +313,12 @@ impl Mask {
};

let clip_rect = tile.size().to_screen_int_rect(0, 0);
let mut subpix = match self.subpixmap(tile.to_int_rect()) {
let mut submask = match self.submask_mut(tile.to_int_rect()) {
Some(v) => v,
None => continue, // technically unreachable
};

let mut blitter = match RasterPipelineBlitter::new_mask(&mut subpix) {
let mut blitter = match RasterPipelineBlitter::new_mask(&mut submask) {
Some(v) => v,
None => continue, // nothing to do, all good
};
Expand All @@ -321,8 +340,8 @@ impl Mask {
}
} else {
let clip_rect = self.size().to_screen_int_rect(0, 0);
let mut subpix = self.as_subpixmap();
let mut blitter = match RasterPipelineBlitter::new_mask(&mut subpix) {
let mut submask = self.as_submask_mut();
let mut blitter = match RasterPipelineBlitter::new_mask(&mut submask) {
Some(v) => v,
None => return, // nothing to do, all good
};
Expand Down Expand Up @@ -402,3 +421,9 @@ impl<'a> SubMaskRef<'a> {
}
}
}

pub(crate) struct SubMaskMut<'a> {
pub(crate) data: &'a mut [u8],
pub(crate) size: IntSize,
pub(crate) real_width: usize,
}
22 changes: 10 additions & 12 deletions src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use tiny_skia_path::{PathStroker, Scalar, SCALAR_MAX};

use crate::geom::ScreenIntRect;
use crate::mask::SubMaskRef;
use crate::pipeline::{RasterPipelineBlitter, RasterPipelineBuilder};
use crate::pixmap::SubPixmapMut;
use crate::pipeline::{GenericPixmapMut, RasterPipelineBlitter, RasterPipelineBuilder};
use crate::pixmap::PixmapMut;
use crate::scan;

use crate::geom::IntSizeExt;
Expand Down Expand Up @@ -196,8 +196,7 @@ impl PixmapMut<'_> {
let clip = self.size().to_screen_int_rect(0, 0);

let mask = mask.map(|mask| mask.as_submask());
let mut subpix = self.as_subpixmap();
let mut blitter = match RasterPipelineBlitter::new(paint, mask, &mut subpix) {
let mut blitter = match RasterPipelineBlitter::new(paint, mask, self) {
Some(v) => v,
None => return, // nothing to do, all good
};
Expand Down Expand Up @@ -286,8 +285,7 @@ impl PixmapMut<'_> {
} else {
let clip_rect = self.size().to_screen_int_rect(0, 0);
let submask = mask.map(|mask| mask.as_submask());
let mut subpix = self.as_subpixmap();
let mut blitter = match RasterPipelineBlitter::new(paint, submask, &mut subpix) {
let mut blitter = match RasterPipelineBlitter::new(paint, submask, self) {
Some(v) => v,
None => return, // nothing to do, all good
};
Expand Down Expand Up @@ -414,7 +412,6 @@ impl PixmapMut<'_> {
paint.shader.transform(ts);
}
} else {
let subpix = &mut self.as_subpixmap();
let submask = mask.map(|mask| mask.as_submask());
if !transform.is_identity() {
paint.shader.transform(transform);
Expand All @@ -428,9 +425,9 @@ impl PixmapMut<'_> {
}
};

Self::stroke_hairline(&path, &paint, stroke.line_cap, submask, subpix);
Self::stroke_hairline(&path, &paint, stroke.line_cap, submask, self);
} else {
Self::stroke_hairline(path, &paint, stroke.line_cap, submask, subpix);
Self::stroke_hairline(path, &paint, stroke.line_cap, submask, self);
}
}
} else {
Expand All @@ -452,9 +449,9 @@ impl PixmapMut<'_> {
paint: &Paint,
line_cap: LineCap,
mask: Option<SubMaskRef>,
pixmap: &mut SubPixmapMut,
pixmap: &mut PixmapMut,
) {
let clip = pixmap.size.to_screen_int_rect(0, 0);
let clip = pixmap.size().to_screen_int_rect(0, 0);
let mut blitter = match RasterPipelineBlitter::new(paint, mask, pixmap) {
Some(v) => v,
None => return, // nothing to do, all good
Expand Down Expand Up @@ -531,12 +528,13 @@ impl PixmapMut<'_> {
p.push(pipeline::Stage::Store);
let mut p = p.compile();
let rect = self.size().to_screen_int_rect(0, 0);

p.run(
&rect,
pipeline::AAMaskCtx::default(),
mask.as_submask().mask_ctx(),
pixmap_src,
&mut self.as_subpixmap(),
GenericPixmapMut::from_pixmap(self),
);
}
}
Expand Down
Loading
Loading