makepad_image_formats/
bmp.rs

1// image_formats::bmp
2// by Desmond Germans, 2019
3
4use crate::ImageBuffer;
5
6const TYPE_C1: u16 = 0x0001;
7const TYPE_C2: u16 = 0x0002;
8const TYPE_C4: u16 = 0x0004;
9const TYPE_C4_RLE: u16 = 0x0204;
10const TYPE_C8: u16 = 0x0008;
11const TYPE_C8_RLE: u16 = 0x0108;
12const TYPE_A1RGB5: u16 = 0x0010;
13const TYPE_B16: u16 = 0x0310;
14const TYPE_RGB8: u16 = 0x0018;
15const TYPE_ARGB8: u16 = 0x0020;
16const TYPE_B32: u16 = 0x0320;
17
18fn from_le16(src: &[u8]) -> u16 {
19    ((src[1] as u16) << 8) | (src[0] as u16)
20}
21
22fn from_le32(src: &[u8]) -> u32 {
23    ((src[3] as u32) << 24) | ((src[2] as u32) << 16) | ((src[1] as u32) << 8) | (src[0] as u32)
24}
25
26struct Component {
27    mask: u32,
28    shift: u32,
29    size: u32,
30}
31
32impl Component {
33    pub fn new(mask: u32) -> Component {
34        let mut shift = 0;
35        let mut size = 0;
36        let mut last_bit = false;
37        let mut shift_found = false;
38        let mut size_found = false;
39        for i in 0..32 {
40            let bit = (mask & (1 << i)) != 0;
41            if bit != last_bit {
42                if bit {
43                    if !shift_found {
44                        shift = i;
45                        shift_found = true;
46                    }
47                } else {
48                    size = i - shift;
49                    size_found = true;
50                    break;
51                }
52                last_bit = bit;
53            }
54        }
55        if !size_found {
56            size = 32 - shift;
57        }
58        Component {
59            mask: mask,
60            shift: shift,
61            size: size,
62        }
63    }
64
65    pub fn get(&self,c: u32,def: u8) -> u8 {
66        if self.size == 0 {
67            return def;
68        }
69        let d = (c & self.mask) >> self.shift;
70        match self.size {
71            1 => if d != 0 { 255 } else { 0 },
72            2 => ((d << 6) | (d << 4) | (d << 2) | d) as u8,
73            3 => ((d << 5) | (d << 2) | (d >> 1)) as u8,
74            4 => ((d << 4) | d) as u8,
75            5 => ((d << 3) | (d >> 2)) as u8,
76            6 => ((d << 2) | (d >> 4)) as u8,
77            7 => ((d << 1) | (d >> 6)) as u8,
78            _ => (d >> (self.size - 8)) as u8,
79        }
80    }
81}
82
83pub fn decode_pixels(dst: &mut [u32],src: &[u8],width: usize,height: usize,bottom_up: bool,itype: u16,palette: &[u32; 256],redmask: u32,greenmask: u32,bluemask: u32,alphamask: u32) {
84    let red = Component::new(redmask);
85    let green = Component::new(greenmask);
86    let blue = Component::new(bluemask);
87    let alpha = Component::new(alphamask);
88    let mut sp = 0usize;
89    let mut y = 0usize;
90    let mut dy = 1isize;
91    if bottom_up {
92        y = height - 1;
93        dy = -1;
94    }
95    let mut line = width * y;
96    let dline = (width as isize) * dy;
97    match itype {
98        TYPE_C1 => {
99            for _l in 0..height {
100                let mut dp = line;
101                for _x in 0..width / 8 {
102                    let d = src[sp];
103                    sp += 1;
104                    for i in 0..8 {
105                        dst[dp] = palette[((d >> (7 - i)) & 1) as usize];
106                        dp += 1;
107                    }
108                }
109                if (width & 7) != 0 {
110                    let d = src[sp];
111                    sp += 1;
112                    for i in 0..(width & 7) {
113                        dst[dp] = palette[((d >> (7 - i)) & 1) as usize];
114                        dp += 1;
115                    }
116                }
117                let rest = ((width + 7) / 8) & 3;
118                if rest > 0 {
119                    sp += 4 - rest;
120                }
121                line = ((line as isize) + dline) as usize;
122            }
123        },
124        TYPE_C2 => {
125            for _l in 0..height {
126                let mut dp = line;
127                for _x in 0..width / 4 {
128                    let d = src[sp];
129                    sp += 1;
130                    for i in 0..4 {
131                        dst[dp] = palette[((d >> (6 - 2 * i)) & 3) as usize];
132                        dp += 1;
133                    }
134                }
135                if (width & 3) != 0 {
136                    let d = src[sp];
137                    sp += 1;
138                    for i in 0..(width & 3) {
139                        dst[dp] = palette[((d >> (6 - 2 * i)) & 3) as usize];
140                        dp += 1;
141                    }
142                }
143                let rest = ((width + 3) / 4) & 3;
144                if rest > 0 {
145                    sp += (4 - rest) as usize;
146                }
147                line = (line as isize + dline) as usize;
148            }
149        },
150        TYPE_C4 => {
151            for _l in 0..height {
152                let mut dp = line;
153                for _x in 0..width / 2 {
154                    let d = src[sp];
155                    sp += 1;
156                    for i in 0..2 {
157                        dst[dp] = palette[((d >> (4 - 4 * i)) & 15) as usize];
158                        dp += 1;
159                    }
160                }
161                if (width & 1) != 0 {
162                    let d = src[sp];
163                    sp += 1;
164                    dst[dp] = palette[(d & 15) as usize];
165                }
166                let rest = ((width + 1) / 2) & 3;
167                if rest > 0 {
168                    sp += (4 - rest) as usize;
169                }
170                line = (line as isize + dline) as usize;
171            }
172        },
173        TYPE_C4_RLE => {
174            let mut x = 0usize;
175            while sp < src.len() {
176                let code: u16 = from_le16(&src[sp..sp+2]);
177                sp += 2;
178                match code {
179                    0x0000 => {
180                        x = 0;
181                        y = ((y as isize) + dy) as usize;
182                    },
183                    0x0100 => {
184                        break;
185                    },
186                    0x0200 => {
187                        x += src[sp] as usize;
188                        y = ((y as isize) + (src[sp + 1] as isize) * dy) as usize;
189                        sp += 2;
190                    },
191                    _ => {
192                        if (code & 255) != 0 {
193                            let count = code & 255;
194                            if x + (count as usize) > width {
195                                break;
196                            }
197                            let c0 = palette[(code >> 12) as usize];
198                            let c1 = palette[((code >> 8) & 15) as usize];
199                            for _i in 0..count / 2 {
200                                dst[(y * width + x) as usize] = c0;
201                                dst[(y * width + x + 1) as usize] = c1;
202                                x += 2;
203                            }
204                            if (count & 1) != 0 {
205                                dst[(y * width + x) as usize] = c0;
206                                x += 1;
207                            }
208                        }
209                        else {
210                            let count = code >> 8;
211                            if x + (count as usize) > width {
212                                break;
213                            }
214                            for _i in 0..count / 4 {
215                                let c = from_le16(&src[sp..sp+2]);
216                                sp += 2;
217                                dst[y * width + x] = palette[((c >> 4) & 15) as usize];
218                                dst[y * width + x + 1] = palette[(c & 15) as usize];
219                                dst[y * width + x + 2] = palette[(c >> 12) as usize];
220                                dst[y * width + x + 3] = palette[((c >> 8) & 15) as usize];
221                                x += 4;
222                            }
223                            if (count & 3) != 0 {
224                                let c = from_le16(&src[sp..sp+2]);
225                                sp += 2;
226                                if (count & 3) >= 1 {
227                                    dst[y * width + x] = palette[((c >> 4) & 15) as usize];
228                                    x += 1;
229                                }
230                                if (count & 3) >= 2 {
231                                    dst[y * width + x] = palette[(c & 15) as usize];
232                                    x += 1;
233                                }
234                                if (count & 3) >= 3 {
235                                    dst[y * width + x] = palette[(c >> 12) as usize];
236                                    x += 1;
237                                }
238                            }
239                        }
240                    }
241                }
242            }
243        },
244        TYPE_C8 => {
245            for _l in 0..height {
246                let mut dp = line;
247                for _x in 0..width {
248                    dst[dp] = palette[src[sp] as usize];
249                    sp += 1;
250                    dp += 1;
251                }
252                let rest = width & 3;
253                if rest > 0 {
254                    sp += (4 - rest) as usize;
255                }
256                line = (line as isize + dline) as usize;
257            }
258        },
259        TYPE_C8_RLE => {
260            let mut x = 0usize;
261            while sp < src.len() {
262                let code: u16 = from_le16(&src[sp..sp+2]);
263                sp += 2;
264                match code {
265                    0x0000 => {
266                        x = 0;
267                        y = ((y as isize) + dy) as usize;
268                    },
269                    0x0100 => {
270                        break;
271                    },
272                    0x0200 => {
273                        x += src[sp] as usize;
274                        y = ((y as isize) + (src[sp + 1] as isize) * dy) as usize;
275                        sp += 2;
276                    },
277                    _ => {
278                        if (code & 255) != 0 {
279                            let count = code & 255;
280                            if x + count as usize > width {
281                                break;
282                            }
283                            let c = palette[(code >> 8) as usize];
284                            for _i in 0..count {
285                                dst[y * width + x] = c;
286                                x += 1;
287                            }
288                        }
289                        else {
290                            let count = code >> 8;
291                            if x + count as usize > width {
292                                break;
293                            }
294                            for _i in 0..count / 2 {
295                                let c = from_le16(&src[sp..sp + 2]);
296                                sp += 2;
297                                dst[y * width + x] = palette[(c & 255) as usize];
298                                dst[y * width + x + 1] = palette[(c >> 8) as usize];
299                                x += 2;
300                            }
301                            if (count & 1) != 0 {
302                                let c = from_le16(&src[sp..sp + 2]);
303                                sp += 2;
304                                dst[y * width + x] = palette[(c & 255) as usize];
305                                x += 1;
306                            }
307                        }
308                    },
309                }
310			}
311        },
312        TYPE_A1RGB5 => {
313            for _l in 0..height {
314                let mut dp = line;
315                for _x in 0..width {
316                    let d = from_le16(&src[sp..sp+2]);
317                    sp += 2;
318                    let mut r = (d >> 10) & 31;
319                    let mut g = (d >> 5) & 31;
320                    let mut b = d & 31;
321                    let a = if alphamask == 0 { 255 } else if (d & 0x8000) != 0 { 255 } else { 0 };
322                    r = (r << 3) | (r >> 2);
323                    g = (g << 3) | (g >> 2);
324                    b = (b << 3) | (b >> 2);
325                    //println!("{},{}: {:04X} - a{} r{} g{} b{}",x,line,d,a,r,g,b);
326                    dst[dp] = ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
327                    dp += 1;
328                }
329                let rest = (width * 2) & 3;
330                if rest > 0 {
331                    sp += 4 - rest;
332                }
333                line = (line as isize + dline) as usize;
334            }
335        },
336        TYPE_B16 => {
337            for _l in 0..height {
338                let mut dp = line;
339                for _x in 0..width {
340                    let d = from_le16(&src[sp..sp + 2]) as u32;
341                    sp += 2;
342                    let r = red.get(d,0);
343                    let g = green.get(d,0);
344                    let b = blue.get(d,0);
345                    let a = if alphamask == 0 { 255 } else { alpha.get(d,255) };
346                    dst[dp] = ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
347                    dp += 1;
348                }
349                let rest = (width * 2) & 3;
350                if rest > 0 {
351                    sp += (4 - rest) as usize;
352                }
353                line = (line as isize + dline) as usize;
354            }
355        },
356        TYPE_RGB8 => {
357            for _l in 0..height {
358                let mut dp = line;
359                for _x in 0..width {
360                    let b = src[sp];
361                    let g = src[sp + 1];
362                    let r = src[sp + 2];
363                    sp += 3;
364                    dst[dp] = 0xFF000000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
365                    dp += 1;
366                }
367                let rest = (width * 3) & 3;
368                if rest > 0 {
369                    sp += (4 - rest) as usize;
370                }
371                line = (line as isize + dline) as usize;
372            }
373        },
374        TYPE_ARGB8 => {
375            for _l in 0..height {
376                let mut dp = line as usize;
377                for _x in 0..width {
378                    let d = from_le32(&src[sp..sp+4]);
379                    sp += 4;
380                    let r = (d >> 16) & 255;
381                    let g = (d >> 8) & 255;
382                    let b = d & 255;
383                    let a = if alphamask == 0 { 255 } else { d >> 24 };
384                    dst[dp] = ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
385                    dp += 1;
386                }
387                line = (line as isize + dline) as usize;
388            }
389        },
390        TYPE_B32 => {
391            for _l in 0..height {
392                let mut dp = line as usize;
393                for _x in 0..width {
394                    let d = from_le32(&src[sp..sp+4]);
395                    sp += 4;
396                    let r = red.get(d,0);
397                    let g = green.get(d,0);
398                    let b = blue.get(d,0);
399                    let a = if alphamask == 0 { 255 } else { alpha.get(d,255) };
400                    dst[dp] = ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
401                    dp += 1;
402                }
403                line = (line as isize + dline) as usize;
404            }
405        },
406        _ => { },
407    }
408}
409
410pub fn test(src: &[u8]) -> Option<(usize,usize)> {
411    let tag = from_le16(&src[0..2]);
412    if (tag == 0x4D42) ||   // BM (Windows BMP)
413        (tag == 0x4142) ||  // BA (OS/2 bitmap)
414        (tag == 0x4943) ||  // CI (OS/2 color icon)
415        (tag == 0x5043) ||  // CP (OS/2 color pointer) 
416        (tag == 0x4349) ||  // IC (OS/2 icon)
417        (tag == 0x5450) {    // PT (OS/2 pointer)
418        let filesize = from_le32(&src[2..6]);
419        let offset = from_le32(&src[10..14]);
420        let headersize = from_le32(&src[14..18]);
421        if (headersize > filesize) || (offset > filesize) || (headersize > offset) || (filesize != src.len() as u32) {
422            return None;
423        }
424        if (headersize != 12) &&
425           (headersize != 40) &&
426           (headersize != 52) &&
427           (headersize != 56) &&
428           (headersize != 108) &&
429           (headersize != 124) {
430            return None;
431        }
432        if headersize == 12 {
433            let width = from_le16(&src[18..20]) as usize;
434            let mut height = from_le16(&src[20..22]) as usize;
435            if (height as i16) < 0 {
436                height = -(height as i16) as usize;
437            }
438            if (width > 32768) || (height > 32768) || (width == 0) || (height == 0) {
439                return None;
440            }
441            let planes = from_le16(&src[22..24]);
442            let itype = from_le16(&src[24..26]);
443            if planes != 1 {
444                return None;
445            }
446            let mut line = match itype {
447                TYPE_C1 => (width + 7) / 8,
448                TYPE_C4 => (width + 1) / 2,
449                TYPE_C8 => width,
450                TYPE_RGB8 => width * 3,
451                _ => { return None; },
452            };
453            let rest = line & 3;
454            if rest > 0 {
455                line += 4 - rest;
456            }
457            if offset as usize + height * line > src.len() {
458                return None;
459            }
460            return Some((width,height));
461        }
462        else {
463            let width = from_le32(&src[18..22]) as usize;
464            let mut height = from_le32(&src[22..26]) as usize;
465            if (height as i32) < 0 {
466                height = -(height as i32) as usize;
467            }
468            if (width > 32768) || (height > 32768) || (width == 0) || (height == 0) {
469                return None;
470            }
471            //let planes = from_le16(&src[26..28]);
472            let bpp = from_le16(&src[28..30]);
473            let compression = from_le32(&src[30..34]) as u16;
474            let itype = (compression << 8) | bpp;
475            let mut line = match itype {
476                TYPE_C1 => (width + 7) / 8,
477                TYPE_C2 => (width + 3) / 4,
478                TYPE_C4 => (width + 1) / 2,
479                TYPE_C4_RLE => 0,
480                TYPE_C8 => width,
481                TYPE_C8_RLE => 0,
482                TYPE_A1RGB5 | TYPE_B16 => width * 2,
483                TYPE_RGB8 => width * 3,
484                TYPE_ARGB8 | TYPE_B32 => width * 4,
485                _ => { return None; },
486            };
487            let rest = line & 3;
488            if rest > 0 {
489                line += 4 - rest;
490            }
491            if (line != 0) && (offset as usize + height * line > src.len()) {
492                return None;
493            }
494            return Some((width,height));
495        }
496    }
497    None
498}
499
500pub fn decode(src: &[u8]) -> Result<ImageBuffer,String> {
501    let tag = from_le16(&src[0..2]);
502    if (tag != 0x4D42) &&
503        (tag != 0x4142) &&
504        (tag != 0x4943) &&
505        (tag != 0x5043) && 
506        (tag != 0x4349) &&
507        (tag != 0x5450) {
508        return Err("Invalid BMP".to_string());
509    }
510    let filesize = from_le32(&src[2..6]);
511    let offset = from_le32(&src[10..14]);
512    let headersize = from_le32(&src[14..18]);
513    if (headersize > filesize) || (offset > filesize) || (headersize > offset) || (filesize != src.len() as u32) {
514        return Err("Invalid BMP".to_string());
515    }
516    if (headersize != 12) &&
517        (headersize != 40) &&
518        (headersize != 52) &&
519        (headersize != 56) &&
520        (headersize != 108) &&
521        (headersize != 124) {
522        return Err("Invalid BMP".to_string());
523    }
524    #[allow(unused_assignments)]
525    let mut width = 0usize;
526    #[allow(unused_assignments)]
527    let mut height = 0usize;
528    let mut bottom_up = true;
529    #[allow(unused_assignments)]
530    let mut itype = 0u16;
531    let mut palette = [0u32; 256];
532    let mut redmask = 0u32;
533    let mut greenmask = 0u32;
534    let mut bluemask = 0u32;
535    let mut alphamask = 0u32;
536    if headersize == 12 {
537        width = from_le16(&src[18..20]) as usize;
538        let pheight = from_le16(&src[20..22]) as i16;
539        height = if pheight < 0 { bottom_up = false; -pheight as usize } else { pheight as usize };
540        if (width > 32768) || (height > 32768) || (width == 0) || (height == 0) {
541            return Err("Invalid BMP".to_string());
542        }
543        let planes = from_le16(&src[22..24]);
544        itype = from_le16(&src[24..26]);
545        if planes != 1 {
546            return Err("Invalid BMP".to_string());
547        }
548        let mut line = match itype {
549            TYPE_C1 => (width + 7) / 8,
550            TYPE_C4 => (width + 1) / 2,
551            TYPE_C8 => width,
552            TYPE_RGB8 => width * 3,
553            _ => { return Err("Invalid BMP".to_string()); },
554        };
555        let rest = line & 3;
556        if rest > 0 {
557            line += 4 - rest;
558        }
559        if offset as usize + (height * line) as usize > src.len() {
560            return Err("Invalid BMP".to_string());
561        }
562    }
563    else {
564        width = from_le32(&src[18..22]) as usize;
565        let pheight = from_le32(&src[22..26]) as i32;
566        height = if pheight < 0 { bottom_up = false; -pheight as usize } else { pheight as usize };
567        if (width > 32768) || (height > 32768) || (width == 0) || (height == 0) {
568            return Err("Invalid BMP".to_string());
569        }
570        //let planes = from_le16(&src[26..28]);
571        let bpp = from_le16(&src[28..30]);
572        let compression = from_le32(&src[30..34]) as u16;
573        itype = (compression << 8) | bpp;
574        let mut line = match itype {
575            TYPE_C1 => (width + 7) / 8,
576            TYPE_C2 => (width + 3) / 4,
577            TYPE_C4 => (width + 1) / 2,
578            TYPE_C4_RLE => 0,
579            TYPE_C8 => width,
580            TYPE_C8_RLE => 0,
581            TYPE_A1RGB5 | TYPE_B16 => width * 2,
582            TYPE_RGB8 => width * 3,
583            TYPE_ARGB8 | TYPE_B32 => width * 4,
584            _ => { return Err("Invalid BMP".to_string()); },
585        };
586        let rest = line & 3;
587        if rest > 0 {
588            line += 4 - rest;
589        }
590        if (line != 0) && (offset as usize + (height * line) as usize > src.len()) {
591            return Err("Invalid BMP".to_string());
592        }
593        let imagesize = from_le32(&src[34..38]);
594        if (compression == 0) && (imagesize > filesize - offset) {
595            return Err("Invalid BMP".to_string());
596        }
597        // 38..46: resolution
598        let mut colors = from_le32(&src[46..50]);
599        // 50..54: important colors
600        match itype {
601            TYPE_C1 | TYPE_C2 | TYPE_C4 | TYPE_C4_RLE | TYPE_C8 | TYPE_C8_RLE => {
602                if colors == 0 {
603                    colors = 1 << bpp;
604                } else if colors > 256 {
605                    return Err("Invalid BMP".to_string());
606                }
607                for i in 0..colors {
608                    let sp = (14 + headersize + i * 4) as usize;
609                    let b = src[sp];
610                    let g = src[sp + 1];
611                    let r = src[sp + 2];
612                    palette[i as usize] = 0xFF000000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
613                }
614            },
615            TYPE_B16 | TYPE_B32 => {
616                redmask = from_le32(&src[54..58]);
617                greenmask = from_le32(&src[58..62]);
618                bluemask = from_le32(&src[62..66]);
619                if (headersize >= 56) || ((offset - headersize - 14) >= 16) {
620                    alphamask = from_le32(&src[66..70]);
621                }
622            },
623            TYPE_A1RGB5 => {
624                alphamask = if headersize < 56 { 0 } else { 0x8000 };
625            },
626            TYPE_ARGB8 => {
627                alphamask = if headersize < 56 { 0 } else { 0xFF000000 };
628            }
629            _ => { },
630        }
631    }
632    let mut image = ImageBuffer::new(width,height);
633    decode_pixels(&mut image.data,&src[offset as usize..],width,height,bottom_up,itype,&palette,redmask,greenmask,bluemask,alphamask);
634    Ok(image)
635}
636
637trait WriteTypes {
638    fn push16(&mut self,d: u16);
639    fn push16b(&mut self,d: u16);
640    fn push32(&mut self,d: u32);
641    fn push32b(&mut self,d: u32);
642}
643
644impl WriteTypes for Vec<u8> {
645    fn push16(&mut self,d: u16) {
646        self.push((d & 255) as u8);
647        self.push((d >> 8) as u8);
648    }
649    fn push16b(&mut self,d: u16) {
650        self.push((d >> 8) as u8);
651        self.push((d & 255) as u8);
652    }
653    fn push32(&mut self,d: u32) {
654        self.push((d & 255) as u8);
655        self.push(((d >> 8) & 255) as u8);
656        self.push(((d >> 16) & 255) as u8);
657        self.push((d >> 24) as u8);
658    }
659    fn push32b(&mut self,d: u32) {
660        self.push((d >> 24) as u8);
661        self.push(((d >> 16) & 255) as u8);
662        self.push(((d >> 8) & 255) as u8);
663        self.push((d & 255) as u8);
664    }
665}
666
667pub fn encode(image: &ImageBuffer) -> Result<Vec<u8>,String> {
668    let headersize = 108;
669    let stride = image.width * 4;
670    let palettesize = 0;
671    let bpp = 32;
672    let compression = 3;
673    let colors = 0;
674    let redmask: u32 = 0x00FF0000;
675    let greenmask: u32 = 0x0000FF00;
676    let bluemask: u32 = 0x000000FF;
677    let alphamask: u32 = 0xFF000000;
678    let imagesize = stride * image.height;
679    let offset = 14 + headersize + palettesize;
680    let filesize = offset + imagesize;
681    let mut dst: Vec<u8> = Vec::new();
682    dst.push16b(0x424D);  // 0
683    dst.push32(filesize as u32);  // 2
684    dst.push32(0);  // 6
685    dst.push32(offset as u32);  // 10
686    dst.push32(headersize as u32);  // 14
687    dst.push32(image.width as u32);  // 18
688    dst.push32(-(image.height as i32) as u32);  // 22
689    dst.push16(1);  // 26
690    dst.push16(bpp);  // 28
691    dst.push32(compression);  // 30
692    dst.push32(imagesize as u32);  // 34
693    dst.push32(1);  // 38
694    dst.push32(1);  // 42
695    dst.push32(colors);  // 46
696    dst.push32(colors);  // 50
697    dst.push32(redmask);  // 54
698    dst.push32(greenmask);  // 58
699    dst.push32(bluemask);  // 62
700    dst.push32(alphamask);  // 66
701    dst.push32(0x57696E20);  // 70
702    dst.push32(0);  // 74
703    dst.push32(0);  // 78
704    dst.push32(0);  // 82
705    dst.push32(0);  // 86
706    dst.push32(0);  // 90
707    dst.push32(0);  // 94
708    dst.push32(0);  // 98
709    dst.push32(0);  // 102
710    dst.push32(0);  // 106
711    dst.push32(0);  // 110
712    dst.push32(0);  // 114
713    dst.push32(0);  // 118
714    for y in 0..image.height {
715        for x in 0..image.width {
716            dst.push32(image.data[y * image.width + x]);  // 122..
717        }
718    }
719    Ok(dst)
720}