xcf-rs 0.5.0

A basic standalone GIMP XCF library in Rust.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

use byteorder::{BigEndian, ByteOrder};

extern crate hex_slice;
use hex_slice::AsHex;

use crate::data::color::ColorType;
use crate::data::layer::Layer;
use crate::data::property::Property;
use crate::data::property::PropertyPayload;
use crate::data::xcf::XcfCompression;
use crate::data::tiles::Tiles;
use crate::LayerColorValue;
use crate::PropertyIdentifier;
use crate::RgbaPixel;

pub struct XcfCreator {
    pub version: u16,
    pub data: Vec<u8>,
    pub index: u64,
    pub compression: XcfCompression,
}

//impl Creator for Xcf {
impl XcfCreator {
    fn extend_u32(&mut self, value: u32) {
        let mut width_buf = vec![0; 4];
        BigEndian::write_u32(&mut width_buf, value);
        self.data.extend_from_slice(&width_buf);
        self.index += 4;
    }

    fn extend_u64(&mut self, value: u64) {
        let mut width_buf = vec![0; 8];
        BigEndian::write_u64(&mut width_buf, value);
        self.data.extend_from_slice(&width_buf);
        self.index += 8;
    }

    fn buf_extend_u32(&mut self, data: &mut Vec<u8>, index: &mut u32, value: u32) {
        let size = 4;
        let mut width_buf = vec![0; size];
        BigEndian::write_u32(&mut width_buf, value);
        data.extend_from_slice(&width_buf);
        *index += size as u32;
    }

    fn buf_extend_u64(&mut self, data: &mut Vec<u8>, index: &mut u32, value: u64) {
        let size = 8;
        let mut width_buf = vec![0; size];
        BigEndian::write_u64(&mut width_buf, value);
        data.extend_from_slice(&mut width_buf);
        *index += size as u32;
    }

    fn create_signature(&mut self, gimp_version: u16) {
        let mut signature = format!("gimp xcf v{:03}\0", gimp_version);
        if gimp_version == 1 {
            signature = "gimp xcf file\0".to_string();
        }
        self.data.extend_from_slice(signature.as_bytes());
        self.index += 14;
    }

    fn v10_gimp_string(&mut self, data: &mut Vec<u8>, index: &mut u32, str: &[u8]) {
        let str_count = str.len() as u32;
        self.buf_extend_u32(data, index, str_count + 4);
        data.extend_from_slice(str);
        *index += str_count;
        self.buf_extend_u32(data, index, 0);
    }

    fn gimp_string(&mut self, data: &mut Vec<u8>, index: &mut u32, str: &[u8]) {
        let str_count = str.len() as u32 + 1;
        self.buf_extend_u32(data, index, str_count);
        data.extend_from_slice(str);
        data.extend_from_slice(&[0]);
        *index += str_count;
    }

    fn parasite_prop(&mut self, data: &mut Vec<u8>, index: &mut u32, parasite_title: &str, parasite_data: &str, flags: u32) {
        let title_len = parasite_title.len() + 1;
        self.buf_extend_u32(data, index, title_len as u32);
        data.extend_from_slice(parasite_title.as_bytes());
        data.extend_from_slice(&[0]);
        *index += title_len as u32;
        self.buf_extend_u32(data, index,flags);

        let data_len = parasite_data.len() + 1;
        self.buf_extend_u32(data, index,data_len as u32);
        data.extend_from_slice(parasite_data.as_bytes());
        data.extend_from_slice(&[0]);
        *index += data_len as u32;
    }

    pub fn new(version: u16, width: u32, height: u32, color_type: ColorType) -> Self {
        let data = vec![];
        let index = 0;

        let mut _self = XcfCreator {
            version,
            data,
            index,
            compression: XcfCompression::None,
        };
        _self.create_signature(version);
        _self.extend_u32(width);
        _self.extend_u32(height);
        _self.extend_u32(color_type as u32);

        if version >= 4 {
            _self.extend_u32(150); // 8-bit gamma integer
        }

        _self
    }

