Mercurial > hg > dmlib
comparison libgfx.c @ 443:f7c9d1619c74
Beginnings of IFF ILBM reader. Not functional, only chunk parsing,
BMHD header chunk parsing and CMAP handling implemented.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sun, 04 Nov 2012 06:41:51 +0200 |
parents | a67600e186d0 |
children | 7d588807f91d |
comparison
equal
deleted
inserted
replaced
442:a67600e186d0 | 443:f7c9d1619c74 |
---|---|
918 fclose(fp); | 918 fclose(fp); |
919 return res; | 919 return res; |
920 } | 920 } |
921 | 921 |
922 | 922 |
923 #define IFF_ID_FORM 0x464F524D // "FORM" | |
924 #define IFF_ID_ILBM 0x494C424D // "ILBM" | |
925 #define IFF_ID_BMHD 0x424D4844 // "BMHD" | |
926 #define IFF_ID_CMAP 0x434D4150 // "CMAP" | |
927 #define IFF_ID_BODY 0x424F4459 // "BODY" | |
928 | |
929 #define IFF_MASK_NONE 0 | |
930 #define IFF_MASK_HAS_MASK 1 | |
931 #define IFF_MASK_TRANSP 2 | |
932 #define IFF_MASK_LASSO 3 | |
933 | |
934 #define IFF_COMP_NONE 0 | |
935 #define IFF_COMP_BYTERUN1 1 | |
936 | |
937 | |
938 typedef struct | |
939 { | |
940 Uint32 id; | |
941 Uint32 size; | |
942 int count; | |
943 } DMIFFChunk; | |
944 | |
945 | |
946 typedef struct | |
947 { | |
948 Uint16 w, h; | |
949 Sint16 x, y; | |
950 Uint8 nplanes; | |
951 Uint8 masking; | |
952 Uint8 compression; | |
953 Uint8 pad1; | |
954 Uint16 transp; | |
955 Uint8 xasp, yasp; | |
956 Sint16 pagew, pageh; | |
957 } DMIFFBMHD; | |
958 | |
959 | |
960 static BOOL dmReadIFFChunk(FILE *fp, DMIFFChunk *chunk) | |
961 { | |
962 if (!dm_fread_be32(fp, &chunk->id) || | |
963 !dm_fread_be32(fp, &chunk->size)) | |
964 { | |
965 dmError("ILBM: Could not read IFF chunk header.\n"); | |
966 return FALSE; | |
967 } | |
968 else | |
969 return TRUE; | |
970 } | |
971 | |
972 static char * dmGetIFFChunkID(DMIFFChunk *chunk, char *buf) | |
973 { | |
974 buf[0] = (chunk->id >> 24) & 0xff; | |
975 buf[1] = (chunk->id >> 16) & 0xff; | |
976 buf[2] = (chunk->id >> 8) & 0xff; | |
977 buf[3] = (chunk->id) & 0xff; | |
978 buf[4] = 0; | |
979 return buf; | |
980 } | |
981 | |
982 static BOOL dmCheckIFFChunk(DMIFFChunk *dest, DMIFFChunk *chunk, BOOL multi, Uint32 minSize) | |
983 { | |
984 if (dest->count > 0 && !multi) | |
985 { | |
986 char buf[6]; | |
987 dmError("ILBM: Multiple instances of chunk %s found.\n", | |
988 dmGetIFFChunkID(chunk, buf)); | |
989 return FALSE; | |
990 } | |
991 | |
992 dest->count++; | |
993 | |
994 if (chunk->size < minSize) | |
995 return FALSE; | |
996 | |
997 return TRUE; | |
998 } | |
999 | |
1000 | |
1001 int dmReadILBMImageFILE(FILE *fp, DMImage **pimg) | |
1002 { | |
1003 Uint32 idILBM; | |
1004 DMIFFChunk chunk, chBMHD, chCMAP, chBODY; | |
1005 DMIFFBMHD bmhd; | |
1006 int ncolors, i; | |
1007 DMColor *pal = NULL; | |
1008 DMImage *img = NULL; | |
1009 BOOL paletted = FALSE, parsed = FALSE; | |
1010 int res = DMERR_OK; | |
1011 | |
1012 memset(&chBMHD, 0, sizeof(DMIFFChunk)); | |
1013 memset(&chCMAP, 0, sizeof(DMIFFChunk)); | |
1014 memset(&chBODY, 0, sizeof(DMIFFChunk)); | |
1015 memset(&bmhd, 0, sizeof(bmhd)); | |
1016 | |
1017 // Read IFF FORM header | |
1018 if (!dmReadIFFChunk(fp, &chunk) || | |
1019 chunk.id != IFF_ID_FORM || | |
1020 chunk.size < 32) | |
1021 { | |
1022 dmError("ILBM: Not a IFF file.\n"); | |
1023 return DMERR_FREAD; | |
1024 } | |
1025 | |
1026 // Check IFF ILBM signature | |
1027 if (!dm_fread_be32(fp, &idILBM) || | |
1028 idILBM != IFF_ID_ILBM) | |
1029 { | |
1030 dmError("ILBM: Not a ILBM file.\n"); | |
1031 return DMERR_INVALID_DATA; | |
1032 } | |
1033 | |
1034 while (!parsed && !feof(fp)) | |
1035 { | |
1036 if (!dmReadIFFChunk(fp, &chunk)) | |
1037 { | |
1038 dmError("ILBM: Error reading IFF ILBM data.\n"); | |
1039 return DMERR_FREAD; | |
1040 } | |
1041 | |
1042 switch (chunk.id) | |
1043 { | |
1044 case IFF_ID_BMHD: | |
1045 if (!dmCheckIFFChunk(&chBMHD, &chunk, FALSE, sizeof(bmhd))) | |
1046 return DMERR_FREAD; | |
1047 | |
1048 if (!dm_fread_be16(fp, &bmhd.w) || | |
1049 !dm_fread_be16(fp, &bmhd.h) || | |
1050 !dm_fread_be16(fp, (Uint16 *) &bmhd.x) || | |
1051 !dm_fread_be16(fp, (Uint16 *) &bmhd.y) || | |
1052 !dm_fread_byte(fp, &bmhd.nplanes) || | |
1053 !dm_fread_byte(fp, &bmhd.masking) || | |
1054 !dm_fread_byte(fp, &bmhd.compression) || | |
1055 !dm_fread_byte(fp, &bmhd.pad1) || | |
1056 !dm_fread_be16(fp, &bmhd.transp) || | |
1057 !dm_fread_byte(fp, &bmhd.xasp) || | |
1058 !dm_fread_byte(fp, &bmhd.yasp) || | |
1059 !dm_fread_be16(fp, (Uint16 *) &bmhd.pagew) || | |
1060 !dm_fread_be16(fp, (Uint16 *) &bmhd.pageh)) | |
1061 { | |
1062 dmError("ILBM: Error reading BMHD chunk.\n"); | |
1063 return DMERR_FREAD; | |
1064 } | |
1065 dmMsg(2, "ILBM: BMHD %d x %d @ %d, %d : nplanes=%d, comp=%d, mask=%d\n", | |
1066 bmhd.w, bmhd.h, bmhd.x, bmhd.y, bmhd.nplanes, bmhd.compression, bmhd.masking); | |
1067 break; | |
1068 | |
1069 | |
1070 case IFF_ID_CMAP: | |
1071 // Check for multiple occurences of CMAP | |
1072 if (!dmCheckIFFChunk(&chCMAP, &chunk, FALSE, 3)) | |
1073 return DMERR_FREAD; | |
1074 | |
1075 // Check for sanity | |
1076 if (chunk.size % 3 != 0) | |
1077 dmError("ILBM: CMAP chunk size not divisible by 3, possibly broken file.\n"); | |
1078 | |
1079 ncolors = chunk.size / 3; | |
1080 dmMsg(2, "ILBM: CMAP %d entries (%d bytes)\n", | |
1081 ncolors, chunk.size, 1 << bmhd.nplanes); | |
1082 | |
1083 if (bmhd.nplanes > 0 && ncolors != 1 << bmhd.nplanes) | |
1084 dmMsg(2, "ILBM: Expected %d entries in CMAP.\n", 1 << bmhd.nplanes); | |
1085 | |
1086 if (ncolors == 0) | |
1087 break; | |
1088 | |
1089 // Allocate palette | |
1090 if ((pal = dmMalloc(sizeof(DMColor) * ncolors)) == NULL) | |
1091 { | |
1092 dmError("ILBM: Could not allocate memory for palette.\n"); | |
1093 return DMERR_MALLOC; | |
1094 } | |
1095 | |
1096 // Read palette | |
1097 for (i = 0; i < ncolors; i++) | |
1098 { | |
1099 Uint8 colR, colG, colB; | |
1100 if (!dm_fread_byte(fp, &colR) || | |
1101 !dm_fread_byte(fp, &colG) || | |
1102 !dm_fread_byte(fp, &colB)) | |
1103 { | |
1104 dmError("ILBM: Error reading CMAP entry #%d, broken file.\n", i); | |
1105 return DMERR_FREAD; | |
1106 } | |
1107 | |
1108 pal[i].r = colR; | |
1109 pal[i].g = colG; | |
1110 pal[i].b = colB; | |
1111 } | |
1112 | |
1113 if (chBMHD.count && chBODY.count) | |
1114 parsed = TRUE; | |
1115 break; | |
1116 | |
1117 case IFF_ID_BODY: | |
1118 if (!dmCheckIFFChunk(&chBODY, &chunk, FALSE, 1)) | |
1119 return DMERR_FREAD; | |
1120 | |
1121 if (!chBMHD.count) | |
1122 { | |
1123 dmError("ILBM: BODY chunk before BMHD?\n"); | |
1124 return DMERR_INVALID_DATA; | |
1125 } | |
1126 | |
1127 dmMsg(2, "ILBM: BODY chunk size %d bytes\n", chunk.size); | |
1128 if (fseeko(fp, chunk.size, SEEK_CUR) != 0) | |
1129 { | |
1130 dmError("ILBM: Error skipping in file."); | |
1131 return DMERR_FREAD; | |
1132 } | |
1133 | |
1134 if (chCMAP.count) | |
1135 parsed = TRUE; | |
1136 break; | |
1137 | |
1138 default: | |
1139 { | |
1140 char buf[6]; | |
1141 dmMsg(3, "Unknown chunk ID '%s', size %d\n", | |
1142 dmGetIFFChunkID(&chunk, buf), chunk.size); | |
1143 | |
1144 if (fseeko(fp, chunk.size, SEEK_CUR) != 0) | |
1145 { | |
1146 dmError("ILBM: Error skipping in file."); | |
1147 return DMERR_FREAD; | |
1148 } | |
1149 } | |
1150 break; | |
1151 } | |
1152 | |
1153 if (chunk.size & 1) | |
1154 fgetc(fp); | |
1155 } | |
1156 | |
1157 return res; | |
1158 } | |
1159 | |
1160 | |
1161 int dmReadILBMImage(const char *filename, DMImage **pimg) | |
1162 { | |
1163 FILE *fp; | |
1164 int res; | |
1165 | |
1166 if ((fp = fopen(filename, "rb")) == NULL) | |
1167 { | |
1168 dmError("ILBM: Could not open file '%s' for reading.\n", filename); | |
1169 return DMERR_FOPEN; | |
1170 } | |
1171 | |
1172 res = dmReadILBMImageFILE(fp, pimg); | |
1173 | |
1174 fclose(fp); | |
1175 return res; | |
1176 } | |
1177 | |
1178 | |
1179 | |
1180 | |
923 static int fmtProbePNG(const Uint8 *buf, const size_t len) | 1181 static int fmtProbePNG(const Uint8 *buf, const size_t len) |
924 { | 1182 { |
925 if (len > 64 && buf[0] == 0x89 && | 1183 if (len > 64 && buf[0] == 0x89 && |
926 buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' && | 1184 buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' && |
927 buf[4] == 0x0d && buf[5] == 0x0a) | 1185 buf[4] == 0x0d && buf[5] == 0x0a) |
1186 { | |
1187 if (buf[12] == 'I' && buf[13] == 'H' && | |
1188 buf[14] == 'D' && buf[15] == 'R') | |
1189 return DM_PROBE_SCORE_MAX; | |
1190 else | |
1191 return DM_PROBE_SCORE_GOOD; | |
1192 } | |
1193 | |
1194 return DM_PROBE_SCORE_FALSE; | |
1195 } | |
1196 | |
1197 | |
1198 static int fmtProbePCX(const Uint8 *buf, const size_t len) | |
1199 { | |
1200 if (len > 128 + 32 && | |
1201 buf[0] == 10 && | |
1202 (buf[1] == 5 || buf[1] == 2 || buf[1] == 3) && | |
1203 buf[2] == 1 && | |
1204 (buf[3] == 8 || buf[3] == 4 || buf[3] == 3 || buf[3] == 1) && | |
1205 buf[65] >= 1 && buf[65] <= 4) | |
928 return DM_PROBE_SCORE_GOOD; | 1206 return DM_PROBE_SCORE_GOOD; |
929 | 1207 |
930 return DM_PROBE_SCORE_FALSE; | 1208 return DM_PROBE_SCORE_FALSE; |
931 } | 1209 } |
932 | 1210 |
933 | 1211 |
934 static int fmtProbePCX(const Uint8 *buf, const size_t len) | 1212 static int fmtProbeILBM(const Uint8 *buf, const size_t len) |
935 { | 1213 { |
936 if (len > 128 + 64 && | 1214 if (len > 32 && |
937 buf[0] == 10 && | 1215 buf[ 0] == 'F' && buf[ 1] == 'O' && |
938 buf[1] == 5 && | 1216 buf[ 2] == 'R' && buf[ 3] == 'M' && |
939 buf[2] == 1 && | 1217 buf[ 8] == 'I' && buf[ 9] == 'L' && |
940 buf[3] == 8) | 1218 buf[10] == 'B' && buf[11] == 'M') |
941 return DM_PROBE_SCORE_GOOD; | 1219 { |
1220 if (buf[12] == 'B' && buf[13] == 'M' && | |
1221 buf[14] == 'H' && buf[15] == 'D') | |
1222 return DM_PROBE_SCORE_MAX; | |
1223 else | |
1224 return DM_PROBE_SCORE_GOOD; | |
1225 } | |
942 | 1226 |
943 return DM_PROBE_SCORE_FALSE; | 1227 return DM_PROBE_SCORE_FALSE; |
944 } | 1228 } |
945 | 1229 |
946 | 1230 |
967 fmtProbePCX, | 1251 fmtProbePCX, |
968 dmReadPCXImage, dmReadPCXImageFILE, | 1252 dmReadPCXImage, dmReadPCXImageFILE, |
969 dmWritePCXImage, dmWritePCXImageFILE, | 1253 dmWritePCXImage, dmWritePCXImageFILE, |
970 }, | 1254 }, |
971 { | 1255 { |
1256 "ILBM", "IFF ILBM", | |
1257 fmtProbeILBM, | |
1258 dmReadILBMImage, dmReadILBMImageFILE, | |
1259 NULL, NULL, | |
1260 }, | |
1261 { | |
972 "ARAW", "IFFMaster Amiga RAW", | 1262 "ARAW", "IFFMaster Amiga RAW", |
973 NULL, | 1263 NULL, |
974 NULL, NULL, | 1264 NULL, NULL, |
975 dmWriteIFFMasterRAWImage, dmWriteIFFMasterRAWImageFILE, | 1265 dmWriteIFFMasterRAWImage, dmWriteIFFMasterRAWImageFILE, |
976 } | 1266 } |