/*! Prepares the work dib for export, i.e. converts to the final bitdepth, compresses the data and fills in \a gr._gfxRec. */ bool grit_prep_gfx(GritRec *gr) { lprintf(LOG_STATUS, "Graphics preparation.\n"); int srcB= dib_get_bpp(gr->_dib); // should be 8 or 16 by now int srcP= dib_get_pitch(gr->_dib); int srcS= dib_get_size_img(gr->_dib); BYTE *srcD= dib_get_img(gr->_dib); int dstB= gr->gfxBpp; // # dst bytes, with # src pixels as 'width' int dstS= dib_align(srcS*8/srcB, dstB); dstS= ALIGN4(dstS); BYTE *dstD= (BYTE*)malloc(dstS); if(dstD == NULL) { lprintf(LOG_ERROR, " Can't allocate graphics data.\n"); return false; } // Convert to final bitdepth // NOTE: do not use dib_convert here, because of potential // problems with padding // NOTE: we're already at 8 or 16 bpp here, with 16 bpp already // accounted for. Only have to do 8->1,2,4 // TODO: offset if(srcB == 8 && srcB != dstB) { lprintf(LOG_STATUS, " Bitpacking: %d -> %d.\n", srcB, dstB); data_bit_pack(dstD, srcD, srcS, srcB, dstB, 0); } else memcpy(dstD, srcD, dstS); RECORD rec= { 1, dstS, dstD }; if( BYTE_ORDER == BIG_ENDIAN && gr->gfxBpp > 8 ) data_byte_rev(rec.data, rec.data, rec_size(&rec), gr->gfxBpp/8); // attach and compress graphics grit_compress(&rec, &rec, gr->gfxCompression); rec_alias(&gr->_gfxRec, &rec); lprintf(LOG_STATUS, "Graphics preparation complete.\n"); return true; }
// xxx_load(const char *fname, PDIBDATA *ppdib, IMG_FMT_INFO *pifi) bool CTgaFile::Load(const char *fpath) { FILE *fp= fopen(fpath, "rb"); CLDIB *dib= NULL; TGAHDR hdr; try { if(!fp) throw CImgFile::sMsgs[ERR_NO_FILE]; fread(&hdr, sizeof(TGAHDR), 1, fp); // ignore image desc (if any) fseek(fp, hdr.id_len, SEEK_CUR); int imgW, imgH, imgB, imgP; imgW= hdr.width; imgH= hdr.height; imgB= hdr.img_bpp; imgP= dib_align(imgW, imgB); // Set-up the full bitmap dib= dib_alloc(imgW, imgH, imgB, NULL, true); if(dib == NULL) throw CImgFile::sMsgs[ERR_ALLOC]; // === get color map === if(hdr.has_table) { if(!tga_read_pal(dib, &hdr, fp)) throw sMsgs[ERR_TGA_BADPAL]; } int ii; int tgaP= (imgW*imgB+7)/8; BYTE *imgD= dib_get_img(dib); switch(hdr.type) { case TGA_BW: case TGA_PAL: case TGA_true: for(ii=0; ii<imgH; ii++) fread(&imgD[ii*imgP], 1, tgaP, fp); break; case TGA_BW_RLE: case TGA_PAL_RLE: case TGA_true_RLE: tga_unrle(dib, &hdr, fp); break; default: throw sMsgs[ERR_TGA_VERSION]; } // TGA's are bottom-up by default, flip if necessary if(~hdr.img_desc & TGA_VFLIP) dib_vflip(dib); } // </try> catch(const char *msg) { SetMsg(msg); dib_free(dib); dib= NULL; } // cleanup if(!dib) return false; // if we're here we've succeeded SetMsg(CImgFile::sMsgs[ERR_NONE]); dib_free(Attach(dib)); SetBpp(dib_get_bpp(dib)); SetPath(fpath); return true; }
// Yes, you can use LoadImage too, but that creates a device // dependent bitmap and you want to stay the fsck away from those. bool CBmpFile::Load(const char *fpath) { FILE *fp= fopen(fpath, "rb"); CLDIB *dib= NULL; try { if(!fp) throw CImgFile::sMsgs[ERR_NO_FILE]; BITMAPFILEHEADER bmfh; fread(&bmfh, sizeof(BITMAPFILEHEADER), 1,fp); // Whoa, not a bitmap, back off if(bmfh.bfType != BMP_TYPE) // 4D42h = "BM". throw CImgFile::sMsgs[ERR_FORMAT]; BITMAPINFOHEADER bmih; bool bCore; // check for bm version first :( fread(&bmih, 4, 1, fp); if(bmih.biSize == sizeof(BITMAPCOREHEADER)) // crap! v2.x BMP { bCore= true; bmih.biSize= BMIH_SIZE; WORD wd; fread(&wd, 2,1,fp); bmih.biWidth= wd; fread(&wd, 2,1,fp); bmih.biHeight= wd; fread(&bmih.biPlanes, 2,1,fp); fread(&bmih.biBitCount, 2,1,fp); memset(&bmih.biCompression, 0, BMIH_SIZE-sizeof(BITMAPCOREHEADER)); } else // normal v3.0 BMP fread(&bmih.biWidth, BMIH_SIZE-4, 1, fp); if(bmih.biPlanes > 1) // no color planes, plz throw sMsgs[ERR_BMP_PLANES]; if(bmih.biCompression != BI_RGB) // no compression either throw sMsgs[ERR_BMP_CPRS]; int dibP, dibHa, dibS; dibHa= abs(bmih.biHeight); dibP= dib_align(bmih.biWidth, bmih.biBitCount); dibS= dibP*dibHa; // set manually, just to be sure bmih.biSizeImage= dibS; // ditto for ClrUsed if(bmih.biBitCount <=8 && bmih.biClrUsed == 0) bmih.biClrUsed= 1<<bmih.biBitCount; // now we set-up the full bitmap dib= dib_alloc(bmih.biWidth, dibHa, bmih.biBitCount, NULL, true); if(dib == NULL) throw CImgFile::sMsgs[ERR_ALLOC]; // read the palette fread(dib_get_pal(dib), RGB_SIZE, bmih.biClrUsed, fp); // read image fread(dib_get_img(dib), dibS, 1, fp); if(bmih.biHeight>=0) // -> TD image dib_vflip(dib); } // </try> catch(const char *msg) { SetMsg(msg); dib_free(dib); dib= NULL; } if(fp) fclose(fp); if(!dib) return false; // if we're here we've succeeded SetMsg(CImgFile::sMsgs[ERR_NONE]); dib_free(Attach(dib)); SetBpp(dib_get_bpp(dib)); SetPath(fpath); return true; }
/*! \param width Bitmap width * \param height Bitmap height * \param bpp Bitmap bitdepth (1, 4, 8, 16, 24, 32) * \param data Data to fill the bitmap with. If \c NULL, data will * be uninitialized. * \param bTopDown If \c true, the bitmap will be top-down (origin in * the top-left); if \c false, it'll be bottom up. Windows bitmaps * are traditionally bottom-up, with all the awkwardness that goes * with it (as matrices and screens are usually top-down). * \c CLDIBs are top-down by default. * \note Always call \c dib_free() on bitmaps when you're done with it. */ CLDIB *dib_alloc(int width, int height, int bpp, const BYTE *data, bool bTopDown /* true */) { int ii; CLDIB *dib= NULL; // check validity of requested bpp const int bpp_allowed[6]= { 1, 4, 8, 16, 24, 32 }; for(ii=0; ii<6; ii++) if(bpp == bpp_allowed[ii]) break; if(ii >= 6) return NULL; int nclrs, dibH, dibP, dibS; nclrs= (bpp > 8 ? 0 : 1<<bpp); dibH= height; dibP= dib_align(width, bpp); dibS= dibP*dibH; // create in two stages, first the dib itself, and then for the data // and conk out if either fails dib= (CLDIB*)malloc(sizeof(CLDIB)); if(dib == NULL) return NULL; dib->data= (BYTE*)malloc(BMIH_SIZE + nclrs*RGB_SIZE + dibS); if(dib->data == NULL) { free(dib); return NULL; } BITMAPINFOHEADER *bmih= dib_get_hdr(dib); bmih->biSize= BMIH_SIZE; bmih->biWidth= width; bmih->biHeight= bTopDown ? -height : height; bmih->biPlanes= 1; bmih->biBitCount= bpp; bmih->biCompression= 0; bmih->biSizeImage= dibS; bmih->biXPelsPerMeter= 0; bmih->biYPelsPerMeter= 0; bmih->biClrUsed= nclrs; bmih->biClrImportant= 0; // init palette, all reds, corresponding to COLORREFs [0-nclrs> // PONDER: is this right? COLORREF *clr= (COLORREF*)dib_get_pal(dib); for(ii=0; ii<nclrs; ii++) clr[ii]= ii<<16; // init data if(data != NULL) { if(bTopDown) memcpy(dib_get_img(dib), data, dibS); else { const BYTE *srcL= &data[(height-1)*dibP]; BYTE *dstL= dib_get_img(dib); for(ii=0; ii<height; ii++) memcpy(&dstL[ii*dibP], &srcL[-ii*dibP], dibP); } } return dib; }