    fn prop_end(&mut self, data: &mut Vec<u8>, index: &mut u32) {
        self.buf_extend_u32(data, index, 0);
        self.buf_extend_u32(data, index, 0);
        //self.extend_u64(0); // prop : End + size : 0
    }

    pub fn add_properties(&mut self, properties: &Vec<Property>) {
        let mut _has_compression = false;
        for property in properties {
            self.extend_u32(property.kind as u32);
            match &property.payload {
                PropertyPayload::Compression(_value) => {
                    self.extend_u32(property.length as u32); // size

                    self.data.extend_from_slice(&[_value.to_u8()]);
                    self.index += 1;
                    self.compression = _value.clone();
                    _has_compression = true;
                }
                PropertyPayload::ResolutionProperty(_value) => {
                    self.extend_u32(property.length as u32); // size

                    self.extend_u32(_value.xres.to_bits()); // X resolution in DPI
                    self.extend_u32(_value.yres.to_bits()); // Y resolution in DPI
                }
                PropertyPayload::Tatoo(_value) | PropertyPayload::Unit(_value) => {
                    self.extend_u32(property.length as u32); // size

                    self.extend_u32(*_value);
                }
                PropertyPayload::Parasites(_parasites) => {
                    let mut parasite_prop_buf = vec![];
                    let mut parasite_prop_len = 0;
                    for parasite in _parasites {
                        self.parasite_prop(
                            &mut parasite_prop_buf, 
                            &mut parasite_prop_len, 
                            &parasite.name,
                            &parasite.data,
                            parasite.flags
                        );
                    }
                    self.extend_u32(parasite_prop_len); // size
                    self.data.extend_from_slice(&parasite_prop_buf);
                    self.index += parasite_prop_len as u64;
                }
                _ => {
                    self.extend_u32(property.length as u32); // size
                }
            }
        }
        if self.version > 10 && !_has_compression {
            self.extend_u32(PropertyIdentifier::PropCompression as u32);
            self.extend_u32(1); // size
            self.data.extend_from_slice(&[XcfCompression::Rle as u8]);
            self.index += 1;
            self.compression = XcfCompression::Rle;

            // resolution
            self.extend_u32(PropertyIdentifier::PropResolution as u32);
            self.extend_u32(8); // size
            let value: f32 = 300.0;
            self.extend_u32(value.to_bits()); // X resolution in DPI
            self.extend_u32(value.to_bits()); // Y resolution in DPI

            // tatoo
            self.extend_u32(PropertyIdentifier::PropTattoo as u32);
            self.extend_u32(4); // size
            self.extend_u32(2);

            // unit
            self.extend_u32(PropertyIdentifier::PropUnit as u32);
            self.extend_u32(4); // size
            self.extend_u32(1);

            // parasites
            let mut parasite_prop_buf = vec![];
            let mut parasite_prop_len = 0;
            self.parasite_prop(
                &mut parasite_prop_buf, 
                &mut parasite_prop_len, 
                "gimp-comment", 
                //"Created with GIMP",
                "Test Comment",
                1
            );
            self.parasite_prop(
                &mut parasite_prop_buf, 
                &mut parasite_prop_len, 
                "gimp-image-grid", 
                "(style solid)\n(fgcolor (color-rgba 0 0 0 1))\n(bgcolor (color-rgba 1 1 1 1))\n(xspacing 10)\n(yspacing 10)\n(spacing-unit inches)\n(xoffset 0)\n(yoffset 0)\n(offset-unit inches)\n",
                1
            );
            self.extend_u32(PropertyIdentifier::PropParasites as u32);
            self.extend_u32(parasite_prop_len); // size
            self.data.extend_from_slice(&parasite_prop_buf);
            self.index += parasite_prop_len as u64;
        }

        // TODO : replace by : self.propend()
        self.extend_u32(0);
        self.extend_u32(0);
    }

