Coverage Report

Created: 2025-12-05 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jpeg-encoder-0.6.1/src/encoder.rs
Line
Count
Source
1
use crate::fdct::fdct;
2
use crate::huffman::{CodingClass, HuffmanTable};
3
use crate::image_buffer::*;
4
use crate::marker::Marker;
5
use crate::quantization::{QuantizationTable, QuantizationTableType};
6
use crate::writer::{JfifWrite, JfifWriter, ZIGZAG};
7
use crate::{Density, EncodingError};
8
9
use alloc::vec;
10
use alloc::vec::Vec;
11
12
#[cfg(feature = "std")]
13
use std::io::BufWriter;
14
15
#[cfg(feature = "std")]
16
use std::fs::File;
17
18
#[cfg(feature = "std")]
19
use std::path::Path;
20
21
/// # Color types used in encoding
22
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
23
pub enum JpegColorType {
24
    /// One component grayscale colorspace
25
    Luma,
26
27
    /// Three component YCbCr colorspace
28
    Ycbcr,
29
30
    /// 4 Component CMYK colorspace
31
    Cmyk,
32
33
    /// 4 Component YCbCrK colorspace
34
    Ycck,
35
}
36
37
impl JpegColorType {
38
0
    pub(crate) fn get_num_components(self) -> usize {
39
        use JpegColorType::*;
40
41
0
        match self {
42
0
            Luma => 1,
43
0
            Ycbcr => 3,
44
0
            Cmyk | Ycck => 4,
45
        }
46
0
    }
47
}
48
49
/// # Color types for input images
50
///
51
/// Available color input formats for [Encoder::encode]. Other types can be used
52
/// by implementing an [ImageBuffer](crate::ImageBuffer).
53
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
54
pub enum ColorType {
55
    /// Grayscale with 1 byte per pixel
56
    Luma,
57
58
    /// RGB with 3 bytes per pixel
59
    Rgb,
60
61
    /// Red, Green, Blue with 4 bytes per pixel. The alpha channel will be ignored during encoding.
62
    Rgba,
63
64
    /// RGB with 3 bytes per pixel
65
    Bgr,
66
67
    /// RGBA with 4 bytes per pixel. The alpha channel will be ignored during encoding.
68
    Bgra,
69
70
    /// YCbCr with 3 bytes per pixel.
71
    Ycbcr,
72
73
    /// CMYK with 4 bytes per pixel.
74
    Cmyk,
75
76
    /// CMYK with 4 bytes per pixel. Encoded as YCCK (YCbCrK)
77
    CmykAsYcck,
78
79
    /// YCCK (YCbCrK) with 4 bytes per pixel.
80
    Ycck,
81
}
82
83
impl ColorType {
84
0
    pub(crate) fn get_bytes_per_pixel(self) -> usize {
85
        use ColorType::*;
86
87
0
        match self {
88
0
            Luma => 1,
89
0
            Rgb | Bgr | Ycbcr => 3,
90
0
            Rgba | Bgra | Cmyk | CmykAsYcck | Ycck => 4,
91
        }
92
0
    }
93
}
94
95
#[repr(u8)]
96
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
97
/// # Sampling factors for chroma subsampling
98
///
99
/// ## Warning
100
/// Sampling factor of 4 are not supported by all decoders or applications
101
#[allow(non_camel_case_types)]
102
pub enum SamplingFactor {
103
    F_1_1 = 1 << 4 | 1,
104
    F_2_1 = 2 << 4 | 1,
105
    F_1_2 = 1 << 4 | 2,
106
    F_2_2 = 2 << 4 | 2,
107
    F_4_1 = 4 << 4 | 1,
108
    F_4_2 = 4 << 4 | 2,
109
    F_1_4 = 1 << 4 | 4,
110
    F_2_4 = 2 << 4 | 4,
111
112
    /// Alias for F_1_1
113
    R_4_4_4 = 0x80 | 1 << 4 | 1,
114
115
    /// Alias for F_1_2
116
    R_4_4_0 = 0x80 | 1 << 4 | 2,
117
118
    /// Alias for F_1_4
119
    R_4_4_1 = 0x80 | 1 << 4 | 4,
120
121
    /// Alias for F_2_1
122
    R_4_2_2 = 0x80 | 2 << 4 | 1,
123
124
    /// Alias for F_2_2
125
    R_4_2_0 = 0x80 | 2 << 4 | 2,
126
127
    /// Alias for F_2_4
128
    R_4_2_1 = 0x80 | 2 << 4 | 4,
129
130
    /// Alias for F_4_1
131
    R_4_1_1 = 0x80 | 4 << 4 | 1,
132
133
    /// Alias for F_4_2
134
    R_4_1_0 = 0x80 | 4 << 4 | 2,
135
}
136
137
impl SamplingFactor {
138
    /// Get variant for supplied factors or None if not supported
139
0
    pub fn from_factors(horizontal: u8, vertical: u8) -> Option<SamplingFactor> {
140
        use SamplingFactor::*;
141
142
0
        match (horizontal, vertical) {
143
0
            (1, 1) => Some(F_1_1),
144
0
            (1, 2) => Some(F_1_2),
145
0
            (1, 4) => Some(F_1_4),
146
0
            (2, 1) => Some(F_2_1),
147
0
            (2, 2) => Some(F_2_2),
148
0
            (2, 4) => Some(F_2_4),
149
0
            (4, 1) => Some(F_4_1),
150
0
            (4, 2) => Some(F_4_2),
151
0
            _ => None,
152
        }
153
0
    }
154
155
0
    pub(crate) fn get_sampling_factors(self) -> (u8, u8) {
156
0
        let value = self as u8;
157
0
        ((value >> 4) & 0x07, value & 0xf)
158
0
    }
159
160
0
    pub(crate) fn supports_interleaved(self) -> bool {
161
        use SamplingFactor::*;
162
163
        // Interleaved mode is only supported with h/v sampling factors of 1 or 2.
164
        // Sampling factors of 4 needs sequential encoding
165
0
        matches!(
166
0
            self,
167
            F_1_1 | F_2_1 | F_1_2 | F_2_2 | R_4_4_4 | R_4_4_0 | R_4_2_2 | R_4_2_0
168
        )
169
0
    }
170
}
171
172
pub(crate) struct Component {
173
    pub id: u8,
174
    pub quantization_table: u8,
175
    pub dc_huffman_table: u8,
176
    pub ac_huffman_table: u8,
177
    pub horizontal_sampling_factor: u8,
178
    pub vertical_sampling_factor: u8,
179
}
180
181
macro_rules! add_component {
182
    ($components:expr, $id:expr, $dest:expr, $h_sample:expr, $v_sample:expr) => {
183
        $components.push(Component {
184
            id: $id,
185
            quantization_table: $dest,
186
            dc_huffman_table: $dest,
187
            ac_huffman_table: $dest,
188
            horizontal_sampling_factor: $h_sample,
189
            vertical_sampling_factor: $v_sample,
190
        });
191
    };
192
}
193
194
/// # The JPEG encoder
195
pub struct Encoder<W: JfifWrite> {
196
    writer: JfifWriter<W>,
197
    density: Density,
198
    quality: u8,
199
200
    components: Vec<Component>,
201
    quantization_tables: [QuantizationTableType; 2],
202
    huffman_tables: [(HuffmanTable, HuffmanTable); 2],
203
204
    sampling_factor: SamplingFactor,
205
206
    progressive_scans: Option<u8>,
207
208
    restart_interval: Option<u16>,
209
210
    optimize_huffman_table: bool,
211
212
    app_segments: Vec<(u8, Vec<u8>)>,
213
}
214
215
impl<W: JfifWrite> Encoder<W> {
216
    /// Create a new encoder with the given quality
217
    ///
218
    /// The quality must be between 1 and 100 where 100 is the highest image quality.<br>
219
    /// By default, quality settings below 90 use a chroma subsampling (2x2 / 4:2:0) which can
220
    /// be changed with [set_sampling_factor](Encoder::set_sampling_factor)
221
0
    pub fn new(w: W, quality: u8) -> Encoder<W> {
222
0
        let huffman_tables = [
223
0
            (
224
0
                HuffmanTable::default_luma_dc(),
225
0
                HuffmanTable::default_luma_ac(),
226
0
            ),
227
0
            (
228
0
                HuffmanTable::default_chroma_dc(),
229
0
                HuffmanTable::default_chroma_ac(),
230
0
            ),
231
0
        ];
232
233
0
        let quantization_tables = [
234
0
            QuantizationTableType::Default,
235
0
            QuantizationTableType::Default,
236
0
        ];
237
238
0
        let sampling_factor = if quality < 90 {
239
0
            SamplingFactor::F_2_2
240
        } else {
241
0
            SamplingFactor::F_1_1
242
        };
243
244
0
        Encoder {
245
0
            writer: JfifWriter::new(w),
246
0
            density: Density::None,
247
0
            quality,
248
0
            components: vec![],
249
0
            quantization_tables,
250
0
            huffman_tables,
251
0
            sampling_factor,
252
0
            progressive_scans: None,
253
0
            restart_interval: None,
254
0
            optimize_huffman_table: false,
255
0
            app_segments: Vec::new(),
256
0
        }
257
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::new
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new
258
259
    /// Set pixel density for the image
260
    ///
261
    /// By default, this value is None which is equal to "1 pixel per pixel".
262
0
    pub fn set_density(&mut self, density: Density) {
263
0
        self.density = density;
264
0
    }
265
266
    /// Return pixel density
267
0
    pub fn density(&self) -> Density {
268
0
        self.density
269
0
    }
270
271
    /// Set chroma subsampling factor
272
0
    pub fn set_sampling_factor(&mut self, sampling: SamplingFactor) {
273
0
        self.sampling_factor = sampling;
274
0
    }
275
276
    /// Get chroma subsampling factor
277
0
    pub fn sampling_factor(&self) -> SamplingFactor {
278
0
        self.sampling_factor
279
0
    }
280
281
    /// Set quantization tables for luma and chroma components
282
0
    pub fn set_quantization_tables(
283
0
        &mut self,
284
0
        luma: QuantizationTableType,
285
0
        chroma: QuantizationTableType,
286
0
    ) {
287
0
        self.quantization_tables = [luma, chroma];
288
0
    }
289
290
    /// Get configured quantization tables
291
0
    pub fn quantization_tables(&self) -> &[QuantizationTableType; 2] {
292
0
        &self.quantization_tables
293
0
    }
294
295
    /// Controls if progressive encoding is used.
296
    ///
297
    /// By default, progressive encoding uses 4 scans.<br>
298
    /// Use [set_progressive_scans](Encoder::set_progressive_scans) to use a different number of scans
299
0
    pub fn set_progressive(&mut self, progressive: bool) {
300
0
        self.progressive_scans = if progressive { Some(4) } else { None };
301
0
    }
302
303
    /// Set number of scans per component for progressive encoding
304
    ///
305
    /// Number of scans must be between 2 and 64.
306
    /// There is at least one scan for the DC coefficients and one for the remaining 63 AC coefficients.
307
    ///
308
    /// # Panics
309
    /// If number of scans is not within valid range
310
0
    pub fn set_progressive_scans(&mut self, scans: u8) {
311
0
        assert!(
312
0
            (2..=64).contains(&scans),
313
0
            "Invalid number of scans: {}",
314
            scans
315
        );
316
0
        self.progressive_scans = Some(scans);
317
0
    }
318
319
    /// Return number of progressive scans if progressive encoding is enabled
320
0
    pub fn progressive_scans(&self) -> Option<u8> {
321
0
        self.progressive_scans
322
0
    }
323
324
    /// Set restart interval
325
    ///
326
    /// Set numbers of MCUs between restart markers.
327
0
    pub fn set_restart_interval(&mut self, interval: u16) {
328
0
        self.restart_interval = if interval == 0 { None } else { Some(interval) };
329
0
    }
330
331
    /// Return the restart interval
332
0
    pub fn restart_interval(&self) -> Option<u16> {
333
0
        self.restart_interval
334
0
    }
335
336
    /// Set if optimized huffman table should be created
337
    ///
338
    /// Optimized tables result in slightly smaller file sizes but decrease encoding performance.
339
0
    pub fn set_optimized_huffman_tables(&mut self, optimize_huffman_table: bool) {
340
0
        self.optimize_huffman_table = optimize_huffman_table;
341
0
    }
342
343
    /// Returns if optimized huffman table should be generated
344
0
    pub fn optimized_huffman_tables(&self) -> bool {
345
0
        self.optimize_huffman_table
346
0
    }
347
348
    /// Appends a custom app segment to the JFIF file
349
    ///
350
    /// Segment numbers need to be in the range between 1 and 15<br>
351
    /// The maximum allowed data length is 2^16 - 2 bytes.
352
    ///
353
    /// # Errors
354
    ///
355
    /// Returns an error if the segment number is invalid or data exceeds the allowed size
356
0
    pub fn add_app_segment(&mut self, segment_nr: u8, data: &[u8]) -> Result<(), EncodingError> {
357
0
        if segment_nr == 0 || segment_nr > 15 {
358
0
            Err(EncodingError::InvalidAppSegment(segment_nr))
359
0
        } else if data.len() > 65533 {
360
0
            Err(EncodingError::AppSegmentTooLarge(data.len()))
361
        } else {
362
0
            self.app_segments.push((segment_nr, data.to_vec()));
363
0
            Ok(())
364
        }
365
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::add_app_segment
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::add_app_segment
366
367
    /// Add an ICC profile
368
    ///
369
    /// The maximum allowed data length is 16,707,345 bytes.
370
    ///
371
    /// # Errors
372
    ///
373
    /// Returns an Error if the data exceeds the maximum size for the ICC profile
374
0
    pub fn add_icc_profile(&mut self, data: &[u8]) -> Result<(), EncodingError> {
375
        // Based on https://www.color.org/ICC_Minor_Revision_for_Web.pdf
376
        // B.4  Embedding ICC profiles in JFIF files
377
378
        const MARKER: &[u8; 12] = b"ICC_PROFILE\0";
379
        const MAX_CHUNK_LENGTH: usize = 65535 - 2 - 12 - 2;
380
381
0
        let num_chunks = ceil_div(data.len(), MAX_CHUNK_LENGTH);
382
383
        // Sequence number is stored as a byte and starts with 1
384
0
        if num_chunks >= 255 {
385
0
            return Err(EncodingError::IccTooLarge(data.len()));
386
0
        }
387
388
0
        let mut chunk_data = Vec::with_capacity(MAX_CHUNK_LENGTH);
389
390
0
        for (i, data) in data.chunks(MAX_CHUNK_LENGTH).enumerate() {
391
0
            chunk_data.clear();
392
0
            chunk_data.extend_from_slice(MARKER);
393
0
            chunk_data.push(i as u8 + 1);
394
0
            chunk_data.push(num_chunks as u8);
395
0
            chunk_data.extend_from_slice(data);
396
397
0
            self.add_app_segment(2, &chunk_data)?;
398
        }
399
400
0
        Ok(())
401
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::add_icc_profile
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::add_icc_profile
402
403
    /// Encode an image
404
    ///
405
    /// Data format and length must conform to specified width, height and color type.
406
0
    pub fn encode(
407
0
        self,
408
0
        data: &[u8],
409
0
        width: u16,
410
0
        height: u16,
411
0
        color_type: ColorType,
412
0
    ) -> Result<(), EncodingError> {
413
0
        let required_data_len = width as usize * height as usize * color_type.get_bytes_per_pixel();
414
415
0
        if data.len() < required_data_len {
416
0
            return Err(EncodingError::BadImageData {
417
0
                length: data.len(),
418
0
                required: required_data_len,
419
0
            });
420
0
        }
421
422
        #[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
423
        {
424
0
            if std::is_x86_feature_detected!("avx2") {
425
                use crate::avx2::*;
426
427
0
                return match color_type {
428
0
                    ColorType::Luma => self
429
0
                        .encode_image_internal::<_, AVX2Operations>(GrayImage(data, width, height)),
430
0
                    ColorType::Rgb => self.encode_image_internal::<_, AVX2Operations>(
431
0
                        RgbImageAVX2(data, width, height),
432
                    ),
433
0
                    ColorType::Rgba => self.encode_image_internal::<_, AVX2Operations>(
434
0
                        RgbaImageAVX2(data, width, height),
435
                    ),
436
0
                    ColorType::Bgr => self.encode_image_internal::<_, AVX2Operations>(
437
0
                        BgrImageAVX2(data, width, height),
438
                    ),
439
0
                    ColorType::Bgra => self.encode_image_internal::<_, AVX2Operations>(
440
0
                        BgraImageAVX2(data, width, height),
441
                    ),
442
0
                    ColorType::Ycbcr => self.encode_image_internal::<_, AVX2Operations>(
443
0
                        YCbCrImage(data, width, height),
444
                    ),
445
0
                    ColorType::Cmyk => self
446
0
                        .encode_image_internal::<_, AVX2Operations>(CmykImage(data, width, height)),
447
0
                    ColorType::CmykAsYcck => self.encode_image_internal::<_, AVX2Operations>(
448
0
                        CmykAsYcckImage(data, width, height),
449
                    ),
450
0
                    ColorType::Ycck => self
451
0
                        .encode_image_internal::<_, AVX2Operations>(YcckImage(data, width, height)),
452
                };
453
0
            }
454
        }
455
456
0
        match color_type {
457
0
            ColorType::Luma => self.encode_image(GrayImage(data, width, height))?,
458
0
            ColorType::Rgb => self.encode_image(RgbImage(data, width, height))?,
459
0
            ColorType::Rgba => self.encode_image(RgbaImage(data, width, height))?,
460
0
            ColorType::Bgr => self.encode_image(BgrImage(data, width, height))?,
461
0
            ColorType::Bgra => self.encode_image(BgraImage(data, width, height))?,
462
0
            ColorType::Ycbcr => self.encode_image(YCbCrImage(data, width, height))?,
463
0
            ColorType::Cmyk => self.encode_image(CmykImage(data, width, height))?,
464
0
            ColorType::CmykAsYcck => self.encode_image(CmykAsYcckImage(data, width, height))?,
465
0
            ColorType::Ycck => self.encode_image(YcckImage(data, width, height))?,
466
        }
467
468
0
        Ok(())
469
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::encode
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode
470
471
    /// Encode an image
472
0
    pub fn encode_image<I: ImageBuffer>(self, image: I) -> Result<(), EncodingError> {
473
        #[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
474
        {
475
0
            if std::is_x86_feature_detected!("avx2") {
476
                use crate::avx2::*;
477
0
                return self.encode_image_internal::<_, AVX2Operations>(image);
478
0
            }
479
        }
480
0
        self.encode_image_internal::<_, DefaultOperations>(image)
481
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::encode_image::<_>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image::<jpeg_encoder::image_buffer::YCbCrImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image::<jpeg_encoder::image_buffer::CmykAsYcckImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image::<jpeg_encoder::image_buffer::BgrImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image::<jpeg_encoder::image_buffer::RgbImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image::<jpeg_encoder::image_buffer::BgraImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image::<jpeg_encoder::image_buffer::CmykImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image::<jpeg_encoder::image_buffer::GrayImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image::<jpeg_encoder::image_buffer::RgbaImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image::<jpeg_encoder::image_buffer::YcckImage>
482
483
0
    fn encode_image_internal<I: ImageBuffer, OP: Operations>(
484
0
        mut self,
485
0
        image: I,
486
0
    ) -> Result<(), EncodingError> {
487
0
        if image.width() == 0 || image.height() == 0 {
488
0
            return Err(EncodingError::ZeroImageDimensions {
489
0
                width: image.width(),
490
0
                height: image.height(),
491
0
            });
492
0
        }
493
494
0
        let q_tables = [
495
0
            QuantizationTable::new_with_quality(&self.quantization_tables[0], self.quality, true),
496
0
            QuantizationTable::new_with_quality(&self.quantization_tables[1], self.quality, false),
497
0
        ];
498
499
0
        let jpeg_color_type = image.get_jpeg_color_type();
500
0
        self.init_components(jpeg_color_type);
501
502
0
        self.writer.write_marker(Marker::SOI)?;
503
504
0
        self.writer.write_header(&self.density)?;
505
506
0
        if jpeg_color_type == JpegColorType::Cmyk {
507
            //Set ColorTransform info to "Unknown"
508
0
            let app_14 = b"Adobe\0\0\0\0\0\0\0";
509
0
            self.writer
510
0
                .write_segment(Marker::APP(14), app_14.as_ref())?;
511
0
        } else if jpeg_color_type == JpegColorType::Ycck {
512
            //Set ColorTransform info to YCCK
513
0
            let app_14 = b"Adobe\0\0\0\0\0\0\x02";
514
0
            self.writer
515
0
                .write_segment(Marker::APP(14), app_14.as_ref())?;
516
0
        }
517
518
0
        for (nr, data) in &self.app_segments {
519
0
            self.writer.write_segment(Marker::APP(*nr), data)?;
520
        }
521
522
0
        if let Some(scans) = self.progressive_scans {
523
0
            self.encode_image_progressive::<_, OP>(image, scans, &q_tables)?;
524
0
        } else if self.optimize_huffman_table || !self.sampling_factor.supports_interleaved() {
525
0
            self.encode_image_sequential::<_, OP>(image, &q_tables)?;
526
        } else {
527
0
            self.encode_image_interleaved::<_, OP>(image, &q_tables)?;
528
        }
529
530
0
        self.writer.write_marker(Marker::EOI)?;
531
532
0
        Ok(())
533
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::encode_image_internal::<_, _>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::YCbCrImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::YCbCrImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::CmykAsYcckImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::CmykAsYcckImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::BgrImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::BgrImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::RgbImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::RgbImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::BgraImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::BgraImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::CmykImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::CmykImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::GrayImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::GrayImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::RgbaImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::RgbaImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::YcckImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::image_buffer::YcckImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::avx2::ycbcr::BgrImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::avx2::ycbcr::RgbImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::avx2::ycbcr::BgraImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_internal::<jpeg_encoder::avx2::ycbcr::RgbaImageAVX2, jpeg_encoder::avx2::AVX2Operations>
534
535
0
    fn init_components(&mut self, color: JpegColorType) {
536
0
        let (horizontal_sampling_factor, vertical_sampling_factor) =
537
0
            self.sampling_factor.get_sampling_factors();
538
539
0
        match color {
540
0
            JpegColorType::Luma => {
541
0
                add_component!(self.components, 0, 0, 1, 1);
542
0
            }
543
0
            JpegColorType::Ycbcr => {
544
0
                add_component!(
545
0
                    self.components,
546
0
                    0,
547
0
                    0,
548
0
                    horizontal_sampling_factor,
549
0
                    vertical_sampling_factor
550
0
                );
551
0
                add_component!(self.components, 1, 1, 1, 1);
552
0
                add_component!(self.components, 2, 1, 1, 1);
553
0
            }
554
0
            JpegColorType::Cmyk => {
555
0
                add_component!(self.components, 0, 1, 1, 1);
556
0
                add_component!(self.components, 1, 1, 1, 1);
557
0
                add_component!(self.components, 2, 1, 1, 1);
558
0
                add_component!(
559
0
                    self.components,
560
0
                    3,
561
0
                    0,
562
0
                    horizontal_sampling_factor,
563
0
                    vertical_sampling_factor
564
0
                );
565
0
            }
566
0
            JpegColorType::Ycck => {
567
0
                add_component!(
568
0
                    self.components,
569
0
                    0,
570
0
                    0,
571
0
                    horizontal_sampling_factor,
572
0
                    vertical_sampling_factor
573
0
                );
574
0
                add_component!(self.components, 1, 1, 1, 1);
575
0
                add_component!(self.components, 2, 1, 1, 1);
576
0
                add_component!(
577
0
                    self.components,
578
0
                    3,
579
0
                    0,
580
0
                    horizontal_sampling_factor,
581
0
                    vertical_sampling_factor
582
0
                );
583
0
            }
584
        }
585
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::init_components
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::init_components
586
587
0
    fn get_max_sampling_size(&self) -> (usize, usize) {
588
0
        let max_h_sampling = self.components.iter().fold(1, |value, component| {
589
0
            value.max(component.horizontal_sampling_factor)
590
0
        });
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::get_max_sampling_size::{closure#0}
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::get_max_sampling_size::{closure#0}
591
592
0
        let max_v_sampling = self.components.iter().fold(1, |value, component| {
593
0
            value.max(component.vertical_sampling_factor)
594
0
        });
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::get_max_sampling_size::{closure#1}
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::get_max_sampling_size::{closure#1}
595
596
0
        (usize::from(max_h_sampling), usize::from(max_v_sampling))
597
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::get_max_sampling_size
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::get_max_sampling_size
598
599
0
    fn write_frame_header<I: ImageBuffer>(
600
0
        &mut self,
601
0
        image: &I,
602
0
        q_tables: &[QuantizationTable; 2],
603
0
    ) -> Result<(), EncodingError> {
604
0
        self.writer.write_frame_header(
605
0
            image.width(),
606
0
            image.height(),
607
0
            &self.components,
608
0
            self.progressive_scans.is_some(),
609
0
        )?;
610
611
0
        self.writer.write_quantization_segment(0, &q_tables[0])?;
612
0
        self.writer.write_quantization_segment(1, &q_tables[1])?;
613
614
0
        self.writer
615
0
            .write_huffman_segment(CodingClass::Dc, 0, &self.huffman_tables[0].0)?;
616
617
0
        self.writer
618
0
            .write_huffman_segment(CodingClass::Ac, 0, &self.huffman_tables[0].1)?;
619
620
0
        if image.get_jpeg_color_type().get_num_components() >= 3 {
621
0
            self.writer
622
0
                .write_huffman_segment(CodingClass::Dc, 1, &self.huffman_tables[1].0)?;
623
624
0
            self.writer
625
0
                .write_huffman_segment(CodingClass::Ac, 1, &self.huffman_tables[1].1)?;
626
0
        }
627
628
0
        if let Some(restart_interval) = self.restart_interval {
629
0
            self.writer.write_dri(restart_interval)?;
630
0
        }
631
632
0
        Ok(())
633
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::write_frame_header::<_>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::image_buffer::YCbCrImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::image_buffer::CmykAsYcckImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::image_buffer::BgrImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::image_buffer::RgbImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::image_buffer::BgraImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::image_buffer::CmykImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::image_buffer::GrayImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::image_buffer::RgbaImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::image_buffer::YcckImage>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::avx2::ycbcr::BgrImageAVX2>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::avx2::ycbcr::RgbImageAVX2>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::avx2::ycbcr::BgraImageAVX2>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_frame_header::<jpeg_encoder::avx2::ycbcr::RgbaImageAVX2>
634
635
0
    fn init_rows(&mut self, buffer_size: usize) -> [Vec<u8>; 4] {
636
        // To simplify the code and to give the compiler more infos to optimize stuff we always initialize 4 components
637
        // Resource overhead should be minimal because an empty Vec doesn't allocate
638
639
0
        match self.components.len() {
640
0
            1 => [
641
0
                Vec::with_capacity(buffer_size),
642
0
                Vec::new(),
643
0
                Vec::new(),
644
0
                Vec::new(),
645
0
            ],
646
0
            3 => [
647
0
                Vec::with_capacity(buffer_size),
648
0
                Vec::with_capacity(buffer_size),
649
0
                Vec::with_capacity(buffer_size),
650
0
                Vec::new(),
651
0
            ],
652
0
            4 => [
653
0
                Vec::with_capacity(buffer_size),
654
0
                Vec::with_capacity(buffer_size),
655
0
                Vec::with_capacity(buffer_size),
656
0
                Vec::with_capacity(buffer_size),
657
0
            ],
658
0
            len => unreachable!("Unsupported component length: {}", len),
659
        }
660
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::init_rows
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::init_rows
661
662
    /// Encode all components with one scan
663
    ///
664
    /// This is only valid for sampling factors of 1 and 2
665
0
    fn encode_image_interleaved<I: ImageBuffer, OP: Operations>(
666
0
        &mut self,
667
0
        image: I,
668
0
        q_tables: &[QuantizationTable; 2],
669
0
    ) -> Result<(), EncodingError> {
670
0
        self.write_frame_header(&image, q_tables)?;
671
0
        self.writer
672
0
            .write_scan_header(&self.components.iter().collect::<Vec<_>>(), None)?;
673
674
0
        let (max_h_sampling, max_v_sampling) = self.get_max_sampling_size();
675
676
0
        let width = image.width();
677
0
        let height = image.height();
678
679
0
        let num_cols = ceil_div(usize::from(width), 8 * max_h_sampling);
680
0
        let num_rows = ceil_div(usize::from(height), 8 * max_v_sampling);
681
682
0
        let buffer_width = num_cols * 8 * max_h_sampling;
683
0
        let buffer_size = buffer_width * 8 * max_v_sampling;
684
685
0
        let mut row: [Vec<_>; 4] = self.init_rows(buffer_size);
686
687
0
        let mut prev_dc = [0i16; 4];
688
689
0
        let restart_interval = self.restart_interval.unwrap_or(0);
690
0
        let mut restarts = 0;
691
0
        let mut restarts_to_go = restart_interval;
692
693
0
        for block_y in 0..num_rows {
694
0
            for r in &mut row {
695
0
                r.clear();
696
0
            }
697
698
0
            for y in 0..(8 * max_v_sampling) {
699
0
                let y = y + block_y * 8 * max_v_sampling;
700
0
                let y = (y.min(height as usize - 1)) as u16;
701
702
0
                image.fill_buffers(y, &mut row);
703
704
0
                for _ in usize::from(width)..buffer_width {
705
0
                    for channel in &mut row {
706
0
                        if !channel.is_empty() {
707
0
                            channel.push(channel[channel.len() - 1]);
708
0
                        }
709
                    }
710
                }
711
            }
712
713
0
            for block_x in 0..num_cols {
714
0
                if restart_interval > 0 && restarts_to_go == 0 {
715
0
                    self.writer.finalize_bit_buffer()?;
716
0
                    self.writer
717
0
                        .write_marker(Marker::RST((restarts % 8) as u8))?;
718
719
0
                    prev_dc[0] = 0;
720
0
                    prev_dc[1] = 0;
721
0
                    prev_dc[2] = 0;
722
0
                    prev_dc[3] = 0;
723
0
                }
724
725
0
                for (i, component) in self.components.iter().enumerate() {
726
0
                    for v_offset in 0..component.vertical_sampling_factor as usize {
727
0
                        for h_offset in 0..component.horizontal_sampling_factor as usize {
728
0
                            let mut block = get_block(
729
0
                                &row[i],
730
0
                                block_x * 8 * max_h_sampling + (h_offset * 8),
731
0
                                v_offset * 8,
732
0
                                max_h_sampling
733
0
                                    / component.horizontal_sampling_factor as usize,
734
0
                                max_v_sampling
735
0
                                    / component.vertical_sampling_factor as usize,
736
0
                                buffer_width,
737
                            );
738
739
0
                            OP::fdct(&mut block);
740
741
0
                            let mut q_block = [0i16; 64];
742
743
0
                            OP::quantize_block(
744
0
                                &block,
745
0
                                &mut q_block,
746
0
                                &q_tables[component.quantization_table as usize],
747
                            );
748
749
0
                            self.writer.write_block(
750
0
                                &q_block,
751
0
                                prev_dc[i],
752
0
                                &self.huffman_tables[component.dc_huffman_table as usize].0,
753
0
                                &self.huffman_tables[component.ac_huffman_table as usize].1,
754
0
                            )?;
755
756
0
                            prev_dc[i] = q_block[0];
757
                        }
758
                    }
759
                }
760
761
0
                if restart_interval > 0 {
762
0
                    if restarts_to_go == 0 {
763
0
                        restarts_to_go = restart_interval;
764
0
                        restarts += 1;
765
0
                        restarts &= 7;
766
0
                    }
767
0
                    restarts_to_go -= 1;
768
0
                }
769
            }
770
        }
771
772
0
        self.writer.finalize_bit_buffer()?;
773
774
0
        Ok(())
775
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::encode_image_interleaved::<_, _>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::YCbCrImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::YCbCrImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::CmykAsYcckImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::CmykAsYcckImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::BgrImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::BgrImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::RgbImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::RgbImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::BgraImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::BgraImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::CmykImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::CmykImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::GrayImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::GrayImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::RgbaImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::RgbaImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::YcckImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::image_buffer::YcckImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::avx2::ycbcr::BgrImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::avx2::ycbcr::RgbImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::avx2::ycbcr::BgraImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_interleaved::<jpeg_encoder::avx2::ycbcr::RgbaImageAVX2, jpeg_encoder::avx2::AVX2Operations>
776
777
    /// Encode components with one scan per component
778
0
    fn encode_image_sequential<I: ImageBuffer, OP: Operations>(
779
0
        &mut self,
780
0
        image: I,
781
0
        q_tables: &[QuantizationTable; 2],
782
0
    ) -> Result<(), EncodingError> {
783
0
        let blocks = self.encode_blocks::<_, OP>(&image, q_tables);
784
785
0
        if self.optimize_huffman_table {
786
0
            self.optimize_huffman_table(&blocks);
787
0
        }
788
789
0
        self.write_frame_header(&image, q_tables)?;
790
791
0
        for (i, component) in self.components.iter().enumerate() {
792
0
            let restart_interval = self.restart_interval.unwrap_or(0);
793
0
            let mut restarts = 0;
794
0
            let mut restarts_to_go = restart_interval;
795
796
0
            self.writer.write_scan_header(&[component], None)?;
797
798
0
            let mut prev_dc = 0;
799
800
0
            for block in &blocks[i] {
801
0
                if restart_interval > 0 && restarts_to_go == 0 {
802
0
                    self.writer.finalize_bit_buffer()?;
803
0
                    self.writer
804
0
                        .write_marker(Marker::RST((restarts % 8) as u8))?;
805
806
0
                    prev_dc = 0;
807
0
                }
808
809
0
                self.writer.write_block(
810
0
                    block,
811
0
                    prev_dc,
812
0
                    &self.huffman_tables[component.dc_huffman_table as usize].0,
813
0
                    &self.huffman_tables[component.ac_huffman_table as usize].1,
814
0
                )?;
815
816
0
                prev_dc = block[0];
817
818
0
                if restart_interval > 0 {
819
0
                    if restarts_to_go == 0 {
820
0
                        restarts_to_go = restart_interval;
821
0
                        restarts += 1;
822
0
                        restarts &= 7;
823
0
                    }
824
0
                    restarts_to_go -= 1;
825
0
                }
826
            }
827
828
0
            self.writer.finalize_bit_buffer()?;
829
        }
830
831
0
        Ok(())
832
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::encode_image_sequential::<_, _>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::YCbCrImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::YCbCrImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::CmykAsYcckImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::CmykAsYcckImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::BgrImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::BgrImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::RgbImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::RgbImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::BgraImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::BgraImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::CmykImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::CmykImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::GrayImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::GrayImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::RgbaImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::RgbaImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::YcckImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::image_buffer::YcckImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::avx2::ycbcr::BgrImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::avx2::ycbcr::RgbImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::avx2::ycbcr::BgraImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_sequential::<jpeg_encoder::avx2::ycbcr::RgbaImageAVX2, jpeg_encoder::avx2::AVX2Operations>
833
834
    /// Encode image in progressive mode
835
    ///
836
    /// This only support spectral selection for now
837
0
    fn encode_image_progressive<I: ImageBuffer, OP: Operations>(
838
0
        &mut self,
839
0
        image: I,
840
0
        scans: u8,
841
0
        q_tables: &[QuantizationTable; 2],
842
0
    ) -> Result<(), EncodingError> {
843
0
        let blocks = self.encode_blocks::<_, OP>(&image, q_tables);
844
845
0
        if self.optimize_huffman_table {
846
0
            self.optimize_huffman_table(&blocks);
847
0
        }
848
849
0
        self.write_frame_header(&image, q_tables)?;
850
851
        // Phase 1: DC Scan
852
        //          Only the DC coefficients can be transfer in the first component scans
853
0
        for (i, component) in self.components.iter().enumerate() {
854
0
            self.writer.write_scan_header(&[component], Some((0, 0)))?;
855
856
0
            let restart_interval = self.restart_interval.unwrap_or(0);
857
0
            let mut restarts = 0;
858
0
            let mut restarts_to_go = restart_interval;
859
860
0
            let mut prev_dc = 0;
861
862
0
            for block in &blocks[i] {
863
0
                if restart_interval > 0 && restarts_to_go == 0 {
864
0
                    self.writer.finalize_bit_buffer()?;
865
0
                    self.writer
866
0
                        .write_marker(Marker::RST((restarts % 8) as u8))?;
867
868
0
                    prev_dc = 0;
869
0
                }
870
871
0
                self.writer.write_dc(
872
0
                    block[0],
873
0
                    prev_dc,
874
0
                    &self.huffman_tables[component.dc_huffman_table as usize].0,
875
0
                )?;
876
877
0
                prev_dc = block[0];
878
879
0
                if restart_interval > 0 {
880
0
                    if restarts_to_go == 0 {
881
0
                        restarts_to_go = restart_interval;
882
0
                        restarts += 1;
883
0
                        restarts &= 7;
884
0
                    }
885
0
                    restarts_to_go -= 1;
886
0
                }
887
            }
888
889
0
            self.writer.finalize_bit_buffer()?;
890
        }
891
892
        // Phase 2: AC scans
893
0
        let scans = scans as usize - 1;
894
895
0
        let values_per_scan = 64 / scans;
896
897
0
        for scan in 0..scans {
898
0
            let start = (scan * values_per_scan).max(1);
899
0
            let end = if scan == scans - 1 {
900
                // ensure last scan is always transfers the remaining coefficients
901
0
                64
902
            } else {
903
0
                (scan + 1) * values_per_scan
904
            };
905
906
0
            for (i, component) in self.components.iter().enumerate() {
907
0
                let restart_interval = self.restart_interval.unwrap_or(0);
908
0
                let mut restarts = 0;
909
0
                let mut restarts_to_go = restart_interval;
910
911
0
                self.writer
912
0
                    .write_scan_header(&[component], Some((start as u8, end as u8 - 1)))?;
913
914
0
                for block in &blocks[i] {
915
0
                    if restart_interval > 0 && restarts_to_go == 0 {
916
0
                        self.writer.finalize_bit_buffer()?;
917
0
                        self.writer
918
0
                            .write_marker(Marker::RST((restarts % 8) as u8))?;
919
0
                    }
920
921
0
                    self.writer.write_ac_block(
922
0
                        block,
923
0
                        start,
924
0
                        end,
925
0
                        &self.huffman_tables[component.ac_huffman_table as usize].1,
926
0
                    )?;
927
928
0
                    if restart_interval > 0 {
929
0
                        if restarts_to_go == 0 {
930
0
                            restarts_to_go = restart_interval;
931
0
                            restarts += 1;
932
0
                            restarts &= 7;
933
0
                        }
934
0
                        restarts_to_go -= 1;
935
0
                    }
936
                }
937
938
0
                self.writer.finalize_bit_buffer()?;
939
            }
940
        }
941
942
0
        Ok(())
943
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::encode_image_progressive::<_, _>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::YCbCrImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::YCbCrImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::CmykAsYcckImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::CmykAsYcckImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::BgrImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::BgrImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::RgbImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::RgbImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::BgraImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::BgraImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::CmykImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::CmykImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::GrayImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::GrayImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::RgbaImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::RgbaImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::YcckImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::image_buffer::YcckImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::avx2::ycbcr::BgrImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::avx2::ycbcr::RgbImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::avx2::ycbcr::BgraImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_image_progressive::<jpeg_encoder::avx2::ycbcr::RgbaImageAVX2, jpeg_encoder::avx2::AVX2Operations>
944
945
0
    fn encode_blocks<I: ImageBuffer, OP: Operations>(
946
0
        &mut self,
947
0
        image: &I,
948
0
        q_tables: &[QuantizationTable; 2],
949
0
    ) -> [Vec<[i16; 64]>; 4] {
950
0
        let width = image.width();
951
0
        let height = image.height();
952
953
0
        let (max_h_sampling, max_v_sampling) = self.get_max_sampling_size();
954
955
0
        let num_cols = ceil_div(usize::from(width), 8 * max_h_sampling) * max_h_sampling;
956
0
        let num_rows = ceil_div(usize::from(height), 8 * max_v_sampling) * max_v_sampling;
957
958
0
        debug_assert!(num_cols > 0);
959
0
        debug_assert!(num_rows > 0);
960
961
0
        let buffer_width = num_cols * 8;
962
0
        let buffer_size = num_cols * num_rows * 64;
963
964
0
        let mut row: [Vec<_>; 4] = self.init_rows(buffer_size);
965
966
0
        for y in 0..num_rows * 8 {
967
0
            let y = (y.min(usize::from(height) - 1)) as u16;
968
969
0
            image.fill_buffers(y, &mut row);
970
971
0
            for _ in usize::from(width)..num_cols * 8 {
972
0
                for channel in &mut row {
973
0
                    if !channel.is_empty() {
974
0
                        channel.push(channel[channel.len() - 1]);
975
0
                    }
976
                }
977
            }
978
        }
979
980
0
        let num_cols = ceil_div(usize::from(width), 8);
981
0
        let num_rows = ceil_div(usize::from(height), 8);
982
983
0
        debug_assert!(num_cols > 0);
984
0
        debug_assert!(num_rows > 0);
985
986
0
        let mut blocks: [Vec<_>; 4] = self.init_block_buffers(buffer_size / 64);
987
988
0
        for (i, component) in self.components.iter().enumerate() {
989
0
            let h_scale = max_h_sampling / component.horizontal_sampling_factor as usize;
990
0
            let v_scale = max_v_sampling / component.vertical_sampling_factor as usize;
991
992
0
            let cols = ceil_div(num_cols, h_scale);
993
0
            let rows = ceil_div(num_rows, v_scale);
994
995
0
            debug_assert!(cols > 0);
996
0
            debug_assert!(rows > 0);
997
998
0
            for block_y in 0..rows {
999
0
                for block_x in 0..cols {
1000
0
                    let mut block = get_block(
1001
0
                        &row[i],
1002
0
                        block_x * 8 * h_scale,
1003
0
                        block_y * 8 * v_scale,
1004
0
                        h_scale,
1005
0
                        v_scale,
1006
0
                        buffer_width,
1007
0
                    );
1008
0
1009
0
                    OP::fdct(&mut block);
1010
0
1011
0
                    let mut q_block = [0i16; 64];
1012
0
1013
0
                    OP::quantize_block(
1014
0
                        &block,
1015
0
                        &mut q_block,
1016
0
                        &q_tables[component.quantization_table as usize],
1017
0
                    );
1018
0
1019
0
                    blocks[i].push(q_block);
1020
0
                }
1021
            }
1022
        }
1023
0
        blocks
1024
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::encode_blocks::<_, _>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::YCbCrImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::YCbCrImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::CmykAsYcckImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::CmykAsYcckImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::BgrImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::BgrImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::RgbImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::RgbImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::BgraImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::BgraImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::CmykImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::CmykImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::GrayImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::GrayImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::RgbaImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::RgbaImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::YcckImage, jpeg_encoder::encoder::DefaultOperations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::image_buffer::YcckImage, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::avx2::ycbcr::BgrImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::avx2::ycbcr::RgbImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::avx2::ycbcr::BgraImageAVX2, jpeg_encoder::avx2::AVX2Operations>
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_blocks::<jpeg_encoder::avx2::ycbcr::RgbaImageAVX2, jpeg_encoder::avx2::AVX2Operations>
1025
1026
0
    fn init_block_buffers(&mut self, buffer_size: usize) -> [Vec<[i16; 64]>; 4] {
1027
        // To simplify the code and to give the compiler more infos to optimize stuff we always initialize 4 components
1028
        // Resource overhead should be minimal because an empty Vec doesn't allocate
1029
1030
0
        match self.components.len() {
1031
0
            1 => [
1032
0
                Vec::with_capacity(buffer_size),
1033
0
                Vec::new(),
1034
0
                Vec::new(),
1035
0
                Vec::new(),
1036
0
            ],
1037
0
            3 => [
1038
0
                Vec::with_capacity(buffer_size),
1039
0
                Vec::with_capacity(buffer_size),
1040
0
                Vec::with_capacity(buffer_size),
1041
0
                Vec::new(),
1042
0
            ],
1043
0
            4 => [
1044
0
                Vec::with_capacity(buffer_size),
1045
0
                Vec::with_capacity(buffer_size),
1046
0
                Vec::with_capacity(buffer_size),
1047
0
                Vec::with_capacity(buffer_size),
1048
0
            ],
1049
0
            len => unreachable!("Unsupported component length: {}", len),
1050
        }
1051
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::init_block_buffers
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::init_block_buffers
1052
1053
    // Create new huffman tables optimized for this image
1054
0
    fn optimize_huffman_table(&mut self, blocks: &[Vec<[i16; 64]>; 4]) {
1055
        // TODO: Find out if it's possible to reuse some code from the writer
1056
1057
0
        let max_tables = self.components.len().min(2) as u8;
1058
1059
0
        for table in 0..max_tables {
1060
0
            let mut dc_freq = [0u32; 257];
1061
0
            dc_freq[256] = 1;
1062
0
            let mut ac_freq = [0u32; 257];
1063
0
            ac_freq[256] = 1;
1064
1065
0
            let mut had_ac = false;
1066
0
            let mut had_dc = false;
1067
1068
0
            for (i, component) in self.components.iter().enumerate() {
1069
0
                if component.dc_huffman_table == table {
1070
0
                    had_dc = true;
1071
1072
0
                    let mut prev_dc = 0;
1073
1074
0
                    debug_assert!(!blocks[i].is_empty());
1075
1076
0
                    for block in &blocks[i] {
1077
0
                        let value = block[0];
1078
0
                        let diff = value - prev_dc;
1079
0
                        let num_bits = get_num_bits(diff);
1080
0
1081
0
                        dc_freq[num_bits as usize] += 1;
1082
0
1083
0
                        prev_dc = value;
1084
0
                    }
1085
0
                }
1086
1087
0
                if component.ac_huffman_table == table {
1088
0
                    had_ac = true;
1089
1090
0
                    if let Some(scans) = self.progressive_scans {
1091
0
                        let scans = scans as usize - 1;
1092
1093
0
                        let values_per_scan = 64 / scans;
1094
1095
0
                        for scan in 0..scans {
1096
0
                            let start = (scan * values_per_scan).max(1);
1097
0
                            let end = if scan == scans - 1 {
1098
                                // Due to rounding we might need to transfer more than values_per_scan values in the last scan
1099
0
                                64
1100
                            } else {
1101
0
                                (scan + 1) * values_per_scan
1102
                            };
1103
1104
0
                            debug_assert!(!blocks[i].is_empty());
1105
1106
0
                            for block in &blocks[i] {
1107
0
                                let mut zero_run = 0;
1108
1109
0
                                for &value in &block[start..end] {
1110
0
                                    if value == 0 {
1111
0
                                        zero_run += 1;
1112
0
                                    } else {
1113
0
                                        while zero_run > 15 {
1114
0
                                            ac_freq[0xF0] += 1;
1115
0
                                            zero_run -= 16;
1116
0
                                        }
1117
0
                                        let num_bits = get_num_bits(value);
1118
0
                                        let symbol = (zero_run << 4) | num_bits;
1119
1120
0
                                        ac_freq[symbol as usize] += 1;
1121
1122
0
                                        zero_run = 0;
1123
                                    }
1124
                                }
1125
1126
0
                                if zero_run > 0 {
1127
0
                                    ac_freq[0] += 1;
1128
0
                                }
1129
                            }
1130
                        }
1131
                    } else {
1132
0
                        for block in &blocks[i] {
1133
0
                            let mut zero_run = 0;
1134
1135
0
                            for &value in &block[1..] {
1136
0
                                if value == 0 {
1137
0
                                    zero_run += 1;
1138
0
                                } else {
1139
0
                                    while zero_run > 15 {
1140
0
                                        ac_freq[0xF0] += 1;
1141
0
                                        zero_run -= 16;
1142
0
                                    }
1143
0
                                    let num_bits = get_num_bits(value);
1144
0
                                    let symbol = (zero_run << 4) | num_bits;
1145
1146
0
                                    ac_freq[symbol as usize] += 1;
1147
1148
0
                                    zero_run = 0;
1149
                                }
1150
                            }
1151
1152
0
                            if zero_run > 0 {
1153
0
                                ac_freq[0] += 1;
1154
0
                            }
1155
                        }
1156
                    }
1157
0
                }
1158
            }
1159
1160
0
            assert!(had_dc, "Missing DC data for table {}", table);
1161
0
            assert!(had_ac, "Missing AC data for table {}", table);
1162
1163
0
            self.huffman_tables[table as usize] = (
1164
0
                HuffmanTable::new_optimized(dc_freq),
1165
0
                HuffmanTable::new_optimized(ac_freq),
1166
            );
1167
        }
1168
0
    }
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<_>>::optimize_huffman_table
Unexecuted instantiation: <jpeg_encoder::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::optimize_huffman_table
1169
}
1170
1171
#[cfg(feature = "std")]
1172
impl Encoder<BufWriter<File>> {
1173
    /// Create a new decoder that writes into a file
1174
    ///
1175
    /// See [new](Encoder::new) for further information.
1176
    ///
1177
    /// # Errors
1178
    ///
1179
    /// Returns an `IoError(std::io::Error)` if the file can't be created
1180
0
    pub fn new_file<P: AsRef<Path>>(
1181
0
        path: P,
1182
0
        quality: u8,
1183
0
    ) -> Result<Encoder<BufWriter<File>>, EncodingError> {
1184
0
        let file = File::create(path)?;
1185
0
        let buf = BufWriter::new(file);
1186
0
        Ok(Self::new(buf, quality))
1187
0
    }
1188
}
1189
1190
0
fn get_block(
1191
0
    data: &[u8],
1192
0
    start_x: usize,
1193
0
    start_y: usize,
1194
0
    col_stride: usize,
1195
0
    row_stride: usize,
1196
0
    width: usize,
1197
0
) -> [i16; 64] {
1198
0
    let mut block = [0i16; 64];
1199
1200
0
    for y in 0..8 {
1201
0
        for x in 0..8 {
1202
0
            let ix = start_x + (x * col_stride);
1203
0
            let iy = start_y + (y * row_stride);
1204
0
1205
0
            block[y * 8 + x] = (data[iy * width + ix] as i16) - 128;
1206
0
        }
1207
    }
1208
1209
0
    block
1210
0
}
1211
1212
0
fn ceil_div(value: usize, div: usize) -> usize {
1213
0
    value / div + usize::from(value % div != 0)
1214
0
}
1215
1216
0
fn get_num_bits(mut value: i16) -> u8 {
1217
0
    if value < 0 {
1218
0
        value = -value;
1219
0
    }
1220
1221
0
    let mut num_bits = 0;
1222
1223
0
    while value > 0 {
1224
0
        num_bits += 1;
1225
0
        value >>= 1;
1226
0
    }
1227
1228
0
    num_bits
1229
0
}
1230
1231
pub(crate) trait Operations {
1232
    #[inline(always)]
1233
0
    fn fdct(data: &mut [i16; 64]) {
1234
0
        fdct(data);
1235
0
    }
Unexecuted instantiation: <_ as jpeg_encoder::encoder::Operations>::fdct
Unexecuted instantiation: <jpeg_encoder::encoder::DefaultOperations as jpeg_encoder::encoder::Operations>::fdct
1236
1237
    #[inline(always)]
1238
0
    fn quantize_block(block: &[i16; 64], q_block: &mut [i16; 64], table: &QuantizationTable) {
1239
0
        for i in 0..64 {
1240
0
            let z = ZIGZAG[i] as usize & 0x3f;
1241
0
            q_block[i] = table.quantize(block[z], z);
1242
0
        }
1243
0
    }
Unexecuted instantiation: <_ as jpeg_encoder::encoder::Operations>::quantize_block
Unexecuted instantiation: <jpeg_encoder::avx2::AVX2Operations as jpeg_encoder::encoder::Operations>::quantize_block
Unexecuted instantiation: <jpeg_encoder::encoder::DefaultOperations as jpeg_encoder::encoder::Operations>::quantize_block
1244
}
1245
1246
pub(crate) struct DefaultOperations;
1247
1248
impl Operations for DefaultOperations {}
1249
1250
#[cfg(test)]
1251
mod tests {
1252
    use alloc::vec;
1253
1254
    use crate::encoder::get_num_bits;
1255
    use crate::writer::get_code;
1256
    use crate::{Encoder, SamplingFactor};
1257
1258
    #[test]
1259
    fn test_get_num_bits() {
1260
        let min_max = 2i16.pow(13);
1261
1262
        for value in -min_max..=min_max {
1263
            let num_bits1 = get_num_bits(value);
1264
            let (num_bits2, _) = get_code(value);
1265
1266
            assert_eq!(
1267
                num_bits1, num_bits2,
1268
                "Difference in num bits for value {}: {} vs {}",
1269
                value, num_bits1, num_bits2
1270
            );
1271
        }
1272
    }
1273
1274
    #[test]
1275
    fn sampling_factors() {
1276
        assert_eq!(SamplingFactor::F_1_1.get_sampling_factors(), (1, 1));
1277
        assert_eq!(SamplingFactor::F_2_1.get_sampling_factors(), (2, 1));
1278
        assert_eq!(SamplingFactor::F_1_2.get_sampling_factors(), (1, 2));
1279
        assert_eq!(SamplingFactor::F_2_2.get_sampling_factors(), (2, 2));
1280
        assert_eq!(SamplingFactor::F_4_1.get_sampling_factors(), (4, 1));
1281
        assert_eq!(SamplingFactor::F_4_2.get_sampling_factors(), (4, 2));
1282
        assert_eq!(SamplingFactor::F_1_4.get_sampling_factors(), (1, 4));
1283
        assert_eq!(SamplingFactor::F_2_4.get_sampling_factors(), (2, 4));
1284
1285
        assert_eq!(SamplingFactor::R_4_4_4.get_sampling_factors(), (1, 1));
1286
        assert_eq!(SamplingFactor::R_4_4_0.get_sampling_factors(), (1, 2));
1287
        assert_eq!(SamplingFactor::R_4_4_1.get_sampling_factors(), (1, 4));
1288
        assert_eq!(SamplingFactor::R_4_2_2.get_sampling_factors(), (2, 1));
1289
        assert_eq!(SamplingFactor::R_4_2_0.get_sampling_factors(), (2, 2));
1290
        assert_eq!(SamplingFactor::R_4_2_1.get_sampling_factors(), (2, 4));
1291
        assert_eq!(SamplingFactor::R_4_1_1.get_sampling_factors(), (4, 1));
1292
        assert_eq!(SamplingFactor::R_4_1_0.get_sampling_factors(), (4, 2));
1293
    }
1294
1295
    #[test]
1296
    fn test_set_progressive() {
1297
        let mut encoder = Encoder::new(vec![], 100);
1298
        encoder.set_progressive(true);
1299
        assert_eq!(encoder.progressive_scans(), Some(4));
1300
1301
        encoder.set_progressive(false);
1302
        assert_eq!(encoder.progressive_scans(), None);
1303
    }
1304
}