1use 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 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) || (tag == 0x4142) || (tag == 0x4943) || (tag == 0x5043) || (tag == 0x4349) || (tag == 0x5450) { 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 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 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 let mut colors = from_le32(&src[46..50]);
599 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); dst.push32(filesize as u32); dst.push32(0); dst.push32(offset as u32); dst.push32(headersize as u32); dst.push32(image.width as u32); dst.push32(-(image.height as i32) as u32); dst.push16(1); dst.push16(bpp); dst.push32(compression); dst.push32(imagesize as u32); dst.push32(1); dst.push32(1); dst.push32(colors); dst.push32(colors); dst.push32(redmask); dst.push32(greenmask); dst.push32(bluemask); dst.push32(alphamask); dst.push32(0x57696E20); dst.push32(0); dst.push32(0); dst.push32(0); dst.push32(0); dst.push32(0); dst.push32(0); dst.push32(0); dst.push32(0); dst.push32(0); dst.push32(0); dst.push32(0); dst.push32(0); for y in 0..image.height {
715 for x in 0..image.width {
716 dst.push32(image.data[y * image.width + x]); }
718 }
719 Ok(dst)
720}