    fn _add_layers_properties(&mut self, data: &mut Vec<u8>, index: &mut u32, layers_properties: &Vec<Property>) {
        for layer_property in layers_properties {
            self.buf_extend_u32(data, index, layer_property.kind as u32);
            self.buf_extend_u32(data, index, layer_property.length as u32); // size
            match &layer_property.payload {
                PropertyPayload::Compression(_value) => {
                    data.extend_from_slice(&[_value.to_u8()]);
                    *index += 1;
                }
                PropertyPayload::OpacityLayer(_value) => {
                    data
                        .extend_from_slice(&[_value.r(), _value.g(), _value.b(), _value.a()]);
                    *index += 4;
                }
                PropertyPayload::FloatOpacityLayer() => {
                    // TODO : à améliorer, ça doit être une valeur en float
                    let float_slice = [63, 128, 0, 0];
                    data.extend_from_slice(&float_slice); // prop float opacity value
                    *index += 4;
                }
                PropertyPayload::VisibleLayer() => {
                    let float_slice = [0, 0, 0, 1];
                    data.extend_from_slice(&float_slice); // prop visible value
                    *index += 4;
                }
                PropertyPayload::OffsetsLayer(_offset_x, _offset_y) => {
                    self.buf_extend_u32(data, index, *_offset_x);
                    self.buf_extend_u32(data, index, *_offset_y);
                }
                PropertyPayload::LinkedLayer(_value)
                | PropertyPayload::ColorTagLayer(_value)
                | PropertyPayload::LockContentLayer(_value)
                | PropertyPayload::LockAlphaLayer(_value)
                | PropertyPayload::LockPositionLayer(_value)
                | PropertyPayload::ApplyMaskLayer(_value)
                | PropertyPayload::EditMaskLayer(_value)
                | PropertyPayload::ShowMaskLayer(_value)
                | PropertyPayload::ModeLayer(_value)
                | PropertyPayload::BlendSpaceLayer(_value)
                | PropertyPayload::CompositeSpaceLayer(_value)
                | PropertyPayload::CompositeModeLayer(_value)
                | PropertyPayload::Tatoo(_value) => {
                    self.buf_extend_u32(data, index, *_value);
                }
                _ => {}
            }
        }
        if self.version > 10 && layers_properties.iter().len() == 0 {
            // active
            self.buf_extend_u32(data, index, PropertyIdentifier::PropActiveLayer as u32);
            self.buf_extend_u32(data, index, 0);
            // opacity
            self.buf_extend_u32(data, index, PropertyIdentifier::PropOpacity as u32);
            self.buf_extend_u32(data, index, 4);
            data.extend_from_slice(&[0, 0, 0, 255]);
            *index += 4;
            // float opacity
            self.buf_extend_u32(data, index, PropertyIdentifier::PropFloatOpacity as u32);
            self.buf_extend_u32(data, index, 4);
            let float_slice = [63, 128, 0, 0];
            data.extend_from_slice(&float_slice); // prop float opacity value
            *index += 4;
            // visible
            self.buf_extend_u32(data, index, PropertyIdentifier::PropVisible as u32);
            self.buf_extend_u32(data, index, 4);
            let float_slice = [0, 0, 0, 1];
            data.extend_from_slice(&float_slice); // prop visible value
            *index += 4;

            // linked
            self.buf_extend_u32(data, index, PropertyIdentifier::PropLinked as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, 0);

            // color tag
            self.buf_extend_u32(data, index, PropertyIdentifier::PropColorTag as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, 0);

            // lock content
            self.buf_extend_u32(data, index, PropertyIdentifier::PropLockContent as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, 0);

            // lock alpha
            self.buf_extend_u32(data, index, PropertyIdentifier::PropLockAlpha as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, 0);

            // lock position
            self.buf_extend_u32(data, index, PropertyIdentifier::PropLockPosition as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, 0);

            // apply mask
            self.buf_extend_u32(data, index, PropertyIdentifier::PropApplyMask as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, 0);

            // edit mask
            self.buf_extend_u32(data, index, PropertyIdentifier::PropEditMask as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, 0);

            // show mask
            self.buf_extend_u32(data, index, PropertyIdentifier::PropShowMask as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, 0);

            // offsets
            self.buf_extend_u32(data, index, PropertyIdentifier::PropOffsets as u32);
            self.buf_extend_u32(data, index, 8);
            self.buf_extend_u32(data, index, 0);
            self.buf_extend_u32(data, index, 0);

            // if version >= 11, than the layer mode must be the new normal mode (not legacy)
            self.buf_extend_u32(data, index, PropertyIdentifier::PropMode as u32);
            self.buf_extend_u32(data, index, 4); // size
            self.buf_extend_u32(data, index, 28); // mode normal after version 10

            // blend space
            self.buf_extend_u32(data, index, PropertyIdentifier::PropBlendSpace as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, 0);

            // composite space
            self.buf_extend_u32(data, index, PropertyIdentifier::PropCompositeSpace as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, u32::MAX);

            // composite mode
            self.buf_extend_u32(data, index, PropertyIdentifier::PropCompositeMode as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, u32::MAX);

            // tatoo
            self.buf_extend_u32(data, index, PropertyIdentifier::PropTattoo as u32);
            self.buf_extend_u32(data, index, 4);
            self.buf_extend_u32(data, index, 2);
        }
        self.prop_end(data, index);
    }

