Fix artboards not exporting with transparency using Vello (#3921)
* Fix hide artboard for raster render mode * Desktop: Fix transparent viewport blending * Fix vello render using wrong color space conversion for background * Review
This commit is contained in:
parent
bf486b4cb5
commit
5b1e1cb2fb
|
|
@ -71,6 +71,8 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
|
||||||
if (viewport_srgb.a < 0.001) {
|
if (viewport_srgb.a < 0.001) {
|
||||||
viewport_srgb = constants.background_color;
|
viewport_srgb = constants.background_color;
|
||||||
|
} else if (viewport_srgb.a < 0.999) {
|
||||||
|
viewport_srgb = blend(viewport_srgb, constants.background_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overlay_srgb.a < 0.001) {
|
if (overlay_srgb.a < 0.001) {
|
||||||
|
|
|
||||||
|
|
@ -440,8 +440,6 @@ impl NodeGraphExecutor {
|
||||||
file_type,
|
file_type,
|
||||||
name,
|
name,
|
||||||
size,
|
size,
|
||||||
#[cfg(feature = "gpu")]
|
|
||||||
transparent_background,
|
|
||||||
artboard_name,
|
artboard_name,
|
||||||
artboard_count,
|
artboard_count,
|
||||||
..
|
..
|
||||||
|
|
@ -491,12 +489,7 @@ impl NodeGraphExecutor {
|
||||||
|
|
||||||
match file_type {
|
match file_type {
|
||||||
FileType::Png => {
|
FileType::Png => {
|
||||||
let result = if transparent_background {
|
let result = image.write_to(&mut cursor, ImageFormat::Png);
|
||||||
image.write_to(&mut cursor, ImageFormat::Png)
|
|
||||||
} else {
|
|
||||||
let image: RgbImage = image.convert();
|
|
||||||
image.write_to(&mut cursor, ImageFormat::Png)
|
|
||||||
};
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
return Err(format!("Failed to encode PNG: {err}"));
|
return Err(format!("Failed to encode PNG: {err}"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -879,42 +879,32 @@ impl Color {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the all components as a u8 slice, first component is red, followed by green, followed by blue, followed by alpha. Use this if the [`Color`] is in gamma space.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn to_rgba8(&self) -> [u8; 4] {
|
||||||
|
[(self.red * 255.) as u8, (self.green * 255.) as u8, (self.blue * 255.) as u8, (self.alpha * 255.) as u8]
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the all components as a u8 slice, first component is red, followed by green, followed by blue, followed by alpha. Use this if the [`Color`] is in linear space.
|
/// Return the all components as a u8 slice, first component is red, followed by green, followed by blue, followed by alpha. Use this if the [`Color`] is in linear space.
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// use core_types::color::Color;
|
|
||||||
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
|
||||||
/// // TODO: Add test
|
|
||||||
/// ```
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn to_rgba8_srgb(&self) -> [u8; 4] {
|
pub fn to_rgba8_srgb(&self) -> [u8; 4] {
|
||||||
let gamma = self.to_gamma_srgb();
|
self.to_gamma_srgb().to_rgba8()
|
||||||
[(gamma.red * 255.) as u8, (gamma.green * 255.) as u8, (gamma.blue * 255.) as u8, (gamma.alpha * 255.) as u8]
|
}
|
||||||
|
|
||||||
|
/// Return the all RGB components as a u8 slice, first component is red, followed by green, followed by blue. Use this if the [`Color`] is in gamma space.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn to_rgb8(&self) -> [u8; 3] {
|
||||||
|
[(self.red * 255.) as u8, (self.green * 255.) as u8, (self.blue * 255.) as u8]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the all RGB components as a u8 slice, first component is red, followed by green, followed by blue. Use this if the [`Color`] is in linear space.
|
/// Return the all RGB components as a u8 slice, first component is red, followed by green, followed by blue. Use this if the [`Color`] is in linear space.
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// use core_types::color::Color;
|
|
||||||
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
|
||||||
/// // TODO: Add test
|
|
||||||
/// ```
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn to_rgb8_srgb(&self) -> [u8; 3] {
|
pub fn to_rgb8_srgb(&self) -> [u8; 3] {
|
||||||
let gamma = self.to_gamma_srgb();
|
self.to_gamma_srgb().to_rgb8()
|
||||||
[(gamma.red * 255.) as u8, (gamma.green * 255.) as u8, (gamma.blue * 255.) as u8]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
|
// https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
|
||||||
/// Convert a [Color] to a hue, saturation, lightness and alpha (all between 0 and 1)
|
/// Convert a [Color] to a hue, saturation, lightness and alpha (all between 0 and 1)
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```
|
|
||||||
/// use core_types::color::Color;
|
|
||||||
/// let color = Color::from_hsla(0.5, 0.2, 0.3, 1.).to_hsla();
|
|
||||||
/// ```
|
|
||||||
pub fn to_hsla(&self) -> [f32; 4] {
|
pub fn to_hsla(&self) -> [f32; 4] {
|
||||||
let min_channel = self.red.min(self.green).min(self.blue);
|
let min_channel = self.red.min(self.green).min(self.blue);
|
||||||
let max_channel = self.red.max(self.green).max(self.blue);
|
let max_channel = self.red.max(self.green).max(self.blue);
|
||||||
|
|
|
||||||
|
|
@ -522,18 +522,21 @@ impl Render for Artboard {
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
// Render background
|
|
||||||
let color = peniko::Color::new([self.background.r(), self.background.g(), self.background.b(), self.background.a()]);
|
|
||||||
let [a, b] = [self.location.as_dvec2(), self.location.as_dvec2() + self.dimensions.as_dvec2()];
|
let [a, b] = [self.location.as_dvec2(), self.location.as_dvec2() + self.dimensions.as_dvec2()];
|
||||||
let rect = kurbo::Rect::new(a.x.min(b.x), a.y.min(b.y), a.x.max(b.x), a.y.max(b.y));
|
let rect = kurbo::Rect::new(a.x.min(b.x), a.y.min(b.y), a.x.max(b.x), a.y.max(b.y));
|
||||||
|
|
||||||
scene.push_layer(peniko::Fill::NonZero, peniko::Mix::Normal, 1., kurbo::Affine::new(transform.to_cols_array()), &rect);
|
// Render background
|
||||||
scene.fill(peniko::Fill::NonZero, kurbo::Affine::new(transform.to_cols_array()), color, None, &rect);
|
if !render_params.hide_artboards {
|
||||||
scene.pop_layer();
|
let color = peniko::Color::new([self.background.r(), self.background.g(), self.background.b(), self.background.a()]);
|
||||||
|
scene.push_layer(peniko::Fill::NonZero, peniko::Mix::Normal, 1., kurbo::Affine::new(transform.to_cols_array()), &rect);
|
||||||
|
scene.fill(peniko::Fill::NonZero, kurbo::Affine::new(transform.to_cols_array()), color, None, &rect);
|
||||||
|
scene.pop_layer();
|
||||||
|
}
|
||||||
|
|
||||||
if self.clip {
|
if self.clip {
|
||||||
scene.push_clip_layer(peniko::Fill::NonZero, kurbo::Affine::new(transform.to_cols_array()), &rect);
|
scene.push_clip_layer(peniko::Fill::NonZero, kurbo::Affine::new(transform.to_cols_array()), &rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since the content's transform is right multiplied in when rendering the content, we just need to right multiply by the artboard offset here.
|
// Since the content's transform is right multiplied in when rendering the content, we just need to right multiply by the artboard offset here.
|
||||||
let child_transform = transform * DAffine2::from_translation(self.location.as_dvec2());
|
let child_transform = transform * DAffine2::from_translation(self.location.as_dvec2());
|
||||||
let mut render_params = render_params.clone();
|
let mut render_params = render_params.clone();
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ impl WgpuExecutor {
|
||||||
if let Some(target_texture) = output.as_mut() {
|
if let Some(target_texture) = output.as_mut() {
|
||||||
target_texture.ensure_size(&self.context.device, size);
|
target_texture.ensure_size(&self.context.device, size);
|
||||||
|
|
||||||
let [r, g, b, a] = background.unwrap_or(Color::TRANSPARENT).to_rgba8_srgb();
|
let [r, g, b, a] = background.unwrap_or(Color::TRANSPARENT).to_rgba8();
|
||||||
let render_params = RenderParams {
|
let render_params = RenderParams {
|
||||||
base_color: vello::peniko::Color::from_rgba8(r, g, b, a),
|
base_color: vello::peniko::Color::from_rgba8(r, g, b, a),
|
||||||
width: size.x,
|
width: size.x,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue