@@ -12,7 +12,8 @@ use crate::shape::{
12
12
13
13
use asdf_pixel_sort:: { sort_with_options, Options } ;
14
14
use core:: { cell:: RefCell , ops:: Add } ;
15
- use image:: { imageops, ImageFormat , ImageReader , Pixel } ;
15
+ use fontdue:: { Font , FontSettings } ;
16
+ use image:: { imageops, DynamicImage , ImageBuffer , ImageFormat , ImageReader , Pixel } ;
16
17
use palette:: { rgb:: Rgba , FromColor } ;
17
18
use tiny_skia:: {
18
19
BlendMode , FillRule , GradientStop , IntSize , LinearGradient , Mask , MaskType , Paint , Path ,
@@ -45,6 +46,16 @@ enum ShapeData<'a> {
45
46
zindex : f32 ,
46
47
mask : Option < Vec < ShapeData < ' a > > > ,
47
48
} ,
49
+ Text {
50
+ font : String ,
51
+ text : String ,
52
+ size : f32 ,
53
+ ops : Vec < ImageOp > ,
54
+ transform : Transform ,
55
+ paint : PixmapPaint ,
56
+ zindex : f32 ,
57
+ mask : Option < Vec < ShapeData < ' a > > > ,
58
+ } ,
48
59
Fill {
49
60
color : tiny_skia:: Color ,
50
61
zindex : f32 ,
@@ -61,6 +72,7 @@ impl ShapeData<'_> {
61
72
ShapeData :: FillPath { zindex, .. }
62
73
| ShapeData :: StrokePath { zindex, .. }
63
74
| ShapeData :: Image { zindex, .. }
75
+ | ShapeData :: Text { zindex, .. }
64
76
| ShapeData :: Fill { zindex, .. }
65
77
| ShapeData :: FillPaint { zindex, .. } => * zindex,
66
78
}
@@ -485,6 +497,45 @@ fn convert_shape_rec(
485
497
mask,
486
498
} ) ;
487
499
}
500
+ Shape :: Text {
501
+ font,
502
+ text,
503
+ size,
504
+ ops,
505
+ transform,
506
+ zindex,
507
+ opacity,
508
+ blend_mode,
509
+ quality,
510
+ mask,
511
+ } => {
512
+ let transform = transform. post_concat ( parent_transform) ;
513
+ let zindex = overwrite_zindex ( * zindex, zindex_overwrite, zindex_shift) ;
514
+ let blend_mode = overwrite_blend_mode ( * blend_mode, blend_mode_overwrite) ;
515
+ let paint = PixmapPaint {
516
+ opacity : * opacity,
517
+ blend_mode,
518
+ quality : * quality,
519
+ } ;
520
+
521
+ let mask = overwrite_mask ( mask. clone ( ) , mask_overwrite) ;
522
+ let mask = mask. map ( |shape| {
523
+ let mut mask_data = Vec :: new ( ) ;
524
+ convert_shape ( & mut mask_data, shape, parent_transform) . unwrap ( ) ;
525
+ mask_data
526
+ } ) ;
527
+
528
+ data. push ( ShapeData :: Text {
529
+ font : font. clone ( ) ,
530
+ text : text. clone ( ) ,
531
+ size : * size,
532
+ ops : ops. clone ( ) ,
533
+ transform,
534
+ paint,
535
+ zindex,
536
+ mask,
537
+ } ) ;
538
+ }
488
539
Shape :: Basic ( BasicShape :: Fill { zindex, color } , _) => {
489
540
let zindex = zindex. unwrap_or ( 0.0 ) ;
490
541
let color = overwrite_color ( color. clone ( ) , color_overwrite, color_shift) ;
@@ -703,7 +754,7 @@ fn convert_shape(
703
754
}
704
755
705
756
fn render_to_pixmap ( shape_data : ShapeData , pixmap : & mut Pixmap , width : u32 , height : u32 ) {
706
- match shape_data {
757
+ match shape_data. clone ( ) {
707
758
ShapeData :: FillPath {
708
759
path,
709
760
transform,
@@ -747,7 +798,13 @@ fn render_to_pixmap(shape_data: ShapeData, pixmap: &mut Pixmap, width: u32, heig
747
798
pixmap. stroke_path ( & path, & paint, & stroke, transform, mask. as_ref ( ) ) ;
748
799
}
749
800
ShapeData :: Image {
750
- path,
801
+ ops,
802
+ transform,
803
+ paint,
804
+ mask,
805
+ ..
806
+ }
807
+ | ShapeData :: Text {
751
808
ops,
752
809
transform,
753
810
paint,
@@ -756,21 +813,64 @@ fn render_to_pixmap(shape_data: ShapeData, pixmap: &mut Pixmap, width: u32, heig
756
813
} => {
757
814
#[ cfg( feature = "std" ) ]
758
815
{
759
- let mut image = match path {
760
- ImagePath :: File ( path) =>
761
- {
762
- #[ cfg( feature = "std" ) ]
763
- ImageReader :: open ( path) . unwrap ( ) . decode ( ) . unwrap ( )
764
- }
765
- ImagePath :: Shape ( shape) => {
766
- let pixmap = render ( shape. clone ( ) , width, height) . unwrap ( ) ;
767
- ImageReader :: with_format (
768
- Cursor :: new ( pixmap. encode_png ( ) . unwrap ( ) ) ,
769
- ImageFormat :: Png ,
770
- )
771
- . decode ( )
772
- . unwrap ( )
816
+ let mut image = match shape_data {
817
+ ShapeData :: Image { path, .. } => match path {
818
+ ImagePath :: File ( path) =>
819
+ {
820
+ #[ cfg( feature = "std" ) ]
821
+ ImageReader :: open ( path) . unwrap ( ) . decode ( ) . unwrap ( )
822
+ }
823
+ ImagePath :: Shape ( shape) => {
824
+ let pixmap = render ( shape. clone ( ) , width, height) . unwrap ( ) ;
825
+ ImageReader :: with_format (
826
+ Cursor :: new ( pixmap. encode_png ( ) . unwrap ( ) ) ,
827
+ ImageFormat :: Png ,
828
+ )
829
+ . decode ( )
830
+ . unwrap ( )
831
+ }
832
+ } ,
833
+ ShapeData :: Text {
834
+ font, text, size, ..
835
+ } => {
836
+ use std:: fs;
837
+
838
+ let font = fs:: read ( font) . unwrap ( ) ;
839
+ let font = Font :: from_bytes ( font, FontSettings :: default ( ) ) . unwrap ( ) ;
840
+
841
+ let mut bitmaps = Vec :: new ( ) ;
842
+ let mut width = 0 ;
843
+ let mut height = 0 ;
844
+
845
+ for c in text. chars ( ) {
846
+ let ( metrics, bitmap) = font. rasterize ( c, size) ;
847
+ width += ( metrics. width as u32 ) . max ( metrics. advance_width as u32 ) ;
848
+ height = height. max ( metrics. height as u32 ) ;
849
+ bitmaps. push ( ( metrics, bitmap) ) ;
850
+ }
851
+
852
+ let mut image = ImageBuffer :: new ( width, height) ;
853
+
854
+ let mut x_offset = 0 ;
855
+ for ( metrics, bitmap) in bitmaps {
856
+ for ( i, & value) in bitmap. iter ( ) . enumerate ( ) {
857
+ let x = ( x_offset as i32
858
+ + metrics. xmin
859
+ + i as i32 % metrics. width as i32 )
860
+ . max ( 0 ) as u32 ;
861
+ let y = height
862
+ - ( metrics. ymin + i as i32 / metrics. width as i32 ) . max ( 0 )
863
+ as u32
864
+ - 1 ;
865
+ image. put_pixel ( x, y, image:: Rgba ( [ value as u8 ; 4 ] ) ) ;
866
+ }
867
+
868
+ x_offset += metrics. advance_width as u32 ;
869
+ }
870
+
871
+ image. into ( )
773
872
}
873
+ _ => unreachable ! ( ) ,
774
874
} ;
775
875
776
876
for op in ops {
0 commit comments