    fn _add_layers_v10(&mut self, _layers: &[Layer]) {
        let mut intermediate_buf = vec![];
        let mut layer_offset_zero_index = 0;

        self.buf_extend_u32(&mut intermediate_buf, &mut layer_offset_zero_index, 0); // layer_offset[n] : 0 = end
        self.buf_extend_u32(&mut intermediate_buf, &mut layer_offset_zero_index, 0); // channel_offset[] = 0 => end

        self.index += layer_offset_zero_index as u64;

        let mut layer_offset_one_buf = vec![];
        let mut layer_offset_one_index = 0;

        self.buf_extend_u32(
            &mut layer_offset_one_buf,
            &mut layer_offset_one_index,
            self.index as u32 + 4,
        ); // layer_offset[0] = le pointer du calque

        layer_offset_one_buf.extend_from_slice(&intermediate_buf);
        self.data.extend_from_slice(&layer_offset_one_buf);
        self.index += layer_offset_one_index as u64;

        self.extend_u32(1); // layer[0] : width=1
        self.extend_u32(1); // layer[0] : height=1
        self.extend_u32(0); // layer[0] : type=RGB

        // layer name :
        let mut layer_name_data = vec!();
        let mut layer_name_len = 0;
        self.v10_gimp_string(&mut layer_name_data, &mut layer_name_len, b"Background");
        self.data.extend_from_slice(&layer_name_data);
        self.index += layer_name_len as u64;

        self.extend_u32(PropertyIdentifier::PropActiveLayer as u32); // prop = 2 : active layer
        self.extend_u32(0);

        self.extend_u32(PropertyIdentifier::PropOpacity as u32); // prop : opacity
        self.extend_u32(4); // prop opacity size
        self.extend_u32(RgbaPixel::new(0, 0, 0, 255).to_u32()); // color of opacity = black

        self.extend_u32(PropertyIdentifier::PropMode as u32); // prop : Mode
        self.extend_u32(4); // prop mode size
        self.extend_u32(0); // prop mode=normal

        // TODO : à améliorer, ça doit être une valeur en float
        self.extend_u32(PropertyIdentifier::PropFloatOpacity as u32); // prop : float opacity
        self.extend_u32(4); // prop float opacity size
        let float_slice = [63, 128, 0, 0];
        self.data.extend_from_slice(&float_slice); // prop float opacity value
        self.index += 4;

        self.extend_u32(PropertyIdentifier::PropVisible as u32); // prop : visible
        self.extend_u32(4); // prop visible size
        let float_slice = [0, 0, 0, 1];
        self.data.extend_from_slice(&float_slice); // prop visible value
        self.index += 4;

        self.extend_u32(PropertyIdentifier::PropLinked as u32); // prop : linked
        self.extend_u32(4); // prop linked size
        self.extend_u32(0); // prop linked value


        // TODO : replace by : self.propend()
        self.extend_u32(0);
        self.extend_u32(0);

        // hierarchy offset
        self.extend_u32(self.index as u32 + 8);
        self.extend_u32(0); // mask offset

        // https://testing.developer.gimp.org/core/standards/xcf/#the-hierarchy-structure
        self.extend_u32(1); // width=1
        self.extend_u32(1); // height=1
        self.extend_u32(3); // bpp=3 : RGB color without alpha in 8-bit precision

        self.extend_u32(self.index as u32 + 8); // offset[0]

        self.extend_u32(0); // offset[n] = 0 => end

        self.extend_u32(1); // level[0] width =1
        self.extend_u32(1); // level[0] height =1
        self.extend_u32(self.index as u32 + 8); // offset= le pointer du contenu

        self.extend_u32(0); // data_offset[0] = 0 => end

        //let slice = [00, 158, 00, 36, 00, 222]; // violet r: 158, g: 23, b: 222  with RLE compression
        let slice = [158, 36, 222]; // violet r: 158, g: 36, b: 222  without compression

        // \0\0\2\xa4\0\0\0\0\0\0\0\0\0\x9e
        self.data.extend_from_slice(&slice);
    }

