URI: 
       tpng.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
       ---
       tpng.c (3726B)
       ---
            1 #include "stdinc.h"
            2 #include "dat.h"
            3 #include "fns.h"
            4 
            5 enum
            6 {
            7         IDATSIZE        = 20000,
            8         FilterNone = 0
            9 };
           10 
           11 typedef struct ZlibR ZlibR;
           12 typedef struct ZlibW ZlibW;
           13 
           14 struct ZlibR
           15 {
           16         uchar *data;
           17         int width;
           18         int dx;
           19         int dy;
           20         int x;
           21         int y;
           22         int pixwid;
           23 };
           24 
           25 struct ZlibW
           26 {
           27         Hio *io;
           28         uchar *buf;
           29         uchar *b;
           30         uchar *e;
           31 };
           32 
           33 static u32int *crctab;
           34 static uchar PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
           35 
           36 static void
           37 put4(uchar *a, ulong v)
           38 {
           39         a[0] = v>>24;
           40         a[1] = v>>16;
           41         a[2] = v>>8;
           42         a[3] = v;
           43 }
           44 
           45 static void
           46 chunk(Hio *io, char *type, uchar *d, int n)
           47 {
           48         uchar buf[4];
           49         ulong crc = 0;
           50 
           51         if(strlen(type) != 4)
           52                 return;
           53         put4(buf, n);
           54         hwrite(io, buf, 4);
           55         hwrite(io, type, 4);
           56         hwrite(io, d, n);
           57         crc = blockcrc(crctab, crc, type, 4);
           58         crc = blockcrc(crctab, crc, d, n);
           59         put4(buf, crc);
           60         hwrite(io, buf, 4);
           61 }
           62 
           63 static int
           64 zread(void *va, void *buf, int n)
           65 {
           66         int a, i, pixels, pixwid;
           67         uchar *b, *e, *img;
           68         ZlibR *z;
           69 
           70         z = va;
           71         pixwid = z->pixwid;
           72         b = buf;
           73         e = b+n;
           74         while(b+pixwid <= e){
           75                 if(z->y >= z->dy)
           76                         break;
           77                 if(z->x == 0)
           78                         *b++ = FilterNone;
           79                 pixels = (e-b)/pixwid;
           80                 if(pixels > z->dx - z->x)
           81                         pixels = z->dx - z->x;
           82                 img = z->data + z->width*z->y + pixwid*z->x;
           83                 memmove(b, img, pixwid*pixels);
           84                 if(pixwid == 4){
           85                         /*
           86                          * Convert to non-premultiplied alpha.
           87                          */
           88                         for(i=0; i<pixels; i++, b+=4){
           89                                 a = b[3];
           90                                 if(a != 0 && a != 255){
           91                                         if(b[0] >= a)
           92                                                 b[0] = a;
           93                                         b[0] = (b[0]*255)/a;
           94                                         if(b[1] >= a)
           95                                                 b[1] = a;
           96                                         b[1] = (b[1]*255)/a;
           97                                         if(b[2] >= a)
           98                                                 b[2] = a;
           99                                         b[2] = (b[2]*255)/a;
          100                                 }
          101                         }
          102                 }else
          103                         b += pixwid*pixels;
          104 
          105                 z->x += pixels;
          106                 if(z->x >= z->dx){
          107                         z->x = 0;
          108                         z->y++;
          109                 }
          110         }
          111         return b - (uchar*)buf;
          112 }
          113 
          114 static void
          115 IDAT(ZlibW *z)
          116 {
          117         chunk(z->io, "IDAT", z->buf, z->b - z->buf);
          118         z->b = z->buf;
          119 }
          120 
          121 static int
          122 zwrite(void *va, void *buf, int n)
          123 {
          124         int m;
          125         uchar *b, *e;
          126         ZlibW *z;
          127 
          128         z = va;
          129         b = buf;
          130         e = b+n;
          131 
          132         while(b < e){
          133                 m = z->e - z->b;
          134                 if(m > e - b)
          135                         m = e - b;
          136                 memmove(z->b, b, m);
          137                 z->b += m;
          138                 b += m;
          139                 if(z->b >= z->e)
          140                         IDAT(z);
          141         }
          142         return n;
          143 }
          144 
          145 static Memimage*
          146 memRGBA(Memimage *i)
          147 {
          148         Memimage *ni;
          149         char buf[32];
          150         ulong dst;
          151 
          152         /*
          153          * [A]BGR because we want R,G,B,[A] in big-endian order.  Sigh.
          154          */
          155         chantostr(buf, i->chan);
          156         if(strchr(buf, 'a'))
          157                 dst = ABGR32;
          158         else
          159                 dst = BGR24;
          160 
          161         if(i->chan == dst)
          162                 return i;
          163 
          164         qlock(&memdrawlock);
          165         ni = allocmemimage(i->r, dst);
          166         if(ni)
          167                 memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
          168         qunlock(&memdrawlock);
          169         return ni;
          170 }
          171 
          172 int
          173 writepng(Hio *io, Memimage *m)
          174 {
          175         static int first = 1;
          176         static QLock lk;
          177         uchar buf[200], *h;
          178         Memimage *rgb;
          179         ZlibR zr;
          180         ZlibW zw;
          181 
          182         if(first){
          183                 qlock(&lk);
          184                 if(first){
          185                         deflateinit();
          186                         crctab = mkcrctab(0xedb88320);
          187                         first = 0;
          188                 }
          189                 qunlock(&lk);
          190         }
          191 
          192         rgb = memRGBA(m);
          193         if(rgb == nil)
          194                 return -1;
          195 
          196         hwrite(io, PNGmagic, sizeof PNGmagic);
          197 
          198         /* IHDR chunk */
          199         h = buf;
          200         put4(h, Dx(m->r)); h += 4;
          201         put4(h, Dy(m->r)); h += 4;
          202         *h++ = 8;        /* 8 bits per channel */
          203         if(rgb->chan == BGR24)
          204                 *h++ = 2;                /* RGB */
          205         else
          206                 *h++ = 6;                /* RGBA */
          207         *h++ = 0;        /* compression - deflate */
          208         *h++ = 0;        /* filter - none */
          209         *h++ = 0;        /* interlace - none */
          210         chunk(io, "IHDR", buf, h-buf);
          211 
          212         /* image data */
          213         zr.dx = Dx(m->r);
          214         zr.dy = Dy(m->r);
          215         zr.width = rgb->width * sizeof(u32int);
          216         zr.data = rgb->data->bdata;
          217         zr.x = 0;
          218         zr.y = 0;
          219         zr.pixwid = chantodepth(rgb->chan)/8;
          220         zw.io = io;
          221         zw.buf = vtmalloc(IDATSIZE);
          222         zw.b = zw.buf;
          223         zw.e = zw.b + IDATSIZE;
          224         if(deflatezlib(&zw, zwrite, &zr, zread, 6, 0) < 0){
          225                 free(zw.buf);
          226                 return -1;
          227         }
          228         if(zw.b > zw.buf)
          229                 IDAT(&zw);
          230         free(zw.buf);
          231         chunk(io, "IEND", nil, 0);
          232 
          233         if(m != rgb){
          234                 qlock(&memdrawlock);
          235                 freememimage(rgb);
          236                 qunlock(&memdrawlock);
          237         }
          238         return 0;
          239 }