| 1 | #include "mupdf/fitz.h" |
| 2 | |
| 3 | #include <string.h> |
| 4 | #include <limits.h> |
| 5 | |
| 6 | static const unsigned char web_palette[] = { |
| 7 | 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x66, 0x00, 0x00, 0x99, 0x00, 0x00, 0xCC, 0x00, 0x00, 0xFF, 0x00, 0x00, |
| 8 | 0x00, 0x00, 0x33, 0x33, 0x00, 0x33, 0x66, 0x00, 0x33, 0x99, 0x00, 0x33, 0xCC, 0x00, 0x33, 0xFF, 0x00, 0x33, |
| 9 | 0x00, 0x00, 0x66, 0x33, 0x00, 0x66, 0x66, 0x00, 0x66, 0x99, 0x00, 0x66, 0xCC, 0x00, 0x66, 0xFF, 0x00, 0x66, |
| 10 | 0x00, 0x00, 0x99, 0x33, 0x00, 0x99, 0x66, 0x00, 0x99, 0x99, 0x00, 0x99, 0xCC, 0x00, 0x99, 0xFF, 0x00, 0x99, |
| 11 | 0x00, 0x00, 0xCC, 0x33, 0x00, 0xCC, 0x66, 0x00, 0xCC, 0x99, 0x00, 0xCC, 0xCC, 0x00, 0xCC, 0xFF, 0x00, 0xCC, |
| 12 | 0x00, 0x00, 0xFF, 0x33, 0x00, 0xFF, 0x66, 0x00, 0xFF, 0x99, 0x00, 0xFF, 0xCC, 0x00, 0xFF, 0xFF, 0x00, 0xFF, |
| 13 | 0x00, 0x33, 0x00, 0x33, 0x33, 0x00, 0x66, 0x33, 0x00, 0x99, 0x33, 0x00, 0xCC, 0x33, 0x00, 0xFF, 0x33, 0x00, |
| 14 | 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF, 0x33, 0x33, |
| 15 | 0x00, 0x33, 0x66, 0x33, 0x33, 0x66, 0x66, 0x33, 0x66, 0x99, 0x33, 0x66, 0xCC, 0x33, 0x66, 0xFF, 0x33, 0x66, |
| 16 | 0x00, 0x33, 0x99, 0x33, 0x33, 0x99, 0x66, 0x33, 0x99, 0x99, 0x33, 0x99, 0xCC, 0x33, 0x99, 0xFF, 0x33, 0x99, |
| 17 | 0x00, 0x33, 0xCC, 0x33, 0x33, 0xCC, 0x66, 0x33, 0xCC, 0x99, 0x33, 0xCC, 0xCC, 0x33, 0xCC, 0xFF, 0x33, 0xCC, |
| 18 | 0x00, 0x33, 0xFF, 0x33, 0x33, 0xFF, 0x66, 0x33, 0xFF, 0x99, 0x33, 0xFF, 0xCC, 0x33, 0xFF, 0xFF, 0x33, 0xFF, |
| 19 | 0x00, 0x66, 0x00, 0x33, 0x66, 0x00, 0x66, 0x66, 0x00, 0x99, 0x66, 0x00, 0xCC, 0x66, 0x00, 0xFF, 0x66, 0x00, |
| 20 | 0x00, 0x66, 0x33, 0x33, 0x66, 0x33, 0x66, 0x66, 0x33, 0x99, 0x66, 0x33, 0xCC, 0x66, 0x33, 0xFF, 0x66, 0x33, |
| 21 | 0x00, 0x66, 0x66, 0x33, 0x66, 0x66, 0x66, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF, 0x66, 0x66, |
| 22 | 0x00, 0x66, 0x99, 0x33, 0x66, 0x99, 0x66, 0x66, 0x99, 0x99, 0x66, 0x99, 0xCC, 0x66, 0x99, 0xFF, 0x66, 0x99, |
| 23 | 0x00, 0x66, 0xCC, 0x33, 0x66, 0xCC, 0x66, 0x66, 0xCC, 0x99, 0x66, 0xCC, 0xCC, 0x66, 0xCC, 0xFF, 0x66, 0xCC, |
| 24 | 0x00, 0x66, 0xFF, 0x33, 0x66, 0xFF, 0x66, 0x66, 0xFF, 0x99, 0x66, 0xFF, 0xCC, 0x66, 0xFF, 0xFF, 0x66, 0xFF, |
| 25 | 0x00, 0x99, 0x00, 0x33, 0x99, 0x00, 0x66, 0x99, 0x00, 0x99, 0x99, 0x00, 0xCC, 0x99, 0x00, 0xFF, 0x99, 0x00, |
| 26 | 0x00, 0x99, 0x33, 0x33, 0x99, 0x33, 0x66, 0x99, 0x33, 0x99, 0x99, 0x33, 0xCC, 0x99, 0x33, 0xFF, 0x99, 0x33, |
| 27 | 0x00, 0x99, 0x66, 0x33, 0x99, 0x66, 0x66, 0x99, 0x66, 0x99, 0x99, 0x66, 0xCC, 0x99, 0x66, 0xFF, 0x99, 0x66, |
| 28 | 0x00, 0x99, 0x99, 0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0x99, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF, 0x99, 0x99, |
| 29 | 0x00, 0x99, 0xCC, 0x33, 0x99, 0xCC, 0x66, 0x99, 0xCC, 0x99, 0x99, 0xCC, 0xCC, 0x99, 0xCC, 0xFF, 0x99, 0xCC, |
| 30 | 0x00, 0x99, 0xFF, 0x33, 0x99, 0xFF, 0x66, 0x99, 0xFF, 0x99, 0x99, 0xFF, 0xCC, 0x99, 0xFF, 0xFF, 0x99, 0xFF, |
| 31 | 0x00, 0xCC, 0x00, 0x33, 0xCC, 0x00, 0x66, 0xCC, 0x00, 0x99, 0xCC, 0x00, 0xCC, 0xCC, 0x00, 0xFF, 0xCC, 0x00, |
| 32 | 0x00, 0xCC, 0x33, 0x33, 0xCC, 0x33, 0x66, 0xCC, 0x33, 0x99, 0xCC, 0x33, 0xCC, 0xCC, 0x33, 0xFF, 0xCC, 0x33, |
| 33 | 0x00, 0xCC, 0x66, 0x33, 0xCC, 0x66, 0x66, 0xCC, 0x66, 0x99, 0xCC, 0x66, 0xCC, 0xCC, 0x66, 0xFF, 0xCC, 0x66, |
| 34 | 0x00, 0xCC, 0x99, 0x33, 0xCC, 0x99, 0x66, 0xCC, 0x99, 0x99, 0xCC, 0x99, 0xCC, 0xCC, 0x99, 0xFF, 0xCC, 0x99, |
| 35 | 0x00, 0xCC, 0xCC, 0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFF, 0xCC, 0xCC, |
| 36 | 0x00, 0xCC, 0xFF, 0x33, 0xCC, 0xFF, 0x66, 0xCC, 0xFF, 0x99, 0xCC, 0xFF, 0xCC, 0xCC, 0xFF, 0xFF, 0xCC, 0xFF, |
| 37 | 0x00, 0xFF, 0x00, 0x33, 0xFF, 0x00, 0x66, 0xFF, 0x00, 0x99, 0xFF, 0x00, 0xCC, 0xFF, 0x00, 0xFF, 0xFF, 0x00, |
| 38 | 0x00, 0xFF, 0x33, 0x33, 0xFF, 0x33, 0x66, 0xFF, 0x33, 0x99, 0xFF, 0x33, 0xCC, 0xFF, 0x33, 0xFF, 0xFF, 0x33, |
| 39 | 0x00, 0xFF, 0x66, 0x33, 0xFF, 0x66, 0x66, 0xFF, 0x66, 0x99, 0xFF, 0x66, 0xCC, 0xFF, 0x66, 0xFF, 0xFF, 0x66, |
| 40 | 0x00, 0xFF, 0x99, 0x33, 0xFF, 0x99, 0x66, 0xFF, 0x99, 0x99, 0xFF, 0x99, 0xCC, 0xFF, 0x99, 0xFF, 0xFF, 0x99, |
| 41 | 0x00, 0xFF, 0xCC, 0x33, 0xFF, 0xCC, 0x66, 0xFF, 0xCC, 0x99, 0xFF, 0xCC, 0xCC, 0xFF, 0xCC, 0xFF, 0xFF, 0xCC, |
| 42 | 0x00, 0xFF, 0xFF, 0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 50 | }; |
| 51 | |
| 52 | static const unsigned char vga_palette[] = { |
| 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0x00, 0xAA, 0xAA, |
| 54 | 0xAA, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0xAA, 0x55, 0x00, 0xAA, 0xAA, 0xAA, |
| 55 | 0x55, 0x55, 0x55, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0x55, 0xFF, 0xFF, |
| 56 | 0xFF, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, |
| 57 | }; |
| 58 | |
| 59 | static const unsigned char gray_palette[] = { |
| 60 | 0x00, 0x00, 0x00, 0x54, 0x54, 0x54, |
| 61 | 0xA8, 0xA8, 0xA8, 0xFF, 0xFF, 0xFF, |
| 62 | }; |
| 63 | |
| 64 | static const unsigned char bw_palette[] = { |
| 65 | 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, |
| 66 | }; |
| 67 | |
| 68 | enum { |
| 69 | BI_RLE24 = -1, |
| 70 | BI_RGB = 0, |
| 71 | BI_RLE8 = 1, |
| 72 | BI_RLE4 = 2, |
| 73 | BI_BITFIELDS = 3, |
| 74 | BI_JPEG = 4, |
| 75 | BI_PNG = 5, |
| 76 | BI_ALPHABITS = 6, |
| 77 | BI_UNSUPPORTED = 42, |
| 78 | }; |
| 79 | |
| 80 | struct info |
| 81 | { |
| 82 | int filesize; |
| 83 | int offset; |
| 84 | int topdown; |
| 85 | int width, height; |
| 86 | int xres, yres; |
| 87 | int bitcount; |
| 88 | int compression; |
| 89 | int colors; |
| 90 | int rmask, gmask, bmask, amask; |
| 91 | unsigned char palette[256 * 3]; |
| 92 | |
| 93 | int ; |
| 94 | int palettetype; |
| 95 | unsigned char *samples; |
| 96 | |
| 97 | int rshift, gshift, bshift, ashift; |
| 98 | int rbits, gbits, bbits, abits; |
| 99 | }; |
| 100 | |
| 101 | #define read8(p) ((p)[0]) |
| 102 | #define read16(p) (((p)[1] << 8) | (p)[0]) |
| 103 | #define read32(p) (((p)[3] << 24) | ((p)[2] << 16) | ((p)[1] << 8) | (p)[0]) |
| 104 | |
| 105 | static const unsigned char * |
| 106 | (fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end) |
| 107 | { |
| 108 | if (end - p < 14) |
| 109 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in file header in bmp image" ); |
| 110 | |
| 111 | if (memcmp(&p[0], "BM" , 2)) |
| 112 | fz_throw(ctx, FZ_ERROR_GENERIC, "invalid signature in bmp image" ); |
| 113 | |
| 114 | info->filesize = read32(p + 2); |
| 115 | info->offset = read32(p + 10); |
| 116 | |
| 117 | return p + 14; |
| 118 | } |
| 119 | |
| 120 | static const unsigned char * |
| 121 | (fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end) |
| 122 | { |
| 123 | int size; |
| 124 | |
| 125 | size = read32(p + 0); |
| 126 | if (size != 12) |
| 127 | fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported core header size in bmp image" ); |
| 128 | |
| 129 | if (size >= 12) |
| 130 | { |
| 131 | if (end - p < 12) |
| 132 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in bitmap core header in bmp image" ); |
| 133 | |
| 134 | info->width = read16(p + 4); |
| 135 | info->height = read16(p + 6); |
| 136 | info->bitcount = read16(p + 10); |
| 137 | } |
| 138 | |
| 139 | info->xres = 2835; |
| 140 | info->yres = 2835; |
| 141 | info->compression = BI_RGB; |
| 142 | info->palettetype = 0; |
| 143 | |
| 144 | return p + size; |
| 145 | } |
| 146 | |
| 147 | static const unsigned char * |
| 148 | (fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end) |
| 149 | { |
| 150 | int size; |
| 151 | |
| 152 | size = read32(p + 0); |
| 153 | if (size != 16 && size != 64) |
| 154 | fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported os2 header size in bmp image" ); |
| 155 | |
| 156 | if (size >= 16) |
| 157 | { |
| 158 | if (end - p < 16) |
| 159 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in bitmap os2 header in bmp image" ); |
| 160 | |
| 161 | info->width = read32(p + 4); |
| 162 | info->height = read32(p + 8); |
| 163 | info->bitcount = read16(p + 14); |
| 164 | |
| 165 | info->compression = BI_RGB; |
| 166 | } |
| 167 | if (size >= 64) |
| 168 | { |
| 169 | if (end - p < 64) |
| 170 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in bitmap os2 header in bmp image" ); |
| 171 | |
| 172 | info->compression = read32(p + 16); |
| 173 | info->xres = read32(p + 24); |
| 174 | info->yres = read32(p + 28); |
| 175 | info->colors = read32(p + 32); |
| 176 | |
| 177 | /* 4 in this header is interpreted as 24 bit RLE encoding */ |
| 178 | if (info->compression < 0) |
| 179 | info->compression = BI_UNSUPPORTED; |
| 180 | else if (info->compression == 4) |
| 181 | info->compression = BI_RLE24; |
| 182 | } |
| 183 | |
| 184 | info->palettetype = 1; |
| 185 | |
| 186 | return p + size; |
| 187 | } |
| 188 | |
| 189 | static void maskinfo(unsigned int mask, int *shift, int *bits) |
| 190 | { |
| 191 | *bits = 0; |
| 192 | *shift = 0; |
| 193 | if (mask) { |
| 194 | while ((mask & 1) == 0) { |
| 195 | *shift += 1; |
| 196 | mask >>= 1; |
| 197 | } |
| 198 | while ((mask & 1) == 1) { |
| 199 | *bits += 1; |
| 200 | mask >>= 1; |
| 201 | } |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | static const unsigned char * |
| 206 | (fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end) |
| 207 | { |
| 208 | int size; |
| 209 | |
| 210 | size = read32(p + 0); |
| 211 | if (size != 40 && size != 52 && size != 56 && size != 64 && |
| 212 | size != 108 && size != 124) |
| 213 | fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported info header size in bmp image" ); |
| 214 | |
| 215 | if (size >= 40) |
| 216 | { |
| 217 | if (end - p < 40) |
| 218 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in bitmap info header in bmp image" ); |
| 219 | |
| 220 | info->width = read32(p + 4); |
| 221 | info->topdown = (p[8 + 3] & 0x80) != 0; |
| 222 | if (info->topdown) |
| 223 | info->height = -read32(p + 8); |
| 224 | else |
| 225 | info->height = read32(p + 8); |
| 226 | info->bitcount = read16(p + 14); |
| 227 | info->compression = read32(p + 16); |
| 228 | info->xres = read32(p + 24); |
| 229 | info->yres = read32(p + 28); |
| 230 | info->colors = read32(p + 32); |
| 231 | |
| 232 | if (size == 40 && info->compression == BI_BITFIELDS && (info->bitcount == 16 || info->bitcount == 32)) |
| 233 | info->extramasks = 1; |
| 234 | else if (size == 40 && info->compression == BI_ALPHABITS && (info->bitcount == 16 || info->bitcount == 32)) |
| 235 | info->extramasks = 1; |
| 236 | |
| 237 | if (info->bitcount == 16) { |
| 238 | info->rmask = 0x00007c00; |
| 239 | info->gmask = 0x000003e0; |
| 240 | info->bmask = 0x0000001f; |
| 241 | info->amask = 0x00000000; |
| 242 | } else if (info->bitcount == 32) { |
| 243 | info->rmask = 0x00ff0000; |
| 244 | info->gmask = 0x0000ff00; |
| 245 | info->bmask = 0x000000ff; |
| 246 | info->amask = 0x00000000; |
| 247 | } |
| 248 | } |
| 249 | if (size >= 52) |
| 250 | { |
| 251 | if (end - p < 52) |
| 252 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in bitmap info header in bmp image" ); |
| 253 | |
| 254 | if (info->compression == BI_BITFIELDS) { |
| 255 | info->rmask = read32(p + 40); |
| 256 | info->gmask = read32(p + 44); |
| 257 | info->bmask = read32(p + 48); |
| 258 | } |
| 259 | } |
| 260 | if (size >= 56) |
| 261 | { |
| 262 | if (end - p < 56) |
| 263 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in bitmap info header in bmp image" ); |
| 264 | |
| 265 | if (info->compression == BI_BITFIELDS) { |
| 266 | info->amask = read32(p + 52); |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | info->palettetype = 1; |
| 271 | |
| 272 | return p + size; |
| 273 | } |
| 274 | |
| 275 | static const unsigned char * |
| 276 | (fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end) |
| 277 | { |
| 278 | int size = 0; |
| 279 | |
| 280 | if (info->compression == BI_BITFIELDS) |
| 281 | { |
| 282 | size = 12; |
| 283 | if (end - p < 12) |
| 284 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in mask header in bmp image" ); |
| 285 | |
| 286 | info->rmask = read32(p + 0); |
| 287 | info->gmask = read32(p + 4); |
| 288 | info->bmask = read32(p + 8); |
| 289 | } |
| 290 | else if (info->compression == BI_ALPHABITS) |
| 291 | { |
| 292 | size = 16; |
| 293 | if (end - p < 16) |
| 294 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in mask header in bmp image" ); |
| 295 | |
| 296 | /* ignore alpha mask */ |
| 297 | info->rmask = read32(p + 0); |
| 298 | info->gmask = read32(p + 4); |
| 299 | info->bmask = read32(p + 8); |
| 300 | } |
| 301 | |
| 302 | return p + size; |
| 303 | } |
| 304 | |
| 305 | static int |
| 306 | bmp_palette_is_gray(fz_context *ctx, struct info *info, int readcolors) |
| 307 | { |
| 308 | int i; |
| 309 | for (i = 0; i < readcolors; i++) |
| 310 | { |
| 311 | int rgdiff = fz_absi(info->palette[3 * i + 0] - info->palette[3 * i + 1]); |
| 312 | int gbdiff = fz_absi(info->palette[3 * i + 1] - info->palette[3 * i + 2]); |
| 313 | int rbdiff = fz_absi(info->palette[3 * i + 0] - info->palette[3 * i + 2]); |
| 314 | if (rgdiff > 2 || gbdiff > 2 || rbdiff > 2) |
| 315 | return 0; |
| 316 | } |
| 317 | return 1; |
| 318 | } |
| 319 | |
| 320 | static void |
| 321 | bmp_load_default_palette(fz_context *ctx, struct info *info, int readcolors) |
| 322 | { |
| 323 | int i; |
| 324 | |
| 325 | fz_warn(ctx, "color table too short; loading default palette" ); |
| 326 | |
| 327 | if (info->bitcount == 8) |
| 328 | { |
| 329 | if (!bmp_palette_is_gray(ctx, info, readcolors)) |
| 330 | memcpy(&info->palette[readcolors * 3], &web_palette[readcolors * 3], |
| 331 | sizeof(web_palette) - readcolors * 3); |
| 332 | else |
| 333 | for (i = readcolors; i < 256; i++) |
| 334 | { |
| 335 | info->palette[3 * i + 0] = i; |
| 336 | info->palette[3 * i + 1] = i; |
| 337 | info->palette[3 * i + 2] = i; |
| 338 | } |
| 339 | } |
| 340 | else if (info->bitcount == 4) |
| 341 | { |
| 342 | if (!bmp_palette_is_gray(ctx, info, readcolors)) |
| 343 | memcpy(&info->palette[readcolors * 3], &vga_palette[readcolors * 3], |
| 344 | sizeof(vga_palette) - readcolors * 3); |
| 345 | else |
| 346 | for (i = readcolors; i < 16; i++) |
| 347 | { |
| 348 | info->palette[3 * i + 0] = (i << 4) | i; |
| 349 | info->palette[3 * i + 1] = (i << 4) | i; |
| 350 | info->palette[3 * i + 2] = (i << 4) | i; |
| 351 | } |
| 352 | } |
| 353 | else if (info->bitcount == 2) |
| 354 | memcpy(info->palette, gray_palette, sizeof(gray_palette)); |
| 355 | else if (info->bitcount == 1) |
| 356 | memcpy(info->palette, bw_palette, sizeof(bw_palette)); |
| 357 | } |
| 358 | |
| 359 | static const unsigned char * |
| 360 | bmp_read_color_table(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end) |
| 361 | { |
| 362 | int i, colors, readcolors; |
| 363 | |
| 364 | if (info->bitcount > 8) |
| 365 | return p; |
| 366 | |
| 367 | if (info->colors == 0) |
| 368 | colors = 1 << info->bitcount; |
| 369 | else |
| 370 | colors = info->colors; |
| 371 | |
| 372 | colors = fz_mini(colors, 1 << info->bitcount); |
| 373 | |
| 374 | if (info->palettetype == 0) |
| 375 | { |
| 376 | readcolors = fz_mini(colors, (end - p) / 3); |
| 377 | for (i = 0; i < readcolors; i++) |
| 378 | { |
| 379 | info->palette[3 * i + 0] = read8(p + i * 3 + 2); |
| 380 | info->palette[3 * i + 1] = read8(p + i * 3 + 1); |
| 381 | info->palette[3 * i + 2] = read8(p + i * 3 + 0); |
| 382 | } |
| 383 | if (readcolors < colors) |
| 384 | bmp_load_default_palette(ctx, info, readcolors); |
| 385 | return p + readcolors * 3; |
| 386 | } |
| 387 | else |
| 388 | { |
| 389 | readcolors = fz_mini(colors, (end - p) / 4); |
| 390 | for (i = 0; i < readcolors; i++) |
| 391 | { |
| 392 | /* ignore alpha channel */ |
| 393 | info->palette[3 * i + 0] = read8(p + i * 4 + 2); |
| 394 | info->palette[3 * i + 1] = read8(p + i * 4 + 1); |
| 395 | info->palette[3 * i + 2] = read8(p + i * 4 + 0); |
| 396 | } |
| 397 | if (readcolors < colors) |
| 398 | bmp_load_default_palette(ctx, info, readcolors); |
| 399 | return p + readcolors * 4; |
| 400 | } |
| 401 | |
| 402 | return p; |
| 403 | } |
| 404 | |
| 405 | static unsigned char * |
| 406 | bmp_decompress_rle24(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char **end) |
| 407 | { |
| 408 | const unsigned char *sp; |
| 409 | unsigned char *dp, *ep, *decompressed; |
| 410 | int width = info->width; |
| 411 | int height = info->height; |
| 412 | int stride; |
| 413 | int x, i; |
| 414 | |
| 415 | stride = (width*3 + 3) / 4 * 4; |
| 416 | |
| 417 | sp = p; |
| 418 | dp = decompressed = fz_calloc(ctx, height, stride); |
| 419 | ep = dp + height * stride; |
| 420 | x = 0; |
| 421 | |
| 422 | while (sp + 2 <= *end) |
| 423 | { |
| 424 | if (sp[0] == 0 && sp[1] == 0) |
| 425 | { /* end of line */ |
| 426 | if (x*3 < stride) |
| 427 | dp += stride - x*3; |
| 428 | sp += 2; |
| 429 | x = 0; |
| 430 | } |
| 431 | else if (sp[0] == 0 && sp[1] == 1) |
| 432 | { /* end of bitmap */ |
| 433 | dp = ep; |
| 434 | break; |
| 435 | } |
| 436 | else if (sp[0] == 0 && sp[1] == 2) |
| 437 | { /* delta */ |
| 438 | int deltax, deltay; |
| 439 | if (sp + 4 > *end) |
| 440 | break; |
| 441 | deltax = sp[2]; |
| 442 | deltay = sp[3]; |
| 443 | dp += deltax*3 + deltay * stride; |
| 444 | sp += 4; |
| 445 | x += deltax; |
| 446 | } |
| 447 | else if (sp[0] == 0 && sp[1] >= 3) |
| 448 | { /* absolute */ |
| 449 | int n = sp[1] * 3; |
| 450 | int nn = (n + 1) / 2 * 2; |
| 451 | if (sp + 2 + nn > *end) |
| 452 | break; |
| 453 | if (dp + n > ep) { |
| 454 | fz_warn(ctx, "buffer overflow in bitmap data in bmp image" ); |
| 455 | break; |
| 456 | } |
| 457 | sp += 2; |
| 458 | for (i = 0; i < n; i++) |
| 459 | dp[i] = sp[i]; |
| 460 | dp += n; |
| 461 | sp += (n + 1) / 2 * 2; |
| 462 | x += n; |
| 463 | } |
| 464 | else |
| 465 | { /* encoded */ |
| 466 | int n = sp[0] * 3; |
| 467 | if (sp + 1 + 3 > *end) |
| 468 | break; |
| 469 | if (dp + n > ep) { |
| 470 | fz_warn(ctx, "buffer overflow in bitmap data in bmp image" ); |
| 471 | break; |
| 472 | } |
| 473 | for (i = 0; i < n / 3; i++) { |
| 474 | dp[i * 3 + 0] = sp[1]; |
| 475 | dp[i * 3 + 1] = sp[2]; |
| 476 | dp[i * 3 + 2] = sp[3]; |
| 477 | } |
| 478 | dp += n; |
| 479 | sp += 1 + 3; |
| 480 | x += n; |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | if (dp < ep) |
| 485 | fz_warn(ctx, "premature end of bitmap data in bmp image" ); |
| 486 | |
| 487 | info->compression = BI_RGB; |
| 488 | info->bitcount = 24; |
| 489 | *end = ep; |
| 490 | return decompressed; |
| 491 | } |
| 492 | |
| 493 | static unsigned char * |
| 494 | bmp_decompress_rle8(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char **end) |
| 495 | { |
| 496 | const unsigned char *sp; |
| 497 | unsigned char *dp, *ep, *decompressed; |
| 498 | int width = info->width; |
| 499 | int height = info->height; |
| 500 | int stride; |
| 501 | int x, i; |
| 502 | |
| 503 | stride = (width + 3) / 4 * 4; |
| 504 | |
| 505 | sp = p; |
| 506 | dp = decompressed = fz_calloc(ctx, height, stride); |
| 507 | ep = dp + height * stride; |
| 508 | x = 0; |
| 509 | |
| 510 | while (sp + 2 <= *end) |
| 511 | { |
| 512 | if (sp[0] == 0 && sp[1] == 0) |
| 513 | { /* end of line */ |
| 514 | if (x < stride) |
| 515 | dp += stride - x; |
| 516 | sp += 2; |
| 517 | x = 0; |
| 518 | } |
| 519 | else if (sp[0] == 0 && sp[1] == 1) |
| 520 | { /* end of bitmap */ |
| 521 | dp = ep; |
| 522 | break; |
| 523 | } |
| 524 | else if (sp[0] == 0 && sp[1] == 2) |
| 525 | { /* delta */ |
| 526 | int deltax, deltay; |
| 527 | if (sp + 4 > *end) |
| 528 | break; |
| 529 | deltax = sp[2]; |
| 530 | deltay = sp[3]; |
| 531 | dp += deltax + deltay * stride; |
| 532 | sp += 4; |
| 533 | x += deltax; |
| 534 | } |
| 535 | else if (sp[0] == 0 && sp[1] >= 3) |
| 536 | { /* absolute */ |
| 537 | int n = sp[1]; |
| 538 | int nn = (n + 1) / 2 * 2; |
| 539 | if (sp + 2 + nn > *end) |
| 540 | break; |
| 541 | if (dp + n > ep) { |
| 542 | fz_warn(ctx, "buffer overflow in bitmap data in bmp image" ); |
| 543 | break; |
| 544 | } |
| 545 | sp += 2; |
| 546 | for (i = 0; i < n; i++) |
| 547 | dp[i] = sp[i]; |
| 548 | dp += n; |
| 549 | sp += (n + 1) / 2 * 2; |
| 550 | x += n; |
| 551 | } |
| 552 | else |
| 553 | { /* encoded */ |
| 554 | int n = sp[0]; |
| 555 | if (dp + n > ep) { |
| 556 | fz_warn(ctx, "buffer overflow in bitmap data in bmp image" ); |
| 557 | break; |
| 558 | } |
| 559 | for (i = 0; i < n; i++) |
| 560 | dp[i] = sp[1]; |
| 561 | dp += n; |
| 562 | sp += 2; |
| 563 | x += n; |
| 564 | } |
| 565 | } |
| 566 | |
| 567 | if (dp < ep) |
| 568 | fz_warn(ctx, "premature end of bitmap data in bmp image" ); |
| 569 | |
| 570 | info->compression = BI_RGB; |
| 571 | info->bitcount = 8; |
| 572 | *end = ep; |
| 573 | return decompressed; |
| 574 | } |
| 575 | |
| 576 | static unsigned char * |
| 577 | bmp_decompress_rle4(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char **end) |
| 578 | { |
| 579 | const unsigned char *sp; |
| 580 | unsigned char *dp, *ep, *decompressed; |
| 581 | int width = info->width; |
| 582 | int height = info->height; |
| 583 | int stride; |
| 584 | int i, x; |
| 585 | |
| 586 | stride = ((width + 1) / 2 + 3) / 4 * 4; |
| 587 | |
| 588 | sp = p; |
| 589 | dp = decompressed = fz_calloc(ctx, height, stride); |
| 590 | ep = dp + height * stride; |
| 591 | x = 0; |
| 592 | |
| 593 | while (sp + 2 <= *end) |
| 594 | { |
| 595 | if (sp[0] == 0 && sp[1] == 0) |
| 596 | { /* end of line */ |
| 597 | int xx = x / 2; |
| 598 | if (xx < stride) |
| 599 | dp += stride - xx; |
| 600 | sp += 2; |
| 601 | x = 0; |
| 602 | } |
| 603 | else if (sp[0] == 0 && sp[1] == 1) |
| 604 | { /* end of bitmap */ |
| 605 | dp = ep; |
| 606 | break; |
| 607 | } |
| 608 | else if (sp[0] == 0 && sp[1] == 2) |
| 609 | { /* delta */ |
| 610 | int deltax, deltay, startlow; |
| 611 | if (sp + 4 > *end) |
| 612 | break; |
| 613 | deltax = sp[2]; |
| 614 | deltay = sp[3]; |
| 615 | startlow = x & 1; |
| 616 | dp += (deltax + startlow) / 2 + deltay * stride; |
| 617 | sp += 4; |
| 618 | x += deltax; |
| 619 | } |
| 620 | else if (sp[0] == 0 && sp[1] >= 3) |
| 621 | { /* absolute */ |
| 622 | int n = sp[1]; |
| 623 | int nn = ((n + 1) / 2 + 1) / 2 * 2; |
| 624 | if (sp + 2 + nn > *end) |
| 625 | break; |
| 626 | if (dp + n / 2 > ep) { |
| 627 | fz_warn(ctx, "buffer overflow in bitmap data in bmp image" ); |
| 628 | break; |
| 629 | } |
| 630 | sp += 2; |
| 631 | for (i = 0; i < n; i++, x++) |
| 632 | { |
| 633 | int val = i & 1 ? (sp[i/2]) & 0xF : (sp[i/2] >> 4) & 0xF; |
| 634 | if (x & 1) |
| 635 | *dp++ |= val; |
| 636 | else |
| 637 | *dp |= val << 4; |
| 638 | } |
| 639 | sp += nn; |
| 640 | } |
| 641 | else |
| 642 | { /* encoded */ |
| 643 | int n = sp[0]; |
| 644 | int hi = (sp[1] >> 4) & 0xF; |
| 645 | int lo = sp[1] & 0xF; |
| 646 | if (dp + n / 2 + (x & 1) > ep) { |
| 647 | fz_warn(ctx, "buffer overflow in bitmap data in bmp image" ); |
| 648 | break; |
| 649 | } |
| 650 | for (i = 0; i < n; i++, x++) |
| 651 | { |
| 652 | int val = i & 1 ? lo : hi; |
| 653 | if (x & 1) |
| 654 | *dp++ |= val; |
| 655 | else |
| 656 | *dp |= val << 4; |
| 657 | } |
| 658 | sp += 2; |
| 659 | } |
| 660 | } |
| 661 | |
| 662 | info->compression = BI_RGB; |
| 663 | info->bitcount = 4; |
| 664 | *end = ep; |
| 665 | return decompressed; |
| 666 | } |
| 667 | |
| 668 | static fz_pixmap * |
| 669 | bmp_read_bitmap(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end) |
| 670 | { |
| 671 | const int mults[] = { 0, 8191, 2730, 1170, 546, 264, 130, 64 }; |
| 672 | fz_pixmap *pix; |
| 673 | const unsigned char *ssp; |
| 674 | unsigned char *ddp; |
| 675 | unsigned char *decompressed = NULL; |
| 676 | int bitcount, width, height; |
| 677 | int sstride, dstride; |
| 678 | int rmult, gmult, bmult, amult; |
| 679 | int rtrunc, gtrunc, btrunc, atrunc; |
| 680 | int x, y; |
| 681 | |
| 682 | if (info->compression == BI_RLE8) |
| 683 | ssp = decompressed = bmp_decompress_rle8(ctx, info, p, &end); |
| 684 | else if (info->compression == BI_RLE4) |
| 685 | ssp = decompressed = bmp_decompress_rle4(ctx, info, p, &end); |
| 686 | else if (info->compression == BI_RLE24) |
| 687 | ssp = decompressed = bmp_decompress_rle24(ctx, info, p, &end); |
| 688 | else |
| 689 | ssp = p; |
| 690 | |
| 691 | bitcount = info->bitcount; |
| 692 | width = info->width; |
| 693 | height = info->height; |
| 694 | |
| 695 | sstride = ((width * bitcount + 31) / 32) * 4; |
| 696 | |
| 697 | if (ssp + sstride * height > end) |
| 698 | { |
| 699 | fz_free(ctx, decompressed); |
| 700 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in bitmap data in bmp image" ); |
| 701 | } |
| 702 | |
| 703 | fz_try(ctx) |
| 704 | pix = fz_new_pixmap(ctx, fz_device_rgb(ctx), width, height, NULL, 1); |
| 705 | fz_catch(ctx) |
| 706 | { |
| 707 | fz_free(ctx, decompressed); |
| 708 | fz_rethrow(ctx); |
| 709 | } |
| 710 | |
| 711 | ddp = pix->samples; |
| 712 | dstride = pix->stride; |
| 713 | if (!info->topdown) |
| 714 | { |
| 715 | ddp = pix->samples + (height - 1) * dstride; |
| 716 | dstride = -dstride; |
| 717 | } |
| 718 | |
| 719 | /* These only apply for components in 16-bit and 32-bit mode |
| 720 | 1-bit (1 * 8191) / 32 |
| 721 | 2-bit (3 * 2730) / 32 |
| 722 | 3-bit (7 * 1170) / 32 |
| 723 | 4-bit (15 * 546) / 32 |
| 724 | 5-bit (31 * 264) / 32 |
| 725 | 6-bit (63 * 130) / 32 |
| 726 | 7-bit (127 * 64) / 32 |
| 727 | */ |
| 728 | rmult = info->rbits < 8 ? mults[info->rbits] : 1; |
| 729 | gmult = info->gbits < 8 ? mults[info->gbits] : 1; |
| 730 | bmult = info->bbits < 8 ? mults[info->bbits] : 1; |
| 731 | amult = info->abits < 8 ? mults[info->abits] : 1; |
| 732 | rtrunc = info->rbits < 8 ? 5 : (info->rbits - 8); |
| 733 | gtrunc = info->gbits < 8 ? 5 : (info->gbits - 8); |
| 734 | btrunc = info->bbits < 8 ? 5 : (info->bbits - 8); |
| 735 | atrunc = info->abits < 8 ? 5 : (info->abits - 8); |
| 736 | |
| 737 | for (y = 0; y < height; y++) |
| 738 | { |
| 739 | const unsigned char *sp = ssp + y * sstride; |
| 740 | unsigned char *dp = ddp + y * dstride; |
| 741 | |
| 742 | switch (bitcount) |
| 743 | { |
| 744 | case 32: |
| 745 | for (x = 0; x < width; x++) |
| 746 | { |
| 747 | unsigned int sample = (sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]; |
| 748 | unsigned int r = (sample & info->rmask) >> info->rshift; |
| 749 | unsigned int g = (sample & info->gmask) >> info->gshift; |
| 750 | unsigned int b = (sample & info->bmask) >> info->bshift; |
| 751 | unsigned int a = info->abits == 0 ? 255 : (sample & info->amask) >> info->ashift; |
| 752 | *dp++ = (r * rmult) >> rtrunc; |
| 753 | *dp++ = (g * gmult) >> gtrunc; |
| 754 | *dp++ = (b * bmult) >> btrunc; |
| 755 | *dp++ = info->abits == 0 ? a : (a * amult) >> atrunc; |
| 756 | sp += 4; |
| 757 | } |
| 758 | break; |
| 759 | case 24: |
| 760 | for (x = 0; x < width; x++) |
| 761 | { |
| 762 | *dp++ = sp[2]; |
| 763 | *dp++ = sp[1]; |
| 764 | *dp++ = sp[0]; |
| 765 | *dp++ = 255; |
| 766 | sp += 3; |
| 767 | } |
| 768 | break; |
| 769 | case 16: |
| 770 | for (x = 0; x < width; x++) |
| 771 | { |
| 772 | unsigned int sample = (sp[1] << 8) | sp[0]; |
| 773 | unsigned int r = (sample & info->rmask) >> info->rshift; |
| 774 | unsigned int g = (sample & info->gmask) >> info->gshift; |
| 775 | unsigned int b = (sample & info->bmask) >> info->bshift; |
| 776 | unsigned int a = (sample & info->amask) >> info->ashift; |
| 777 | *dp++ = (r * rmult) >> rtrunc; |
| 778 | *dp++ = (g * gmult) >> gtrunc; |
| 779 | *dp++ = (b * bmult) >> btrunc; |
| 780 | *dp++ = info->abits == 0 ? 255 : (a * amult) >> atrunc; |
| 781 | sp += 2; |
| 782 | } |
| 783 | break; |
| 784 | case 8: |
| 785 | for (x = 0; x < width; x++) |
| 786 | { |
| 787 | *dp++ = info->palette[3 * sp[0] + 0]; |
| 788 | *dp++ = info->palette[3 * sp[0] + 1]; |
| 789 | *dp++ = info->palette[3 * sp[0] + 2]; |
| 790 | *dp++ = 255; |
| 791 | sp++; |
| 792 | } |
| 793 | break; |
| 794 | case 4: |
| 795 | for (x = 0; x < width; x++) |
| 796 | { |
| 797 | int idx; |
| 798 | switch (x & 1) |
| 799 | { |
| 800 | case 0: idx = (sp[0] >> 4) & 0x0f; break; |
| 801 | case 1: idx = (sp[0] >> 0) & 0x0f; sp++; break; |
| 802 | } |
| 803 | *dp++ = info->palette[3 * idx + 0]; |
| 804 | *dp++ = info->palette[3 * idx + 1]; |
| 805 | *dp++ = info->palette[3 * idx + 2]; |
| 806 | *dp++ = 255; |
| 807 | } |
| 808 | break; |
| 809 | case 2: |
| 810 | for (x = 0; x < width; x++) |
| 811 | { |
| 812 | int idx; |
| 813 | switch (x & 3) |
| 814 | { |
| 815 | case 0: idx = (sp[0] >> 6) & 0x03; break; |
| 816 | case 1: idx = (sp[0] >> 4) & 0x03; break; |
| 817 | case 2: idx = (sp[0] >> 2) & 0x03; break; |
| 818 | case 3: idx = (sp[0] >> 0) & 0x03; sp++; break; |
| 819 | } |
| 820 | *dp++ = info->palette[3 * idx + 0]; |
| 821 | *dp++ = info->palette[3 * idx + 1]; |
| 822 | *dp++ = info->palette[3 * idx + 2]; |
| 823 | *dp++ = 255; |
| 824 | } |
| 825 | break; |
| 826 | case 1: |
| 827 | for (x = 0; x < width; x++) |
| 828 | { |
| 829 | int idx; |
| 830 | switch (x & 7) |
| 831 | { |
| 832 | case 0: idx = (sp[0] >> 7) & 0x01; break; |
| 833 | case 1: idx = (sp[0] >> 6) & 0x01; break; |
| 834 | case 2: idx = (sp[0] >> 5) & 0x01; break; |
| 835 | case 3: idx = (sp[0] >> 4) & 0x01; break; |
| 836 | case 4: idx = (sp[0] >> 3) & 0x01; break; |
| 837 | case 5: idx = (sp[0] >> 2) & 0x01; break; |
| 838 | case 6: idx = (sp[0] >> 1) & 0x01; break; |
| 839 | case 7: idx = (sp[0] >> 0) & 0x01; sp++; break; |
| 840 | } |
| 841 | *dp++ = info->palette[3 * idx + 0]; |
| 842 | *dp++ = info->palette[3 * idx + 1]; |
| 843 | *dp++ = info->palette[3 * idx + 2]; |
| 844 | *dp++ = 255; |
| 845 | } |
| 846 | break; |
| 847 | } |
| 848 | } |
| 849 | |
| 850 | fz_free(ctx, decompressed); |
| 851 | fz_premultiply_pixmap(ctx, pix); |
| 852 | return pix; |
| 853 | } |
| 854 | |
| 855 | static fz_pixmap * |
| 856 | bmp_read_image(fz_context *ctx, struct info *info, const unsigned char *p, size_t total, int only_metadata) |
| 857 | { |
| 858 | const unsigned char *begin = p; |
| 859 | const unsigned char *end = p + total; |
| 860 | int size; |
| 861 | |
| 862 | memset(info, 0x00, sizeof (*info)); |
| 863 | |
| 864 | p = bmp_read_file_header(ctx, info, p, end); |
| 865 | |
| 866 | info->filesize = fz_mini(info->filesize, (int)total); |
| 867 | |
| 868 | if (end - p < 4) |
| 869 | fz_throw(ctx, FZ_ERROR_GENERIC, "premature end in bitmap core header in bmp image" ); |
| 870 | size = read32(p + 0); |
| 871 | |
| 872 | if (size == 12) |
| 873 | p = bmp_read_bitmap_core_header(ctx, info, p, end); |
| 874 | else if (size == 40 || size == 52 || size == 56 || size == 108 || size == 124) |
| 875 | { |
| 876 | p = bmp_read_bitmap_info_header(ctx, info, p, end); |
| 877 | if (info->extramasks) |
| 878 | p = bmp_read_extra_masks(ctx, info, p, end); |
| 879 | } |
| 880 | else if (size == 16 || size == 64) |
| 881 | p = bmp_read_bitmap_os2_header(ctx, info, p, end); |
| 882 | else |
| 883 | fz_throw(ctx, FZ_ERROR_GENERIC, "invalid header size (%d) in bmp image" , size); |
| 884 | |
| 885 | maskinfo(info->rmask, &info->rshift, &info->rbits); |
| 886 | maskinfo(info->gmask, &info->gshift, &info->gbits); |
| 887 | maskinfo(info->bmask, &info->bshift, &info->bbits); |
| 888 | maskinfo(info->amask, &info->ashift, &info->abits); |
| 889 | |
| 890 | if (info->width <= 0 || info->width > SHRT_MAX || info->height <= 0 || info->height > SHRT_MAX) |
| 891 | fz_throw(ctx, FZ_ERROR_GENERIC, "dimensions (%d x %d) out of range in bmp image" , |
| 892 | info->width, info->height); |
| 893 | if (info->compression != BI_RGB && info->compression != BI_RLE8 && |
| 894 | info->compression != BI_RLE4 && info->compression != BI_BITFIELDS && |
| 895 | info->compression != BI_JPEG && info->compression != BI_PNG && |
| 896 | info->compression != BI_ALPHABITS && info->compression != BI_RLE24) |
| 897 | fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported compression method (%d) in bmp image" , info->compression); |
| 898 | if ((info->compression == BI_RGB && info->bitcount != 1 && |
| 899 | info->bitcount != 2 && info->bitcount != 4 && |
| 900 | info->bitcount != 8 && info->bitcount != 16 && |
| 901 | info->bitcount != 24 && info->bitcount != 32) || |
| 902 | (info->compression == BI_RLE8 && info->bitcount != 8) || |
| 903 | (info->compression == BI_RLE4 && info->bitcount != 4) || |
| 904 | (info->compression == BI_BITFIELDS && info->bitcount != 16 && info->bitcount != 32) || |
| 905 | (info->compression == BI_JPEG && info->bitcount != 0) || |
| 906 | (info->compression == BI_PNG && info->bitcount != 0) || |
| 907 | (info->compression == BI_ALPHABITS && info->bitcount != 16 && info->bitcount != 32) || |
| 908 | (info->compression == BI_RLE24 && info->bitcount != 24)) |
| 909 | fz_throw(ctx, FZ_ERROR_GENERIC, "invalid bits per pixel (%d) for compression (%d) in bmp image" , |
| 910 | info->bitcount, info->compression); |
| 911 | if (info->rbits < 0 || info->rbits > info->bitcount) |
| 912 | fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported %d bit red mask in bmp image" , info->rbits); |
| 913 | if (info->gbits < 0 || info->gbits > info->bitcount) |
| 914 | fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported %d bit green mask in bmp image" , info->gbits); |
| 915 | if (info->bbits < 0 || info->bbits > info->bitcount) |
| 916 | fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported %d bit blue mask in bmp image" , info->bbits); |
| 917 | if (info->abits < 0 || info->abits > info->bitcount) |
| 918 | fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported %d bit alpha mask in bmp image" , info->abits); |
| 919 | |
| 920 | if (only_metadata) |
| 921 | return NULL; |
| 922 | |
| 923 | if (info->compression == BI_JPEG) |
| 924 | { |
| 925 | if (p - begin < info->offset) |
| 926 | p = begin + info->offset; |
| 927 | return fz_load_jpeg(ctx, p, end - p); |
| 928 | } |
| 929 | else if (info->compression == BI_PNG) |
| 930 | { |
| 931 | if (p - begin < info->offset) |
| 932 | p = begin + info->offset; |
| 933 | return fz_load_png(ctx, p, end - p); |
| 934 | } |
| 935 | else |
| 936 | { |
| 937 | const unsigned char *color_table_end = begin + info->offset; |
| 938 | if (end - begin < info->offset) |
| 939 | color_table_end = end; |
| 940 | p = bmp_read_color_table(ctx, info, p, color_table_end); |
| 941 | |
| 942 | if (p - begin < info->offset) |
| 943 | p = begin + info->offset; |
| 944 | return bmp_read_bitmap(ctx, info, p, end); |
| 945 | } |
| 946 | } |
| 947 | |
| 948 | fz_pixmap * |
| 949 | fz_load_bmp(fz_context *ctx, const unsigned char *p, size_t total) |
| 950 | { |
| 951 | struct info bmp; |
| 952 | fz_pixmap *image; |
| 953 | |
| 954 | image = bmp_read_image(ctx, &bmp, p, total, 0); |
| 955 | image->xres = bmp.xres / (1000.0f / 25.4f); |
| 956 | image->yres = bmp.yres / (1000.0f / 25.4f); |
| 957 | |
| 958 | return image; |
| 959 | } |
| 960 | |
| 961 | void |
| 962 | fz_load_bmp_info(fz_context *ctx, const unsigned char *p, size_t total, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) |
| 963 | { |
| 964 | struct info bmp; |
| 965 | |
| 966 | bmp_read_image(ctx, &bmp, p, total, 1); |
| 967 | |
| 968 | *cspacep = fz_keep_colorspace(ctx, fz_device_rgb(ctx)); |
| 969 | *wp = bmp.width; |
| 970 | *hp = bmp.height; |
| 971 | *xresp = bmp.xres / (1000.0f / 25.4f); |
| 972 | *yresp = bmp.yres / (1000.0f / 25.4f); |
| 973 | } |
| 974 | |