makepad_image_formats/
jpeg.rs

1// image_formats::jpeg
2// by Desmond Germans, 2019
3
4use crate::ImageBuffer;
5
6const TYPE_Y: u16 = 0x000C;
7const TYPE_YUV420: u16 = 0x3900;
8const TYPE_YUV422: u16 = 0x0390;
9const TYPE_YUV440: u16 = 0x1390;
10const TYPE_YUV444: u16 = 0x00E4;
11const TYPE_RGB444: u16 = 0x01E4;
12
13const FOLDING: [u8; 64] = [56u8, 57, 8, 40, 9, 58, 59, 10, 41, 0, 48, 1, 42, 11, 60, 61, 12, 43, 2, 49, 16, 32, 17, 50, 3, 44, 13, 62, 63, 14, 45, 4, 51, 18, 33, 24, 25, 34, 19, 52, 5, 46, 15, 47, 6, 53, 20, 35, 26, 27, 36, 21, 54, 7, 55, 22, 37, 28, 29, 38, 23, 39, 30, 31,];
14const FC0: f32 = 1.0;
15const FC1: f32 = 0.98078528;
16const FC2: f32 = 0.92387953;
17const FC3: f32 = 0.83146961;
18const FC4: f32 = 0.70710678;
19const FC5: f32 = 0.55557023;
20const FC6: f32 = 0.38268343;
21const FC7: f32 = 0.19509032;
22
23const FIX: u8 = 8;
24const ONE: f32 = (1 << FIX) as f32;
25const C0: i32 = (FC0 * ONE) as i32;
26const C1: i32 = (FC1 * ONE) as i32;
27const C2: i32 = (FC2 * ONE) as i32;
28const C3: i32 = (FC3 * ONE) as i32;
29const C4: i32 = (FC4 * ONE) as i32;
30const C5: i32 = (FC5 * ONE) as i32;
31const C6: i32 = (FC6 * ONE) as i32;
32const C7: i32 = (FC7 * ONE) as i32;
33
34const C7PC1: i32 = C7 + C1;
35const C5PC3: i32 = C5 + C3;
36const C7MC1: i32 = C7 - C1;
37const C5MC3: i32 = C5 - C3;
38const C0S: i32 = C0 >> 1;
39const C6PC2: i32 = C6 + C2;
40const C6MC2: i32 = C6 - C2;
41
42fn from_le16(src: &[u8]) -> u16 {
43    ((src[1] as u16) << 8) | (src[0] as u16)
44}
45
46fn from_le32(src: &[u8]) -> u32 {
47    ((src[3] as u32) << 24) | ((src[2] as u32) << 16) | ((src[1] as u32) << 8) | (src[0] as u32)
48}
49
50fn from_be16(src: &[u8]) -> u16 {
51    ((src[0] as u16) << 8) | (src[1] as u16)
52}
53
54fn from_be32(src: &[u8]) -> u32 {
55    ((src[0] as u32) << 24) | ((src[1] as u32) << 16) | ((src[2] as u32) << 8) | (src[3] as u32)
56}
57
58fn make_coeff(cat: u8, code: isize) -> i32 {
59    let mcat = cat - 1;
60    let hmcat = 1 << mcat;
61    let base = code & (hmcat - 1);
62    if (code & hmcat) != 0 {
63        (base + hmcat) as i32
64    }
65    else {
66        (base + 1 - (1 << cat)) as i32
67    }
68}
69
70#[derive(Copy, Clone)]
71struct Table {
72    prefix: [u16; 65536],
73}
74
75impl Table {
76    pub fn new_empty() -> Table {
77        Table {
78            prefix: [0u16; 65536],
79        }
80    }
81    
82    pub fn new(bits: [u8; 16], huffval: [u8; 256]) -> Table {
83        let mut prefix = [0u16; 65536];
84        let mut dp = 0;
85        let mut count = 0;
86        for i in 1..17 {
87            //println!("{}-bit codes:",i);
88            for _k in 0..bits[i - 1] {
89                //println!("    code {}: {}",count,huffval[count]);
90                let runcat = huffval[count] as u16;
91                for _l in 0..(65536 >> i) {
92                    prefix[dp] = (runcat << 8) | (i as u16);
93                    dp += 1;
94                }
95                count += 1;
96            }
97        }
98        Table {
99            prefix: prefix,
100        }
101    }
102}
103
104fn jpeg_get8(block: &[u8], rp: &mut usize) -> u8 {
105    let mut b = block[*rp];
106    //println!("[{:02X}]",b);
107    *rp += 1;
108    if b == 0xFF {
109        b = block[*rp];
110        //println!("[{:02X}]",b);
111        *rp += 1;
112        if b == 0 {
113            return 0xFF;
114        }
115    }
116    b
117}
118
119struct Reader<'a> {
120    block: &'a [u8],
121    rp: usize,
122    bit: u32,
123    cache: u32,
124}
125
126impl<'a> Reader<'a> {
127    pub fn new(block: &'a [u8]) -> Reader<'a> {
128        let mut rp = 0usize;
129        let mut bit = 0u32;
130        let mut cache = 0u32;
131        while bit <= 24 {
132            let b = jpeg_get8(block, &mut rp);
133            cache |= (b as u32) << (24 - bit);
134            bit += 8;
135        }
136        Reader {
137            block: block,
138            rp: rp,
139            bit: bit,
140            cache: cache,
141        }
142    }
143    
144    fn restock(&mut self) {
145        while self.bit <= 24 {
146            let b = if self.rp >= self.block.len() {0} else {jpeg_get8(self.block, &mut self.rp)}; // fill with 0 if at end of block
147            self.cache |= (b as u32) << (24 - self.bit);
148            self.bit += 8;
149        }
150    }
151    
152    pub fn peek(&self, n: usize) -> u32 {
153        self.cache >> (32 - n)
154    }
155    
156    pub fn skip(&mut self, n: usize) {
157        self.cache <<= n;
158        self.bit -= n as u32;
159        self.restock();
160    }
161    
162    pub fn get1(&mut self) -> bool {
163        let result = self.peek(1) == 1;
164        //println!(" 1 bit : {}",if result { 1 } else { 0 });
165        self.skip(1);
166        result
167    }
168    
169    pub fn getn(&mut self, n: usize) -> u32 {
170        let result = self.peek(n);
171        //println!("{} bits: ({:0b}) {}",n,self.cache >> (32 - n),result);
172        self.skip(n);
173        result
174    }
175    
176    pub fn get_code(&mut self, table: &Table) -> u8 {
177        let index = self.cache >> 16;
178        let d = table.prefix[index as usize];
179        let symbol = (d >> 8) & 255;
180        let n = d & 255;
181        //println!("{} bits: ({:0b}) runcat {:02X}",n,index >> (16 - n),symbol);
182        self.skip(n as usize);
183        symbol as u8
184    }
185    
186    pub fn enter(&mut self, rp: usize) {
187        self.rp = rp;
188        self.cache = 0;
189        self.bit = 0;
190        self.restock();
191    }
192    
193    pub fn leave(&mut self) -> usize {
194        //println!("leave: bit = {}, rp = {}",self.bit,self.rp);
195        // superspecial case: no JPEG data read at all (only during initial programming)
196        if (self.bit == 32) && (self.rp == 4) {
197            return 0;
198        }
199        /*// first search FFD9 to elimiate stray FFs past end of buffer
200		if (self.block[self.rp - 5] == 0xFF) && (self.block[self.rp - 4] == 0xD9) {
201			return self.rp - 5;
202		}
203		if (self.block[self.rp - 4] == 0xFF) && (self.block[self.rp - 3] == 0xD9) {
204			return self.rp - 4;
205		}
206		if (self.block[self.rp - 3] == 0xFF) && (self.block[self.rp - 2] == 0xD9) {
207			return self.rp - 3;
208		}
209		if (self.block[self.rp - 2] == 0xFF) && (self.block[self.rp - 1] == 0xD9) {
210			return self.rp - 2;
211		}
212		if (self.block[self.rp - 1] == 0xFF) && (self.block[self.rp] == 0xD9) {
213			return self.rp - 1;
214		}*/
215        // anything else
216        for _i in 0..((self.bit + 7) / 8) - 2 {
217            if (self.block[self.rp - 1] == 0x00) && (self.block[self.rp - 2] == 0xFF) {
218                self.rp -= 1;
219            }
220            self.rp -= 1;
221        }
222        //println!("and leaving with rp = {} ({:02X} {:02X})",self.rp,self.block[self.rp],self.block[self.rp + 1]);
223        self.rp
224    }
225}
226
227fn unpack_sequential(reader: &mut Reader, coeffs: &mut [i32], dcht: &Table, acht: &Table, dc: &mut i32) {
228    let cat = reader.get_code(dcht);
229    if cat > 0 {
230        let code = reader.getn(cat as usize);
231        *dc += make_coeff(cat, code as isize) as i32;
232    }
233    coeffs[FOLDING[0] as usize] = *dc;
234    //println!("DC {}",*dc);
235    let mut i = 1;
236    while i < 64 {
237        let runcat = reader.get_code(acht);
238        let run = runcat >> 4;
239        let cat = runcat & 15;
240        if cat > 0 {
241            let code = reader.getn(cat as usize);
242            let coeff = make_coeff(cat, code as isize) as i32;
243            i += run;
244            coeffs[FOLDING[i as usize] as usize] = coeff;
245            //println!("coeffs[{}] = {}",i,coeff);
246        }
247        else {
248            if run == 15 { // ZRL
249                i += 15;
250                //println!("ZRL");
251            }
252            else { // EOB
253                //println!("EOB");
254                break;
255            }
256        }
257        i += 1;
258    }
259}
260
261fn unpack_progressive_start_dc(reader: &mut Reader, coeffs: &mut[i32], dcht: &Table, dc: &mut i32, shift: u8) {
262    let cat = reader.get_code(dcht);
263    if cat > 0 {
264        let code = reader.getn(cat as usize);
265        *dc += make_coeff(cat, code as isize) as i32;
266    }
267    //println!("DC = {}",*dc << shift);
268    coeffs[FOLDING[0] as usize] = *dc << shift;
269}
270
271fn unpack_progressive_start_ac(reader: &mut Reader, coeffs: &mut[i32], acht: &Table, start: u8, end: u8, shift: u8, eobrun: &mut usize) {
272    if *eobrun != 0 {
273        *eobrun -= 1;
274    }
275    else {
276        let mut i = start;
277        while i <= end {
278            let runcat = reader.get_code(acht);
279            let run = runcat >> 4;
280            let cat = runcat & 15;
281            if cat != 0 {
282                let code = reader.getn(cat as usize);
283                let coeff = make_coeff(cat, code as isize);
284                i += run;
285                coeffs[FOLDING[i as usize] as usize] = (coeff << shift) as i32;
286            }
287            else {
288                if run == 15 {
289                    i += 15;
290                }
291                else {
292                    *eobrun = 1 << run;
293                    if run != 0 {
294                        *eobrun += reader.getn(run as usize) as usize;
295                    }
296                    *eobrun -= 1;
297                    break;
298                }
299            }
300            i += 1;
301        }
302    }
303}
304
305fn unpack_progressive_refine_dc(reader: &mut Reader, coeffs: &mut[i32], shift: u8) {
306    if reader.get1() {
307        coeffs[FOLDING[0] as usize] |= 1 << shift;
308    }
309}
310
311fn update_nonzeros(reader: &mut Reader, coeffs: &mut[i32], start: u8, end: u8, shift: u8, count: u8) -> u8 {
312    let mut i = start;
313    let mut k = count;
314    while i <= end {
315        if coeffs[FOLDING[i as usize] as usize] != 0 {
316            if reader.get1() {
317                if coeffs[FOLDING[i as usize] as usize] > 0 {
318                    coeffs[FOLDING[i as usize] as usize] += 1 << shift;
319                }
320                else {
321                    coeffs[FOLDING[i as usize] as usize] -= 1 << shift;
322                }
323            }
324        }
325        else {
326            if k == 0 {
327                return i;
328            }
329            k -= 1;
330        }
331        i += 1;
332    }
333    i
334}
335
336fn unpack_progressive_refine_ac(reader: &mut Reader, coeffs: &mut[i32], acht: &Table, start: u8, end: u8, shift: u8, eobrun: &mut usize) {
337    if *eobrun != 0 {
338        update_nonzeros(reader, &mut coeffs[0..64], start, end, shift, 64);
339        *eobrun -= 1;
340    }
341    else {
342        let mut i = start;
343        while i <= end {
344            let runcat = reader.get_code(acht);
345            let run = runcat >> 4;
346            let cat = runcat & 15;
347            if cat != 0 {
348                let sb = reader.get1();
349                i = update_nonzeros(reader, &mut coeffs[0..64], i, end, shift, run);
350                if sb {
351                    coeffs[FOLDING[i as usize] as usize] = 1 << shift;
352                }
353                else {
354                    coeffs[FOLDING[i as usize] as usize] = 11 << shift;
355                }
356            }
357            else {
358                if run == 15 {
359                    i = update_nonzeros(reader, &mut coeffs[0..64], i, end, shift, 15);
360                }
361                else {
362                    *eobrun = 1 << run;
363                    if run != 0 {
364                        *eobrun += reader.getn(run as usize) as usize;
365                    }
366                    *eobrun -= 1;
367                    update_nonzeros(reader, &mut coeffs[0..64], i, end, shift, 64);
368                    break;
369                }
370            }
371        }
372    }
373}
374
375fn unpack_block(reader: &mut Reader, coeffs: &mut [i32], dcht: &Table, acht: &Table, dc: &mut i32, start: u8, end: u8, shift: u8, refine: bool, eobrun: &mut usize) {
376    if refine {
377        if start == 0 {
378            unpack_progressive_refine_dc(reader, &mut coeffs[0..64], shift);
379        }
380        else {
381            unpack_progressive_refine_ac(reader, &mut coeffs[0..64], &acht, start, end, shift, eobrun);
382        }
383    }
384    else {
385        if start == 0 {
386            if (end == 63) && (shift == 0) {
387                unpack_sequential(reader, &mut coeffs[0..64], &dcht, &acht, dc);
388            }
389            else {
390                unpack_progressive_start_dc(reader, &mut coeffs[0..64], &dcht, dc, shift);
391            }
392        }
393        else {
394            unpack_progressive_start_ac(reader, &mut coeffs[0..64], &acht, start, end, shift, eobrun);
395        }
396    }
397}
398
399fn unpack_macroblock(
400    reader: &mut Reader,
401    coeffs: &mut [i32],
402    dcht: &[Table],
403    acht: &[Table],
404    dt: &[usize],
405    at: &[usize],
406    dc: &mut [i32],
407    start: u8,
408    end: u8,
409    shift: u8,
410    refine: bool,
411    eobrun: &mut usize,
412    itype: u16,
413    rescnt: &mut usize,
414    resint: usize,
415    mask: u8
416) {
417    match itype {
418        TYPE_Y => {
419            if (mask & 1) != 0 {
420                unpack_block(reader, &mut coeffs[0..64], &dcht[dt[0]], &acht[at[0]], &mut dc[0], start, end, shift, refine, eobrun);
421            }
422        },
423        TYPE_YUV420 => {
424            if (mask & 1) != 0 {
425                unpack_block(reader, &mut coeffs[0..64], &dcht[dt[0]], &acht[at[0]], &mut dc[0], start, end, shift, refine, eobrun);
426                unpack_block(reader, &mut coeffs[64..128], &dcht[dt[0]], &acht[at[0]], &mut dc[0], start, end, shift, refine, eobrun);
427                unpack_block(reader, &mut coeffs[128..192], &dcht[dt[0]], &acht[at[0]], &mut dc[0], start, end, shift, refine, eobrun);
428                unpack_block(reader, &mut coeffs[192..256], &dcht[dt[0]], &acht[at[0]], &mut dc[0], start, end, shift, refine, eobrun);
429            }
430            if (mask & 2) != 0 {
431                unpack_block(reader, &mut coeffs[256..320], &dcht[dt[1]], &acht[at[1]], &mut dc[1], start, end, shift, refine, eobrun);
432            }
433            if (mask & 4) != 0 {
434                unpack_block(reader, &mut coeffs[320..384], &dcht[dt[2]], &acht[at[2]], &mut dc[2], start, end, shift, refine, eobrun);
435            }
436        },
437        TYPE_YUV422 | TYPE_YUV440 => {
438            if (mask & 1) != 0 {
439                unpack_block(reader, &mut coeffs[0..64], &dcht[dt[0]], &acht[at[0]], &mut dc[0], start, end, shift, refine, eobrun);
440                unpack_block(reader, &mut coeffs[64..128], &dcht[dt[0]], &acht[at[0]], &mut dc[0], start, end, shift, refine, eobrun);
441            }
442            if (mask & 2) != 0 {
443                unpack_block(reader, &mut coeffs[128..192], &dcht[dt[1]], &acht[at[1]], &mut dc[1], start, end, shift, refine, eobrun);
444            }
445            if (mask & 4) != 0 {
446                unpack_block(reader, &mut coeffs[192..256], &dcht[dt[2]], &acht[at[2]], &mut dc[2], start, end, shift, refine, eobrun);
447            }
448        },
449        TYPE_YUV444 | TYPE_RGB444 => {
450            if (mask & 1) != 0 {
451                unpack_block(reader, &mut coeffs[0..64], &dcht[dt[0]], &acht[at[0]], &mut dc[0], start, end, shift, refine, eobrun);
452            }
453            if (mask & 2) != 0 {
454                unpack_block(reader, &mut coeffs[64..128], &dcht[dt[1]], &acht[at[1]], &mut dc[1], start, end, shift, refine, eobrun);
455            }
456            if (mask & 4) != 0 {
457                unpack_block(reader, &mut coeffs[128..192], &dcht[dt[2]], &acht[at[2]], &mut dc[2], start, end, shift, refine, eobrun);
458            }
459        },
460        _ => {},
461    }
462    if resint != 0 {
463        *rescnt -= 1;
464        if *rescnt == 0 {
465            let mut tsp = reader.leave();
466            if (reader.block[tsp] == 0xFF) && ((reader.block[tsp + 1] >= 0xD0) && (reader.block[tsp + 1] < 0xD8)) {
467                tsp += 2;
468                *rescnt = resint;
469                dc[0] = 0;
470                dc[1] = 0;
471                dc[2] = 0;
472            }
473            reader.enter(tsp);
474        }
475    }
476}
477
478fn partial_idct(out: &mut [i32], inp: &[i32]) {
479    
480    for i in 0..8 {
481        let x3 = inp[i];
482        let x1 = inp[i + 8];
483        let x5 = inp[i + 16];
484        let x7 = inp[i + 24];
485        let x6 = inp[i + 32];
486        let x2 = inp[i + 40];
487        let x4 = inp[i + 48];
488        let x0 = inp[i + 56];
489        
490        let q17 = C1 * (x1 + x7);
491        let q35 = C3 * (x3 + x5);
492        let r3 = C7PC1 * x1 - q17;
493        let d3 = C5PC3 * x3 - q35;
494        let r0 = C7MC1 * x7 + q17;
495        let d0 = C5MC3 * x5 + q35;
496        let b0 = r0 + d0;
497        let d2 = r3 + d3;
498        let d1 = r0 - d0;
499        let b3 = r3 - d3;
500        let b1 = C4 * ((d1 + d2) >> FIX);
501        let b2 = C4 * ((d1 - d2) >> FIX);
502        let q26 = C2 * (x2 + x6);
503        let p04 = C4 * (x0 + x4) + C0S;
504        let n04 = C4 * (x0 - x4) + C0S;
505        let p26 = C6MC2 * x6 + q26;
506        let n62 = C6PC2 * x2 - q26;
507        let a0 = p04 + p26;
508        let a1 = n04 + n62;
509        let a3 = p04 - p26;
510        let a2 = n04 - n62;
511        let y0 = (a0 + b0) >> (FIX + 1);
512        let y1 = (a1 + b1) >> (FIX + 1);
513        let y3 = (a3 + b3) >> (FIX + 1);
514        let y2 = (a2 + b2) >> (FIX + 1);
515        let y7 = (a0 - b0) >> (FIX + 1);
516        let y6 = (a1 - b1) >> (FIX + 1);
517        let y4 = (a3 - b3) >> (FIX + 1);
518        let y5 = (a2 - b2) >> (FIX + 1);
519        
520        out[i] = y0;
521        out[i + 8] = y1;
522        out[i + 16] = y3;
523        out[i + 24] = y2;
524        out[i + 32] = y7;
525        out[i + 40] = y6;
526        out[i + 48] = y4;
527        out[i + 56] = y5;
528    }
529}
530
531
532//fn m32x4s(a: bool) -> Mask::<i32, 4> {Mask::<i32, 4>::from_array([a; 4])}
533
534// this is not faster :) I think LLVM autovectorises the top version
535/*
536fn i32x4v(a: i32, b: i32, c: i32, d: i32) -> i32x4 {i32x4::from_array([a, b, c, d])}
537fn i32x4s(a: i32) -> i32x4 {i32x4::from_array([a; 4])}
538
539fn _partial_idct_simd(out: &mut [i32], inp: &[i32]) {
540    for i in 0..2 {
541        let i = i * 4;
542        let x3 = i32x4v(inp[i + 0 + 0], inp[i + 1 + 0], inp[i + 2 + 0], inp[i + 3 + 0]);
543        let x1 = i32x4v(inp[i + 0 + 8], inp[i + 1 + 8], inp[i + 2 + 8], inp[i + 3 + 8]);
544        let x5 = i32x4v(inp[i + 0 + 16], inp[i + 1 + 16], inp[i + 2 + 16], inp[i + 3 + 16]);
545        let x7 = i32x4v(inp[i + 0 + 24], inp[i + 1 + 24], inp[i + 2 + 24], inp[i + 3 + 24]);
546        let x6 = i32x4v(inp[i + 0 + 32], inp[i + 1 + 32], inp[i + 2 + 32], inp[i + 3 + 32]);
547        let x2 = i32x4v(inp[i + 0 + 40], inp[i + 1 + 40], inp[i + 2 + 40], inp[i + 3 + 40]);
548        let x4 = i32x4v(inp[i + 0 + 48], inp[i + 1 + 48], inp[i + 2 + 48], inp[i + 3 + 48]);
549        let x0 = i32x4v(inp[i + 0 + 56], inp[i + 1 + 56], inp[i + 2 + 56], inp[i + 3 + 56]);
550        
551        let q17 = i32x4s(C1) * (x1 + x7);
552        let q35 = i32x4s(C3) * (x3 + x5);
553        let r3 = i32x4s(C7PC1) * x1 - q17;
554        let d3 = i32x4s(C5PC3) * x3 - q35;
555        let r0 = i32x4s(C7MC1) * x7 + q17;
556        let d0 = i32x4s(C5MC3) * x5 + q35;
557        let b0 = r0 + d0;
558        let d2 = r3 + d3;
559        let d1 = r0 - d0;
560        let b3 = r3 - d3;
561        let b1 = i32x4s(C4) * ((d1 + d2) >> i32x4s(8));
562        let b2 = i32x4s(C4) * ((d1 - d2) >> i32x4s(8));
563        let q26 = i32x4s(C2) * (x2 + x6);
564        let p04 = i32x4s(C4) * (x0 + x4) + i32x4s(C0S);
565        let n04 = i32x4s(C4) * (x0 - x4) + i32x4s(C0S);
566        let p26 = i32x4s(C6MC2) * x6 + q26;
567        let n62 = i32x4s(C6PC2) * x2 - q26;
568        let a0 = p04 + p26;
569        let a1 = n04 + n62;
570        let a3 = p04 - p26;
571        let a2 = n04 - n62;
572        let y0 = (a0 + b0) >> i32x4s(9);
573        let y1 = (a1 + b1) >> i32x4s(9);
574        let y3 = (a3 + b3) >> i32x4s(9);
575        let y2 = (a2 + b2) >> i32x4s(9);
576        let y7 = (a0 - b0) >> i32x4s(9);
577        let y6 = (a1 - b1) >> i32x4s(9);
578        let y4 = (a3 - b3) >> i32x4s(9);
579        let y5 = (a2 - b2) >> i32x4s(9);
580        
581        for l in 0..4 {
582            out[i + l + 0] = y0[l];
583            out[i + l + 8] = y1[l];
584            out[i + l + 16] = y3[l];
585            out[i + l + 24] = y2[l];
586            out[i + l + 32] = y7[l];
587            out[i + l + 40] = y6[l];
588            out[i + l + 48] = y4[l];
589            out[i + l + 56] = y5[l];
590        }
591    }
592}*/
593
594fn unswizzle_transpose_swizzle(out: &mut [i32], inp: &[i32]) {
595    out[0] = inp[3];
596    out[1] = inp[11];
597    out[2] = inp[27];
598    out[3] = inp[19];
599    out[4] = inp[51];
600    out[5] = inp[59];
601    out[6] = inp[43];
602    out[7] = inp[35];
603    out[8] = inp[1];
604    out[9] = inp[9];
605    out[10] = inp[25];
606    out[11] = inp[17];
607    out[12] = inp[49];
608    out[13] = inp[57];
609    out[14] = inp[41];
610    out[15] = inp[33];
611    
612    out[16] = inp[5];
613    out[17] = inp[13];
614    out[18] = inp[29];
615    out[19] = inp[21];
616    out[20] = inp[53];
617    out[21] = inp[61];
618    out[22] = inp[45];
619    out[23] = inp[37];
620    out[24] = inp[7];
621    out[25] = inp[15];
622    out[26] = inp[31];
623    out[27] = inp[23];
624    out[28] = inp[55];
625    out[29] = inp[63];
626    out[30] = inp[47];
627    out[31] = inp[39];
628    
629    out[32] = inp[6];
630    out[33] = inp[14];
631    out[34] = inp[30];
632    out[35] = inp[22];
633    out[36] = inp[54];
634    out[37] = inp[62];
635    out[38] = inp[46];
636    out[39] = inp[38];
637    out[40] = inp[2];
638    out[41] = inp[10];
639    out[42] = inp[26];
640    out[43] = inp[18];
641    out[44] = inp[50];
642    out[45] = inp[58];
643    out[46] = inp[42];
644    out[47] = inp[34];
645    
646    out[48] = inp[4];
647    out[49] = inp[12];
648    out[50] = inp[28];
649    out[51] = inp[20];
650    out[52] = inp[52];
651    out[53] = inp[60];
652    out[54] = inp[44];
653    out[55] = inp[36];
654    out[56] = inp[0];
655    out[57] = inp[8];
656    out[58] = inp[24];
657    out[59] = inp[16];
658    out[60] = inp[48];
659    out[61] = inp[56];
660    out[62] = inp[40];
661    out[63] = inp[32];
662}
663
664fn unswizzle_transpose(out: &mut [i32], inp: &[i32]) {
665    out[0] = inp[0];
666    out[1] = inp[8];
667    out[2] = inp[24];
668    out[3] = inp[16];
669    out[4] = inp[48];
670    out[5] = inp[56];
671    out[6] = inp[40];
672    out[7] = inp[32];
673    out[8] = inp[1];
674    out[9] = inp[9];
675    out[10] = inp[25];
676    out[11] = inp[17];
677    out[12] = inp[49];
678    out[13] = inp[57];
679    out[14] = inp[41];
680    out[15] = inp[33];
681    
682    out[16] = inp[2];
683    out[17] = inp[10];
684    out[18] = inp[26];
685    out[19] = inp[18];
686    out[20] = inp[50];
687    out[21] = inp[58];
688    out[22] = inp[42];
689    out[23] = inp[34];
690    out[24] = inp[3];
691    out[25] = inp[11];
692    out[26] = inp[27];
693    out[27] = inp[19];
694    out[28] = inp[51];
695    out[29] = inp[59];
696    out[30] = inp[43];
697    out[31] = inp[35];
698    
699    out[32] = inp[4];
700    out[33] = inp[12];
701    out[34] = inp[28];
702    out[35] = inp[20];
703    out[36] = inp[52];
704    out[37] = inp[60];
705    out[38] = inp[44];
706    out[39] = inp[36];
707    out[40] = inp[5];
708    out[41] = inp[13];
709    out[42] = inp[29];
710    out[43] = inp[21];
711    out[44] = inp[53];
712    out[45] = inp[61];
713    out[46] = inp[45];
714    out[47] = inp[37];
715    
716    out[48] = inp[6];
717    out[49] = inp[14];
718    out[50] = inp[30];
719    out[51] = inp[22];
720    out[52] = inp[54];
721    out[53] = inp[62];
722    out[54] = inp[46];
723    out[55] = inp[38];
724    out[56] = inp[7];
725    out[57] = inp[15];
726    out[58] = inp[31];
727    out[59] = inp[23];
728    out[60] = inp[55];
729    out[61] = inp[63];
730    out[62] = inp[47];
731    out[63] = inp[39];
732}
733
734fn convert_block(block: &mut [i32], qtable: &[i32]) {
735    let mut temp0 = [0i32; 64];
736    for i in 0..64 {
737        temp0[i] = block[i] * qtable[i];
738    }
739    let mut temp1 = [0i32; 64];
740    partial_idct(&mut temp1, &temp0);
741    let mut temp2 = [0i32; 64];
742    unswizzle_transpose_swizzle(&mut temp2, &temp1);
743    let mut temp3 = [0i32; 64];
744    partial_idct(&mut temp3, &temp2);
745    unswizzle_transpose(block, &temp3);
746}
747
748fn convert_blocks(coeffs: &mut [i32], count: usize, pattern: u16, qtable: &[[i32; 64]], qt: &[usize; 3]) {
749    let mut curp = pattern;
750    for i in 0..count {
751        if (curp & 3) == 3 {
752            curp = pattern;
753        }
754        convert_block(&mut coeffs[i * 64..i * 64 + 64], &qtable[qt[(curp & 3) as usize]]);
755        curp >>= 2;
756    }
757}
758
759fn clamp<T: std::cmp::PartialOrd>(v: T, min: T, max: T) -> T {
760    if v < min {
761        return min;
762    }
763    else if v > max {
764        return max;
765    }
766    v
767}
768
769fn draw_rgb(image: &mut ImageBuffer, px: usize, py: usize, r: i32, g: i32, b: i32) {
770    image.data[py * image.width + px] = 0xFF000000 | ((clamp(r, 0, 255) as u32) << 16) | ((clamp(g, 0, 255) as u32) << 8) | (clamp(b, 0, 255) as u32);
771}
772
773fn draw_yuv(image: &mut ImageBuffer, px: usize, py: usize, y: i32, u: i32, v: i32) {
774    let r = ((y << 8) + 359 * v) >> 8;
775    let g = ((y << 8) - 88 * u - 183 * v) >> 8;
776    let b = ((y << 8) + 454 * u) >> 8;
777    draw_rgb(image, px, py, r, g, b);
778}
779
780fn draw_macroblock_y(image: &mut ImageBuffer, x0: usize, y0: usize, width: usize, height: usize, coeffs: &[i32]) {
781    for i in 0..height {
782        for k in 0..width {
783            draw_yuv(image, x0 + k, y0 + i, (coeffs[i * 8 + k] + 128) as i32, 0, 0);
784        }
785    }
786}
787
788fn draw_macroblock_yuv420(image: &mut ImageBuffer, x0: usize, y0: usize, width: usize, height: usize, coeffs: &[i32]) {
789    for i in 0..height {
790        for k in 0..width {
791            let by = (i >> 3) * 2 + (k >> 3);
792            let si = i & 7;
793            let sk = k & 7;
794            let y = coeffs[by * 64 + si * 8 + sk] + 128;
795            let hi = i >> 1;
796            let hk = k >> 1;
797            let u = coeffs[256 + hi * 8 + hk];
798            let v = coeffs[320 + hi * 8 + hk];
799            draw_yuv(image, x0 + k, y0 + i, y as i32, u as i32, v as i32);
800        }
801    }
802}
803
804fn draw_macroblock_yuv422_normal(image: &mut ImageBuffer, x0: usize, y0: usize, width: usize, height: usize, coeffs: &[i32]) {
805    for i in 0..height {
806        for k in 0..width {
807            let by = k >> 3;
808            let sk = k & 7;
809            let hk = k >> 1;
810            let y = coeffs[by * 64 + i * 8 + sk] + 128;
811            let u = coeffs[128 + i * 8 + hk];
812            let v = coeffs[192 + i * 8 + hk];
813            draw_yuv(image, x0 + k, y0 + i, y as i32, u as i32, v as i32);
814        }
815    }
816}
817
818#[cfg(feature="nightly")]
819fn draw_macroblock_yuv422(image: &mut ImageBuffer, x0: usize, y0: usize, width: usize, height: usize, coeffs: &[i32]) {
820    if width & 3 != 0 {
821        return draw_macroblock_yuv422_normal(image, x0, y0, width, height, coeffs);
822    }
823    return draw_macroblock_yuv422_simd(image, x0, y0, width, height, coeffs);
824}
825
826#[cfg(not(feature="nightly"))]
827fn draw_macroblock_yuv422(image: &mut ImageBuffer, x0: usize, y0: usize, width: usize, height: usize, coeffs: &[i32]) {
828    return draw_macroblock_yuv422_normal(image, x0, y0, width, height, coeffs);
829}
830
831#[cfg(feature="nightly")]
832fn draw_macroblock_yuv422_simd(image: &mut ImageBuffer, x0: usize, y0: usize, width: usize, height: usize, coeffs: &[i32]) {
833    use std::simd::*;
834
835    fn draw_rgb_simd(image: &mut ImageBuffer, px: usize, py: usize, r: i32x4, g: i32x4, b: i32x4) {
836        for i in 0..4 {
837            image.data[py * image.width + px + i] = 0xFF000000 | ((r[i] as u32) << 16) | ((g[i] as u32) << 8) | (b[i] as u32);
838        }
839    }
840
841    fn i32x4v(a: i32, b: i32, c: i32, d: i32) -> i32x4 {i32x4::from_array([a, b, c, d])}
842    fn i32x4s(a: i32) -> i32x4 {i32x4::from_array([a; 4])}
843
844    fn draw_yuv_simd(image: &mut ImageBuffer, px: usize, py: usize, y: i32x4, u: i32x4, v: i32x4) {
845        // ok lets simd this.
846        let r = ((y << i32x4s(8)) + i32x4s(359) * v) >> i32x4s(8);
847        let g = ((y << i32x4s(8)) - i32x4s(88) * u - i32x4s(183) * v) >> i32x4s(8);
848        let b = ((y << i32x4s(8)) + i32x4s(454) * u) >> i32x4s(8);
849        draw_rgb_simd(image, px, py, r.clamp(i32x4s(0), i32x4s(255)), g.clamp(i32x4s(0), i32x4s(255)), b.clamp(i32x4s(0), i32x4s(255)));
850    }
851
852    for i in 0..height {
853        for k in (0..width).step_by(4) {
854            let k0 = k;
855            let hk0 = k0 >> 1;
856            let by0 = k0 >> 3;
857            let sk0 = k0 & 7;
858            let k1 = k + 1;
859            let hk1 = k1 >> 1;
860            let by1 = k1 >> 3;
861            let sk1 = k1 & 7;
862            let k2 = k + 2;
863            let hk2 = k2 >> 1;
864            let by2 = k2 >> 3;
865            let sk2 = k2 & 7;
866            let k3 = k + 3;
867            let hk3 = k3 >> 1;
868            let by3 = k3 >> 3;
869            let sk3 = k3 & 7;
870            let y = i32x4v(coeffs[by0 * 64 + i * 8 + sk0], coeffs[by1 * 64 + i * 8 + sk1], coeffs[by2 * 64 + i * 8 + sk2], coeffs[by3 * 64 + i * 8 + sk3]) + i32x4s(128);
871            let u = i32x4v(coeffs[128 + i * 8 + hk0], coeffs[128 + i * 8 + hk1], coeffs[128 + i * 8 + hk2], coeffs[128 + i * 8 + hk3]);
872            let v = i32x4v(coeffs[192 + i * 8 + hk0], coeffs[192 + i * 8 + hk1], coeffs[192 + i * 8 + hk2], coeffs[192 + i * 8 + hk3]);
873            draw_yuv_simd(image, x0 + k, y0 + i, y, u, v);
874        }
875    }
876}
877
878fn draw_macroblock_yuv440(image: &mut ImageBuffer, x0: usize, y0: usize, width: usize, height: usize, coeffs: &[i32]) {
879    for i in 0..height {
880        for k in 0..width {
881            let by = i >> 3;
882            let si = k & 7;
883            let y = coeffs[by * 64 + si * 8 + k] + 128;
884            let hi = i >> 1;
885            let u = coeffs[128 + hi * 8 + k];
886            let v = coeffs[192 + hi * 8 + k];
887            draw_yuv(image, x0 + k, y0 + i, y as i32, u as i32, v as i32);
888        }
889    }
890}
891
892fn draw_macroblock_yuv444(image: &mut ImageBuffer, x0: usize, y0: usize, width: usize, height: usize, coeffs: &[i32]) {
893    for i in 0..height {
894        for k in 0..width {
895            let y = coeffs[i * 8 + k] + 128;
896            let u = coeffs[64 + i * 8 + k];
897            let v = coeffs[128 + i * 8 + k];
898            draw_yuv(image, x0 + k, y0 + i, y as i32, u as i32, v as i32);
899        }
900    }
901}
902
903fn draw_macroblock_rgb444(image: &mut ImageBuffer, x0: usize, y0: usize, width: usize, height: usize, coeffs: &[i32]) {
904    for i in 0..height {
905        for k in 0..width {
906            let r = coeffs[i * 8 + k] + 128;
907            let g = coeffs[64 + i * 8 + k] + 128;
908            let b = coeffs[128 + i * 8 + k] + 128;
909            draw_rgb(image, x0 + k, y0 + i, r as i32, g as i32, b as i32);
910        }
911    }
912}
913
914pub fn test(src: &[u8]) -> Option<(usize, usize)> {
915    let mut sp = 0;
916    if from_be16(&src[sp..sp + 2]) != 0xFFD8 {
917        return None;
918    }
919    sp += 2;
920    while sp < src.len() {
921        let marker = from_be16(&src[sp..sp + 2]);
922        let length = from_be16(&src[sp + 2..sp + 4]) as usize;
923        match marker {
924            0xFFC0 | 0xFFC1 | 0xFFC2 => {
925                let width = from_be16(&src[sp + 5..sp + 7]) as usize;
926                let height = from_be16(&src[sp + 7..sp + 9]) as usize;
927                let components = src[sp + 9];
928                if (components == 1) || (components == 3) { // does not support RGBA or CMYK JPEGs
929                    return Some((width, height));
930                }
931                return None;
932            },
933            _ => {},
934        }
935        sp += length + 2;
936    }
937    None
938}
939
940pub fn decode(src: &[u8]) -> Result<ImageBuffer, String> {
941    if from_be16(&src[0..2]) != 0xFFD8 {
942        return Err("Invalid JPEG 1".to_string());
943    }
944    let mut qtable = [[0i32; 64]; 4];
945    let mut dcht = [Table::new_empty(); 4];
946    let mut acht = [Table::new_empty(); 4];
947    let mut qt = [0usize; 3];
948    let mut dt = [0usize; 3];
949    let mut at = [0usize; 3];
950    #[allow(unused_assignments)]
951    let mut width = 1;
952    #[allow(unused_assignments)]
953    let mut height = 1;
954    #[allow(unused_assignments)]
955    let mut itype = 0; // image type
956    #[allow(unused_assignments)]
957    let mut mbtotal = 0; // total number of macroblocks
958    #[allow(unused_assignments)]
959    let mut mbwidth = 0;
960    #[allow(unused_assignments)]
961    let mut mbheight = 0;
962    #[allow(unused_assignments)]
963    let mut cpmb = 0;
964    let mut coeffs: Vec<i32> = Vec::new(); // the coefficients
965    #[allow(unused_assignments)]
966    let mut resint = 0;
967    #[allow(unused_assignments)]
968    let mut sp = 2;
969    while sp < src.len() {
970        let marker = from_be16(&src[sp..sp + 2]);
971        let length = if marker != 0xFFD9 {from_be16(&src[sp + 2..sp + 4]) as usize} else {0};
972        //println!("marker {:04X}, length {}",marker,length);
973        match marker {
974            0xFFC0 | 0xFFC1 | 0xFFC2 => { // baseline sequential, extended sequential, progressive
975                //println!("precision {}",src[sp + 4]);
976                if src[sp + 4] != 8 {
977                    return Err("Invalid JPEG 2".to_string());
978                }
979                height = from_be16(&src[sp + 5..sp + 7]) as usize;
980                width = from_be16(&src[sp + 7..sp + 9]) as usize;
981                let components = src[sp + 9];
982                //println!("size {}x{}, components {}",width,height,components);
983                if (components != 1) && (components != 3) {
984                    return Err("Invalid JPEG 3".to_string());
985                }
986                let mut samp = [0u8; 3];
987                let mut tsp = sp + 10;
988                for i in 0..components {
989                    if src[tsp] != i + 1 {
990                        return Err("Invalid JPEG 4".to_string());
991                    }
992                    samp[i as usize] = src[tsp + 1];
993                    qt[i as usize] = src[tsp + 2] as usize;
994                    tsp += 3;
995                    //println!("{}: samp {:02X}, qt {}",i,samp[i as usize],qt[i as usize]);
996                }
997                if components == 3 {
998                    if (samp[1] != 0x11) || (samp[2] != 0x11) {
999                        return Err("Invalid JPEG 5".to_string());
1000                    }
1001                    let sw = ((samp[0] >> 4) * 8) as usize;
1002                    let sh = ((samp[0] & 15) * 8) as usize;
1003                    //println!("one macroblock = {}x{}",sw,sh);
1004                    mbwidth = (width + sw - 1) / sw;
1005                    mbheight = (height + sh - 1) / sh;
1006                    //println!("{}x{} macroblocks ({}x{} pixels)",mbwidth,mbheight,mbwidth * sw,mbheight * sh);
1007                    cpmb = 128 + 64 * ((samp[0] >> 4) as usize) * ((samp[0] & 15) as usize);
1008                    itype = match samp[0] {
1009                        0x11 => TYPE_YUV444,
1010                        0x12 => TYPE_YUV440,
1011                        0x21 => TYPE_YUV422,
1012                        0x22 => TYPE_YUV420,
1013                        _ => {
1014                            return Err("Invalid JPEG 6".to_string());
1015                        },
1016                    };
1017                }
1018                else {
1019                    mbwidth = (width + 7) / 8;
1020                    mbheight = (height + 7) / 8;
1021                    cpmb = 64;
1022                    itype = TYPE_Y;
1023                }
1024                mbtotal = mbwidth * mbheight;
1025                coeffs.resize(mbtotal * cpmb as usize, 0);
1026                //println!("type {:04X}, {} macroblocks in total, {} coefficients per row",itype,mbtotal,mbstride);
1027                //println!("size {}x{}, macroblocks {}",width,height,mbtotal);
1028            },
1029            0xFFC4 => { // huffman tables
1030                let mut tsp = sp + 4;
1031                while tsp < sp + length + 2 {
1032                    let d = src[tsp];
1033                    tsp += 1;
1034                    let tc = d >> 4;
1035                    let n = d & 15;
1036                    //println!("tc = {}, n = {}",tc,n);
1037                    let mut bits = [0u8; 16];
1038                    let mut total = 0usize;
1039                    for i in 0..16 {
1040                        bits[i] = src[tsp];
1041                        tsp += 1;
1042                        total += bits[i] as usize;
1043                    }
1044                    if total >= 256 {
1045                        return Err("Invalid JPEG 7".to_string());
1046                    }
1047                    //println!("total codes: {}",total);
1048                    let mut huffval = [0u8; 256];
1049                    for i in 0..total {
1050                        huffval[i] = src[tsp];
1051                        //println!("code {}: run {}, cat {}",i,huffval[i] >> 4,huffval[i] & 15);
1052                        tsp += 1;
1053                    }
1054                    let table = Table::new(bits, huffval);
1055                    if tc != 0 {
1056                        acht[n as usize] = table;
1057                    }
1058                    else {
1059                        dcht[n as usize] = table;
1060                    }
1061                }
1062            },
1063            0xFFD8 => { // image start
1064            },
1065            0xFFDA => { // scan start
1066                //println!("scan start");
1067                let mut tsp = sp + 4;
1068                let count = src[tsp];
1069                tsp += 1;
1070                // acht[4], dcht[4]
1071                let mut mask = 0;
1072                for _i in 0..count {
1073                    let index = src[tsp] - 1;
1074                    tsp += 1;
1075                    mask |= 1 << index;
1076                    let n = src[tsp];
1077                    tsp += 1;
1078                    dt[index as usize] = (n >> 4) as usize;
1079                    at[index as usize] = (n & 15) as usize;
1080                    //println!("index {}, dt {}, at {}",index,n >> 4,n & 15);
1081                }
1082                let start = src[tsp];
1083                tsp += 1;
1084                let end = src[tsp];
1085                tsp += 1;
1086                let d = src[tsp];
1087                tsp += 1;
1088                let refine = (d & 0xF0) != 0;
1089                let shift = d & 15;
1090                //println!("start = {}, end = {}, refine = {}, shift = {}",start,end,refine,shift);
1091                let mut reader = Reader::new(&src[tsp..]);
1092                let mut rescnt = resint;
1093                let mut eobrun = 0;
1094                let mut dc = [0i32; 3];
1095                for i in 0..mbtotal {
1096                    //println!("macroblock {}:",i);
1097                    unpack_macroblock(&mut reader, &mut coeffs[i * cpmb..(i + 1) * cpmb], &dcht, &acht, &dt, &at, &mut dc, start, end, shift, refine, &mut eobrun, itype, &mut rescnt, resint, mask);
1098                }
1099                sp = (tsp + reader.leave()) - length - 2;
1100                //println!("sp = {}, ({:02X} {:02X})",sp,src[sp + length + 2],src[sp + length + 2 + 1]);
1101            },
1102            0xFFDB => { // quantization tables
1103                let mut tsp = sp + 4;
1104                while tsp < sp + length + 2 {
1105                    let d = src[tsp];
1106                    tsp += 1;
1107                    let n = d & 15;
1108                    //println!("updating qtable[{}]",n);
1109                    if (d >> 4) != 0 {
1110                        for k in 0..64 {
1111                            qtable[n as usize][FOLDING[k as usize] as usize] = from_be16(&src[tsp..tsp + 2]) as i32;
1112                            tsp += 2;
1113                        }
1114                    }
1115                    else {
1116                        for k in 0..64 {
1117                            qtable[n as usize][FOLDING[k as usize] as usize] = src[tsp] as i32;
1118                            tsp += 1;
1119                        }
1120                    }
1121                }
1122            },
1123            0xFFDD => { // restart interval
1124                resint = from_be16(&src[sp + 4..sp + 6]) as usize;
1125            },
1126            0xFFE1 => { // EXIF
1127                let header = from_be32(&src[sp + 4..sp + 8]);
1128                if header == 0x45786966 { // Exif
1129                    let start = sp + 10;
1130                    let mut tsp = start;
1131                    let le = from_be16(&src[tsp..tsp + 2]) == 0x4949; // figure out endianness
1132                    tsp += 4; // skip 0x2A
1133                    tsp += (if le {from_le32(&src[tsp..tsp + 4])} else {from_be32(&src[tsp..tsp + 4])} -8) as usize; // go to IFD0
1134                    let entries = if le {from_le16(&src[tsp..tsp + 2])} else {from_be16(&src[tsp..tsp + 2])}; // number of entries
1135                    tsp += 2;
1136                    for _i in 0..entries {
1137                        let tag = if le {from_le16(&src[tsp..tsp + 2])} else {from_be16(&src[tsp..tsp + 2])};
1138                        tsp += 2;
1139                        let format = if le {from_le16(&src[tsp..tsp + 2])} else {from_be16(&src[tsp..tsp + 2])};
1140                        tsp += 2;
1141                        if format > 12 {
1142                            return Err("Invalid JPEG 8".to_string());
1143                        }
1144                        let components = if le {from_le32(&src[tsp..tsp + 4])} else {from_be32(&src[tsp..tsp + 4])};
1145                        tsp += 4;
1146                        let data = if le {from_le32(&src[tsp..tsp + 4])} else {from_be32(&src[tsp..tsp + 4])};
1147                        tsp += 4;
1148                        let elsize = [0usize, 1, 1, 2, 4, 8, 1, 0, 2, 4, 8, 4, 8];
1149                        let total = elsize[format as usize] * (components as usize);
1150                        let mut dsp = start + data as usize;
1151                        if total <= 4 {
1152                            dsp = tsp - 4;
1153                        }
1154                        //println!("EXIF tag {:04X}, format {}, components {}, data {:08X}",tag,format,components,data);
1155                        match tag {
1156                            0x0106 => { // photometric interpretation
1157                                let pe = if le {from_le16(&src[dsp..dsp + 2])} else {from_be16(&src[dsp..dsp + 2])};
1158                                if (pe != 2) || (itype != TYPE_YUV444) {
1159                                    return Err("Invalid JPEG 9".to_string());
1160                                }
1161                                itype = TYPE_RGB444;
1162                            },
1163                            0xA001 => { // colorspace
1164                            },
1165                            _ => {
1166                            }
1167                        }
1168                    }
1169                }
1170            },
1171            0xFFC8 | 0xFFDC | 0xFFE0 | 0xFFE2..=0xFFEF | 0xFFF0..=0xFFFF => { // other accepted markers
1172            },
1173            _ => { // image end
1174                //println!("end");
1175                let mut image = ImageBuffer::new(width, height);
1176                match itype {
1177                    TYPE_Y => {convert_blocks(&mut coeffs, mbtotal, TYPE_Y, &qtable, &qt);},
1178                    TYPE_YUV420 => {convert_blocks(&mut coeffs, mbtotal * 6, TYPE_YUV420, &qtable, &qt);},
1179                    TYPE_YUV422 => {convert_blocks(&mut coeffs, mbtotal * 4, TYPE_YUV422, &qtable, &qt);},
1180                    TYPE_YUV440 => {convert_blocks(&mut coeffs, mbtotal * 4, TYPE_YUV440, &qtable, &qt);},
1181                    TYPE_YUV444 => {convert_blocks(&mut coeffs, mbtotal * 3, TYPE_YUV444, &qtable, &qt);},
1182                    TYPE_RGB444 => {convert_blocks(&mut coeffs, mbtotal * 3, TYPE_RGB444, &qtable, &qt);},
1183                    _ => {},
1184                }
1185                #[allow(unused_assignments)]
1186                let mut mb = 0;
1187                for i in 0..mbheight - 1 {
1188                    for k in 0..mbwidth - 1 {
1189                        match itype {
1190                            TYPE_Y => {draw_macroblock_y(&mut image, k * 8, i * 8, 8, 8, &coeffs[mb..mb + 64]); mb += 64;},
1191                            TYPE_YUV420 => {draw_macroblock_yuv420(&mut image, k * 16, i * 16, 16, 16, &coeffs[mb..mb + 384]); mb += 384;},
1192                            TYPE_YUV422 => {draw_macroblock_yuv422(&mut image, k * 16, i * 8, 16, 8, &coeffs[mb..mb + 256]); mb += 256;},
1193                            TYPE_YUV440 => {draw_macroblock_yuv440(&mut image, k * 8, i * 16, 8, 16, &coeffs[mb..mb + 256]); mb += 256;},
1194                            TYPE_YUV444 => {draw_macroblock_yuv444(&mut image, k * 8, i * 8, 8, 8, &coeffs[mb..mb + 192]); mb += 192;},
1195                            TYPE_RGB444 => {draw_macroblock_rgb444(&mut image, k * 8, i * 8, 8, 8, &coeffs[mb..mb + 192]); mb += 192;},
1196                            _ => {},
1197                        }
1198                    }
1199                    match itype {
1200                        TYPE_Y => {draw_macroblock_y(&mut image, mbwidth * 8 - 8, i * 8, width - (mbwidth - 1) * 8, 8, &coeffs[mb..mb + 64]); mb += 64;},
1201                        TYPE_YUV420 => {draw_macroblock_yuv420(&mut image, mbwidth * 16 - 16, i * 16, width - (mbwidth - 1) * 16, 16, &coeffs[mb..mb + 384]); mb += 384;},
1202                        TYPE_YUV422 => {draw_macroblock_yuv422(&mut image, mbwidth * 16 - 16, i * 8, width - (mbwidth - 1) * 16, 8, &coeffs[mb..mb + 256]); mb += 256;},
1203                        TYPE_YUV440 => {draw_macroblock_yuv440(&mut image, mbwidth * 8 - 8, i * 16, width - (mbwidth - 1) * 8, 16, &coeffs[mb..mb + 256]); mb += 256;},
1204                        TYPE_YUV444 => {draw_macroblock_yuv444(&mut image, mbwidth * 8 - 8, i * 8, width - (mbwidth - 1) * 8, 8, &coeffs[mb..mb + 192]); mb += 192;},
1205                        TYPE_RGB444 => {draw_macroblock_rgb444(&mut image, mbwidth * 8 - 8, i * 8, width - (mbwidth - 1) * 8, 8, &coeffs[mb..mb + 192]); mb += 192;},
1206                        _ => {},
1207                    }
1208                }
1209                for k in 0..mbwidth - 1 {
1210                    match itype {
1211                        TYPE_Y => {draw_macroblock_y(&mut image, k * 8, mbheight * 8 - 8, 8, mbheight * 8 - height, &coeffs[mb..mb + 64]); mb += 64;},
1212                        TYPE_YUV420 => {draw_macroblock_yuv420(&mut image, k * 16, mbheight * 16 - 16, 16, height - (mbheight - 1) * 16, &coeffs[mb..mb + 384]); mb += 384;},
1213                        TYPE_YUV422 => {draw_macroblock_yuv422(&mut image, k * 16, mbheight * 8 - 8, 16, height - (mbheight - 1) * 8, &coeffs[mb..mb + 256]); mb += 256;},
1214                        TYPE_YUV440 => {draw_macroblock_yuv440(&mut image, k * 8, mbheight * 16 - 16, 8, height - (mbheight - 1) * 16, &coeffs[mb..mb + 256]); mb += 256;},
1215                        TYPE_YUV444 => {draw_macroblock_yuv444(&mut image, k * 8, mbheight * 8 - 8, 8, height - (mbheight - 1) * 8, &coeffs[mb..mb + 192]); mb += 192;},
1216                        TYPE_RGB444 => {draw_macroblock_rgb444(&mut image, k * 8, mbheight * 8 - 8, 8, height - (mbheight - 1) * 8, &coeffs[mb..mb + 192]); mb += 192;},
1217                        _ => {},
1218                    }
1219                }
1220                match itype {
1221                    TYPE_Y => {draw_macroblock_y(&mut image, mbwidth * 8 - 8, mbheight * 8 - 8, width - (mbwidth - 1) * 8, height - (mbheight - 1) * 8, &coeffs[mb..mb + 64]);},
1222                    TYPE_YUV420 => {draw_macroblock_yuv420(&mut image, mbwidth * 16 - 16, mbheight * 16 - 16, width - (mbwidth - 1) * 16, height - (mbheight - 1) * 16, &coeffs[mb..mb + 384]);},
1223                    TYPE_YUV422 => {draw_macroblock_yuv422(&mut image, mbwidth * 16 - 16, mbheight * 8 - 8, width - (mbwidth - 1) * 16, height - (mbheight - 1) * 8, &coeffs[mb..mb + 256]);},
1224                    TYPE_YUV440 => {draw_macroblock_yuv440(&mut image, mbwidth * 8 - 8, mbheight * 16 - 16, width - (mbwidth - 1) * 8, height - (mbheight - 1) * 16, &coeffs[mb..mb + 256]);},
1225                    TYPE_YUV444 => {draw_macroblock_yuv444(&mut image, mbwidth * 8 - 8, mbheight * 8 - 8, width - (mbwidth - 1) * 8, height - (mbheight - 1) * 8, &coeffs[mb..mb + 192]);},
1226                    TYPE_RGB444 => {draw_macroblock_rgb444(&mut image, mbwidth * 8 - 8, mbheight * 8 - 8, width - (mbwidth - 1) * 8, height - (mbheight - 1) * 8, &coeffs[mb..mb + 192]);},
1227                    _ => {},
1228                }
1229                return Ok(image);
1230            },
1231            
1232            /*_ => {
1233                return Err("Invalid JPEG 10".to_string());
1234            },*/
1235        }
1236        sp += length + 2;
1237    }
1238    Err("Invalid JPEG 11".to_string())
1239}
1240
1241pub fn encode(_image: &ImageBuffer) -> Result<Vec<u8>, String> {
1242    Err("not implemented yet".to_string())
1243}