    pub fn add_layers(&mut self, layers: &Vec<Layer>) {
        if self.version < 11 {
            self._add_layers_v10(layers);
            return;
        }
        let nb_layers = layers.iter().len();

        let mut layer_data = vec![];
        let mut layer_index = 0;
        for layer in layers {
            layer_index += 1;
            let mut layer_len = 0;

            let tiles = Tiles::new(layer);

            // Each layers is 8 bits + 8 bits for close layers + 8 bits for close channels
            let layer_offset = self.index + (nb_layers - layer_index + 1) as u64 * 8 + layer_len as u64 + 16;
            /*
            println!(
                "layer[{}] >>>> self.index : {} ---- layer_index {} ---- nb_layers {} layer_len {} ===> {}",
                layer_index - 1,
                self.index,
                layer_index,
                nb_layers,
                layer_len,
                layer_offset
            );
            */
            self.extend_u64(layer_offset); // layer_offset[index -1]
            //self.buf_extend_u64(&mut layer_data, &mut layer_len, pos_layer); // layer_offset[index -1]

            self.buf_extend_u32(&mut layer_data, &mut layer_len, layer.width);
            self.buf_extend_u32(&mut layer_data, &mut layer_len, layer.height);
            self.buf_extend_u32(&mut layer_data, &mut layer_len, layer.kind.kind.clone() as u32);

            // layer name
            self.gimp_string(&mut layer_data, &mut layer_len, layer.name.as_bytes());

            // layer properties
            self._add_layers_properties(&mut layer_data, &mut layer_len, &layer.properties);

            let mut hierarchy_data = vec![];
            let mut hierarchy_len = 0;
            // https://testing.developer.gimp.org/core/standards/xcf/#the-hierarchy-structure
            self.buf_extend_u32(&mut hierarchy_data, &mut hierarchy_len,layer.pixels.width); // width=1
            self.buf_extend_u32(&mut hierarchy_data, &mut hierarchy_len,layer.pixels.height); // height=1

            let layer_has_alpha = LayerColorValue::has_alpha(layer.kind.kind.clone());
            if layer_has_alpha {
                self.buf_extend_u32(&mut hierarchy_data, &mut hierarchy_len, 4); // bpp with alpha
            } else {
                self.buf_extend_u32(&mut hierarchy_data, &mut hierarchy_len, 3); // bpp without alpha
            }

            let mut tiles_headers = vec![];
            let mut tiles_body = vec![];
            let mut tiles_pixels: Vec<Vec<RgbaPixel>> = vec![];
            for _x in 0..tiles.nb {
                tiles_pixels.push(vec![]);
            }

            let mut pixel_index = 0;
            let mut x = 0;
            let mut y = 1;
            for pixel in &layer.pixels.pixels {
                pixel_index += 1;
                x += 1;

                let tile_x = (x as f32 / 64.0).ceil();
                let tile_y = (y as f32 / 64.0).ceil();

                //println!("tiles_len : {}, tile_width_nb: {}, y: {}, tile_y: {}, tile_x: {}, i: {}",
                //    tiles.len(),
                //    tile_width_nb,
                //    y,
                //    tile_y,
                //    tile_x,
                //    tile_width_nb as usize * (tile_y as usize - 1) + tile_x as usize - 1
                //);
                tiles_pixels[tiles.nb_width as usize * (tile_y as usize - 1) + tile_x as usize - 1].push(*pixel);

                if pixel_index % layer.width == 0 {
                    y += 1;
                    x = 0;
                }
            }

            /*
            let mut inc = 0;
            for _t in &tiles {
                inc +=1;
                println!("tile[{}] = length {}", inc, _t.len());
                if inc == 1 {
                    println!("tile : \n\n {:?}", tiles[0]);
                }
            }
            */

            if self.compression == XcfCompression::Rle {
                /*
                let pixels_index = self.index + layer_index as u64 * 8 + nb_layers as u64 * 8 + layer_len as u64;
                println!(
                    "pixels_index : {} = {}",
                    layer_offset,
                    pixels_index
                );
                */
                let nb_of_pixels = layer.pixels.pixels.iter().len() as u32;
                let nb_pixels_of_layers = layer.pixels.width * layer.pixels.height;
                if nb_pixels_of_layers != nb_of_pixels {
                    panic!(
                        "Number of pixels on the layers {} and pixels {} aren't equals",
                        nb_pixels_of_layers, nb_of_pixels
                    );
                }

                //let tile_pointer_size = 8 * nb_of_tiles + 4;

                let mut offset_data = vec![];
                let mut offset_len = 0;
                //let hierarchy_ofs = self.index + layer_index as u64 * 8 + nb_layers as u64 * 8 + 8 + layer_len as u64 + 8;
                let hierarchy_ofs =  layer_offset + layer_len as u64 + 16;
                //println!(
                //    "hierarchy_ofs : {} + {} = {}",
                //    layer_offset,
                //    layer_len,
                //    hierarchy_ofs
                //);
                self.buf_extend_u32(&mut offset_data, &mut offset_len,layer.pixels.width); // level[0] width
                self.buf_extend_u32(&mut offset_data, &mut offset_len,layer.pixels.height); // level[0] height
                self.buf_extend_u32(&mut offset_data, &mut offset_len,0); // ptr : Pointer to tile data
    
                let offset_index = hierarchy_ofs + offset_len as u64 + tiles.nb as u64 * 8 + 8;
                //println!(
                //    "offset_index : {} + {} + {} + 8 = offset_index = {}",
                //    hierarchy_ofs,
                //    offset_len,
                //    tiles.nb,
                //    offset_index
                //);
                for _tile in &tiles_pixels {
                    self.buf_extend_u64(&mut hierarchy_data, &mut hierarchy_len, offset_index); // offset[n]
                }
                self.buf_extend_u64(&mut hierarchy_data, &mut hierarchy_len, 0); // offset[2]

                let mut tiles_headers_len = 0;
                for tile in &tiles_pixels {
                    let tile_index = offset_index as u32 + 16 + tiles.nb * 8 + tiles_body.len() as u32;
                    //println!("tile_index : {}, offset_index: {}, nb_of_tiles : {}, tiles_len : {}", tile_index, offset_index, nb_of_tiles, tiles_body.len());
                    self.buf_extend_u32(&mut tiles_headers, &mut tiles_headers_len, tile_index);
                    self.buf_extend_u32(&mut tiles_headers, &mut tiles_headers_len, 0);
                    tiles_headers_len = 0;

                    let mut buffer_r = vec![];
                    let mut buffer_g = vec![];
                    let mut buffer_b = vec![];
                    let mut buffer_a = vec![];
                    for pixel in tile {
                        buffer_r.push(pixel.r());
                        buffer_g.push(pixel.g());
                        buffer_b.push(pixel.b());
                        if layer_has_alpha {
                            buffer_a.push(pixel.a());
                        }
                    }

                    let rle_r = rle_compress(&buffer_r);
                    //println!("buffer r : {:?}", buffer_r);
                    //println!("rle r : {:?}\n\n", rle_r);
                    tiles_body.extend(rle_r);

                    let rle_g = rle_compress(&buffer_g);
                    //println!("buffer g : {:?}", buffer_g);
                    //println!("rle g : {:?}\n\n", rle_g);
                    tiles_body.extend(rle_g);

                    let  rle_b = rle_compress(&buffer_b);
                    //println!("buffer b : {:?}", buffer_b);
                    //println!("rle b : {:?}\n\n", rle_b);
                    tiles_body.extend(rle_b);

                    if layer_has_alpha {
                        let rle_a = rle_compress(&buffer_a);
                        //println!("buffer a : {:?}", buffer_a);
                        //println!("rle a : {:?}\n\n", rle_a);
                        tiles_body.extend(rle_a);
                    }
                }

                hierarchy_data.extend_from_slice(&offset_data);
                hierarchy_len += offset_len;

                // hierarchy offset
                self.buf_extend_u64(&mut layer_data, &mut layer_len, hierarchy_ofs); // hierarchy_ofs=
                self.buf_extend_u64(&mut layer_data, &mut layer_len,0); // layer mask offset

                layer_data.extend_from_slice(&hierarchy_data);
                layer_len += hierarchy_len;
                tiles_headers.extend_from_slice(&[0, 0, 0, 0]);

                layer_data.extend_from_slice(&tiles_headers);
                layer_data.extend_from_slice(&tiles_body);
                layer_len += tiles_headers.len() as u32 + tiles_body.len() as u32;
                self.index += layer_len as u64;
            } else {
                panic!("not implemented");
            }
        }
        self.extend_u64(0); // layer_offset[1] = 0
        self.extend_u64(0); // channel_offset[0] = 0
        self.data.extend_from_slice(&layer_data);
    }

