Make it possible to save XBoard piece images as Windows bitmaps
authorH.G.Muller <hgm@hgm-xboard.(none)>
Wed, 30 Nov 2016 16:16:50 +0000 (17:16 +0100)
committerH.G.Muller <hgm@hgm-xboard.(none)>
Fri, 13 Jan 2017 15:39:24 +0000 (16:39 +0100)
A new option -bmpSave N would make XBoard save the images of the first
N pieces of each color, plus the King, as a Windows .bmp file with alpha
channel (32 bits/pixel). This happens in a sub-directory 'bmaps'. After the
black King is saved, XBoard will exit.

args.h
common.h
draw.c

diff --git a/args.h b/args.h
index c6914b0..1da2448 100644 (file)
--- a/args.h
+++ b/args.h
@@ -112,6 +112,7 @@ char *firstEngineLine;
 char *secondEngineLine;
 char *icsNick;
 char *theme;
+char *replace;
 
 void EnsureOnScreen(int *x, int *y, int minX, int minY);
 char StringGet(void *getClosure);
@@ -620,6 +621,7 @@ ArgDescriptor argDescriptors[] = {
   { "replace", ArgString, (void *) &replace, FALSE, (ArgIniType) NULL },
   { "fixedSize", ArgBoolean, (void *) &appData.fixedSize, TRUE, (ArgIniType) FALSE },
   { "showMoveTime", ArgBoolean, (void *) &appData.moveTime, TRUE, (ArgIniType) FALSE },
+  { "bmpSave", ArgInt, (void *) &appData.bmpSave, FALSE, 0 },
 
   // [HGM] tournament options
   { "tourneyFile", ArgFilename, (void *) &appData.tourneyFile, FALSE, (ArgIniType) "" },
@@ -1184,7 +1186,7 @@ ParseArgs(GetFunc get, void *cl)
         break;
       }
       if(replace) { // previous -replace option makes this string option conditional
-       char *p = replace;
+       char *p = (char*) replace;
        free(replace); replace = NULL; // but expires in the process
         if(strcmp(*(char**) ad->argLoc, p)) break; // only use to replace the given string
       }
index 2aff360..b1b239c 100644 (file)
--- a/common.h
+++ b/common.h
@@ -818,6 +818,7 @@ typedef struct {
     int tourneyType;
     int tourneyCycles;
     int seedBase;
+    int bmpSave;
     Boolean roundSync;
     Boolean cycleSync;
     Boolean numberTag;
diff --git a/draw.c b/draw.c
index 8b78892..79518a0 100644 (file)
--- a/draw.c
+++ b/draw.c
@@ -375,6 +375,38 @@ LoadSVG (char *dir, int color, int piece, int retry)
     return NULL;
 }
 
+static void Wint(FILE *f, int n)
+{   // write 32-bit int, lsb first
+    fprintf(f, "%c%c%c%c", n&255, n>>8&255, n>>16&255, n>>24&255);
+}
+
+static void
+SaveWindowsBitmap(ChessSquare piece, int color, int *data, int stride, int w, int h, int bpp)
+{
+    int i, v, line = (w*bpp + 3)>>2, size = line*4*h;
+    char buf[100];
+    FILE *f;
+    snprintf(buf, 100, "bmaps/piece%d_%d%c.bmp", piece, w, color ? 's': 'o');
+    if(piece >= appData.bmpSave && piece != WhiteKing) return;
+    f = fopen(buf, "wb");
+    if(!f) return;
+    fprintf(f, "BM");
+    Wint(f, size+54); Wint(f, 0); Wint(f, 54); Wint(f, 40); // file size, reserved, image offset, header size
+    Wint(f, w); Wint(f, h); Wint(f, 8*bpp << 16 | 1); // width, height, planes & bits/pix
+    Wint(f, 0); // compression
+    Wint(f, size); Wint(f, 3780); Wint(f, 3780); Wint(f, 0); Wint(f, 0); // image size, pix/m (H and V), color-table size (2x)
+    for(v=h-1; v>=0; v--) {
+       for(i=0; i<w; i++) {
+           int pix = data[stride*v+i], r=pix>>16&255, g=pix>>8&255, b=pix&255, a=pix>>24&255;
+           r = r*a/255; b = b*a/255; g = g*a/255;
+           if(bpp == 4) fprintf(f, "%c%c%c%c", b, g, r, a); else fprintf(f, "%c%c%c", b, g, r);
+       }
+       i *= bpp; while(i++ < line*4) fprintf(f, "%c", 0); // padding
+    }
+    fclose(f);
+    if(appData.bmpSave && piece == WhiteKing && color) exit(0);
+}
+
 static void
 ScaleOnePiece (int color, int piece, char *pieceDir)
 {
@@ -431,6 +463,7 @@ ScaleOnePiece (int color, int piece, char *pieceDir)
     int i, j, p;
     sscanf(color ? appData.blackPieceColor+1 : appData.whitePieceColor+1, "%x", &p); // replacement color
     cairo_surface_flush(cs);
+    SaveWindowsBitmap(piece, color, buf, stride, squareSize, squareSize, 4);
     for(i=0; i<squareSize; i++) for(j=0; j<squareSize; j++) {
        int r, a;
        float f;