New upstream version 3.1.1
[xfishtank.git] / src / ixpm.c
diff --git a/src/ixpm.c b/src/ixpm.c
new file mode 100644 (file)
index 0000000..f885c5a
--- /dev/null
@@ -0,0 +1,385 @@
+/* -copyright-
+#-# Copyright © 2021 Eric Bina, Dave Black, TJ Phan, 
+#-#    Vincent Renardias, Willem Vermin
+#-# 
+#-# Permission is hereby granted, free of charge, to any person 
+#-# obtaining a copy of this software and associated documentation 
+#-# files (the “Software”), to deal in the Software without 
+#-# restriction, including without limitation the rights to use, 
+#-# copy, modify, merge, publish, distribute, sublicense, and/or 
+#-# sell copies of the Software, and to permit persons to whom 
+#-# the Software is furnished to do so, subject to the following 
+#-# conditions:
+#-# 
+#-# The above copyright notice and this permission notice shall 
+#-# be included in all copies or substantial portions of the Software.
+#-# 
+#-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 
+#-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
+#-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+#-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
+#-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
+#-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+#-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
+#-# OTHER DEALINGS IN THE SOFTWARE.
+#-# 
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "ixpm.h"
+#include "debug.h"
+#include "utils.h"
+// from the xpm package:
+static void xpmCreatePixmapFromImage(
+      Display  *display,
+      Drawable  d,
+      XImage   *ximage,
+      Pixmap   *pixmap_return)
+{
+   GC gc;
+   XGCValues values;
+
+   *pixmap_return = XCreatePixmap(display, d, ximage->width,
+        ximage->height, ximage->depth);
+   /* set fg and bg in case we have an XYBitmap */
+   values.foreground = 1;
+   values.background = 0;
+   gc = XCreateGC(display, *pixmap_return,
+        GCForeground | GCBackground, &values);
+
+   XPutImage(display, *pixmap_return, gc, ximage, 0, 0, 0, 0,
+        ximage->width, ximage->height);
+
+   XFreeGC(display, gc);
+}
+
+void paintit(XImage *img, long int color)
+{
+   int x,y;
+   for (y=0; y<img->height; y++)
+      for (x=0; x<img->width; x++)
+      {
+        XPutPixel(img, x,y,color);
+      }
+}
+
+
+// reverse characters in string, characters taken in chunks of l
+// if you know what I mean
+static void strrevert(char*s, size_t l)
+{
+   assert(l>0);
+   size_t n = strlen(s)/l;
+   size_t i;
+   char *c = (char *)malloc(l*sizeof(*c));
+   char *a = s;
+   char *b = s+strlen(s)-l;
+   for (i=0; i<n/2; i++)
+   {
+      strncpy(c,a,l);
+      strncpy(a,b,l);
+      strncpy(b,c,l);
+      a+=l;
+      b-=l;
+   }
+   free(c);
+}
+
+//
+//  equal to XpmCreatePixmapFromData, with extra flags:
+//  flop: if 1, reverse the data horizontally
+//  Extra: 0xff000000 is added to the pixmap data
+//
+int iXpmCreatePixmapFromData(Display *display, Drawable d, 
+      const char *data[], Pixmap *p, Pixmap *s, XpmAttributes *attr, int flop)
+{
+   int rc, lines, i, ncolors, height, w;
+   char **idata;
+
+   sscanf(data[0],"%*s %d %d %d", &height, &ncolors, &w);
+   lines = height+ncolors+1;
+   assert(lines>0);
+   idata = (char **)malloc(lines*sizeof(*idata));
+   for (i=0; i<lines; i++)
+      idata[i] = strdup(data[i]);
+   if(flop)
+      // flop the image data
+      for (i=1+ncolors; i<lines; i++)
+        strrevert(idata[i],w);
+
+   XImage *ximage,*shapeimage;
+   rc = XpmCreateImageFromData(display,idata,&ximage,&shapeimage,attr);
+   if (rc != 0)
+   {
+      I("rc from XpmCreateImageFromData: ");
+      switch (rc)
+      {
+        case 1:
+           printf("XpmColorError\n");
+           for (i=0; i<lines; i++)
+              printf("\"%s\",\n",idata[i]);
+           break;
+        case -1:
+           printf("XpmOpenFailed\n");
+           break;
+        case -2:
+           printf("XpmFileInvalid\n");
+           break;
+        case -3:
+           printf("XpmNoMemory: maybe issue with width of data: w=%d\n",w);
+           break;
+        case -4:
+           printf("XpmColorFailed\n");
+           for (i=0; i<lines; i++)
+              printf("\"%s\",\n",idata[i]);
+           break;
+        default:
+           printf("%d\n",rc);
+           break;
+      }
+      printf("exiting\n");
+      fflush(NULL);
+      abort();
+   }
+   XAddPixel(ximage,0xff000000);
+   if(p)
+      xpmCreatePixmapFromImage(display, d, ximage, p);
+   if(s)
+      xpmCreatePixmapFromImage(display, d, shapeimage, s);
+   XDestroyImage(ximage);
+   XDestroyImage(shapeimage);
+   for(i=0; i<lines; i++) free(idata[i]);
+   free(idata);
+   return rc;
+}
+
+// given xpmdata **data, add the non-transparent pixels to Region r
+Region regionfromxpm(const char **data, int flop)
+{
+   int w,h,nc,n;
+   Region r = XCreateRegion();
+   // width, height, #colors, $chars to code color
+   sscanf(*data,"%d %d %d %d",&w,&h,&nc,&n);
+   // find color "None":
+   int i;
+   char *code = (char *)"";
+   int offset = nc + 1;
+   for(i=1; i<=nc; i++)
+   {
+      char s[100];
+      P("%s\n",data[i]);
+      sscanf(data[i]+n,"%*s %100s",s);
+      P("%s\n",s);
+      if(!strcasecmp(s,"None"))
+      {
+        code = strndup(data[i],n);
+        break;
+      }
+   }
+   XRectangle rect;
+   rect.width = 1;
+   rect.height = 1;
+   int y;
+   for (y=0; y<h; y++)
+   {
+      int x;
+      char*s = strdup(data[y+offset]);
+      if(flop)
+        strrevert(s,n);
+      for(x=0; x<w; x++)
+      {
+        if (strncmp(s+n*x,code,n))
+        {
+           rect.x = x;
+           rect.y = y;
+           XUnionRectWithRegion(&rect,r,r);
+        }
+      }
+      free(s);
+   }
+   free(code);
+   return r;
+}
+
+/*
+ * converts xpm data to bitmap
+ * xpm:        input xpm data
+ * bitsreturn: output bitmap, allocated by this function
+ * wreturn:    width of bitmap
+ * hreturn:    height of bitmap
+ * lreturn:    length of bitmap
+ *
+ * Return value: 1: OK, 0: not OK.
+ * BUGS: this code has not been tested on a big endian system
+ */
+int xpmtobits(char *xpm[],unsigned char **bitsreturn, int *wreturn, int *hreturn, int *lreturn)
+{
+   int nc,cpp,w,h;
+
+   unsigned char *bits = (unsigned char*) malloc(sizeof(unsigned char)*1);
+   if (sscanf(xpm[0],"%d %d %d %d",&w,&h,&nc,&cpp)!=4)
+      return 0;
+   if(cpp <=0 || w<0 || h<0 || nc<0)
+      return 0;
+   *wreturn = w;
+   *hreturn = h;
+   int l = ((int)w + 7)/8;   // # chars needed for this w
+   *lreturn = l*h;
+   // l*h+1: we do not want allocate 0 bytes
+   bits = (unsigned char*) realloc(bits,sizeof(unsigned char)*(l*h+1));
+   *bitsreturn = bits;
+   int i;
+   for(i=0; i<l*h; i++)
+      bits[i] = 0;
+
+   char *code = (char *)malloc(sizeof(char)*cpp);
+   for (i=0; i<cpp; i++)
+      code[i] = ' ';
+
+   int offset = nc + 1;
+   for(i=1; i<=nc; i++)
+   {
+      char s[100];
+      if (strlen(xpm[i]) > (size_t)cpp + 6)
+      {
+        sscanf(xpm[i]+cpp,"%*s %100s",s);
+        if(!strcasecmp(s,"none"))
+        {
+           free(code);
+           code = strndup(xpm[i],cpp);
+           break;
+        }
+      }
+   }
+   int y;
+   unsigned char c = 0;
+   int j = 0;
+   if (is_little_endian())
+      for (y=0; y<h; y++)         // little endian
+      {
+        int x,k=0;
+        const char *s = xpm[y+offset];
+        int l = strlen(s);
+        for(x=0; x<w; x++)
+        {
+           c >>= 1;
+           if (cpp*x + cpp <= l)
+           {
+              if (strncmp(s+cpp*x,code,cpp))
+                 c |= 0x80;
+           }
+           k++;
+           if (k == 8)
+           {
+              bits[j++] = c;
+              k = 0;
+           }
+        }
+        if (k)
+           bits[j++] = c>>(8-k);
+      }
+   else  
+      for (y=0; y<h; y++)      // big endian  NOT tested
+      {
+        int x,k=0;
+        const char *s = xpm[y+offset];
+        int l = strlen(s);
+        for(x=0; x<w; x++)
+        {
+           c <<= 1;
+           if (cpp*x + cpp <= l)
+           {
+              if (strncmp(s+cpp*x,code,cpp))
+                 c |= 0x01;
+           }
+           k++;
+           if (k == 8)
+           {
+              bits[j++] = c;
+              k = 0;
+           }
+        }
+        if (k)
+           bits[j++] = c<<(8-k);
+      }
+
+   free(code);
+   return 1;
+}
+
+
+// given color and xmpdata **data of a monocolored picture like:
+// 
+//XPM_TYPE *snow06_xpm[] = {
+///* columns rows colors chars-per-pixel */
+//"3 3 2 1 ",
+//"  c none",
+//". c black",
+///* pixels */
+//". .",
+//" . ",
+//". ."
+//};
+// change the second color to color and put the result in out.
+// lines will become the number of lines in out, comes in handy
+// when wanteing to free out.
+void xpm_set_color(char **data, char ***out, int *lines, const char *color)
+{
+   int n;  
+   sscanf(data[0],"%*d %d",&n);
+   assert(n+3>0);
+   *out = (char**)malloc(sizeof(char *)*(n+3));
+   char **x = *out;
+   int j;
+   for (j=0; j<2; j++)
+      x[j] = strdup(data[j]);
+   x[2] = (char *)malloc(5+strlen(color));
+   x[2][0] = '\0';
+   strcat(x[2],". c ");
+   strcat(x[2],color);
+   P("c: [%s]\n",x[2]);
+
+   for (j=3; j<n+3; j++)
+   {
+      x[j] = strdup(data[j]);
+      P("%d %s\n",j,x[j]);
+   }
+   *lines = n+3;
+}
+
+void xpm_destroy(char **data)
+{
+   int h,nc;
+   sscanf(data[0],"%*d %d %d",&h,&nc);
+   int i;
+   for (i=0; i<h+nc+1; i++)
+      free(data[i]);
+   free(data);
+}
+
+void xpm_print(char **xpm)
+{
+   int w,h,nc;
+   sscanf(xpm[0],"%d %d %d",&w,&h,&nc);
+   int i,j;
+   printf("%s\n",xpm[0]);
+   for (i=1; i<1+nc; i++)
+      printf("%s\n",xpm[i]);
+   for (i=0; i<2*w+2; i++)
+      printf("_");
+   printf("\n");
+   for (i=0; i<h; i++)
+   {
+      printf("|");
+      for (j=0; j<w; j++)
+        printf("%2c",xpm[i+nc+1][j]);
+      printf("|");
+      printf("\n");
+   }
+   for (i=0; i<2*w+2; i++)
+      printf("-");
+   printf("\n");
+}
+
This page took 0.015096 seconds and 4 git commands to generate.