Allow Imaginate layers to work with rotation and skew (#806)
* Fix AI layer rotation * Transform things by matricies * Clean up size calculation Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
b10d7a93b6
commit
05169935ad
|
|
@ -328,8 +328,9 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
||||||
}
|
}
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let size = bounds[1] - bounds[0];
|
let size = bounds[1] - bounds[0];
|
||||||
|
let transform = DAffine2::from_scale_angle_translation(1. / size, 0., -bounds[0]);
|
||||||
|
|
||||||
let document = self.render_document(bounds, persistent_data, DocumentRenderMode::Root);
|
let document = self.render_document(size, transform, persistent_data, DocumentRenderMode::Root);
|
||||||
|
|
||||||
let file_suffix = &format!(".{file_type:?}").to_lowercase();
|
let file_suffix = &format!(".{file_type:?}").to_lowercase();
|
||||||
let name = match file_name.ends_with(FILE_SAVE_SUFFIX) {
|
let name = match file_name.ends_with(FILE_SAVE_SUFFIX) {
|
||||||
|
|
@ -912,6 +913,7 @@ impl DocumentMessageHandler {
|
||||||
|
|
||||||
// Prepare the Imaginate parameters and base image
|
// Prepare the Imaginate parameters and base image
|
||||||
|
|
||||||
|
let transform = self.graphene_document.root.transform.inverse() * self.graphene_document.multiply_transforms(&layer_path).unwrap();
|
||||||
let layer = self.graphene_document.layer(&layer_path).unwrap();
|
let layer = self.graphene_document.layer(&layer_path).unwrap();
|
||||||
let imaginate_layer = layer.as_imaginate().unwrap();
|
let imaginate_layer = layer.as_imaginate().unwrap();
|
||||||
|
|
||||||
|
|
@ -928,11 +930,10 @@ impl DocumentMessageHandler {
|
||||||
tiling: imaginate_layer.tiling,
|
tiling: imaginate_layer.tiling,
|
||||||
};
|
};
|
||||||
let base_image = if imaginate_layer.use_img2img {
|
let base_image = if imaginate_layer.use_img2img {
|
||||||
// Calculate the bounding box of the region to be exported
|
// Calculate the size of the region to be exported
|
||||||
let bounds = layer.aabb(&persistent_data.font_cache).unwrap_or_default();
|
let size = transform.transform_point2(DVec2::ONE) - transform.transform_point2(DVec2::ZERO);
|
||||||
let size = bounds[1] - bounds[0];
|
|
||||||
|
|
||||||
let svg = self.render_document(bounds, persistent_data, DocumentRenderMode::OnlyBelowLayerInFolder(&layer_path));
|
let svg = self.render_document(size, transform.inverse(), persistent_data, DocumentRenderMode::OnlyBelowLayerInFolder(&layer_path));
|
||||||
|
|
||||||
Some(ImaginateBaseImage { svg, size })
|
Some(ImaginateBaseImage { svg, size })
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -952,8 +953,9 @@ impl DocumentMessageHandler {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_document(&mut self, bounds: [DVec2; 2], persistent_data: &PersistentData, render_mode: DocumentRenderMode) -> String {
|
pub fn render_document(&mut self, size: DVec2, transform: DAffine2, persistent_data: &PersistentData, render_mode: DocumentRenderMode) -> String {
|
||||||
// Remove the artwork and artboard pan/tilt/zoom to render it without the user's viewport navigation, and save it to be restored at the end
|
// Remove the artwork and artboard pan/tilt/zoom to render it without the user's viewport navigation, and save it to be restored at the end
|
||||||
|
info!("Transform {transform}");
|
||||||
|
|
||||||
let old_artwork_transform = self.graphene_document.root.transform;
|
let old_artwork_transform = self.graphene_document.root.transform;
|
||||||
self.graphene_document.root.transform = DAffine2::IDENTITY;
|
self.graphene_document.root.transform = DAffine2::IDENTITY;
|
||||||
|
|
@ -965,7 +967,6 @@ impl DocumentMessageHandler {
|
||||||
|
|
||||||
// Render the document SVG code
|
// Render the document SVG code
|
||||||
|
|
||||||
let size = bounds[1] - bounds[0];
|
|
||||||
let render_data = RenderData::new(ViewMode::Normal, &persistent_data.font_cache, None);
|
let render_data = RenderData::new(ViewMode::Normal, &persistent_data.font_cache, None);
|
||||||
|
|
||||||
let artwork = match render_mode {
|
let artwork = match render_mode {
|
||||||
|
|
@ -974,10 +975,15 @@ impl DocumentMessageHandler {
|
||||||
};
|
};
|
||||||
let artboards = self.artboard_message_handler.artboards_graphene_document.render_root(render_data);
|
let artboards = self.artboard_message_handler.artboards_graphene_document.render_root(render_data);
|
||||||
let outside_artboards_color = if self.artboard_message_handler.artboard_ids.is_empty() { "#ffffff" } else { "#000000" };
|
let outside_artboards_color = if self.artboard_message_handler.artboard_ids.is_empty() { "#ffffff" } else { "#000000" };
|
||||||
let outside_artboards = format!(r#"<rect x="{}" y="{}" width="100%" height="100%" fill="{}" />"#, bounds[0].x, bounds[0].y, outside_artboards_color);
|
let outside_artboards = format!(r#"<rect x="0" y="0" width="100%" height="100%" fill="{}" />"#, outside_artboards_color);
|
||||||
|
let matrix = transform
|
||||||
|
.to_cols_array()
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.fold(String::new(), |accum, (i, entry)| accum + &(entry.to_string() + if i == 5 { "" } else { "," }));
|
||||||
let svg = format!(
|
let svg = format!(
|
||||||
r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="{} {} {} {}" width="{}" height="{}">{}{}{}{}</svg>"#,
|
r#"<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 1 1" width="{}" height="{}">{}{}<g transform="matrix({})">{}{}</g></svg>"#,
|
||||||
bounds[0].x, bounds[0].y, size.x, size.y, size.x, size.y, "\n", outside_artboards, artboards, artwork
|
size.x, size.y, "\n", outside_artboards, matrix, artboards, artwork
|
||||||
);
|
);
|
||||||
|
|
||||||
// Transform the artwork and artboard back to their original scales
|
// Transform the artwork and artboard back to their original scales
|
||||||
|
|
|
||||||
|
|
@ -188,8 +188,7 @@ impl LayerData for ImaginateLayer {
|
||||||
let transform = self.transform(transforms, render_data.view_mode);
|
let transform = self.transform(transforms, render_data.view_mode);
|
||||||
let inverse = transform.inverse();
|
let inverse = transform.inverse();
|
||||||
|
|
||||||
let matrix_values = transform.matrix2.to_cols_array();
|
let (width, height) = (transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length());
|
||||||
let (width, height) = (matrix_values[0], matrix_values[3]);
|
|
||||||
|
|
||||||
if !inverse.is_finite() {
|
if !inverse.is_finite() {
|
||||||
let _ = write!(svg, "<!-- SVG shape has an invalid transform -->");
|
let _ = write!(svg, "<!-- SVG shape has an invalid transform -->");
|
||||||
|
|
@ -205,25 +204,29 @@ impl LayerData for ImaginateLayer {
|
||||||
if let Some(blob_url) = &self.blob_url {
|
if let Some(blob_url) = &self.blob_url {
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
svg,
|
svg,
|
||||||
r#"<image width="{}" height="{}" transform="matrix(1,0,0,1,{},{})" preserveAspectRatio="none" href="{}"/>"#,
|
r#"<image width="{}" height="{}" preserveAspectRatio="none" href="{}" transform="matrix("#,
|
||||||
width.abs(),
|
width.abs(),
|
||||||
height.abs(),
|
height.abs(),
|
||||||
if width >= 0. { transform.translation.x } else { transform.translation.x + width },
|
|
||||||
if height >= 0. { transform.translation.y } else { transform.translation.y + height },
|
|
||||||
blob_url
|
blob_url
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
svg,
|
svg,
|
||||||
r#"<rect width="{}" height="{}" transform="matrix(1,0,0,1,{},{})" fill="none" stroke="var(--color-data-raster)" stroke-width="3" stroke-dasharray="8"/>"#,
|
r#"<rect width="{}" height="{}" fill="none" stroke="var(--color-data-raster)" stroke-width="3" stroke-dasharray="8" transform="matrix("#,
|
||||||
width.abs(),
|
width.abs(),
|
||||||
height.abs(),
|
height.abs(),
|
||||||
if width >= 0. { transform.translation.x } else { transform.translation.x + width },
|
|
||||||
if height >= 0. { transform.translation.y } else { transform.translation.y + height },
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = svg.write_str("</g>");
|
(transform * DAffine2::from_scale((width, height).into()).inverse())
|
||||||
|
.to_cols_array()
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.for_each(|(i, entry)| {
|
||||||
|
let _ = svg.write_str(&(entry.to_string() + if i == 5 { "" } else { "," }));
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = svg.write_str(r#")" /> </g>"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bounding_box(&self, transform: glam::DAffine2, _font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
fn bounding_box(&self, transform: glam::DAffine2, _font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue