hschumann2/TempleOS-Source-Code
0847
1 2#help_index "Graphics/Windows BMP Files"3 4#define BMP_COLORS_NUM 165 6class CFileBMP7{8 U16 type;9 U32 file_size;10 U32 reserved;11 U32 data_offset;12 13 U32 header_size;14 U32 width;15 U32 height;16 U16 planes;17 U16 bit_cnt;18 U32 compression;19 U32 image_size;20 U32 x_pixs_per_meter;21 U32 y_pixs_per_meter;22 U32 colors_used;23 U32 important_colors;24 25 U0 end;26 27 CBGR24 palette[BMP_COLORS_NUM];28};29 30public CFileBMP *BMP4To(CDC *dc)31{//To Windows 4-bit BMP.32 U8 *src,*ptr;33 CBGR48 palette[COLORS_NUM];34 I64 i,x,y,w=dc->width>>1,35 size=sizeof(CFileBMP)+dc->width*dc->height>>1;36 CFileBMP *bmp =CAlloc(size);37 bmp->type ='BM';38 bmp->planes =1;39 bmp->file_size =size;40 bmp->data_offset=sizeof(CFileBMP);41 bmp->header_size=offset(CFileBMP.end)-offset(CFileBMP.header_size);42 bmp->width =dc->width;43 bmp->height =dc->height;44 bmp->bit_cnt =4;45 bmp->image_size =dc->width*dc->height>>1;46 GrPaletteGet(palette);47#assert COLORS_NUM==BMP_COLORS_NUM48 for (i=0;i<BMP_COLORS_NUM;i++) {49 bmp->palette[i].b=palette[i].b>>8;50 bmp->palette[i].g=palette[i].g>>8;51 bmp->palette[i].r=palette[i].r>>8;52 bmp->palette[i].pad=0;53 }54 ptr=bmp(U8 *)+bmp->data_offset;55 for (y=dc->height-1;y>=0;y--) {56 src=y*dc->width_internal+dc->body;57 for (x=0;x<w;x++) {58 *ptr|=(*src++&15)<<4;59 *ptr|=*src++&15;60 ptr++;61 }62 }63 return bmp;64}65 66public CFileBMP *BMPRLE4To(CDC *dc)67{//To Windows RLE4 bit BMP.68 U8 *src,*ptr,*start;69 I64 i,x,y,w=dc->width,cnt,pattern;70 CBGR48 palette[COLORS_NUM];71 CFileBMP *bmp =CAlloc(sizeof(CFileBMP)+2*(dc->width+1)*dc->height);72 bmp->type ='BM';73 bmp->planes =1;74 bmp->data_offset=sizeof(CFileBMP);75 bmp->header_size=offset(CFileBMP.end)-offset(CFileBMP.header_size);76 bmp->width =dc->width;77 bmp->height =dc->height;78 bmp->bit_cnt =4;79 bmp->compression=2; //RLE480 GrPaletteGet(palette);81#assert COLORS_NUM==BMP_COLORS_NUM82 for (i=0;i<BMP_COLORS_NUM;i++) {83 bmp->palette[i].b=palette[i].b>>8;84 bmp->palette[i].g=palette[i].g>>8;85 bmp->palette[i].r=palette[i].r>>8;86 bmp->palette[i].pad=0;87 }88 start=ptr=bmp(U8 *)+bmp->data_offset;89 for (y=dc->height-1;y>=0;y--) {90 src=y*dc->width_internal+dc->body;91 x=0;92 while (x<w) {93 pattern=(src[0]&15)<<4+src[1]&15;94 if (x+1<w && src[0]&15==src[1]&15) {95 src+=2;96 cnt=2;97 x+=2;98 while (x<w && cnt<U8_MAX) {99 if (*src&15==pattern&15) {100 src++;101 cnt++;102 x++;103 } else104 break;105 }106 } else {107 src+=2;108 if (x+1<w)109 cnt=2;110 else111 cnt=1;112 x+=2;113 }114 *ptr++=cnt;115 *ptr++=pattern;116 }117 *ptr(U16 *)++=0;118 }119 bmp->image_size=ptr-start;120 bmp->file_size=sizeof(CFileBMP)+bmp->image_size;121 return bmp;122}123 124public CFileBMP *BMP24To(CDC *dc)125{//To Windows 24-bit BMP.126 U8 *src;127 I64 i,x,y,size=offset(CFileBMP.end)+dc->width*dc->height*sizeof(CBGR24);128 CBGR24 *bgr;129 CFileBMP *bmp =CAlloc(size);130 bmp->type ='BM';131 bmp->planes =1;132 bmp->file_size =size;133 bmp->data_offset=offset(CFileBMP.end);134 bmp->header_size=offset(CFileBMP.end)-offset(CFileBMP.header_size);135 bmp->width =dc->width;136 bmp->height =dc->height;137 bmp->bit_cnt =32;138 bmp->image_size =dc->width*dc->height<<2;139 140 bgr=bmp(U8 *)+bmp->data_offset;141 for (y=dc->height-1;y>=0;y--) {142 src=y*dc->width_internal+dc->body;143 for (x=0;x<dc->width;x++) {144 i=*src++;145 if (i&BLUE) bgr->b=0x7F;146 if (i&GREEN) bgr->g=0x7F;147 if (i&RED) bgr->r=0x7F;148 if (i&8) {149 if (bgr->b) bgr->b=0xFF;150 if (bgr->g) bgr->g=0xFF;151 if (bgr->r) bgr->r=0xFF;152 }153 bgr(U8 *)+=4;154 }155 }156 return bmp;157}158 159public I64 BMPWrite(U8 *filename,CDC *dc,I64 bits=4)160{//Window's BMP Files.161 I64 size;162 CFileBMP *bmp;163 if (bits==4) {164 if (IsDotZ(filename)) //.Z compression is better than RLE165 bmp=BMP4To(dc);166 else {167 bmp=BMPRLE4To(dc);168 if (bmp->file_size>sizeof(CFileBMP)+dc->width*dc->height>>1) {169 Free(bmp);170 bmp=BMP4To(dc);171 }172 }173 } else if (bits==24)174 bmp=BMP24To(dc);175 else {176 "Format Not Supported.\n";177 return 0;178 }179 size=bmp->file_size;180 FileWrite(filename,bmp,bmp->file_size);181 Free(bmp);182 return size;183}184 185U8 *BMPPaletteNew(CFileBMP *bmp)186{187 I64 i,j,best,score,best_score;188 CBGR48 palette[COLORS_NUM];189 U8 *res=CAlloc(BMP_COLORS_NUM*sizeof(U8));190 GrPaletteGet(palette);191#assert COLORS_NUM==BMP_COLORS_NUM192 for (i=0;i<BMP_COLORS_NUM;i++) {193 best=i;194 best_score=I64_MAX;195 for (j=0;j<BMP_COLORS_NUM;j++) {196 score=SqrI64(bmp->palette[i].r-palette[j].r>>8)+197 SqrI64(bmp->palette[i].g-palette[j].g>>8)+198 SqrI64(bmp->palette[i].b-palette[j].b>>8);199 if (score<best_score) {200 best=j;201 best_score=score;202 }203 }204 res[i]=best;205 }206 return res;207}208 209U8 ms_paint_palette[BMP_COLORS_NUM]={0,4,2,6,1,5,3,8,7,12,10,14,9,13,11,15};210 211I64 BMP24Color(CBGR24 *ptr,Bool dither_probability)212{213 I64 res,k;214 if (dither_probability) {215 k=RandU32;216 if (SqrI64(ptr->r)+SqrI64(ptr->g)+SqrI64(ptr->b)>=3*SqrI64(k.u8[0]))217 res=8;218 else219 res=0;220 if (ptr->r>=k.u8[1]) res|=RED;221 if (ptr->g>=k.u8[2]) res|=GREEN;222 if (ptr->b>=k.u8[3]) res|=BLUE;223 } else {224 if (SqrI64(ptr->r)+SqrI64(ptr->g)+SqrI64(ptr->b)>=SqrI64(0x80)) {225 res=8;226 if (ptr->r>=0x80) res|=RED;227 if (ptr->g>=0x80) res|=GREEN;228 if (ptr->b>=0x80) res|=BLUE;229 } else {230 res=0;231 if (ptr->r>=0x40) res|=RED;232 if (ptr->g>=0x40) res|=GREEN;233 if (ptr->b>=0x40) res|=BLUE;234 }235 }236 return res;237}238 239public CDC *BMPRead(U8 *filename,Bool dither_probability=FALSE,240 Bool use_ms_paint_palette=FALSE)241{//Window's BMP Files.242 I64 i,j,cnt;243 U8 *palette_map,*ptr;244 Bool rle;245 CFileBMP *bmp;246 CDC *res=NULL;247 if (ptr=FileRead(filename)) {248 bmp=ptr;249 if (0<bmp->width<I32_MAX && 0<bmp->height<I32_MAX) {250 res=DCNew(bmp->width,bmp->height);251 ptr+=bmp->data_offset;252 if (bmp->compression==2)253 rle=TRUE;254 else255 rle=FALSE;256 if (use_ms_paint_palette)257 palette_map=ms_paint_palette;258 else259 palette_map=BMPPaletteNew(bmp);260 if (bmp->bit_cnt==4) {261 for (i=bmp->height-1;i>=0;i--)262 if (rle) {//We don't support full RLE4, just our own subset263 j=0;264 while (cnt=*ptr++) {265 if (cnt==1) {266 res->color=palette_map[*ptr++&15];267 GrPlot(res,j++,i);268 } else {269 if (cnt==2 && *ptr>>4!=*ptr&15) {270 res->color=palette_map[*ptr&15];271 GrPlot(res,j+1,i);272 res->color=palette_map[*ptr>>4];273 GrPlot(res,j,i);274 ptr++;275 j+=2;276 } else {277 res->color=palette_map[*ptr++&15];278 while (cnt--)279 GrPlot(res,j++,i);280 }281 }282 }283 ptr++;284 } else285 for (j=0;j<(bmp->width+7)&~7;) {286 res->color=palette_map[*ptr&15];287 GrPlot(res,j+1,i);288 res->color=palette_map[*ptr>>4];289 GrPlot(res,j,i);290 ptr++;291 j+=2;292 }293 if (!use_ms_paint_palette)294 Free(palette_map);295 } else if (bmp->bit_cnt==24) {296 for (i=bmp->height-1;i>=0;i--) {297 for (j=0;j<bmp->width;j++,ptr+=3) {298 res->color=BMP24Color(ptr,dither_probability);299 GrPlot(res,j,i);300 }301 ptr+=bmp->width&3;302 }303 if (!use_ms_paint_palette)304 Free(palette_map);305 } else if (bmp->bit_cnt>=32) {306 for (i=bmp->height-1;i>=0;i--)307 for (j=0;j<bmp->width;j++,ptr+=4) {308 res->color=BMP24Color(ptr,dither_probability);309 GrPlot(res,j,i);310 }311 if (!use_ms_paint_palette)312 Free(palette_map);313 } else {314 "Format Not Supported.\n";315 DCDel(res);316 res=NULL;317 }318 } else319 "Invalid BMP File\n";320 Free(bmp);321 }322 return res;323}324 325#help_index "Graphics/Sprite;Graphics/Windows BMP Files;"\326 "DolDoc/Output;StdOut/DolDoc"327public U0 DocBMP(CDoc *doc=NULL,U8 *filename,Bool dither_probability=FALSE,328 Bool use_ms_paint_palette=FALSE)329{//Put a BMP file into a document as a sprite.330 CDC *dc=BMPRead(filename,dither_probability,use_ms_paint_palette);331 U8 *elems=DC2Sprite(dc);332 DocSprite(doc,elems);333 Free(elems);334 DCDel(dc);335}336 337#help_index "Graphics/Windows BMP Files;Graphics/Scrn"338public I64 BMPScrnCapture(U8 *filename,I64 bits=4,Bool include_zoom=TRUE)339{//Capture scrn as BMP file.340 CDC *dc=DCScrnCapture(include_zoom);341 I64 size=BMPWrite(filename,dc,bits);342 DCDel(dc);343 return size;344}345 