// 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; }
//! Flip a bitmap horizontally (8, 16, 24, 32) bool dib_hflip(CLDIB *dib) { if(dib == NULL) return false; int dibW, dibH, dibB, dibP; dib_get_attr(dib, &dibW, &dibH, &dibB, &dibP); if(dibB < 8) return false; BYTE *dibL, *bufD; bufD= (BYTE*)malloc(dibP); if(bufD == NULL) return false; dibL= dib_get_img(dib); int ix, iy, ib, nb= dibB/8; for(iy=0; iy<dibH; iy++) { memcpy(bufD, dibL, dibP); //# TODO: 1, 4 bpp for(ix=0; ix<dibW; ix++) { for(ib=0; ib<nb; ib++) dibL[ix*nb+ib] = bufD[(dibW-1-ix)*nb+ib]; } dibL += dibP; } free(bufD); return true; }
/*! \param dib DIB to reduce the palette of. Must be paletted. Pixels will be rearranged to match the palette. \param extPal External palette record. \a dib will use this and its own palette. Can be NULL. The new reduced palette goes here too. \return Number of reduced colors, or 0 if not 8bpp. \note The order of colors is the order of appearance, except for the first one. */ int dib_pal_reduce(CLDIB *dib, RECORD *extPal) { // Only for 8bpp (for now) if(dib == NULL || dib_get_bpp(dib) != 8) return 0; int ii, jj, kk, ix, iy; int dibW, dibH, dibP; dib_get_attr(dib, &dibW, &dibH, NULL, &dibP); BYTE *dibD= dib_get_img(dib); // Get palette histogram int histo[256]; memset(histo, 0, sizeof(histo)); for(iy=0; iy<dibH; iy++) for(ix=0; ix<dibW; ix++) histo[dibD[iy*dibP+ix]]++; // Allocate room for new palette and init with ext pal // NOTE: extPal is assumed reduced! // NOTE: double-size for rdxPal for worst-case scenario. // NOTE: the *Clr things are just to make comparisons easier. // pointers ftw! int count; RGBQUAD *rdxPal= (RGBQUAD*)malloc(512*RGB_SIZE); COLORREF *rdxClr= (COLORREF*)rdxPal, *dibClr= (COLORREF*)dib_get_pal(dib); memset(rdxPal, 0, 512*RGB_SIZE); if(extPal != NULL && extPal->data != NULL) { memcpy(rdxPal, extPal->data, rec_size(extPal)); count= extPal->height; } else { rdxClr[0]= dibClr[0]; count= 1; } // PONDER: always keep index 0 ? // Create reduced palette and prep tables for pixel conversion. DWORD srcIdx[PAL_MAX], dstIdx[PAL_MAX]; kk=0; for(ii=0; ii<PAL_MAX; ii++) { if(histo[ii]) { for(jj=0; jj<count; jj++) if(rdxClr[jj] == dibClr[ii]) break; // Match: add color to table if(jj == count) { rdxClr[jj]= dibClr[ii]; count++; } srcIdx[kk]= jj; dstIdx[kk]= ii; kk++; } } // PONDER: what *should* happen if nn > PAL_MAX ? // Fail, trunc or re-quantize? // Update palette and remap pixels memcpy(dibClr, rdxClr, PAL_MAX*RGB_SIZE); dib_pixel_replace(dib, dstIdx, srcIdx, kk); // Update rdxPal's data if(extPal) { extPal->width= RGB_SIZE; extPal->height= count; free(extPal->data); extPal->data= (BYTE*)malloc(count*RGB_SIZE); memcpy(extPal->data, rdxClr, count*RGB_SIZE); } return count; }