1 #![allow(clippy::too_many_arguments)]
2 
3 use std::convert::TryFrom;
4 use std::io::{self, Write};
5 
6 use num_iter::range_step;
7 
8 use crate::{Bgr, Bgra, ColorType, GenericImageView, ImageBuffer, Luma, LumaA, Pixel, Rgb, Rgba};
9 use crate::error::{ImageError, ImageResult, ParameterError, ParameterErrorKind, UnsupportedError, UnsupportedErrorKind};
10 use crate::image::{ImageEncoder, ImageFormat};
11 use crate::utils::clamp;
12 
13 use super::entropy::build_huff_lut;
14 use super::transform;
15 
16 // Markers
17 // Baseline DCT
18 static SOF0: u8 = 0xC0;
19 // Huffman Tables
20 static DHT: u8 = 0xC4;
21 // Start of Image (standalone)
22 static SOI: u8 = 0xD8;
23 // End of image (standalone)
24 static EOI: u8 = 0xD9;
25 // Start of Scan
26 static SOS: u8 = 0xDA;
27 // Quantization Tables
28 static DQT: u8 = 0xDB;
29 // Application segments start and end
30 static APP0: u8 = 0xE0;
31 
32 // section K.1
33 // table K.1
34 #[rustfmt::skip]
35 static STD_LUMA_QTABLE: [u8; 64] = [
36     16, 11, 10, 16,  24,  40,  51,  61,
37     12, 12, 14, 19,  26,  58,  60,  55,
38     14, 13, 16, 24,  40,  57,  69,  56,
39     14, 17, 22, 29,  51,  87,  80,  62,
40     18, 22, 37, 56,  68, 109, 103,  77,
41     24, 35, 55, 64,  81, 104, 113,  92,
42     49, 64, 78, 87, 103, 121, 120, 101,
43     72, 92, 95, 98, 112, 100, 103,  99,
44 ];
45 
46 // table K.2
47 #[rustfmt::skip]
48 static STD_CHROMA_QTABLE: [u8; 64] = [
49     17, 18, 24, 47, 99, 99, 99, 99,
50     18, 21, 26, 66, 99, 99, 99, 99,
51     24, 26, 56, 99, 99, 99, 99, 99,
52     47, 66, 99, 99, 99, 99, 99, 99,
53     99, 99, 99, 99, 99, 99, 99, 99,
54     99, 99, 99, 99, 99, 99, 99, 99,
55     99, 99, 99, 99, 99, 99, 99, 99,
56     99, 99, 99, 99, 99, 99, 99, 99,
57 ];
58 
59 // section K.3
60 // Code lengths and values for table K.3
61 static STD_LUMA_DC_CODE_LENGTHS: [u8; 16] = [
62     0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 ];
64 
65 static STD_LUMA_DC_VALUES: [u8; 12] = [
66     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
67 ];
68 
69 // Code lengths and values for table K.4
70 static STD_CHROMA_DC_CODE_LENGTHS: [u8; 16] = [
71     0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
72 ];
73 
74 static STD_CHROMA_DC_VALUES: [u8; 12] = [
75     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
76 ];
77 
78 // Code lengths and values for table k.5
79 static STD_LUMA_AC_CODE_LENGTHS: [u8; 16] = [
80     0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D,
81 ];
82 
83 static STD_LUMA_AC_VALUES: [u8; 162] = [
84     0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
85     0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0,
86     0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,
87     0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
88     0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
89     0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
90     0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
91     0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
92     0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
93     0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
94     0xF9, 0xFA,
95 ];
96 
97 // Code lengths and values for table k.6
98 static STD_CHROMA_AC_CODE_LENGTHS: [u8; 16] = [
99     0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
100 ];
101 static STD_CHROMA_AC_VALUES: [u8; 162] = [
102     0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
103     0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0,
104     0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,
105     0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
106     0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
107     0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
108     0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,
109     0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
110     0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
111     0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
112     0xF9, 0xFA,
113 ];
114 
115 static DCCLASS: u8 = 0;
116 static ACCLASS: u8 = 1;
117 
118 static LUMADESTINATION: u8 = 0;
119 static CHROMADESTINATION: u8 = 1;
120 
121 static LUMAID: u8 = 1;
122 static CHROMABLUEID: u8 = 2;
123 static CHROMAREDID: u8 = 3;
124 
125 /// The permutation of dct coefficients.
126 #[rustfmt::skip]
127 static UNZIGZAG: [u8; 64] = [
128      0,  1,  8, 16,  9,  2,  3, 10,
129     17, 24, 32, 25, 18, 11,  4,  5,
130     12, 19, 26, 33, 40, 48, 41, 34,
131     27, 20, 13,  6,  7, 14, 21, 28,
132     35, 42, 49, 56, 57, 50, 43, 36,
133     29, 22, 15, 23, 30, 37, 44, 51,
134     58, 59, 52, 45, 38, 31, 39, 46,
135     53, 60, 61, 54, 47, 55, 62, 63,
136 ];
137 
138 /// A representation of a JPEG component
139 #[derive(Copy, Clone)]
140 struct Component {
141     /// The Component's identifier
142     id: u8,
143 
144     /// Horizontal sampling factor
145     h: u8,
146 
147     /// Vertical sampling factor
148     v: u8,
149 
150     /// The quantization table selector
151     tq: u8,
152 
153     /// Index to the Huffman DC Table
154     dc_table: u8,
155 
156     /// Index to the AC Huffman Table
157     ac_table: u8,
158 
159     /// The dc prediction of the component
160     _dc_pred: i32,
161 }
162 
163 pub(crate) struct BitWriter<'a, W: 'a> {
164     w: &'a mut W,
165     accumulator: u32,
166     nbits: u8,
167 }
168 
169 impl<'a, W: Write + 'a> BitWriter<'a, W> {
new(w: &'a mut W) -> Self170     fn new(w: &'a mut W) -> Self {
171         BitWriter {
172             w,
173             accumulator: 0,
174             nbits: 0,
175         }
176     }
177 
write_bits(&mut self, bits: u16, size: u8) -> io::Result<()>178     fn write_bits(&mut self, bits: u16, size: u8) -> io::Result<()> {
179         if size == 0 {
180             return Ok(());
181         }
182 
183         self.nbits += size;
184         self.accumulator |= u32::from(bits) << (32 - self.nbits) as usize;
185 
186         while self.nbits >= 8 {
187             let byte = self.accumulator >> 24;
188             self.w.write_all(&[byte as u8])?;
189 
190             if byte == 0xFF {
191                 self.w.write_all(&[0x00])?;
192             }
193 
194             self.nbits -= 8;
195             self.accumulator <<= 8;
196         }
197 
198         Ok(())
199     }
200 
pad_byte(&mut self) -> io::Result<()>201     fn pad_byte(&mut self) -> io::Result<()> {
202         self.write_bits(0x7F, 7)
203     }
204 
huffman_encode(&mut self, val: u8, table: &[(u8, u16); 256]) -> io::Result<()>205     fn huffman_encode(&mut self, val: u8, table: &[(u8, u16); 256]) -> io::Result<()> {
206         let (size, code) = table[val as usize];
207 
208         if size > 16 {
209             panic!("bad huffman value");
210         }
211 
212         self.write_bits(code, size)
213     }
214 
write_block( &mut self, block: &[i32; 64], prevdc: i32, dctable: &[(u8, u16); 256], actable: &[(u8, u16); 256], ) -> io::Result<i32>215     fn write_block(
216         &mut self,
217         block: &[i32; 64],
218         prevdc: i32,
219         dctable: &[(u8, u16); 256],
220         actable: &[(u8, u16); 256],
221     ) -> io::Result<i32> {
222         // Differential DC encoding
223         let dcval = block[0];
224         let diff = dcval - prevdc;
225         let (size, value) = encode_coefficient(diff);
226 
227         self.huffman_encode(size, dctable)?;
228         self.write_bits(value, size)?;
229 
230         // Figure F.2
231         let mut zero_run = 0;
232 
233         for &k in &UNZIGZAG[1..] {
234             if block[k as usize] == 0 {
235                 zero_run += 1;
236             } else {
237                 while zero_run > 15 {
238                     self.huffman_encode(0xF0, actable)?;
239                     zero_run -= 16;
240                 }
241 
242                 let (size, value) = encode_coefficient(block[k as usize]);
243                 let symbol = (zero_run << 4) | size;
244 
245                 self.huffman_encode(symbol, actable)?;
246                 self.write_bits(value, size)?;
247 
248                 zero_run = 0;
249             }
250         }
251 
252         if block[UNZIGZAG[63] as usize] == 0 {
253             self.huffman_encode(0x00, actable)?;
254         }
255 
256         Ok(dcval)
257     }
258 
write_marker(&mut self, marker: u8) -> io::Result<()>259     fn write_marker(&mut self, marker: u8) -> io::Result<()> {
260         self.w.write_all(&[0xFF, marker])
261     }
262 
write_segment(&mut self, marker: u8, data: &[u8]) -> io::Result<()>263     fn write_segment(&mut self, marker: u8, data: &[u8]) -> io::Result<()> {
264         self.w.write_all(&[0xFF, marker])?;
265         self.w.write_all(&(data.len() as u16 + 2).to_be_bytes())?;
266         self.w.write_all(data)
267     }
268 }
269 
270 /// Represents a unit in which the density of an image is measured
271 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
272 pub enum PixelDensityUnit {
273     /// Represents the absence of a unit, the values indicate only a
274     /// [pixel aspect ratio](https://en.wikipedia.org/wiki/Pixel_aspect_ratio)
275     PixelAspectRatio,
276 
277     /// Pixels per inch (2.54 cm)
278     Inches,
279 
280     /// Pixels per centimeter
281     Centimeters,
282 }
283 
284 /// Represents the pixel density of an image
285 ///
286 /// For example, a 300 DPI image is represented by:
287 ///
288 /// ```rust
289 /// use image::jpeg::*;
290 /// let hdpi = PixelDensity::dpi(300);
291 /// assert_eq!(hdpi, PixelDensity {density: (300,300), unit: PixelDensityUnit::Inches})
292 /// ```
293 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
294 pub struct PixelDensity {
295     /// A couple of values for (Xdensity, Ydensity)
296     pub density: (u16, u16),
297     /// The unit in which the density is measured
298     pub unit: PixelDensityUnit,
299 }
300 
301 impl PixelDensity {
302     /// Creates the most common pixel density type:
303     /// the horizontal and the vertical density are equal,
304     /// and measured in pixels per inch.
dpi(density: u16) -> Self305     pub fn dpi(density: u16) -> Self {
306         PixelDensity {
307             density: (density, density),
308             unit: PixelDensityUnit::Inches,
309         }
310     }
311 }
312 
313 impl Default for PixelDensity {
314     /// Returns a pixel density with a pixel aspect ratio of 1
default() -> Self315     fn default() -> Self {
316         PixelDensity {
317             density: (1, 1),
318             unit: PixelDensityUnit::PixelAspectRatio,
319         }
320     }
321 }
322 
323 /// The representation of a JPEG encoder
324 pub struct JpegEncoder<'a, W: 'a> {
325     writer: BitWriter<'a, W>,
326 
327     components: Vec<Component>,
328     tables: Vec<[u8; 64]>,
329 
330     luma_dctable: Box<[(u8, u16); 256]>,
331     luma_actable: Box<[(u8, u16); 256]>,
332     chroma_dctable: Box<[(u8, u16); 256]>,
333     chroma_actable: Box<[(u8, u16); 256]>,
334 
335     pixel_density: PixelDensity,
336 }
337 
338 /// JPEG Encoder
339 ///
340 /// An alias of [`JpegEncoder`].
341 ///
342 /// TODO: remove
343 ///
344 /// [`JpegEncoder`]: struct.JpegEncoder.html
345 #[allow(dead_code)]
346 #[deprecated(note = "Use `JpegEncoder` instead")]
347 pub type JPEGEncoder<'a, W> = JpegEncoder<'a, W>;
348 
349 impl<'a, W: Write> JpegEncoder<'a, W> {
350     /// Create a new encoder that writes its output to ```w```
new(w: &mut W) -> JpegEncoder<W>351     pub fn new(w: &mut W) -> JpegEncoder<W> {
352         JpegEncoder::new_with_quality(w, 75)
353     }
354 
355     /// Create a new encoder that writes its output to ```w```, and has
356     /// the quality parameter ```quality``` with a value in the range 1-100
357     /// where 1 is the worst and 100 is the best.
new_with_quality(w: &mut W, quality: u8) -> JpegEncoder<W>358     pub fn new_with_quality(w: &mut W, quality: u8) -> JpegEncoder<W> {
359         let ld = Box::new(build_huff_lut(&STD_LUMA_DC_CODE_LENGTHS, &STD_LUMA_DC_VALUES));
360         let la = Box::new(build_huff_lut(&STD_LUMA_AC_CODE_LENGTHS, &STD_LUMA_AC_VALUES));
361 
362         let cd = Box::new(build_huff_lut(&STD_CHROMA_DC_CODE_LENGTHS, &STD_CHROMA_DC_VALUES));
363         let ca = Box::new(build_huff_lut(&STD_CHROMA_AC_CODE_LENGTHS, &STD_CHROMA_AC_VALUES));
364 
365         let components = vec![
366             Component {
367                 id: LUMAID,
368                 h: 1,
369                 v: 1,
370                 tq: LUMADESTINATION,
371                 dc_table: LUMADESTINATION,
372                 ac_table: LUMADESTINATION,
373                 _dc_pred: 0,
374             },
375             Component {
376                 id: CHROMABLUEID,
377                 h: 1,
378                 v: 1,
379                 tq: CHROMADESTINATION,
380                 dc_table: CHROMADESTINATION,
381                 ac_table: CHROMADESTINATION,
382                 _dc_pred: 0,
383             },
384             Component {
385                 id: CHROMAREDID,
386                 h: 1,
387                 v: 1,
388                 tq: CHROMADESTINATION,
389                 dc_table: CHROMADESTINATION,
390                 ac_table: CHROMADESTINATION,
391                 _dc_pred: 0,
392             },
393         ];
394 
395         // Derive our quantization table scaling value using the libjpeg algorithm
396         let scale = u32::from(clamp(quality, 1, 100));
397         let scale = if scale < 50 {
398             5000 / scale
399         } else {
400             200 - scale * 2
401         };
402 
403         let mut tables = vec![STD_LUMA_QTABLE, STD_CHROMA_QTABLE];
404         tables.iter_mut().for_each(|t|
405             t.iter_mut().for_each(|v| {
406                 *v = clamp(
407                     (u32::from(*v) * scale + 50) / 100,
408                     1, u32::from(u8::max_value())) as u8;
409             })
410         );
411 
412         JpegEncoder {
413             writer: BitWriter::new(w),
414 
415             components,
416             tables,
417 
418             luma_dctable: ld,
419             luma_actable: la,
420             chroma_dctable: cd,
421             chroma_actable: ca,
422 
423             pixel_density: PixelDensity::default(),
424         }
425     }
426 
427     /// Set the pixel density of the images the encoder will encode.
428     /// If this method is not called, then a default pixel aspect ratio of 1x1 will be applied,
429     /// and no DPI information will be stored in the image.
set_pixel_density(&mut self, pixel_density: PixelDensity)430     pub fn set_pixel_density(&mut self, pixel_density: PixelDensity) {
431         self.pixel_density = pixel_density;
432     }
433 
434     /// Encodes the image stored in the raw byte buffer ```image```
435     /// that has dimensions ```width``` and ```height```
436     /// and ```ColorType``` ```c```
437     ///
438     /// The Image in encoded with subsampling ratio 4:2:2
encode( &mut self, image: &[u8], width: u32, height: u32, color_type: ColorType, ) -> ImageResult<()>439     pub fn encode(
440         &mut self,
441         image: &[u8],
442         width: u32,
443         height: u32,
444         color_type: ColorType,
445     ) -> ImageResult<()> {
446         match color_type {
447             ColorType::L8 => {
448                 let image: ImageBuffer<Luma<_>, _> = ImageBuffer::from_raw(width, height, image).unwrap();
449                 self.encode_image(&image)
450             },
451             ColorType::La8 => {
452                 let image: ImageBuffer<LumaA<_>, _> = ImageBuffer::from_raw(width, height, image).unwrap();
453                 self.encode_image(&image)
454             },
455             ColorType::Rgb8 => {
456                 let image: ImageBuffer<Rgb<_>, _> = ImageBuffer::from_raw(width, height, image).unwrap();
457                 self.encode_image(&image)
458             },
459             ColorType::Rgba8 => {
460                 let image: ImageBuffer<Rgba<_>, _> = ImageBuffer::from_raw(width, height, image).unwrap();
461                 self.encode_image(&image)
462             },
463             ColorType::Bgr8 => {
464                 let image: ImageBuffer<Bgr<_>, _> = ImageBuffer::from_raw(width, height, image).unwrap();
465                 self.encode_image(&image)
466             },
467             ColorType::Bgra8 => {
468                 let image: ImageBuffer<Bgra<_>, _> = ImageBuffer::from_raw(width, height, image).unwrap();
469                 self.encode_image(&image)
470             },
471             _ => {
472                 Err(ImageError::Unsupported(
473                     UnsupportedError::from_format_and_kind(
474                         ImageFormat::Jpeg.into(),
475                         UnsupportedErrorKind::Color(color_type.into()),
476                     ),
477                 ))
478             },
479         }
480     }
481 
482     /// Encodes the given image.
483     ///
484     /// As a special feature this does not require the whole image to be present in memory at the
485     /// same time such that it may be computed on the fly, which is why this method exists on this
486     /// encoder but not on others. Instead the encoder will iterate over 8-by-8 blocks of pixels at
487     /// a time, inspecting each pixel exactly once. You can rely on this behaviour when calling
488     /// this method.
489     ///
490     /// The Image in encoded with subsampling ratio 4:2:2
encode_image<I: GenericImageView>( &mut self, image: &I, ) -> ImageResult<()>491     pub fn encode_image<I: GenericImageView>(
492         &mut self,
493         image: &I,
494     ) -> ImageResult<()> {
495         let n = I::Pixel::CHANNEL_COUNT;
496         let num_components = if n == 1 || n == 2 { 1 } else { 3 };
497 
498         self.writer.write_marker(SOI)?;
499 
500         let mut buf = Vec::new();
501 
502         build_jfif_header(&mut buf, self.pixel_density);
503         self.writer.write_segment(APP0, &buf)?;
504 
505         build_frame_header(
506             &mut buf,
507             8,
508             // TODO: not idiomatic yet. Should be an EncodingError and mention jpg. Further it
509             // should check dimensions prior to writing.
510             u16::try_from(image.width()).map_err(|_| {
511                 ImageError::Parameter(ParameterError::from_kind(
512                     ParameterErrorKind::DimensionMismatch,
513                 ))
514             })?,
515             u16::try_from(image.height()).map_err(|_| {
516                 ImageError::Parameter(ParameterError::from_kind(
517                     ParameterErrorKind::DimensionMismatch,
518                 ))
519             })?,
520             &self.components[..num_components],
521         );
522         self.writer.write_segment(SOF0, &buf)?;
523 
524         assert_eq!(self.tables.len(), 2);
525         let numtables = if num_components == 1 { 1 } else { 2 };
526 
527         for (i, table) in self.tables[..numtables].iter().enumerate() {
528             build_quantization_segment(&mut buf, 8, i as u8, table);
529             self.writer.write_segment(DQT, &buf)?;
530         }
531 
532         build_huffman_segment(
533             &mut buf,
534             DCCLASS,
535             LUMADESTINATION,
536             &STD_LUMA_DC_CODE_LENGTHS,
537             &STD_LUMA_DC_VALUES,
538         );
539         self.writer.write_segment(DHT, &buf)?;
540 
541         build_huffman_segment(
542             &mut buf,
543             ACCLASS,
544             LUMADESTINATION,
545             &STD_LUMA_AC_CODE_LENGTHS,
546             &STD_LUMA_AC_VALUES,
547         );
548         self.writer.write_segment(DHT, &buf)?;
549 
550         if num_components == 3 {
551             build_huffman_segment(
552                 &mut buf,
553                 DCCLASS,
554                 CHROMADESTINATION,
555                 &STD_CHROMA_DC_CODE_LENGTHS,
556                 &STD_CHROMA_DC_VALUES,
557             );
558             self.writer.write_segment(DHT, &buf)?;
559 
560             build_huffman_segment(
561                 &mut buf,
562                 ACCLASS,
563                 CHROMADESTINATION,
564                 &STD_CHROMA_AC_CODE_LENGTHS,
565                 &STD_CHROMA_AC_VALUES,
566             );
567             self.writer.write_segment(DHT, &buf)?;
568         }
569 
570         build_scan_header(&mut buf, &self.components[..num_components]);
571         self.writer.write_segment(SOS, &buf)?;
572 
573 
574         if I::Pixel::COLOR_TYPE.has_color() {
575             self.encode_rgb(image)
576         } else {
577             self.encode_gray(image)
578         }?;
579 
580         self.writer.pad_byte()?;
581         self.writer.write_marker(EOI)?;
582         Ok(())
583     }
584 
encode_gray<I: GenericImageView>( &mut self, image: &I, ) -> io::Result<()>585     fn encode_gray<I: GenericImageView>(
586         &mut self,
587         image: &I,
588     ) -> io::Result<()> {
589         let mut yblock = [0u8; 64];
590         let mut y_dcprev = 0;
591         let mut dct_yblock = [0i32; 64];
592 
593         for y in range_step(0, image.height(), 8) {
594             for x in range_step(0, image.width(), 8) {
595                 copy_blocks_gray(image, x, y, &mut yblock);
596 
597                 // Level shift and fdct
598                 // Coeffs are scaled by 8
599                 transform::fdct(&yblock, &mut dct_yblock);
600 
601                 // Quantization
602                 for (i, dct) in dct_yblock.iter_mut().enumerate() {
603                     *dct = ((*dct / 8) as f32 / f32::from(self.tables[0][i])).round() as i32;
604                 }
605 
606                 let la = &*self.luma_actable;
607                 let ld = &*self.luma_dctable;
608 
609                 y_dcprev = self.writer.write_block(&dct_yblock, y_dcprev, ld, la)?;
610             }
611         }
612 
613         Ok(())
614     }
615 
encode_rgb<I: GenericImageView>( &mut self, image: &I, ) -> io::Result<()>616     fn encode_rgb<I: GenericImageView>(
617         &mut self,
618         image: &I,
619     ) -> io::Result<()> {
620         let mut y_dcprev = 0;
621         let mut cb_dcprev = 0;
622         let mut cr_dcprev = 0;
623 
624         let mut dct_yblock = [0i32; 64];
625         let mut dct_cb_block = [0i32; 64];
626         let mut dct_cr_block = [0i32; 64];
627 
628         let mut yblock = [0u8; 64];
629         let mut cb_block = [0u8; 64];
630         let mut cr_block = [0u8; 64];
631 
632         for y in range_step(0, image.height(), 8) {
633             for x in range_step(0, image.width(), 8) {
634                 // RGB -> YCbCr
635                 copy_blocks_ycbcr(
636                     image,
637                     x,
638                     y,
639                     &mut yblock,
640                     &mut cb_block,
641                     &mut cr_block,
642                 );
643 
644                 // Level shift and fdct
645                 // Coeffs are scaled by 8
646                 transform::fdct(&yblock, &mut dct_yblock);
647                 transform::fdct(&cb_block, &mut dct_cb_block);
648                 transform::fdct(&cr_block, &mut dct_cr_block);
649 
650                 // Quantization
651                 for i in 0usize..64 {
652                     dct_yblock[i] =
653                         ((dct_yblock[i] / 8) as f32 / f32::from(self.tables[0][i])).round() as i32;
654                     dct_cb_block[i] = ((dct_cb_block[i] / 8) as f32
655                         / f32::from(self.tables[1][i]))
656                         .round() as i32;
657                     dct_cr_block[i] = ((dct_cr_block[i] / 8) as f32
658                         / f32::from(self.tables[1][i]))
659                         .round() as i32;
660                 }
661 
662                 let la = &*self.luma_actable;
663                 let ld = &*self.luma_dctable;
664                 let cd = &*self.chroma_dctable;
665                 let ca = &*self.chroma_actable;
666 
667                 y_dcprev = self.writer.write_block(&dct_yblock, y_dcprev, ld, la)?;
668                 cb_dcprev = self.writer.write_block(&dct_cb_block, cb_dcprev, cd, ca)?;
669                 cr_dcprev = self.writer.write_block(&dct_cr_block, cr_dcprev, cd, ca)?;
670             }
671         }
672 
673         Ok(())
674     }
675 }
676 
677 impl<'a, W: Write> ImageEncoder for JpegEncoder<'a, W> {
write_image( mut self, buf: &[u8], width: u32, height: u32, color_type: ColorType, ) -> ImageResult<()>678     fn write_image(
679         mut self,
680         buf: &[u8],
681         width: u32,
682         height: u32,
683         color_type: ColorType,
684     ) -> ImageResult<()> {
685         self.encode(buf, width, height, color_type)
686     }
687 }
688 
build_jfif_header(m: &mut Vec<u8>, density: PixelDensity)689 fn build_jfif_header(m: &mut Vec<u8>, density: PixelDensity) {
690     m.clear();
691     m.extend_from_slice(b"JFIF");
692     m.extend_from_slice(&[0, 0x01, 0x02,
693         match density.unit {
694         PixelDensityUnit::PixelAspectRatio => 0x00,
695         PixelDensityUnit::Inches => 0x01,
696         PixelDensityUnit::Centimeters => 0x02,
697     }]);
698     m.extend_from_slice(&density.density.0.to_be_bytes());
699     m.extend_from_slice(&density.density.1.to_be_bytes());
700     m.extend_from_slice(&[0, 0]);
701 }
702 
build_frame_header( m: &mut Vec<u8>, precision: u8, width: u16, height: u16, components: &[Component], )703 fn build_frame_header(
704     m: &mut Vec<u8>,
705     precision: u8,
706     width: u16,
707     height: u16,
708     components: &[Component],
709 ) {
710     m.clear();
711 
712     m.push(precision);
713     m.extend_from_slice(&height.to_be_bytes());
714     m.extend_from_slice(&width.to_be_bytes());
715     m.push(components.len() as u8);
716 
717     for &comp in components.iter() {
718         let hv = (comp.h << 4) | comp.v;
719         m.extend_from_slice(&[comp.id, hv, comp.tq]);
720     }
721 }
722 
build_scan_header(m: &mut Vec<u8>, components: &[Component])723 fn build_scan_header(m: &mut Vec<u8>, components: &[Component]) {
724     m.clear();
725 
726     m.push(components.len() as u8);
727 
728     for &comp in components.iter() {
729         let tables = (comp.dc_table << 4) | comp.ac_table;
730         m.extend_from_slice(&[comp.id, tables]);
731     }
732 
733     // spectral start and end, approx. high and low
734     m.extend_from_slice(&[0, 63, 0]);
735 }
736 
build_huffman_segment( m: &mut Vec<u8>, class: u8, destination: u8, numcodes: &[u8; 16], values: &[u8], )737 fn build_huffman_segment(
738     m: &mut Vec<u8>,
739     class: u8,
740     destination: u8,
741     numcodes: &[u8; 16],
742     values: &[u8],
743 ) {
744     m.clear();
745 
746     let tcth = (class << 4) | destination;
747     m.push(tcth);
748 
749     m.extend_from_slice(numcodes);
750 
751     let sum: usize = numcodes
752                         .iter()
753                         .map(|&x| x as usize)
754                         .sum();
755 
756     assert_eq!(sum, values.len());
757 
758     m.extend_from_slice(values);
759 }
760 
build_quantization_segment(m: &mut Vec<u8>, precision: u8, identifier: u8, qtable: &[u8; 64])761 fn build_quantization_segment(m: &mut Vec<u8>, precision: u8, identifier: u8, qtable: &[u8; 64]) {
762     m.clear();
763 
764     let p = if precision == 8 { 0 } else { 1 };
765 
766     let pqtq = (p << 4) | identifier;
767     m.push(pqtq);
768 
769     for &i in &UNZIGZAG[..] {
770         m.push(qtable[i as usize]);
771     }
772 }
773 
encode_coefficient(coefficient: i32) -> (u8, u16)774 fn encode_coefficient(coefficient: i32) -> (u8, u16) {
775     let mut magnitude = coefficient.abs() as u16;
776     let mut num_bits = 0u8;
777 
778     while magnitude > 0 {
779         magnitude >>= 1;
780         num_bits += 1;
781     }
782 
783     let mask = (1 << num_bits as usize) - 1;
784 
785     let val = if coefficient < 0 {
786         (coefficient - 1) as u16 & mask
787     } else {
788         coefficient as u16 & mask
789     };
790 
791     (num_bits, val)
792 }
793 
794 #[inline]
rgb_to_ycbcr<P: Pixel>(pixel: P) -> (u8, u8, u8)795 fn rgb_to_ycbcr<P: Pixel>(pixel: P) -> (u8, u8, u8) {
796     use num_traits::{cast::ToPrimitive, bounds::Bounded};
797     let [r, g, b] = pixel.to_rgb().0;
798     let max: f32 = P::Subpixel::max_value().to_f32().unwrap();
799     let r: f32 = r.to_f32().unwrap();
800     let g: f32 = g.to_f32().unwrap();
801     let b: f32 = b.to_f32().unwrap();
802 
803     // Coefficients from JPEG File Interchange Format (Version 1.02), multiplied for 255 maximum.
804     let y = 76.245 / max * r + 149.685 / max * g + 29.07 / max * b;
805     let cb = -43.0185 / max * r - 84.4815 / max * g + 127.5 / max * b + 128.;
806     let cr = 127.5 / max * r - 106.7685 / max * g - 20.7315 / max * b + 128.;
807 
808     (y as u8, cb as u8, cr as u8)
809 }
810 
811 
812 /// Returns the pixel at (x,y) if (x,y) is in the image,
813 /// otherwise the closest pixel in the image
814 #[inline]
pixel_at_or_near<I: GenericImageView>(source: &I, x: u32, y: u32) -> I::Pixel815 fn pixel_at_or_near<I: GenericImageView>(source: &I, x: u32, y: u32) -> I::Pixel {
816     if source.in_bounds(x, y) {
817         source.get_pixel(x, y)
818     } else {
819         source.get_pixel(
820             x.min(source.width() - 1),
821             y.min(source.height() - 1),
822         )
823     }
824 }
825 
copy_blocks_ycbcr<I: GenericImageView>( source: &I, x0: u32, y0: u32, yb: &mut [u8; 64], cbb: &mut [u8; 64], crb: &mut [u8; 64], )826 fn copy_blocks_ycbcr<I: GenericImageView>(
827     source: &I,
828     x0: u32,
829     y0: u32,
830     yb: &mut [u8; 64],
831     cbb: &mut [u8; 64],
832     crb: &mut [u8; 64],
833 ) {
834     for y in 0..8 {
835         for x in 0..8 {
836             let pixel = pixel_at_or_near(source, x + x0, y + y0);
837             let (yc, cb, cr) = rgb_to_ycbcr(pixel);
838 
839             yb[(y * 8 + x) as usize] = yc;
840             cbb[(y * 8 + x) as usize] = cb;
841             crb[(y * 8 + x) as usize] = cr;
842         }
843     }
844 }
845 
copy_blocks_gray<I: GenericImageView>( source: &I, x0: u32, y0: u32, gb: &mut [u8; 64], )846 fn copy_blocks_gray<I: GenericImageView>(
847     source: &I,
848     x0: u32,
849     y0: u32,
850     gb: &mut [u8; 64],
851 ) {
852     use num_traits::cast::ToPrimitive;
853     for y in 0..8 {
854         for x in 0..8 {
855             let pixel = pixel_at_or_near(source, x0 + x, y0 + y);
856             let [luma] = pixel.to_luma().0;
857             gb[(y * 8 + x) as usize] = luma.to_u8().unwrap();
858         }
859     }
860 }
861 
862 #[cfg(test)]
863 mod tests {
864     use std::io::Cursor;
865 
866     #[cfg(feature = "benchmarks")]
867     extern crate test;
868     #[cfg(feature = "benchmarks")]
869     use test::{Bencher};
870 
871     use crate::{Bgra, ImageBuffer, ImageEncoder, ImageError};
872     use crate::color::ColorType;
873     use crate::error::ParameterErrorKind::DimensionMismatch;
874     use crate::image::ImageDecoder;
875 
876     use super::{
877         build_jfif_header,
878         build_huffman_segment,
879         build_scan_header,
880         build_quantization_segment,
881         build_frame_header,
882         Component,
883         DCCLASS,
884         JpegEncoder,
885         LUMADESTINATION,
886         PixelDensity,
887         STD_LUMA_DC_CODE_LENGTHS,
888         STD_LUMA_DC_VALUES,
889     };
890     use super::super::JpegDecoder;
891 
892 
decode(encoded: &[u8]) -> Vec<u8>893     fn decode(encoded: &[u8]) -> Vec<u8> {
894         let decoder = JpegDecoder::new(Cursor::new(encoded))
895             .expect("Could not decode image");
896 
897         let mut decoded = vec![0; decoder.total_bytes() as usize];
898         decoder.read_image(&mut decoded).expect("Could not decode image");
899         decoded
900     }
901 
902     #[test]
roundtrip_sanity_check()903     fn roundtrip_sanity_check() {
904         // create a 1x1 8-bit image buffer containing a single red pixel
905         let img = [255u8, 0, 0];
906 
907         // encode it into a memory buffer
908         let mut encoded_img = Vec::new();
909         {
910             let encoder = JpegEncoder::new_with_quality(&mut encoded_img, 100);
911             encoder
912                 .write_image(&img, 1, 1, ColorType::Rgb8)
913                 .expect("Could not encode image");
914         }
915 
916         // decode it from the memory buffer
917         {
918             let decoded = decode(&encoded_img);
919             // note that, even with the encode quality set to 100, we do not get the same image
920             // back. Therefore, we're going to assert that it's at least red-ish:
921             assert_eq!(3, decoded.len());
922             assert!(decoded[0] > 0x80);
923             assert!(decoded[1] < 0x80);
924             assert!(decoded[2] < 0x80);
925         }
926     }
927 
928     #[test]
grayscale_roundtrip_sanity_check()929     fn grayscale_roundtrip_sanity_check() {
930         // create a 2x2 8-bit image buffer containing a white diagonal
931         let img = [255u8, 0, 0, 255];
932 
933         // encode it into a memory buffer
934         let mut encoded_img = Vec::new();
935         {
936             let encoder = JpegEncoder::new_with_quality(&mut encoded_img, 100);
937             encoder
938                 .write_image(&img[..], 2, 2, ColorType::L8)
939                 .expect("Could not encode image");
940         }
941 
942         // decode it from the memory buffer
943         {
944             let decoded = decode(&encoded_img);
945             // note that, even with the encode quality set to 100, we do not get the same image
946             // back. Therefore, we're going to assert that the diagonal is at least white-ish:
947             assert_eq!(4, decoded.len());
948             assert!(decoded[0] > 0x80);
949             assert!(decoded[1] < 0x80);
950             assert!(decoded[2] < 0x80);
951             assert!(decoded[3] > 0x80);
952         }
953     }
954 
955     #[test]
jfif_header_density_check()956     fn jfif_header_density_check() {
957         let mut buffer = Vec::new();
958         build_jfif_header(&mut buffer, PixelDensity::dpi(300));
959         assert_eq!(buffer, vec![
960                 b'J', b'F', b'I', b'F',
961                 0, 1, 2, // JFIF version 1.2
962                 1, // density is in dpi
963                 300u16.to_be_bytes()[0], 300u16.to_be_bytes()[1],
964                 300u16.to_be_bytes()[0], 300u16.to_be_bytes()[1],
965                 0, 0, // No thumbnail
966             ]
967         );
968     }
969 
970     #[test]
test_image_too_large()971     fn test_image_too_large() {
972         // JPEG cannot encode images larger than 65,535×65,535
973         // create a 65,536×1 8-bit black image buffer
974         let img = [0; 65_536];
975         // Try to encode an image that is too large
976         let mut encoded = Vec::new();
977         let encoder = JpegEncoder::new_with_quality(&mut encoded, 100);
978         let result = encoder.write_image(&img, 65_536, 1, ColorType::L8);
979         match result {
980             Err(ImageError::Parameter(err)) => {
981                 assert_eq!(err.kind(), DimensionMismatch)
982             }
983             other => {
984                 assert!(false, "Encoding an image that is too large should return a DimensionError \
985                                 it returned {:?} instead", other)
986             }
987         }
988     }
989 
990     #[test]
test_bgra16()991     fn test_bgra16() {
992         // Test encoding an RGBA 16-bit image.
993         // Jpeg is RGB 8-bit, so the conversion should be done on the fly
994         let mut encoded = Vec::new();
995         let max = std::u16::MAX;
996         let image: ImageBuffer<Bgra<u16>, _> = ImageBuffer::from_raw(
997             1, 1, vec![0, max / 2, max, max]).unwrap();
998         let mut encoder = JpegEncoder::new_with_quality(&mut encoded, 100);
999         encoder.encode_image(&image).unwrap();
1000         let decoded = decode(&encoded);
1001         assert!(decoded[0] > 200, "bad red channel in {:?}", &decoded);
1002         assert!(100 < decoded[1] && decoded[1] < 150, "bad green channel in {:?}", &decoded);
1003         assert!(decoded[2] < 50, "bad blue channel in {:?}", &decoded);
1004     }
1005 
1006     #[test]
test_build_jfif_header()1007     fn test_build_jfif_header() {
1008         let mut buf = vec![];
1009         let density = PixelDensity::dpi(100);
1010         build_jfif_header(&mut buf, density);
1011         assert_eq!(buf, [0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0, 100, 0, 100, 0, 0]);
1012     }
1013 
1014     #[test]
test_build_frame_header()1015     fn test_build_frame_header() {
1016         let mut buf = vec![];
1017         let components = vec![
1018             Component {
1019                 id: 1,
1020                 h: 1,
1021                 v: 1,
1022                 tq: 5,
1023                 dc_table: 5,
1024                 ac_table: 5,
1025                 _dc_pred: 0,
1026             },
1027             Component {
1028                 id: 2,
1029                 h: 1,
1030                 v: 1,
1031                 tq: 4,
1032                 dc_table: 4,
1033                 ac_table: 4,
1034                 _dc_pred: 0,
1035             },
1036         ];
1037         build_frame_header(&mut buf, 5, 100, 150, &components);
1038         assert_eq!(buf, [5, 0, 150, 0, 100, 2, 1, 1 << 4 | 1, 5, 2, 1 << 4 | 1, 4]);
1039     }
1040 
1041     #[test]
test_build_scan_header()1042     fn test_build_scan_header() {
1043         let mut buf = vec![];
1044         let components = vec![
1045             Component {
1046                 id: 1,
1047                 h: 1,
1048                 v: 1,
1049                 tq: 5,
1050                 dc_table: 5,
1051                 ac_table: 5,
1052                 _dc_pred: 0,
1053             },
1054             Component {
1055                 id: 2,
1056                 h: 1,
1057                 v: 1,
1058                 tq: 4,
1059                 dc_table: 4,
1060                 ac_table: 4,
1061                 _dc_pred: 0,
1062             },
1063         ];
1064         build_scan_header(&mut buf, &components);
1065         assert_eq!(buf, [2, 1, 5 << 4 | 5, 2, 4 << 4 | 4, 0, 63, 0]);
1066     }
1067 
1068     #[test]
test_build_huffman_segment()1069     fn test_build_huffman_segment() {
1070         let mut buf = vec![];
1071         build_huffman_segment(
1072             &mut buf,
1073             DCCLASS,
1074             LUMADESTINATION,
1075             &STD_LUMA_DC_CODE_LENGTHS,
1076             &STD_LUMA_DC_VALUES,
1077         );
1078         assert_eq!(buf, vec![0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
1079     }
1080 
1081     #[test]
test_build_quantization_segment()1082     fn test_build_quantization_segment() {
1083         let mut buf = vec![];
1084         let qtable = [0u8; 64];
1085         build_quantization_segment(&mut buf, 8, 1, &qtable);
1086         let mut expected = vec![];
1087         expected.push(0 << 4 | 1);
1088         expected.extend_from_slice(&[0; 64]);
1089         assert_eq!(buf, expected)
1090     }
1091 
1092     #[cfg(feature = "benchmarks")]
1093     #[bench]
bench_jpeg_encoder_new(b: &mut Bencher)1094     fn bench_jpeg_encoder_new(b: &mut Bencher) {
1095         b.iter(|| {
1096             let mut y = vec![];
1097             let x = JpegEncoder::new(&mut y);
1098         })
1099     }
1100 
1101 }
1102