/*! \param dib bitmap to flip. * \note This is an in-place flip. */ bool dib_vflip(CLDIB *dib) { BYTE *topL, *botL, *tempD; if(dib == NULL) return false; DWORD dibP= dib_get_pitch(dib), dibH= dib_get_height(dib); tempD= (BYTE*)malloc(dibP); if(tempD == NULL) return false; topL= dib_get_img(dib); botL= topL+dibP*(dibH-1); dibH /= 2; while(dibH--) { memcpy(tempD, topL, dibP); memcpy(topL, botL, dibP); memcpy(botL, tempD, dibP); topL += dibP; botL -= dibP; } free(tempD); return true; }
// CHK: unpadded works // DESC: redimensions/(un)tiles a dib into a column of tiles with // dimensions dstW x tileH. Can also work in reverse (if srcW<dstW) // NOTE: padding pixels may cause problems CLDIB *dib_redim_copy(CLDIB *src, int dstW, int tileH, int tileN) { if(src == NULL) return NULL; int srcW, srcH, srcB, srcP; dib_get_attr(src, &srcW, &srcH, &srcB, &srcP); // Force byte alignment if( (dstW*srcB&7) ) return NULL; // setup redim int srcR= srcW*srcB>>3, dstR= dstW*srcB>>3; // bytes/row RECORD srcRec= { srcR, srcH, dib_get_img(src) }; RECORD dstRec= { dstR, 0, 0 }; int ii; BYTE *srcD= NULL; if(srcR&3) // depad for src { srcD= (BYTE*)malloc(srcR*srcH); if(srcD == NULL) return NULL; for(ii=0; ii<srcH; ii++) memcpy(&srcD[ii*srcR], &srcRec.data[ii*srcP], srcR); srcRec.data= srcD; } bool bOK= data_redim(&srcRec, &dstRec, tileH, tileN); SAFE_FREE(srcD); if(!bOK) return NULL; CLDIB *dst= dib_alloc(dstW, dstRec.height, srcB, NULL, dib_is_topdown(src)); if(dst == NULL) return NULL; int dstH= dib_get_height(dst); // bytes/row int dstP= dib_get_pitch(dst); BYTE *dstD= dib_get_img(dst); if(dstR&3) // repad for dst { for(ii=0; ii<dstH; ii++) memcpy(&dstD[ii*dstP], &dstRec.data[ii*dstR], dstP); } else memcpy(dstD, dstRec.data, dstP*dstH); SAFE_FREE(dstRec.data); memcpy(dib_get_pal(dst), dib_get_pal(src), dib_get_nclrs(src)*RGB_SIZE); return dst; }
bool CBmpFile::Save(const char *fpath) { FILE *fp= NULL; bool bOK= true;; try { if(!mDib) throw CImgFile::sMsgs[ERR_GENERAL]; fp = fopen(fpath, "wb"); if(!fp) throw CImgFile::sMsgs[ERR_NO_FILE]; BITMAPINFOHEADER bmih= *dib_get_hdr(mDib); int dibH= dib_get_height2(mDib), dibHa= dib_get_height(mDib); int dibP= dib_get_pitch(mDib), dibPa= dibP; int dibS= dibHa*dibPa, nclrs= dib_get_nclrs(mDib); bmih.biHeight= dibHa; bmih.biSizeImage= dibS; // fill in fileheader BITMAPFILEHEADER bmfh; bmfh.bfType= BMP_TYPE; bmfh.bfOffBits= sizeof(BITMAPFILEHEADER)+BMIH_SIZE+nclrs*RGB_SIZE; bmfh.bfSize= bmfh.bfOffBits + dibS; bmfh.bfReserved1= bmfh.bfReserved2= 0; // write down header fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, fp); fwrite(&bmih, BMIH_SIZE, 1, fp); // write down palette fwrite(dib_get_pal(mDib), RGB_SIZE, nclrs, fp); // write down rows, with possible flipping BYTE *dibL= dib_get_img(mDib); if(dibH<0) { dibL += (dibHa-1)*dibPa; dibP= -dibP; } for(int iy=0; iy<dibHa; iy++) fwrite(dibL+iy*dibP, dibPa, 1, fp); } catch(const char *msg) { SetMsg(msg); bOK= false; } if(fp) fclose(fp); return bOK; }
// TGA RLE; // * lines are byte-aligned // * RLE can cross lines // * RLE works by the pixel for true clr, by byte for paletted // * The RLE header byte, ch: // ch{0-6} : # chunks -1 // ch{7} : stretch. void tga_unrle(CLDIB *dib, TGAHDR *hdr, FILE *fp) { int ii, ix, iy; int imgW= dib_get_width(dib); int imgH= dib_get_height(dib); int imgB= dib_get_bpp(dib); int imgP= dib_get_pitch(dib); BYTE *imgL= dib_get_img(dib), *imgEnd= imgL+imgH*imgP; int tgaP= (imgW*imgB+7)/8; // pseudo pitch int tgaN= (imgB+7)/8; // chunk size BYTE ch, chunk[4]; ix=0, iy=0; while(1) { ch= fgetc(fp); if(ch>127) // stretch { ch -= 127; fread(chunk, 1, tgaN, fp); while(ch--) { for(ii=0; ii<tgaN; ii++) imgL[ix+ii]= chunk[ii]; ix += tgaN; if(ix >= tgaP) { imgL += imgP; ix= 0; if(imgL >= imgEnd) return; } } } // </stretch> else // no stretch { ch++; while(ch--) { fread(&imgL[ix], 1, tgaN, fp); ix += tgaN; if(ix >= tgaP) { imgL += imgP; ix= 0; if(imgL >= imgEnd) return; } } } // </no stretch> } // </while(1)> }
/*! Similar to \c dib_clone, but can crop the image too. The * boundaries of the new bitmap need not fit inside the source; the * outside parts will be zeroed. * \param src Source bitmap. * \param ll Left of rectangle. * \param tt Top of rectangle. * \param rr Right of rectangle. * \param bb Bottom of rectangle. * \param bClip If \c true, the rectangle will be clipped to the * dimensions of \c src. * \return Copied and cropped bitmap. */ CLDIB *dib_copy(CLDIB *src, int ll, int tt, int rr, int bb, bool bClip) { if(src==NULL || ll==rr || tt==bb) return NULL; int srcW= dib_get_width(src); int srcH= dib_get_height(src); int srcB= dib_get_bpp(src); int srcP= dib_get_pitch(src); // Normalize rect if(rr<ll) { int tmp=ll; ll=rr; rr=tmp; } if(bb<tt) { int tmp=tt; tt=bb; bb=tmp; } // Clip if requested if(bClip) { if(ll<0) ll= 0; if(tt<0) tt= 0; if(rr>srcW) rr= srcW; if(bb>srcH) bb= srcH; } int dstW= rr-ll, dstH= bb-tt; CLDIB *dst= dib_alloc(dstW, dstH, srcB, NULL, true); if(dst==NULL) return NULL; dib_pal_cpy(dst, src); // set base src,dst pointers int dstP= dib_get_pitch(dst); BYTE *srcL= dib_get_img(src), *dstL= dib_get_img(dst); if(ll>=0) // set horz base srcL += ll*srcB>>3; else
//! Get the main attributes of a DIB bool dib_get_attr(CLDIB *dib, int *width, int *height, int *bpp, int *pitch) { if(dib == NULL) return false; if(width) *width= dib_get_width(dib); if(height) *height= dib_get_height(dib); if(bpp) *bpp= dib_get_bpp(dib); if(pitch) *pitch= dib_get_pitch(dib); return true; }
/*! 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; }
bool CTgaFile::Save(const char *fpath) { int ii, iy; FILE *fp= NULL; bool bOK= true; try { if(!mDib) throw CImgFile::sMsgs[ERR_GENERAL]; fp = fopen(fpath, "wb"); if(!fp) throw CImgFile::sMsgs[ERR_NO_FILE]; int imgW= dib_get_width(mDib); int imgH= dib_get_height(mDib), imgHs= dib_get_height2(mDib); int imgP= dib_get_pitch(mDib); int imgB= dib_get_bpp(mDib); int imgS= imgH*imgP, nclrs= dib_get_nclrs(mDib); TGAHDR hdr; memset(&hdr, 0, sizeof(TGAHDR)); if(imgB==1) hdr.type= TGA_BW; else if(imgB <= 8) hdr.type= TGA_PAL; else hdr.type= TGA_true; if(imgB<=8) // paletted { hdr.has_table= 1; hdr.pal_len= dib_get_nclrs(mDib); hdr.pal_bpp= 24; } else // true color hdr.has_table=0; hdr.width= imgW; hdr.height= imgH; hdr.img_bpp= imgB; hdr.img_desc= 0; fwrite(&hdr, 1, sizeof(TGAHDR), fp); // write palette if(imgB <= 8) { RGBQUAD *pal= dib_get_pal(mDib); for(ii=0; ii<hdr.pal_len; ii++) fwrite(&pal[ii], 1, 3, fp); } // TGA should be bottom up: BYTE *imgL= dib_get_img(mDib); if(dib_is_topdown(mDib)) { imgL += imgP*(imgH-1); imgP= -imgP; } // write image (not RLEd, because that's awful to do) int tgaP= (imgW*imgB+7)/8; for(iy=0; iy<imgH; iy++) fwrite(&imgL[iy*imgP], 1, tgaP, fp); } catch(const char *msg) { SetMsg(msg); bOK= false; } if(fp) fclose(fp); return bOK; }
/*! \note Works at the byte level. If you have sub-8 bpps, you'll * still have to shift a bit. */ BYTE *dib_get_img_at(CLDIB *dib, int x, int y) { BYTE *dibD= dib_get_img(dib); return &dibD[x*dib_get_bpp(dib)/8 + y*dib_get_pitch(dib)]; }