Skip to content

Commit e3cdf52

Browse files
committed
add writer
1 parent 63c4940 commit e3cdf52

File tree

6 files changed

+92
-0
lines changed

6 files changed

+92
-0
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/rnote-engine/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ usvg = { workspace = true }
5757
xmlwriter = { workspace = true }
5858
# the long-term plan is to remove the gtk4 dependency entirely after switching to another renderer.
5959
gtk4 = { workspace = true, optional = true }
60+
writer_inkml = {workspace = true}
6061

6162
[dev-dependencies]
6263
approx = { workspace = true }

crates/rnote-engine/src/engine/strokecontent.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,15 @@ impl StrokeContent {
174174

175175
Ok(())
176176
}
177+
178+
pub fn to_inkml(&self, current_dpi: f64) -> Result<Vec<u8>, std::io::Error> {
179+
writer_inkml::writer(
180+
self.strokes
181+
.iter()
182+
.map(|stroke| stroke.into_inkml(current_dpi))
183+
.filter(|x| x.is_some())
184+
.map(|x| x.unwrap())
185+
.collect(),
186+
)
187+
}
177188
}

crates/rnote-engine/src/pens/selector/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::snap::SnapCorner;
1111
use crate::store::StrokeKey;
1212
use crate::strokes::Content;
1313
use crate::{Camera, DrawableOnDoc, Engine, WidgetFlags};
14+
use core::str;
1415
use futures::channel::oneshot;
1516
use kurbo::Shape;
1617
use p2d::bounding_volume::{Aabb, BoundingSphere, BoundingVolume};
@@ -23,6 +24,7 @@ use rnote_compose::penpath::Element;
2324
use rnote_compose::style::indicators;
2425
use rnote_compose::{Color, color};
2526
use std::time::Instant;
27+
use tracing::debug;
2628
use tracing::error;
2729

2830
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -171,6 +173,8 @@ impl PenBehaviour for Selector {
171173
None
172174
};
173175

176+
let dpi = engine_view.document.config.format.dpi();
177+
174178
rayon::spawn(move || {
175179
let result = move || {
176180
if let Some(stroke_content) = stroke_content {
@@ -186,6 +190,20 @@ impl PenBehaviour for Selector {
186190
serde_json::to_string(&stroke_content)?.into_bytes(),
187191
StrokeContent::MIME_TYPE.to_string(),
188192
));
193+
194+
// add inkml content
195+
let inkml_contents = stroke_content.to_inkml(dpi);
196+
match inkml_contents {
197+
Ok(inkml_bytes) => {
198+
println!("generated inkml : {:?}", str::from_utf8(&inkml_bytes));
199+
clipboard_content.push((
200+
inkml_bytes,
201+
"application/x.windows.InkML Format".to_string(),
202+
));
203+
}
204+
_ => (),
205+
}
206+
189207
if let Some(stroke_content_svg) = stroke_content_svg {
190208
// Add generated Svg
191209
clipboard_content.push((

crates/rnote-engine/src/strokes/stroke.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rnote_compose::ext::AabbExt;
1414
use rnote_compose::penpath::Element;
1515
use rnote_compose::shapes::{Rectangle, Shapeable};
1616
use rnote_compose::style::smooth::SmoothOptions;
17+
use rnote_compose::style::PressureCurve;
1718
use rnote_compose::transform::Transform;
1819
use rnote_compose::transform::Transformable;
1920
use rnote_compose::{Color, PenPath, Style};
@@ -672,4 +673,63 @@ impl Stroke {
672673
}
673674
}
674675
}
676+
677+
/// converts a stroke into the input format used by the inkml writer
678+
pub fn into_inkml(
679+
&self,
680+
current_dpi: f64,
681+
) -> Option<(writer_inkml::FormattedStroke, writer_inkml::Brush)> {
682+
let pixel_to_cm_factor = 2.54 / current_dpi;
683+
match self {
684+
Stroke::BrushStroke(brushstroke) => {
685+
// remark : style is not preserved here, we will always get a smooth
686+
// version
687+
let fill_color = brushstroke.style.stroke_color().unwrap_or_default();
688+
let elements = brushstroke.path.clone().into_elements();
689+
let ignore_pressure = match &brushstroke.style {
690+
Style::Smooth(smooth_options) => match smooth_options.pressure_curve {
691+
PressureCurve::Const => false,
692+
_ => true,
693+
},
694+
Style::Rough(_) => false,
695+
Style::Textured(_) => false,
696+
};
697+
tracing::debug!("formatting strokes");
698+
Some((
699+
writer_inkml::FormattedStroke {
700+
x: elements
701+
.iter()
702+
.map(|element| pixel_to_cm_factor * element.pos.x)
703+
.collect(), // need the scale !
704+
y: elements
705+
.iter()
706+
.map(|element| pixel_to_cm_factor * element.pos.y)
707+
.collect(),
708+
f: elements
709+
.iter()
710+
.map(|element| pixel_to_cm_factor * element.pressure)
711+
.collect(),
712+
},
713+
writer_inkml::Brush::init(
714+
String::from(""),
715+
(
716+
(fill_color.r * 255.0) as u8,
717+
(fill_color.g * 255.0) as u8,
718+
(fill_color.b * 255.0) as u8,
719+
),
720+
ignore_pressure,
721+
((1.0 - fill_color.a) * 255.0) as u8,
722+
brushstroke.style.stroke_width() * pixel_to_cm_factor,
723+
),
724+
))
725+
}
726+
Stroke::ShapeStroke(_) => {
727+
// could be done : relatively easy to do for lines, the rest would have to be discretized
728+
None
729+
}
730+
Stroke::TextStroke(_) => None,
731+
Stroke::VectorImage(_) => None,
732+
Stroke::BitmapImage(_) => None,
733+
}
734+
}
675735
}

crates/rnote-ui/src/appwindow/actions.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rnote_compose::SplitOrder;
1717
use rnote_compose::penevent::ShortcutKey;
1818
use rnote_engine::engine::StrokeContent;
1919
use rnote_engine::ext::GraphenePointExt;
20+
use rnote_engine::pens::PenStyle;
2021
use rnote_engine::strokes::resize::{ImageSizeOption, Resize};
2122
use rnote_engine::strokes::BrushStroke;
2223
use rnote_engine::strokes::Stroke;

0 commit comments

Comments
 (0)