URI:
       tgfx.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tgfx.c (5918B)
       ---
            1 /*
            2  * graphics file reading for page
            3  */
            4 
            5 #include <u.h>
            6 #include <libc.h>
            7 #include <draw.h>
            8 #include <thread.h>
            9 #include <bio.h>
           10 #include <cursor.h>
           11 #include "page.h"
           12 
           13 typedef struct Convert        Convert;
           14 typedef struct GfxInfo        GfxInfo;
           15 
           16 struct Convert {
           17         char *name;
           18         char *cmd;
           19         char *truecmd;        /* cmd for true color */
           20 };
           21 
           22 struct GfxInfo {
           23         Graphic *g;
           24 };
           25 
           26 /*
           27  * N.B. These commands need to read stdin if %a is replaced
           28  * with an empty string.
           29  */
           30 Convert cvt[] = {
           31         { "plan9",        "fb/3to1 rgbv %a |fb/pcp -tplan9" },
           32         { "tiff",        "fb/tiff2pic %a | fb/3to1 rgbv | fb/pcp -tplan9" },
           33         { "jpeg",        "jpg -9 %a", "jpg -t9 %a" },
           34         { "gif",        "gif -9 %a", "gif -t9 %a" },
           35         { "inferno",        nil },
           36         { "fax",        "aux/g3p9bit -g %a" },
           37         { "unknown",        "fb/cvt2pic %a |fb/3to1 rgbv" },
           38         { "plan9bm",        nil },
           39         { "ppm",        "ppm -9 %a", "ppm -t9 %a" },
           40         { "png",        "png -9 %a", "png -t9 %a" },
           41         { "yuv",        "yuv -9 %a", "yuv -t9 %a"  },
           42         { "bmp",        "bmp -9 %a", "bmp -t9 %a"  },
           43 };
           44 
           45 static Image*        gfxdrawpage(Document *d, int page);
           46 static char*        gfxpagename(Document*, int);
           47 static int        spawnrc(char*, Graphic*);
           48 //static void        waitrc(void);
           49 //static int        spawnpost(int);
           50 static int        addpage(Document*, char*);
           51 static int        rmpage(Document*, int);
           52 static int        genaddpage(Document*, char*, uchar*, int);
           53 
           54 static char*
           55 gfxpagename(Document *doc, int page)
           56 {
           57         GfxInfo *gfx = doc->extra;
           58         return gfx->g[page].name;
           59 }
           60 
           61 static Image*
           62 gfxdrawpage(Document *doc, int page)
           63 {
           64         GfxInfo *gfx = doc->extra;
           65         return convert(gfx->g+page);
           66 }
           67 
           68 Document*
           69 initgfx(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
           70 {
           71         GfxInfo *gfx;
           72         Document *doc;
           73         int i;
           74 
           75         USED(b);
           76 
           77         doc = emalloc(sizeof(*doc));
           78         gfx = emalloc(sizeof(*gfx));
           79         gfx->g = nil;
           80 
           81         doc->npage = 0;
           82         doc->drawpage = gfxdrawpage;
           83         doc->pagename = gfxpagename;
           84         doc->addpage = addpage;
           85         doc->rmpage = rmpage;
           86         doc->extra = gfx;
           87         doc->fwdonly = 0;
           88         doc->type = Tgfx;
           89 
           90         fprint(2, "reading through graphics...\n");
           91         if(argc==0 && buf)
           92                 genaddpage(doc, nil, buf, nbuf);
           93         else{
           94                 for(i=0; i<argc; i++)
           95                         if(addpage(doc, argv[i]) < 0)
           96                                 fprint(2, "warning: not including %s: %r\n", argv[i]);
           97         }
           98 
           99         return doc;
          100 }
          101 
          102 static int
          103 genaddpage(Document *doc, char *name, uchar *buf, int nbuf)
          104 {
          105         Graphic *g;
          106         GfxInfo *gfx;
          107         Biobuf *b;
          108         uchar xbuf[32];
          109         int i, l;
          110 
          111         l = 0;
          112         gfx = doc->extra;
          113 
          114         assert((name == nil) ^ (buf == nil));
          115         assert(name != nil || doc->npage == 0);
          116 
          117         for(i=0; i<doc->npage; i++)
          118                 if(strcmp(gfx->g[i].name, name) == 0)
          119                         return i;
          120 
          121         if(name){
          122                 l = strlen(name);
          123                 if((b = Bopen(name, OREAD)) == nil) {
          124                         werrstr("Bopen: %r");
          125                         return -1;
          126                 }
          127 
          128                 if(Bread(b, xbuf, sizeof xbuf) != sizeof xbuf) {
          129                         werrstr("short read: %r");
          130                         return -1;
          131                 }
          132                 Bterm(b);
          133                 buf = xbuf;
          134                 nbuf = sizeof xbuf;
          135         }
          136 
          137 
          138         gfx->g = erealloc(gfx->g, (doc->npage+1)*(sizeof(*gfx->g)));
          139         g = &gfx->g[doc->npage];
          140 
          141         memset(g, 0, sizeof *g);
          142         if(memcmp(buf, "GIF", 3) == 0)
          143                 g->type = Igif;
          144         else if(memcmp(buf, "\111\111\052\000", 4) == 0)
          145                 g->type = Itiff;
          146         else if(memcmp(buf, "\115\115\000\052", 4) == 0)
          147                 g->type = Itiff;
          148         else if(memcmp(buf, "\377\330\377", 3) == 0)
          149                 g->type = Ijpeg;
          150         else if(memcmp(buf, "\211PNG\r\n\032\n", 3) == 0)
          151                 g->type = Ipng;
          152         else if(memcmp(buf, "compressed\n", 11) == 0)
          153                 g->type = Iinferno;
          154         else if(memcmp(buf, "\0PC Research, Inc", 17) == 0)
          155                 g->type = Ifax;
          156         else if(memcmp(buf, "TYPE=ccitt-g31", 14) == 0)
          157                 g->type = Ifax;
          158         else if(memcmp(buf, "II*", 3) == 0)
          159                 g->type = Ifax;
          160         else if(memcmp(buf, "TYPE=", 5) == 0)
          161                 g->type = Ipic;
          162         else if(buf[0] == 'P' && '0' <= buf[1] && buf[1] <= '9')
          163                 g->type = Ippm;
          164         else if(memcmp(buf, "BM", 2) == 0)
          165                 g->type = Ibmp;
          166         else if(memcmp(buf, "          ", 10) == 0 &&
          167                 '0' <= buf[10] && buf[10] <= '9' &&
          168                 buf[11] == ' ')
          169                 g->type = Iplan9bm;
          170         else if(strtochan((char*)buf) != 0)
          171                 g->type = Iplan9bm;
          172         else if (l > 4 && strcmp(name + l -4, ".yuv") == 0)
          173                 g->type = Iyuv;
          174         else
          175                 g->type = Icvt2pic;
          176 
          177         if(name){
          178                 g->name = estrdup(name);
          179                 g->fd = -1;
          180         }else{
          181                 g->name = estrdup("stdin");        /* so it can be freed */
          182                 g->fd = stdinpipe(buf, nbuf);
          183         }
          184 
          185         if(chatty) fprint(2, "classified \"%s\" as \"%s\"\n", g->name, cvt[g->type].name);
          186         return doc->npage++;
          187 }
          188 
          189 static int
          190 addpage(Document *doc, char *name)
          191 {
          192         return genaddpage(doc, name, nil, 0);
          193 }
          194 
          195 static int
          196 rmpage(Document *doc, int n)
          197 {
          198         int i;
          199         GfxInfo *gfx;
          200 
          201         if(n < 0 || n >= doc->npage)
          202                 return -1;
          203 
          204         gfx = doc->extra;
          205         doc->npage--;
          206         free(gfx->g[n].name);
          207 
          208         for(i=n; i<doc->npage; i++)
          209                 gfx->g[i] = gfx->g[i+1];
          210 
          211         if(n < doc->npage)
          212                 return n;
          213         if(n == 0)
          214                 return 0;
          215         return n-1;
          216 }
          217 
          218 
          219 Image*
          220 convert(Graphic *g)
          221 {
          222         int fd;
          223         Convert c;
          224         char *cmd;
          225         char *name, buf[1000];
          226         Image *im;
          227         int rcspawned = 0;
          228 
          229         c = cvt[g->type];
          230         if(c.cmd == nil) {
          231                 if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name);
          232                 if(g->fd < 0){        /* not stdin */
          233                         fd = open(g->name, OREAD);
          234                         if(fd < 0) {
          235                                 fprint(2, "cannot open file: %r\n");
          236                                 wexits("open");
          237                         }
          238                 }else
          239                         fd = g->fd;
          240         } else {
          241                 cmd = c.cmd;
          242                 if(truecolor && c.truecmd)
          243                         cmd = c.truecmd;
          244 
          245                 if(g->fd >= 0)        /* is pipe */
          246                         name = "";
          247                 else
          248                         name = g->name;
          249                 if(strlen(cmd)+strlen(name) > sizeof buf) {
          250                         fprint(2, "command too long\n");
          251                         wexits("convert");
          252                 }
          253                 snprint(buf, sizeof buf, cmd, name);
          254                 if(chatty) fprint(2, "using \"%s\" to convert \"%s\"...\n", buf, g->name);
          255                 fd = spawnrc(buf, g);
          256                 rcspawned++;
          257                 if(fd < 0) {
          258                         fprint(2, "cannot spawn converter: %r\n");
          259                         wexits("convert");
          260                 }
          261         }
          262 
          263         im = readimage(display, fd, 0);
          264         if(im == nil) {
          265                 fprint(2, "warning: couldn't read image: %r\n");
          266         }
          267 
          268         close(fd);
          269         return im;
          270 }
          271 
          272 static int
          273 spawnrc(char *cmd, Graphic *g)
          274 {
          275         int pfd[2];
          276         int fd[3];
          277 
          278         if(chatty) fprint(2, "spawning(%s)...", cmd);
          279 
          280         if(pipe(pfd) < 0)
          281                 return -1;
          282 
          283         if(g->fd > 0)
          284                 fd[0] = dup(g->fd, -1);
          285         else
          286                 fd[0] = open("/dev/null", OREAD);
          287         fd[1] = pfd[1];
          288         fd[2] = dup(2, -1);
          289 
          290         if(threadspawnl(fd, "rc", "rc", "-c", cmd, nil) == -1)
          291                 return -1;
          292 
          293         return pfd[0];
          294 }