    pub fn save(&mut self, path: &PathBuf) -> Result<File, crate::Error> {
        let mut new_file = File::create(&path)?;
        new_file.write_all(self.data.as_slice())?;
        Ok(new_file)
    }
}

pub fn short_run_identical(verbatim: &[u8]) -> Vec<u8> {
    println!("short run identical");
    if verbatim.len() < 1 {
        panic!("Wrong verbatim lengh : {}", verbatim.len());
    }
    vec![(verbatim.len() - 1) as u8, verbatim[0]]
}

pub fn long_run_identical(verbatim: &[u8]) -> Vec<u8> {
    println!("long run identical");
    if verbatim.len() < 127 {
        panic!("Wrong verbatim lengh : {}", verbatim.len());
    }
    // verbatim_len = p*256+q
    let p = verbatim.len() / 256;
    let q = verbatim.len() % 256;
    vec![127, p as u8, q as u8, verbatim[0]]
}

pub fn run_identical(verbatim: &[u8]) -> Vec<u8> {
    if verbatim.len() > 126 {
        return long_run_identical(&verbatim);
    }
    short_run_identical(&verbatim)
}

pub fn short_run_diff(verbatim: &[u8]) -> Vec<u8> {
    println!("short run diff");
    if verbatim.len() < 1 {
        panic!("Wrong verbatim lengh : {}", verbatim.len());
    }
    let mut r = vec![(256 - verbatim.len()) as u8];
    r.extend_from_slice(verbatim);
    r
}

