1 | /* |
1 | /* |
2 | parse_image.c - Part of psiconv, a PSION 5 file formats converter |
2 | parse_image.c - Part of psiconv, a PSION 5 file formats converter |
3 | Copyright (c) 1999, 2000 Frodo Looijaard <frodol@dds.nl> |
3 | Copyright (c) 1999-2004 Frodo Looijaard <frodol@dds.nl> |
4 | |
4 | |
5 | This program is free software; you can redistribute it and/or modify |
5 | This program is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by |
6 | it under the terms of the GNU General Public License as published by |
7 | the Free Software Foundation; either version 2 of the License, or |
7 | the Free Software Foundation; either version 2 of the License, or |
8 | (at your option) any later version. |
8 | (at your option) any later version. |
… | |
… | |
27 | #include "image.h" |
27 | #include "image.h" |
28 | |
28 | |
29 | #ifdef DMALLOC |
29 | #ifdef DMALLOC |
30 | #include <dmalloc.h> |
30 | #include <dmalloc.h> |
31 | #endif |
31 | #endif |
|
|
32 | |
|
|
33 | /* Extreme debugging info */ |
|
|
34 | #undef LOUD |
32 | |
35 | |
33 | static int psiconv_decode_rle8 (const psiconv_config config, int lev, |
36 | static int psiconv_decode_rle8 (const psiconv_config config, int lev, |
34 | psiconv_u32 off, |
37 | psiconv_u32 off, |
35 | const psiconv_pixel_bytes encoded, |
38 | const psiconv_pixel_bytes encoded, |
36 | psiconv_pixel_bytes *decoded); |
39 | psiconv_pixel_bytes *decoded); |
… | |
… | |
107 | return 0; |
110 | return 0; |
108 | |
111 | |
109 | ERROR2: |
112 | ERROR2: |
110 | psiconv_list_free(*result); |
113 | psiconv_list_free(*result); |
111 | ERROR1: |
114 | ERROR1: |
112 | psiconv_warn(config,lev+1,off,"Reading of Jumptable Section failed"); |
115 | psiconv_error(config,lev+1,off,"Reading of Jumptable Section failed"); |
113 | if (length) |
116 | if (length) |
114 | *length = 0; |
117 | *length = 0; |
115 | if (!res) |
118 | if (!res) |
116 | return -PSICONV_E_NOMEM; |
119 | return -PSICONV_E_NOMEM; |
117 | else |
120 | else |
… | |
… | |
151 | psiconv_progress(config,lev+2,off+len,"Going to read pixel data offset"); |
154 | psiconv_progress(config,lev+2,off+len,"Going to read pixel data offset"); |
152 | offset = psiconv_read_u32(config,buf,lev+2,off+len,&res); |
155 | offset = psiconv_read_u32(config,buf,lev+2,off+len,&res); |
153 | if (res) |
156 | if (res) |
154 | goto ERROR3; |
157 | goto ERROR3; |
155 | if (offset != 0x28) { |
158 | if (offset != 0x28) { |
156 | psiconv_warn(config,lev+2,off+len, |
159 | psiconv_error(config,lev+2,off+len, |
157 | "Paint data section data offset has unexpected value"); |
160 | "Paint data section data offset has unexpected value"); |
158 | psiconv_debug(config,lev+2,off+len, |
161 | psiconv_debug(config,lev+2,off+len, |
159 | "Data offset: read %08x, expected %08x",offset,0x28); |
162 | "Data offset: read %08x, expected %08x",offset,0x28); |
160 | res = -1; |
163 | res = -1; |
161 | } |
164 | } |
… | |
… | |
277 | "All image types except 2-bit greyscale are experimental!"); |
280 | "All image types except 2-bit greyscale are experimental!"); |
278 | |
281 | |
279 | psiconv_progress(config,lev+2,off+len,"Going to read the pixel data"); |
282 | psiconv_progress(config,lev+2,off+len,"Going to read the pixel data"); |
280 | for (i = 0; i < datasize; i++) { |
283 | for (i = 0; i < datasize; i++) { |
281 | byte = psiconv_read_u8(config,buf,lev+2,off+len+i,&res); |
284 | byte = psiconv_read_u8(config,buf,lev+2,off+len+i,&res); |
|
|
285 | #ifdef LOUD |
282 | psiconv_debug(config,lev+2,off+len+i, |
286 | psiconv_debug(config,lev+2,off+len+i, |
283 | "Pixel byte %04x of %04x has value %02x", |
287 | "Pixel byte %04x of %04x has value %02x", |
284 | i,datasize,byte); |
288 | i,datasize,byte); |
|
|
289 | #endif |
285 | if (res) |
290 | if (res) |
286 | goto ERROR3; |
291 | goto ERROR3; |
287 | psiconv_list_add(bytes,&byte); |
292 | psiconv_list_add(bytes,&byte); |
288 | } |
293 | } |
289 | len += datasize; |
294 | len += datasize; |
… | |
… | |
360 | ERROR3: |
365 | ERROR3: |
361 | psiconv_list_free(bytes); |
366 | psiconv_list_free(bytes); |
362 | ERROR2: |
367 | ERROR2: |
363 | free(*result); |
368 | free(*result); |
364 | ERROR1: |
369 | ERROR1: |
365 | psiconv_warn(config,lev+1,off,"Reading of Paint Data Section failed"); |
370 | psiconv_error(config,lev+1,off,"Reading of Paint Data Section failed"); |
366 | if (length) |
371 | if (length) |
367 | *length = 0; |
372 | *length = 0; |
368 | if (!res) |
373 | if (!res) |
369 | return -PSICONV_E_NOMEM; |
374 | return -PSICONV_E_NOMEM; |
370 | else |
375 | else |
… | |
… | |
525 | ERROR3: |
530 | ERROR3: |
526 | psiconv_free_paint_data_section((*result)->picture); |
531 | psiconv_free_paint_data_section((*result)->picture); |
527 | ERROR2: |
532 | ERROR2: |
528 | free (*result); |
533 | free (*result); |
529 | ERROR1: |
534 | ERROR1: |
530 | psiconv_warn(config,lev+1,off,"Reading of Sketch Section failed"); |
535 | psiconv_error(config,lev+1,off,"Reading of Sketch Section failed"); |
531 | if (length) |
536 | if (length) |
532 | *length = 0; |
537 | *length = 0; |
533 | if (!res) |
538 | if (!res) |
534 | return -PSICONV_E_NOMEM; |
539 | return -PSICONV_E_NOMEM; |
535 | else |
540 | else |
… | |
… | |
628 | return 0; |
633 | return 0; |
629 | |
634 | |
630 | ERROR2: |
635 | ERROR2: |
631 | free (*result); |
636 | free (*result); |
632 | ERROR1: |
637 | ERROR1: |
633 | psiconv_warn(config,lev+1,off,"Reading of Font failed"); |
638 | psiconv_error(config,lev+1,off,"Reading of Font failed"); |
634 | if (length) |
639 | if (length) |
635 | *length = 0; |
640 | *length = 0; |
636 | if (!res) |
641 | if (!res) |
637 | return -PSICONV_E_NOMEM; |
642 | return -PSICONV_E_NOMEM; |
638 | else |
643 | else |
… | |
… | |
650 | psiconv_progress(config,lev+1,off,"Going to decode the RLE8 encoding"); |
655 | psiconv_progress(config,lev+1,off,"Going to decode the RLE8 encoding"); |
651 | if (!(*decoded = psiconv_list_new(sizeof(psiconv_u8)))) |
656 | if (!(*decoded = psiconv_list_new(sizeof(psiconv_u8)))) |
652 | goto ERROR1; |
657 | goto ERROR1; |
653 | |
658 | |
654 | for (i = 0; i < psiconv_list_length(encoded);) { |
659 | for (i = 0; i < psiconv_list_length(encoded);) { |
|
|
660 | #ifdef LOUD |
655 | psiconv_progress(config,lev+2,off,"Going to read marker byte at %04x",i); |
661 | psiconv_progress(config,lev+2,off,"Going to read marker byte at %04x",i); |
|
|
662 | #endif |
656 | if (!(marker = psiconv_list_get(encoded,i))) |
663 | if (!(marker = psiconv_list_get(encoded,i))) |
657 | goto ERROR2; |
664 | goto ERROR2; |
|
|
665 | #ifdef LOUD |
658 | psiconv_debug(config,lev+2,off,"Marker byte: %02x",*marker); |
666 | psiconv_debug(config,lev+2,off,"Marker byte: %02x",*marker); |
|
|
667 | #endif |
659 | if (*marker < 0x80) { |
668 | if (*marker < 0x80) { |
|
|
669 | #ifdef LOUD |
660 | psiconv_debug(config,lev+2,off,"Marker: repeat value byte %02x times", |
670 | psiconv_debug(config,lev+2,off,"Marker: repeat value byte %02x times", |
661 | *marker+1); |
671 | *marker+1); */ |
662 | psiconv_progress(config,lev+2,off,"Going to read value byte at %04x",i+1); |
672 | psiconv_progress(config,lev+2,off,"Going to read value byte at %04x",i+1); |
|
|
673 | #endif |
663 | if (!(value = psiconv_list_get(encoded,i+1))) |
674 | if (!(value = psiconv_list_get(encoded,i+1))) |
664 | goto ERROR2; |
675 | goto ERROR2; |
|
|
676 | #ifdef LOUD |
665 | psiconv_debug(config,lev+2,off,"Value byte: %02x",*value); |
677 | psiconv_debug(config,lev+2,off,"Value byte: %02x",*value); |
666 | psiconv_progress(config,lev+2,off,"Adding %02x pixels %02x", |
678 | psiconv_progress(config,lev+2,off,"Adding %02x pixels %02x", |
667 | *marker+1,*value); |
679 | *marker+1,*value); |
|
|
680 | #endif |
668 | for (j = 0; j < *marker + 1; j++) |
681 | for (j = 0; j < *marker + 1; j++) |
669 | if ((res = psiconv_list_add(*decoded,value))) |
682 | if ((res = psiconv_list_add(*decoded,value))) |
670 | goto ERROR2; |
683 | goto ERROR2; |
671 | i += 2; |
684 | i += 2; |
672 | } else { |
685 | } else { |
|
|
686 | #ifdef LOUD |
673 | psiconv_debug(config,lev+2,off,"Marker: %02x value bytes follow", |
687 | psiconv_debug(config,lev+2,off,"Marker: %02x value bytes follow", |
674 | 0x100 - *marker); |
688 | 0x100 - *marker); |
|
|
689 | #endif |
675 | for (j = 0; j < (0x100 - *marker); j++) { |
690 | for (j = 0; j < (0x100 - *marker); j++) { |
|
|
691 | #ifdef LOUD |
676 | psiconv_progress(config,lev+2,off,"Going to read value byte at %04x", |
692 | psiconv_progress(config,lev+2,off,"Going to read value byte at %04x", |
677 | i+j+1); |
693 | i+j+1); |
|
|
694 | #endif |
678 | if (!(value = psiconv_list_get(encoded,i+j+1))) |
695 | if (!(value = psiconv_list_get(encoded,i+j+1))) |
679 | goto ERROR2; |
696 | goto ERROR2; |
|
|
697 | #ifdef LOUD |
680 | psiconv_debug(config,lev+2,off,"Value: %02x",*value); |
698 | psiconv_debug(config,lev+2,off,"Value: %02x",*value); |
|
|
699 | #endif |
681 | if ((res = psiconv_list_add(*decoded,value))) |
700 | if ((res = psiconv_list_add(*decoded,value))) |
682 | goto ERROR2; |
701 | goto ERROR2; |
683 | } |
702 | } |
684 | i += (0x100 - *marker) + 1; |
703 | i += (0x100 - *marker) + 1; |
685 | } |
704 | } |
… | |
… | |
689 | return 0; |
708 | return 0; |
690 | |
709 | |
691 | ERROR2: |
710 | ERROR2: |
692 | psiconv_list_free(*decoded); |
711 | psiconv_list_free(*decoded); |
693 | ERROR1: |
712 | ERROR1: |
694 | psiconv_warn(config,lev+1,off,"Decoding of RLE8 failed"); |
713 | psiconv_error(config,lev+1,off,"Decoding of RLE8 failed"); |
695 | if (!res) |
714 | if (!res) |
696 | return -PSICONV_E_NOMEM; |
715 | return -PSICONV_E_NOMEM; |
697 | else |
716 | else |
698 | return res; |
717 | return res; |
699 | } |
718 | } |
… | |
… | |
732 | return 0; |
751 | return 0; |
733 | |
752 | |
734 | ERROR2: |
753 | ERROR2: |
735 | psiconv_list_free(*decoded); |
754 | psiconv_list_free(*decoded); |
736 | ERROR1: |
755 | ERROR1: |
737 | psiconv_warn(config,lev+1,off,"Decoding of RLE12 failed"); |
756 | psiconv_error(config,lev+1,off,"Decoding of RLE12 failed"); |
738 | if (!res) |
757 | if (!res) |
739 | return -PSICONV_E_NOMEM; |
758 | return -PSICONV_E_NOMEM; |
740 | else |
759 | else |
741 | return res; |
760 | return res; |
742 | } |
761 | } |
… | |
… | |
798 | return 0; |
817 | return 0; |
799 | |
818 | |
800 | ERROR2: |
819 | ERROR2: |
801 | psiconv_list_free(*decoded); |
820 | psiconv_list_free(*decoded); |
802 | ERROR1: |
821 | ERROR1: |
803 | psiconv_warn(config,lev+1,off,"Decoding of RLE16 failed"); |
822 | psiconv_error(config,lev+1,off,"Decoding of RLE16 failed"); |
804 | if (!res) |
823 | if (!res) |
805 | return -PSICONV_E_NOMEM; |
824 | return -PSICONV_E_NOMEM; |
806 | else |
825 | else |
807 | return res; |
826 | return res; |
808 | } |
827 | } |
… | |
… | |
868 | return 0; |
887 | return 0; |
869 | |
888 | |
870 | ERROR2: |
889 | ERROR2: |
871 | psiconv_list_free(*decoded); |
890 | psiconv_list_free(*decoded); |
872 | ERROR1: |
891 | ERROR1: |
873 | psiconv_warn(config,lev+1,off,"Decoding of RLE24 failed"); |
892 | psiconv_error(config,lev+1,off,"Decoding of RLE24 failed"); |
874 | if (!res) |
893 | if (!res) |
875 | return -PSICONV_E_NOMEM; |
894 | return -PSICONV_E_NOMEM; |
876 | else |
895 | else |
877 | return res; |
896 | return res; |
878 | } |
897 | } |
… | |
… | |
899 | while (nr % 4) |
918 | while (nr % 4) |
900 | nr ++; |
919 | nr ++; |
901 | input = 0; |
920 | input = 0; |
902 | ibits = 0; |
921 | ibits = 0; |
903 | for (x= 0; x < xsize; x++) { |
922 | for (x= 0; x < xsize; x++) { |
|
|
923 | #ifdef LOUD |
904 | psiconv_progress(config,lev+2,off, |
924 | psiconv_progress(config,lev+2,off, |
905 | "Processing pixel at (x,y) = (%04x,%04x)",x,y); |
925 | "Processing pixel at (x,y) = (%04x,%04x)",x,y); |
|
|
926 | #endif |
906 | output = 0; |
927 | output = 0; |
907 | obits = 0; |
928 | obits = 0; |
908 | while (obits < colordepth) { |
929 | while (obits < colordepth) { |
909 | if (ibits == 0) { |
930 | if (ibits == 0) { |
|
|
931 | #ifdef LOUD |
910 | psiconv_progress(config,lev+3,off, |
932 | psiconv_progress(config,lev+3,off, |
911 | "Going to read byte %08x",nr); |
933 | "Going to read byte %08x",nr); |
|
|
934 | #endif |
912 | if (!(ientry = psiconv_list_get(bytes,nr))) |
935 | if (!(ientry = psiconv_list_get(bytes,nr))) |
913 | goto ERROR2; |
936 | goto ERROR2; |
|
|
937 | #ifdef LOUD |
914 | psiconv_debug(config,lev+3,off,"Byte value: %02x",*ientry); |
938 | psiconv_debug(config,lev+3,off,"Byte value: %02x",*ientry); |
|
|
939 | #endif |
915 | input = *ientry; |
940 | input = *ientry; |
916 | ibits = 8; |
941 | ibits = 8; |
917 | nr ++; |
942 | nr ++; |
918 | } |
943 | } |
919 | bits = ibits + obits > colordepth?colordepth-obits:ibits; |
944 | bits = ibits + obits > colordepth?colordepth-obits:ibits; |
… | |
… | |
921 | output |= input & ((1 << bits) - 1); |
946 | output |= input & ((1 << bits) - 1); |
922 | input = input >> bits; |
947 | input = input >> bits; |
923 | ibits -= bits; |
948 | ibits -= bits; |
924 | obits += bits; |
949 | obits += bits; |
925 | } |
950 | } |
|
|
951 | #ifdef LOUD |
926 | psiconv_debug(config,lev+2,off,"Pixel value: %08x",output); |
952 | psiconv_debug(config,lev+2,off,"Pixel value: %08x",output); |
|
|
953 | #endif |
927 | if ((res = psiconv_list_add(*pixels,&output))) |
954 | if ((res = psiconv_list_add(*pixels,&output))) |
928 | goto ERROR2; |
955 | goto ERROR2; |
929 | } |
956 | } |
930 | } |
957 | } |
931 | |
958 | |
… | |
… | |
935 | |
962 | |
936 | |
963 | |
937 | ERROR2: |
964 | ERROR2: |
938 | psiconv_list_free(*pixels); |
965 | psiconv_list_free(*pixels); |
939 | ERROR1: |
966 | ERROR1: |
940 | psiconv_warn(config,lev+1,off,"Converting bytes to pixels failed"); |
967 | psiconv_error(config,lev+1,off,"Converting bytes to pixels failed"); |
941 | if (!res) |
968 | if (!res) |
942 | return -PSICONV_E_NOMEM; |
969 | return -PSICONV_E_NOMEM; |
943 | else |
970 | else |
944 | return res; |
971 | return res; |
945 | } |
972 | } |
… | |
… | |
969 | (*floats).length = psiconv_list_length(pixels); |
996 | (*floats).length = psiconv_list_length(pixels); |
970 | |
997 | |
971 | for (i = 0; i < psiconv_list_length(pixels); i++) { |
998 | for (i = 0; i < psiconv_list_length(pixels); i++) { |
972 | if (!(pixel = psiconv_list_get(pixels,i))) |
999 | if (!(pixel = psiconv_list_get(pixels,i))) |
973 | goto ERROR4; |
1000 | goto ERROR4; |
|
|
1001 | #ifdef LOUD |
974 | psiconv_progress(config,lev+2,off, "Handling pixel %04x (%04x)",i,*pixel); |
1002 | psiconv_progress(config,lev+2,off, "Handling pixel %04x (%04x)",i,*pixel); |
|
|
1003 | #endif |
975 | if (!palet.length) { |
1004 | if (!palet.length) { |
976 | if (color) { |
1005 | if (color) { |
977 | (*floats).blue[i] = ((float) (*pixel & ((1 << bluebits) - 1))) / |
1006 | (*floats).blue[i] = ((float) (*pixel & ((1 << bluebits) - 1))) / |
978 | (1 << bluebits); |
1007 | ((1 << bluebits) - 1); |
979 | (*floats).green[i] = ((float) ((*pixel >> bluebits) & |
1008 | (*floats).green[i] = ((float) ((*pixel >> bluebits) & |
980 | ((1 << greenbits) - 1))) / (1 << greenbits); |
1009 | ((1 << greenbits) - 1))) / ((1 << greenbits) - 1); |
981 | (*floats).red[i] = ((float) ((*pixel >> (bluebits+greenbits)) & |
1010 | (*floats).red[i] = ((float) ((*pixel >> (bluebits+greenbits)) & |
982 | ((1 << redbits) - 1))) / (1 << redbits); |
1011 | ((1 << redbits) - 1))) / ((1 << redbits) - 1); |
983 | } else { |
1012 | } else { |
984 | (*floats).red[i] = (*floats).green[i] = |
1013 | (*floats).red[i] = (*floats).green[i] = |
985 | (*floats).blue[i] = ((float) *pixel) / |
1014 | (*floats).blue[i] = ((float) *pixel) / |
986 | (1 << colordepth); |
1015 | ((1 << colordepth) - 1); |
987 | } |
1016 | } |
988 | } else { |
1017 | } else { |
989 | if (*pixel >= palet.length) { |
1018 | if (*pixel >= palet.length) { |
990 | psiconv_warn(config,lev+2,off, |
1019 | psiconv_warn(config,lev+2,off, |
991 | "Invalid palet color found (using color 0x00)"); |
1020 | "Invalid palet color found (using color 0x00)"); |
… | |
… | |
996 | (*floats).red[i] = palet.red[*pixel]; |
1025 | (*floats).red[i] = palet.red[*pixel]; |
997 | (*floats).green[i] = palet.green[*pixel]; |
1026 | (*floats).green[i] = palet.green[*pixel]; |
998 | (*floats).blue[i] = palet.blue[*pixel]; |
1027 | (*floats).blue[i] = palet.blue[*pixel]; |
999 | } |
1028 | } |
1000 | } |
1029 | } |
|
|
1030 | #ifdef LOUD |
1001 | psiconv_debug(config,lev+2,off, "Pixel: Red (%f), green (%f), blue (%f)", |
1031 | psiconv_debug(config,lev+2,off, "Pixel: Red (%f), green (%f), blue (%f)", |
1002 | (*floats).red[i],(*floats).green[i],(*floats).blue[i]); |
1032 | (*floats).red[i],(*floats).green[i],(*floats).blue[i]); |
|
|
1033 | #endif |
1003 | } |
1034 | } |
1004 | psiconv_progress(config,lev+1,off,"Finished converting pixels to floats"); |
1035 | psiconv_progress(config,lev+1,off,"Finished converting pixels to floats"); |
1005 | return 0; |
1036 | return 0; |
1006 | |
1037 | |
1007 | ERROR4: |
1038 | ERROR4: |
… | |
… | |
1009 | ERROR3: |
1040 | ERROR3: |
1010 | free((*floats).green); |
1041 | free((*floats).green); |
1011 | ERROR2: |
1042 | ERROR2: |
1012 | free((*floats).red); |
1043 | free((*floats).red); |
1013 | ERROR1: |
1044 | ERROR1: |
1014 | psiconv_warn(config,lev+1,off,"Converting pixels to floats failed"); |
1045 | psiconv_error(config,lev+1,off,"Converting pixels to floats failed"); |
1015 | if (!res) |
1046 | if (!res) |
1016 | return -PSICONV_E_NOMEM; |
1047 | return -PSICONV_E_NOMEM; |
1017 | else |
1048 | else |
1018 | return res; |
1049 | return res; |
1019 | } |
1050 | } |