gdispImageError gdispImageOpenGFile(gdispImage *img, GFILE *f) { gdispImageError err; if (!f) return GDISP_IMAGE_ERR_NOSUCHFILE; img->f = f; img->bgcolor = White; for(img->fns = ImageHandlers; img->fns < ImageHandlers+sizeof(ImageHandlers)/sizeof(ImageHandlers[0]); img->fns++) { err = img->fns->open(img); if (err != GDISP_IMAGE_ERR_BADFORMAT) { if ((err & GDISP_IMAGE_ERR_UNRECOVERABLE)) goto unrecoverable; // Everything is possible return err; } // Try the next decoder gfileSetPos(img->f, 0); } err = GDISP_IMAGE_ERR_BADFORMAT; img->type = GDISP_IMAGE_TYPE_UNKNOWN; unrecoverable: gfileClose(img->f); img->f = 0; img->flags = 0; img->fns = 0; img->priv = 0; return err; }
int gstdioSeek(FILE *f, size_t offset, int origin) { switch(origin) { case SEEK_SET: break; case SEEK_CUR: offset += f->pos; break; case SEEK_END: offset += gfileGetSize(f); break; default: return -1; } return gfileSetPos(f, offset) ? 0 : -1; }
gdispImageError gdispGImageDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { coord_t mx, mcx; size_t pos, len; gdispImagePrivate_NATIVE * priv; priv = (gdispImagePrivate_NATIVE *)img->priv; /* Check some reasonableness */ if (sx >= img->width || sy >= img->height) return GDISP_IMAGE_ERR_OK; if (sx + cx > img->width) cx = img->width - sx; if (sy + cy > img->height) cy = img->height - sy; /* Draw from the image cache - if it exists */ if (priv->frame0cache) { gdispGBlitArea(g, x, y, cx, cy, sx, sy, img->width, priv->frame0cache); return GDISP_IMAGE_ERR_OK; } /* For this image decoder we cheat and just seek straight to the region we want to display */ pos = FRAME0POS_NATIVE + (img->width * sy + sx) * sizeof(pixel_t); /* Cycle through the lines */ for(;cy;cy--, y++) { /* Move to the start of the line */ gfileSetPos(img->f, pos); /* Draw the line in chunks using BitBlt */ for(mx = x, mcx = cx; mcx > 0; mcx -= len, mx += len) { // Read the data len = gfileRead(img->f, priv->buf, mcx > BLIT_BUFFER_SIZE_NATIVE ? (BLIT_BUFFER_SIZE_NATIVE*sizeof(pixel_t)) : (mcx * sizeof(pixel_t))) / sizeof(pixel_t); if (!len) return GDISP_IMAGE_ERR_BADDATA; /* Blit the chunk of data */ gdispGBlitArea(g, mx, y, len, 1, 0, 0, len, priv->buf); } /* Get the position for the start of the next line */ pos += img->width*sizeof(pixel_t); } return GDISP_IMAGE_ERR_OK; }
gdispImageError gdispImageCache_NATIVE(gdispImage *img) { size_t len; gdispImagePrivate_NATIVE * priv; /* If we are already cached - just return OK */ priv = (gdispImagePrivate_NATIVE *)img->priv; if (priv->frame0cache) return GDISP_IMAGE_ERR_OK; /* We need to allocate the cache */ len = img->width * img->height * sizeof(pixel_t); priv->frame0cache = (pixel_t *)gdispImageAlloc(img, len); if (!priv->frame0cache) return GDISP_IMAGE_ERR_NOMEMORY; /* Read the entire bitmap into cache */ gfileSetPos(img->f, FRAME0POS_NATIVE); if (gfileRead(img->f, priv->frame0cache, len) != len) return GDISP_IMAGE_ERR_BADDATA; return GDISP_IMAGE_ERR_OK; }
gdispImageError gdispImageOpen_BMP(gdispImage *img) { gdispImagePrivate *priv; uint8_t hdr[2]; uint16_t aword; uint32_t adword; uint32_t offsetColorTable; /* Read the file identifier */ if (gfileRead(img->f, hdr, 2) != 2) return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us /* Process the BITMAPFILEHEADER structure */ /** * We only accept Windows V2+ bitmaps. * - we don't support OS/2 bitmaps, icons, pointers, or Windows V1 bitmaps. */ if (hdr[0] != 'B' || hdr[1] != 'M') return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us /* We know we are a BMP format image */ img->flags = 0; /* Allocate our private area */ if (!(img->priv = (gdispImagePrivate *)gdispImageAlloc(img, sizeof(gdispImagePrivate)))) return GDISP_IMAGE_ERR_NOMEMORY; /* Initialise the essential bits in the private area */ priv = img->priv; priv->frame0cache = 0; priv->bmpflags = 0; #if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE priv->palette = 0; #endif /* Skip the size field and the 2 reserved fields */ if (gfileRead(img->f, priv->buf, 8) != 8) goto baddatacleanup; /* Get the offset to the bitmap data */ if (gfileRead(img->f, &priv->frame0pos, 4) != 4) goto baddatacleanup; CONVERT_FROM_DWORD_LE(priv->frame0pos); /* Process the BITMAPCOREHEADER structure */ /* Get the offset to the colour data */ if (gfileRead(img->f, &offsetColorTable, 4) != 4) goto baddatacleanup; CONVERT_FROM_DWORD_LE(offsetColorTable); offsetColorTable += 14; // Add the size of the BITMAPFILEHEADER // Detect our bitmap version if (offsetColorTable == 12+14) { img->priv->bmpflags |= BMP_V2; // Read the header if (gfileRead(img->f, priv->buf, 12-4) != 12-4) goto baddatacleanup; // Get the width img->width = *(uint16_t *)(((uint8_t *)priv->buf)+0); CONVERT_FROM_WORD_LE(img->width); // Get the height img->height = *(uint16_t *)(((uint8_t *)priv->buf)+2); CONVERT_FROM_WORD_LE(img->height); if (img->height < 0) { img->priv->bmpflags |= BMP_TOP_TO_BOTTOM; img->height = -img->height; } // Get the planes aword = *(uint16_t *)(((uint8_t *)priv->buf)+4); CONVERT_FROM_WORD_LE(aword); if (aword != 1) goto unsupportedcleanup; // Get the bits per pixel aword = *(uint16_t *)(((uint8_t *)priv->buf)+6); CONVERT_FROM_WORD_LE(aword); switch(aword) { #if GDISP_NEED_IMAGE_BMP_1 case 1: #endif #if GDISP_NEED_IMAGE_BMP_4 case 4: #endif #if GDISP_NEED_IMAGE_BMP_8 case 8: #endif #if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_8 priv->bmpflags |= BMP_PALETTE; priv->palsize = 1<<aword; break; #endif #if GDISP_NEED_IMAGE_BMP_24 case 24: break; #endif default: goto unsupportedcleanup; } priv->bitsperpixel = aword; } else if (offsetColorTable >= 40+14) { if (offsetColorTable > 40+14) priv->bmpflags |= BMP_V4; // Read the header if (gfileRead(img->f, priv->buf, 40-4) != 40-4) goto baddatacleanup; // Get the width adword = *(uint32_t *)(((uint8_t *)priv->buf)+0); CONVERT_FROM_DWORD_LE(adword); if (adword > 32768) // This also picks up negative values goto unsupportedcleanup; img->width = adword; // Get the height adword = *(uint32_t *)(((uint8_t *)priv->buf)+4); CONVERT_FROM_DWORD_LE(adword); if ((int32_t)adword < 0) { // Negative test priv->bmpflags |= BMP_TOP_TO_BOTTOM; adword = -adword; } if (adword > 32768) goto unsupportedcleanup; img->height = adword; // Get the planes aword = *(uint16_t *)(((uint8_t *)priv->buf)+8); CONVERT_FROM_WORD_LE(aword); if (aword != 1) goto unsupportedcleanup; // Get the bits per pixel aword = *(uint16_t *)(((uint8_t *)priv->buf)+10); CONVERT_FROM_WORD_LE(aword); switch(aword) { #if GDISP_NEED_IMAGE_BMP_1 case 1: #endif #if GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE case 4: #endif #if GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE case 8: #endif #if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE priv->bmpflags |= BMP_PALETTE; priv->palsize = 1<<aword; break; #endif #if GDISP_NEED_IMAGE_BMP_16 case 16: #endif #if GDISP_NEED_IMAGE_BMP_24 case 24: #endif #if GDISP_NEED_IMAGE_BMP_32 case 32: #endif #if GDISP_NEED_IMAGE_BMP_16 || GDISP_NEED_IMAGE_BMP_24 || GDISP_NEED_IMAGE_BMP_32 break; #endif default: goto unsupportedcleanup; } priv->bitsperpixel = aword; // Get the compression adword = *(uint32_t *)(((uint8_t *)priv->buf)+12); CONVERT_FROM_DWORD_LE(adword); switch(adword) { case 0: // BI_RGB - uncompressed break; #if GDISP_NEED_IMAGE_BMP_8_RLE case 1: // BI_RLE8 compression if (priv->bitsperpixel != 8) goto unsupportedcleanup; priv->bmpflags |= BMP_COMP_RLE; break; #endif #if GDISP_NEED_IMAGE_BMP_4_RLE case 2: // BI_RLE4 compression if (priv->bitsperpixel != 4) goto unsupportedcleanup; priv->bmpflags |= BMP_COMP_RLE; break; #endif #if GDISP_NEED_IMAGE_BMP_16 || GDISP_NEED_IMAGE_BMP_32 case 3: // BI_BITFIELDS decoding if (priv->bitsperpixel < 16 || priv->bitsperpixel == 24) goto unsupportedcleanup; priv->bmpflags |= BMP_COMP_MASK; if (priv->bmpflags & BMP_V4) // V4 stored the masks in the header offsetColorTable = 40+14; break; #endif default: goto unsupportedcleanup; } priv->bitsperpixel = aword; #if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE // Get the actual colors used adword = *(uint32_t *)(((uint8_t *)priv->buf)+28); CONVERT_FROM_DWORD_LE(adword); if (adword && adword < priv->palsize) priv->palsize = adword; #endif } else goto baddatacleanup; #if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE /* Load the palette tables */ if (priv->bmpflags & BMP_PALETTE) { gfileSetPos(img->f, offsetColorTable); if (!(priv->palette = (color_t *)gdispImageAlloc(img, priv->palsize*sizeof(color_t)))) return GDISP_IMAGE_ERR_NOMEMORY; if (priv->bmpflags & BMP_V2) { for(aword = 0; aword < priv->palsize; aword++) { if (gfileRead(img->f, &priv->buf, 3) != 3) goto baddatacleanup; priv->palette[aword] = RGB2COLOR(((uint8_t *)priv->buf)[2], ((uint8_t *)priv->buf)[1], ((uint8_t *)priv->buf)[0]); } } else { for(aword = 0; aword < priv->palsize; aword++) { if (gfileRead(img->f, &priv->buf, 4) != 4) goto baddatacleanup; priv->palette[aword] = RGB2COLOR(((uint8_t *)priv->buf)[2], ((uint8_t *)priv->buf)[1], ((uint8_t *)priv->buf)[0]); } } } #endif #if GDISP_NEED_IMAGE_BMP_16 || GDISP_NEED_IMAGE_BMP_32 /* Load the bit masks */ if (priv->bmpflags & BMP_COMP_MASK) { gfileSetPos(img->f, offsetColorTable); if (gfileRead(img->f, &priv->maskred, 4) != 4) goto baddatacleanup; CONVERT_FROM_DWORD_LE(priv->maskred); if (gfileRead(img->f, &priv->maskgreen, 4) != 4) goto baddatacleanup; CONVERT_FROM_DWORD_LE(priv->maskgreen); if (gfileRead(img->f, &priv->maskblue, 4) != 4) goto baddatacleanup; CONVERT_FROM_DWORD_LE(priv->maskblue); if (priv->bmpflags & BMP_V4) { if (gfileRead(img->f, &priv->maskalpha, 4) != 4) goto baddatacleanup; CONVERT_FROM_DWORD_LE(priv->maskalpha); } else priv->maskalpha = 0; } else if (priv->bitsperpixel == 16) { priv->bmpflags |= BMP_COMP_MASK; priv->maskred = 0x7C00; priv->maskgreen = 0x03E0; priv->maskblue = 0x001F; priv->maskalpha = 0; } else if (priv->bitsperpixel == 32) { priv->bmpflags |= BMP_COMP_MASK; priv->maskred = 0x00FF0000; priv->maskgreen = 0x0000FF00; priv->maskblue = 0x000000FF; priv->maskalpha = 0; } /* We need to adjust the masks and calculate the shift values so the result scales 0 -> 255 */ if (priv->bmpflags & BMP_COMP_MASK) { priv->shiftred = 0; priv->shiftgreen = 0; priv->shiftblue = 0; if (priv->maskred) { if (priv->maskred < 256) for(adword = priv->maskred; adword < 128; priv->shiftred--, adword <<= 1); else for(adword = priv->maskred; adword > 255; priv->shiftred++, adword >>= 1); } if (priv->maskgreen) { if (priv->maskgreen < 256) for(adword = priv->maskgreen; adword < 128; priv->shiftgreen--, adword <<= 1); else for(adword = priv->maskgreen; adword > 255; priv->shiftgreen++, adword >>= 1); } if (priv->maskblue) { if (priv->maskblue < 256) for(adword = priv->maskblue; adword < 128; priv->shiftblue--, adword <<= 1); else for(adword = priv->maskblue; adword > 255; priv->shiftblue++, adword >>= 1); } if (priv->maskalpha) { if (priv->maskalpha < 256) for(adword = priv->maskalpha; adword < 128; priv->shiftalpha--, adword <<= 1); else for(adword = priv->maskalpha; adword > 255; priv->shiftalpha++, adword >>= 1); } }