/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jpeg-encoder-0.6.1/src/image_buffer.rs
Line | Count | Source |
1 | | #![allow(clippy::identity_op)] |
2 | | |
3 | | use alloc::vec::Vec; |
4 | | |
5 | | use crate::encoder::JpegColorType; |
6 | | |
7 | | /// Conversion from RGB to YCbCr |
8 | | #[inline] |
9 | 0 | pub fn rgb_to_ycbcr(r: u8, g: u8, b: u8) -> (u8, u8, u8) { |
10 | | // To avoid floating point math this scales everything by 2^16 which gives |
11 | | // a precision of approx 4 digits. |
12 | | // |
13 | | // Non scaled conversion: |
14 | | // Y = 0.29900 * R + 0.58700 * G + 0.11400 * B |
15 | | // Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + 128 |
16 | | // Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + 128 |
17 | | |
18 | 0 | let r = r as i32; |
19 | 0 | let g = g as i32; |
20 | 0 | let b = b as i32; |
21 | | |
22 | 0 | let y = 19595 * r + 38470 * g + 7471 * b; |
23 | 0 | let cb = -11059 * r - 21709 * g + 32768 * b + (128 << 16); |
24 | 0 | let cr = 32768 * r - 27439 * g - 5329 * b + (128 << 16); |
25 | | |
26 | 0 | let y = (y + 0x7FFF) >> 16; |
27 | 0 | let cb = (cb + 0x7FFF) >> 16; |
28 | 0 | let cr = (cr + 0x7FFF) >> 16; |
29 | | |
30 | 0 | (y as u8, cb as u8, cr as u8) |
31 | 0 | } Unexecuted instantiation: jpeg_encoder::image_buffer::rgb_to_ycbcr Unexecuted instantiation: jpeg_encoder::image_buffer::rgb_to_ycbcr |
32 | | |
33 | | /// Conversion from CMYK to YCCK (YCbCrK) |
34 | | #[inline] |
35 | 0 | pub fn cmyk_to_ycck(c: u8, m: u8, y: u8, k: u8) -> (u8, u8, u8, u8) { |
36 | 0 | let (y, cb, cr) = rgb_to_ycbcr(c, m, y); |
37 | 0 | (y, cb, cr, 255 - k) |
38 | 0 | } |
39 | | |
40 | | /// # Buffer used as input value for image encoding |
41 | | /// |
42 | | /// Image encoding with [Encoder::encode_image](crate::Encoder::encode_image) needs an ImageBuffer |
43 | | /// as input for the image data. For convenience the [Encoder::encode](crate::Encoder::encode) |
44 | | /// function contains implementations for common byte based pixel formats. |
45 | | /// Users that needs other pixel formats or don't have the data available as byte slices |
46 | | /// can create their own buffer implementations. |
47 | | /// |
48 | | /// ## Example: ImageBuffer implementation for RgbImage from the `image` crate |
49 | | /// ```no_compile |
50 | | /// use image::RgbImage; |
51 | | /// use jpeg_encoder::{ImageBuffer, JpegColorType, rgb_to_ycbcr}; |
52 | | /// |
53 | | /// pub struct RgbImageBuffer { |
54 | | /// image: RgbImage, |
55 | | /// } |
56 | | /// |
57 | | /// impl ImageBuffer for RgbImageBuffer { |
58 | | /// fn get_jpeg_color_type(&self) -> JpegColorType { |
59 | | /// // Rgb images are encoded as YCbCr in JFIF files |
60 | | /// JpegColorType::Ycbcr |
61 | | /// } |
62 | | /// |
63 | | /// fn width(&self) -> u16 { |
64 | | /// self.image.width() as u16 |
65 | | /// } |
66 | | /// |
67 | | /// fn height(&self) -> u16 { |
68 | | /// self.image.height() as u16 |
69 | | /// } |
70 | | /// |
71 | | /// fn fill_buffers(&self, y: u16, buffers: &mut [Vec<u8>; 4]){ |
72 | | /// for x in 0..self.width() { |
73 | | /// let pixel = self.image.get_pixel(x as u32 ,y as u32); |
74 | | /// |
75 | | /// let (y,cb,cr) = rgb_to_ycbcr(pixel[0], pixel[1], pixel[2]); |
76 | | /// |
77 | | /// // For YCbCr the 4th buffer is not used |
78 | | /// buffers[0].push(y); |
79 | | /// buffers[1].push(cb); |
80 | | /// buffers[2].push(cr); |
81 | | /// } |
82 | | /// } |
83 | | /// } |
84 | | /// |
85 | | /// ``` |
86 | | pub trait ImageBuffer { |
87 | | /// The color type used in the image encoding |
88 | | fn get_jpeg_color_type(&self) -> JpegColorType; |
89 | | |
90 | | /// Width of the image |
91 | | fn width(&self) -> u16; |
92 | | |
93 | | /// Height of the image |
94 | | fn height(&self) -> u16; |
95 | | |
96 | | /// Add color values for the row to color component buffers |
97 | | fn fill_buffers(&self, y: u16, buffers: &mut [Vec<u8>; 4]); |
98 | | } |
99 | | |
100 | | pub(crate) struct GrayImage<'a>(pub &'a [u8], pub u16, pub u16); |
101 | | |
102 | | impl<'a> ImageBuffer for GrayImage<'a> { |
103 | 0 | fn get_jpeg_color_type(&self) -> JpegColorType { |
104 | 0 | JpegColorType::Luma |
105 | 0 | } |
106 | | |
107 | 0 | fn width(&self) -> u16 { |
108 | 0 | self.1 |
109 | 0 | } |
110 | | |
111 | 0 | fn height(&self) -> u16 { |
112 | 0 | self.2 |
113 | 0 | } |
114 | | |
115 | 0 | fn fill_buffers(&self, y: u16, buffers: &mut [Vec<u8>; 4]) { |
116 | 0 | let line = get_line(self.0, y, self.width(), 1); |
117 | | |
118 | 0 | for &pixel in line { |
119 | 0 | buffers[0].push(pixel); |
120 | 0 | } |
121 | 0 | } |
122 | | } |
123 | | |
124 | | #[inline(always)] |
125 | 0 | fn get_line(data: &[u8], y: u16, width:u16, num_colors: usize) -> &[u8] { |
126 | 0 | let width= usize::from(width); |
127 | 0 | let y = usize::from(y); |
128 | | |
129 | 0 | let start = y *width * num_colors; |
130 | 0 | let end = start + width * num_colors; |
131 | | |
132 | 0 | &data[start..end] |
133 | 0 | } |
134 | | |
135 | | macro_rules! ycbcr_image { |
136 | | ($name:ident, $num_colors:expr, $o1:expr, $o2:expr, $o3:expr) => { |
137 | | pub(crate) struct $name<'a>(pub &'a [u8], pub u16, pub u16); |
138 | | |
139 | | impl<'a> ImageBuffer for $name<'a> { |
140 | 0 | fn get_jpeg_color_type(&self) -> JpegColorType { |
141 | 0 | JpegColorType::Ycbcr |
142 | 0 | } Unexecuted instantiation: <jpeg_encoder::image_buffer::RgbImage as jpeg_encoder::image_buffer::ImageBuffer>::get_jpeg_color_type Unexecuted instantiation: <jpeg_encoder::image_buffer::RgbaImage as jpeg_encoder::image_buffer::ImageBuffer>::get_jpeg_color_type Unexecuted instantiation: <jpeg_encoder::image_buffer::BgrImage as jpeg_encoder::image_buffer::ImageBuffer>::get_jpeg_color_type Unexecuted instantiation: <jpeg_encoder::image_buffer::BgraImage as jpeg_encoder::image_buffer::ImageBuffer>::get_jpeg_color_type |
143 | | |
144 | 0 | fn width(&self) -> u16 { |
145 | 0 | self.1 |
146 | 0 | } Unexecuted instantiation: <jpeg_encoder::image_buffer::RgbImage as jpeg_encoder::image_buffer::ImageBuffer>::width Unexecuted instantiation: <jpeg_encoder::image_buffer::RgbaImage as jpeg_encoder::image_buffer::ImageBuffer>::width Unexecuted instantiation: <jpeg_encoder::image_buffer::BgrImage as jpeg_encoder::image_buffer::ImageBuffer>::width Unexecuted instantiation: <jpeg_encoder::image_buffer::BgraImage as jpeg_encoder::image_buffer::ImageBuffer>::width |
147 | | |
148 | 0 | fn height(&self) -> u16 { |
149 | 0 | self.2 |
150 | 0 | } Unexecuted instantiation: <jpeg_encoder::image_buffer::RgbImage as jpeg_encoder::image_buffer::ImageBuffer>::height Unexecuted instantiation: <jpeg_encoder::image_buffer::RgbaImage as jpeg_encoder::image_buffer::ImageBuffer>::height Unexecuted instantiation: <jpeg_encoder::image_buffer::BgrImage as jpeg_encoder::image_buffer::ImageBuffer>::height Unexecuted instantiation: <jpeg_encoder::image_buffer::BgraImage as jpeg_encoder::image_buffer::ImageBuffer>::height |
151 | | |
152 | | #[inline(always)] |
153 | 0 | fn fill_buffers(&self, y: u16, buffers: &mut [Vec<u8>; 4]) { |
154 | 0 | let line = get_line(self.0, y, self.width(), $num_colors); |
155 | | |
156 | 0 | for pixel in line.chunks_exact($num_colors) { |
157 | 0 | let (y, cb, cr) = rgb_to_ycbcr( |
158 | 0 | pixel[$o1], |
159 | 0 | pixel[$o2], |
160 | 0 | pixel[$o3], |
161 | 0 | ); |
162 | 0 |
|
163 | 0 | buffers[0].push(y); |
164 | 0 | buffers[1].push(cb); |
165 | 0 | buffers[2].push(cr); |
166 | 0 | } |
167 | 0 | } Unexecuted instantiation: <jpeg_encoder::image_buffer::RgbImage as jpeg_encoder::image_buffer::ImageBuffer>::fill_buffers Unexecuted instantiation: <jpeg_encoder::image_buffer::RgbaImage as jpeg_encoder::image_buffer::ImageBuffer>::fill_buffers Unexecuted instantiation: <jpeg_encoder::image_buffer::BgrImage as jpeg_encoder::image_buffer::ImageBuffer>::fill_buffers Unexecuted instantiation: <jpeg_encoder::image_buffer::BgraImage as jpeg_encoder::image_buffer::ImageBuffer>::fill_buffers |
168 | | } |
169 | | }; |
170 | | } |
171 | | |
172 | | ycbcr_image!(RgbImage, 3, 0, 1, 2); |
173 | | ycbcr_image!(RgbaImage, 4, 0, 1, 2); |
174 | | ycbcr_image!(BgrImage, 3, 2, 1, 0); |
175 | | ycbcr_image!(BgraImage, 4, 2, 1, 0); |
176 | | |
177 | | pub(crate) struct YCbCrImage<'a>(pub &'a [u8], pub u16, pub u16); |
178 | | |
179 | | impl<'a> ImageBuffer for YCbCrImage<'a> { |
180 | 0 | fn get_jpeg_color_type(&self) -> JpegColorType { |
181 | 0 | JpegColorType::Ycbcr |
182 | 0 | } |
183 | | |
184 | 0 | fn width(&self) -> u16 { |
185 | 0 | self.1 |
186 | 0 | } |
187 | | |
188 | 0 | fn height(&self) -> u16 { |
189 | 0 | self.2 |
190 | 0 | } |
191 | | |
192 | 0 | fn fill_buffers(&self, y: u16, buffers: &mut [Vec<u8>; 4]) { |
193 | 0 | let line = get_line(self.0, y, self.width(), 3); |
194 | | |
195 | 0 | for pixel in line.chunks_exact(3) { |
196 | 0 | buffers[0].push(pixel[0]); |
197 | 0 | buffers[1].push(pixel[1]); |
198 | 0 | buffers[2].push(pixel[2]); |
199 | 0 | } |
200 | 0 | } |
201 | | } |
202 | | |
203 | | pub(crate) struct CmykImage<'a>(pub &'a [u8], pub u16, pub u16); |
204 | | |
205 | | impl<'a> ImageBuffer for CmykImage<'a> { |
206 | 0 | fn get_jpeg_color_type(&self) -> JpegColorType { |
207 | 0 | JpegColorType::Cmyk |
208 | 0 | } |
209 | | |
210 | 0 | fn width(&self) -> u16 { |
211 | 0 | self.1 |
212 | 0 | } |
213 | | |
214 | 0 | fn height(&self) -> u16 { |
215 | 0 | self.2 |
216 | 0 | } |
217 | | |
218 | 0 | fn fill_buffers(&self, y: u16, buffers: &mut [Vec<u8>; 4]) { |
219 | 0 | let line = get_line(self.0, y, self.width(), 4); |
220 | | |
221 | 0 | for pixel in line.chunks_exact(4) { |
222 | 0 | buffers[0].push(255 - pixel[0]); |
223 | 0 | buffers[1].push(255 - pixel[1]); |
224 | 0 | buffers[2].push(255 - pixel[2]); |
225 | 0 | buffers[3].push(255 - pixel[3]); |
226 | 0 | } |
227 | 0 | } |
228 | | } |
229 | | |
230 | | pub(crate) struct CmykAsYcckImage<'a>(pub &'a [u8], pub u16, pub u16); |
231 | | |
232 | | impl<'a> ImageBuffer for CmykAsYcckImage<'a> { |
233 | 0 | fn get_jpeg_color_type(&self) -> JpegColorType { |
234 | 0 | JpegColorType::Ycck |
235 | 0 | } |
236 | | |
237 | 0 | fn width(&self) -> u16 { |
238 | 0 | self.1 |
239 | 0 | } |
240 | | |
241 | 0 | fn height(&self) -> u16 { |
242 | 0 | self.2 |
243 | 0 | } |
244 | | |
245 | 0 | fn fill_buffers(&self, y: u16, buffers: &mut [Vec<u8>; 4]) { |
246 | 0 | let line = get_line(self.0, y, self.width(), 4); |
247 | | |
248 | 0 | for pixel in line.chunks_exact(4) { |
249 | 0 |
|
250 | 0 | let (y, cb, cr, k) = cmyk_to_ycck( |
251 | 0 | pixel[0], |
252 | 0 | pixel[1], |
253 | 0 | pixel[2], |
254 | 0 | pixel[3], |
255 | 0 | ); |
256 | 0 |
|
257 | 0 | buffers[0].push(y); |
258 | 0 | buffers[1].push(cb); |
259 | 0 | buffers[2].push(cr); |
260 | 0 | buffers[3].push(k); |
261 | 0 | } |
262 | 0 | } |
263 | | } |
264 | | |
265 | | pub(crate) struct YcckImage<'a>(pub &'a [u8], pub u16, pub u16); |
266 | | |
267 | | impl<'a> ImageBuffer for YcckImage<'a> { |
268 | 0 | fn get_jpeg_color_type(&self) -> JpegColorType { |
269 | 0 | JpegColorType::Ycck |
270 | 0 | } |
271 | | |
272 | 0 | fn width(&self) -> u16 { |
273 | 0 | self.1 |
274 | 0 | } |
275 | | |
276 | 0 | fn height(&self) -> u16 { |
277 | 0 | self.2 |
278 | 0 | } |
279 | | |
280 | 0 | fn fill_buffers(&self, y: u16, buffers: &mut [Vec<u8>; 4]) { |
281 | 0 | let line = get_line(self.0, y, self.width(), 4); |
282 | | |
283 | 0 | for pixel in line.chunks_exact(4) { |
284 | 0 |
|
285 | 0 | buffers[0].push(pixel[0]); |
286 | 0 | buffers[1].push(pixel[1]); |
287 | 0 | buffers[2].push(pixel[2]); |
288 | 0 | buffers[3].push(pixel[3]); |
289 | 0 | } |
290 | 0 | } |
291 | | } |
292 | | |
293 | | #[cfg(test)] |
294 | | mod tests { |
295 | | use crate::rgb_to_ycbcr; |
296 | | |
297 | | fn assert_rgb_to_ycbcr(rgb: [u8; 3], ycbcr: [u8; 3]) { |
298 | | let (y, cb, cr) = rgb_to_ycbcr(rgb[0], rgb[1], rgb[2]); |
299 | | assert_eq!([y, cb, cr], ycbcr); |
300 | | } |
301 | | |
302 | | #[test] |
303 | | fn test_rgb_to_ycbcr() { |
304 | | |
305 | | assert_rgb_to_ycbcr([0, 0, 0], [0, 128, 128]); |
306 | | assert_rgb_to_ycbcr([255, 255, 255], [255, 128, 128]); |
307 | | assert_rgb_to_ycbcr([255, 0, 0], [76, 85, 255]); |
308 | | assert_rgb_to_ycbcr([0, 255, 0], [150, 44, 21]); |
309 | | assert_rgb_to_ycbcr([0, 0, 255], [29, 255, 107]); |
310 | | |
311 | | // Values taken from libjpeg for a common image |
312 | | |
313 | | assert_rgb_to_ycbcr([59, 109, 6], [82, 85, 111]); |
314 | | assert_rgb_to_ycbcr([29, 60, 11], [45, 109, 116]); |
315 | | assert_rgb_to_ycbcr([57, 114, 26], [87, 94, 107]); |
316 | | assert_rgb_to_ycbcr([30, 60, 6], [45, 106, 117]); |
317 | | assert_rgb_to_ycbcr([41, 75, 11], [58, 102, 116]); |
318 | | assert_rgb_to_ycbcr([145, 184, 108], [164, 97, 115]); |
319 | | assert_rgb_to_ycbcr([33, 85, 7], [61, 98, 108]); |
320 | | assert_rgb_to_ycbcr([61, 90, 40], [76, 108, 118]); |
321 | | assert_rgb_to_ycbcr([75, 127, 45], [102, 96, 109]); |
322 | | assert_rgb_to_ycbcr([30, 56, 14], [43, 111, 118]); |
323 | | assert_rgb_to_ycbcr([106, 142, 81], [124, 104, 115]); |
324 | | assert_rgb_to_ycbcr([35, 59, 11], [46, 108, 120]); |
325 | | assert_rgb_to_ycbcr([170, 203, 123], [184, 94, 118]); |
326 | | assert_rgb_to_ycbcr([45, 87, 16], [66, 100, 113]); |
327 | | assert_rgb_to_ycbcr([59, 109, 21], [84, 92, 110]); |
328 | | assert_rgb_to_ycbcr([100, 167, 36], [132, 74, 105]); |
329 | | assert_rgb_to_ycbcr([17, 53, 5], [37, 110, 114]); |
330 | | assert_rgb_to_ycbcr([226, 244, 220], [236, 119, 121]); |
331 | | assert_rgb_to_ycbcr([192, 214, 120], [197, 85, 125]); |
332 | | assert_rgb_to_ycbcr([63, 107, 22], [84, 93, 113]); |
333 | | assert_rgb_to_ycbcr([44, 78, 19], [61, 104, 116]); |
334 | | assert_rgb_to_ycbcr([72, 106, 54], [90, 108, 115]); |
335 | | assert_rgb_to_ycbcr([99, 123, 73], [110, 107, 120]); |
336 | | assert_rgb_to_ycbcr([188, 216, 148], [200, 99, 120]); |
337 | | assert_rgb_to_ycbcr([19, 46, 7], [33, 113, 118]); |
338 | | assert_rgb_to_ycbcr([56, 95, 40], [77, 107, 113]); |
339 | | assert_rgb_to_ycbcr([81, 120, 56], [101, 103, 114]); |
340 | | assert_rgb_to_ycbcr([9, 30, 0], [20, 117, 120]); |
341 | | assert_rgb_to_ycbcr([90, 118, 46], [101, 97, 120]); |
342 | | assert_rgb_to_ycbcr([24, 52, 0], [38, 107, 118]); |
343 | | assert_rgb_to_ycbcr([32, 69, 9], [51, 104, 114]); |
344 | | assert_rgb_to_ycbcr([74, 134, 33], [105, 88, 106]); |
345 | | assert_rgb_to_ycbcr([37, 74, 7], [55, 101, 115]); |
346 | | assert_rgb_to_ycbcr([69, 119, 31], [94, 92, 110]); |
347 | | assert_rgb_to_ycbcr([63, 112, 21], [87, 91, 111]); |
348 | | assert_rgb_to_ycbcr([90, 148, 17], [116, 72, 110]); |
349 | | assert_rgb_to_ycbcr([50, 97, 30], [75, 102, 110]); |
350 | | assert_rgb_to_ycbcr([99, 129, 72], [114, 105, 118]); |
351 | | assert_rgb_to_ycbcr([161, 196, 57], [170, 64, 122]); |
352 | | assert_rgb_to_ycbcr([10, 26, 1], [18, 118, 122]); |
353 | | assert_rgb_to_ycbcr([87, 128, 68], [109, 105, 112]); |
354 | | assert_rgb_to_ycbcr([111, 155, 73], [132, 94, 113]); |
355 | | assert_rgb_to_ycbcr([33, 75, 11], [55, 103, 112]); |
356 | | assert_rgb_to_ycbcr([70, 122, 51], [98, 101, 108]); |
357 | | assert_rgb_to_ycbcr([22, 74, 3], [50, 101, 108]); |
358 | | assert_rgb_to_ycbcr([88, 142, 45], [115, 89, 109]); |
359 | | assert_rgb_to_ycbcr([66, 107, 40], [87, 101, 113]); |
360 | | assert_rgb_to_ycbcr([18, 45, 0], [32, 110, 118]); |
361 | | assert_rgb_to_ycbcr([163, 186, 88], [168, 83, 124]); |
362 | | assert_rgb_to_ycbcr([47, 104, 4], [76, 88, 108]); |
363 | | assert_rgb_to_ycbcr([147, 211, 114], [181, 90, 104]); |
364 | | assert_rgb_to_ycbcr([42, 77, 18], [60, 104, 115]); |
365 | | assert_rgb_to_ycbcr([37, 72, 6], [54, 101, 116]); |
366 | | assert_rgb_to_ycbcr([84, 140, 55], [114, 95, 107]); |
367 | | assert_rgb_to_ycbcr([46, 98, 25], [74, 100, 108]); |
368 | | assert_rgb_to_ycbcr([48, 97, 20], [74, 98, 110]); |
369 | | assert_rgb_to_ycbcr([189, 224, 156], [206, 100, 116]); |
370 | | assert_rgb_to_ycbcr([36, 83, 0], [59, 94, 111]); |
371 | | assert_rgb_to_ycbcr([159, 186, 114], [170, 97, 120]); |
372 | | assert_rgb_to_ycbcr([75, 118, 46], [97, 99, 112]); |
373 | | assert_rgb_to_ycbcr([193, 233, 158], [212, 97, 114]); |
374 | | assert_rgb_to_ycbcr([76, 116, 48], [96, 101, 114]); |
375 | | assert_rgb_to_ycbcr([108, 157, 79], [133, 97, 110]); |
376 | | assert_rgb_to_ycbcr([180, 208, 155], [194, 106, 118]); |
377 | | assert_rgb_to_ycbcr([74, 126, 53], [102, 100, 108]); |
378 | | assert_rgb_to_ycbcr([72, 123, 46], [99, 98, 109]); |
379 | | assert_rgb_to_ycbcr([71, 123, 34], [97, 92, 109]); |
380 | | assert_rgb_to_ycbcr([130, 184, 72], [155, 81, 110]); |
381 | | assert_rgb_to_ycbcr([30, 61, 17], [47, 111, 116]); |
382 | | assert_rgb_to_ycbcr([27, 71, 0], [50, 100, 112]); |
383 | | assert_rgb_to_ycbcr([45, 73, 24], [59, 108, 118]); |
384 | | assert_rgb_to_ycbcr([139, 175, 93], [155, 93, 117]); |
385 | | assert_rgb_to_ycbcr([11, 38, 0], [26, 114, 118]); |
386 | | assert_rgb_to_ycbcr([34, 87, 15], [63, 101, 107]); |
387 | | assert_rgb_to_ycbcr([43, 76, 35], [61, 113, 115]); |
388 | | assert_rgb_to_ycbcr([18, 35, 7], [27, 117, 122]); |
389 | | assert_rgb_to_ycbcr([69, 97, 48], [83, 108, 118]); |
390 | | assert_rgb_to_ycbcr([139, 176, 50], [151, 71, 120]); |
391 | | assert_rgb_to_ycbcr([21, 51, 7], [37, 111, 117]); |
392 | | assert_rgb_to_ycbcr([209, 249, 189], [230, 105, 113]); |
393 | | assert_rgb_to_ycbcr([32, 66, 14], [50, 108, 115]); |
394 | | assert_rgb_to_ycbcr([100, 143, 67], [121, 97, 113]); |
395 | | assert_rgb_to_ycbcr([40, 96, 14], [70, 96, 107]); |
396 | | assert_rgb_to_ycbcr([88, 130, 64], [110, 102, 112]); |
397 | | assert_rgb_to_ycbcr([52, 112, 14], [83, 89, 106]); |
398 | | assert_rgb_to_ycbcr([49, 72, 25], [60, 108, 120]); |
399 | | assert_rgb_to_ycbcr([144, 193, 75], [165, 77, 113]); |
400 | | assert_rgb_to_ycbcr([49, 94, 1], [70, 89, 113]); |
401 | | } |
402 | | } |