pub fn long_run_diff(verbatim: &[u8]) -> Vec<u8> {
    println!("long run diff");
    if verbatim.len() < 127 {
        panic!("Wrong verbatim lengh : {}", verbatim.len());
    }
    // verbatim_len = p*256+q
    let p = verbatim.len() / 256;
    let q = verbatim.len() % 256;
    let mut r = vec![128, p as u8, q as u8];
    r.extend_from_slice(verbatim);
    r
}

pub fn run_diff(verbatim: &[u8]) -> Vec<u8> {
    if verbatim.len() > 126 {
        return long_run_diff(&verbatim);
    }
    short_run_diff(&verbatim)
}

pub fn is_identiqual(values: &[u8]) -> bool {
    if values.len() < 2 {
        panic!("Wrong values lengh : {}", values.len());
    }
    let value = values[0];
    for v in &values[1..values.len()] {
        if value != *v {
            return false;
        }
    }
    return true;
}

// https://testing.developer.gimp.org/core/standards/xcf/#rle-compressed-tile-data
pub fn rle_compress(data: &Vec<u8>) -> Vec<u8> {
    let mut compress_data = vec![];
    let mut verbatim: Vec<u8> = vec![];
    let mut i = 0;
    for byte in data {
        i += 1;
        verbatim.push(*byte);

        if i >= data.len() - 1 {
            break;
        }
        let val = *byte;
        let mut val_last_1 = val;
        let mut val_last_2 = val;
        if i > 1 {
            val_last_1 = data[i - 2];
        }
        if i > 2 {
            val_last_2 = data[i - 3];
        }
        let val_1 = data[i];
        let val_2 = data[i + 1];
        let mut val_3 = val_2;
        if i < data.len() - 2 {
            val_3 = data[i + 2];
        }

        //println!(
        //    "i: {}, val-2: {}, val-1: {}, val: {}, val+1: {}, val+2: {}, val+3: {}, v_len: {}",
        //    i,
        //    val_last_2,
        //    val_last_1,
        //    val,
        //    val_1,
        //    val_2,
        //    val_3,
        //    verbatim.len()
        //);
        if i == 2
        && val_last_1 == val
        && val != val_1 {
            let buffer = short_run_identical(&verbatim);
            compress_data.extend_from_slice(&buffer);
            verbatim = vec![];
            continue;
        }
        if i == 1
        && val != val_1
        && val_1 == val_2
        && val_2 == val_3 {
            let buffer = run_diff(&verbatim);
            compress_data.extend_from_slice(&buffer);
            verbatim = vec![];
            continue;
        }
        if i > 2
        && val_last_2 == val_last_1
        && val_last_1 == val
        && val != val_1 {
            println!("f 2: {:?}", verbatim);
            let buffer = run_identical(&verbatim);
            compress_data.extend_from_slice(&buffer);
            verbatim = vec![];
            continue;
        }

        if i > 4  && i < data.len() - 2
           && is_identiqual(&vec![data[i - 3], data[i - 4], data[i - 5]])
           && val_last_1 == val
           && val != val_1
        {
            println!("f 3: {:?}", verbatim);
            let buffer = run_identical(&verbatim);
            compress_data.extend_from_slice(&buffer);
            verbatim = vec![];
            continue;
        }

        if i < data.len() - 2
        && val != val_1
        && val_1 == val_2
        && val_2 == val_3 {
            println!("f 4");
            let buffer = run_diff(&verbatim);
            compress_data.extend_from_slice(&buffer);
            verbatim = vec![];
            continue;
        }
    }
    verbatim.push(data[data.len() - 1]);
    let val = verbatim[verbatim.len() - 1];
    let mut val_last_1 = val;
    let mut val_last_2 = val;
    let mut val_last_3 = val;
    if verbatim.len() > 1 {
        val_last_1 = verbatim[verbatim.len() - 2];
    }
    if verbatim.len() > 2 {
        val_last_2 = verbatim[verbatim.len() - 3];
    }
    if verbatim.len() > 3 {
        val_last_3 = verbatim[verbatim.len() - 4];
    }
    let mut buffer;

    if verbatim.len() >= 2 && val == val_last_1 && val_last_1 == val_last_2 {
        println!("1.");
        if data.len() == 1 {
            buffer = vec![0, verbatim[0]];
        } else {
            buffer = run_identical(&verbatim);
        }
    } else if verbatim.len() >= 2 && val != val_last_1 && val_last_1 == val_last_2 && val_last_2 == val_last_3 {
        println!("1.1");
        buffer = run_identical(&verbatim[..verbatim.len() - 1]);
        buffer.push(0);
        buffer.push(val);
    } else if verbatim.len() >= 2 && val == val_last_1 {
        println!("2.");
        //println!("2. c: {:?}, v: {:?}", compress_data, verbatim);
        buffer = run_diff(&verbatim[..verbatim.len() - 2]);
        buffer.push(1);
        buffer.push(verbatim[verbatim.len() - 1]);
    } else {
        println!("3.");
        buffer = run_diff(&verbatim);
    }

    compress_data.extend_from_slice(&buffer);
    compress_data
}