17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <memdraw.h>
57dd7cddfSDavid du Colombier #include <bio.h>
67dd7cddfSDavid du Colombier
77dd7cddfSDavid du Colombier #define MAXLINE 70
87dd7cddfSDavid du Colombier
9*bacfa46cSDavid du Colombier /* imported from libdraw/arith.c to permit an extern log2 function */
10*bacfa46cSDavid du Colombier static int log2[] = {
11*bacfa46cSDavid du Colombier -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
12*bacfa46cSDavid du Colombier -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
13*bacfa46cSDavid du Colombier };
14*bacfa46cSDavid du Colombier
157dd7cddfSDavid du Colombier /*
167dd7cddfSDavid du Colombier * Write data
177dd7cddfSDavid du Colombier */
187dd7cddfSDavid du Colombier static
197dd7cddfSDavid du Colombier char*
writedata(Biobuf * fd,Image * image,Memimage * memimage)207dd7cddfSDavid du Colombier writedata(Biobuf *fd, Image *image, Memimage *memimage)
217dd7cddfSDavid du Colombier {
227dd7cddfSDavid du Colombier char *err;
237dd7cddfSDavid du Colombier uchar *data;
247dd7cddfSDavid du Colombier int i, x, y, ndata, depth, col, pix, xmask, pmask;
257dd7cddfSDavid du Colombier ulong chan;
267dd7cddfSDavid du Colombier Rectangle r;
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier if(memimage != nil){
297dd7cddfSDavid du Colombier r = memimage->r;
307dd7cddfSDavid du Colombier depth = memimage->depth;
317dd7cddfSDavid du Colombier chan = memimage->chan;
327dd7cddfSDavid du Colombier }else{
337dd7cddfSDavid du Colombier r = image->r;
347dd7cddfSDavid du Colombier depth = image->depth;
357dd7cddfSDavid du Colombier chan = image->chan;
367dd7cddfSDavid du Colombier }
377dd7cddfSDavid du Colombier
387dd7cddfSDavid du Colombier /*
397dd7cddfSDavid du Colombier * Read image data into memory
407dd7cddfSDavid du Colombier * potentially one extra byte on each end of each scan line
417dd7cddfSDavid du Colombier */
427dd7cddfSDavid du Colombier ndata = Dy(r)*(2+Dx(r)*depth/8);
437dd7cddfSDavid du Colombier data = malloc(ndata);
447dd7cddfSDavid du Colombier if(data == nil)
457dd7cddfSDavid du Colombier return "WritePPM: malloc failed";
467dd7cddfSDavid du Colombier if(memimage != nil)
477dd7cddfSDavid du Colombier ndata = unloadmemimage(memimage, r, data, ndata);
487dd7cddfSDavid du Colombier else
497dd7cddfSDavid du Colombier ndata = unloadimage(image, r, data, ndata);
507dd7cddfSDavid du Colombier if(ndata < 0){
519a747e4fSDavid du Colombier err = malloc(ERRMAX);
527dd7cddfSDavid du Colombier if(err == nil)
537dd7cddfSDavid du Colombier return "WritePPM: malloc failed";
549a747e4fSDavid du Colombier snprint(err, ERRMAX, "WriteGIF: %r");
557dd7cddfSDavid du Colombier free(data);
567dd7cddfSDavid du Colombier return err;
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier
597dd7cddfSDavid du Colombier /* Encode and emit the data */
607dd7cddfSDavid du Colombier col = 0;
617dd7cddfSDavid du Colombier switch(chan){
627dd7cddfSDavid du Colombier case GREY1:
637dd7cddfSDavid du Colombier case GREY2:
647dd7cddfSDavid du Colombier case GREY4:
657dd7cddfSDavid du Colombier pmask = (1<<depth)-1;
667dd7cddfSDavid du Colombier xmask = 7>>log2[depth];
677dd7cddfSDavid du Colombier for(y=r.min.y; y<r.max.y; y++){
687dd7cddfSDavid du Colombier i = (y-r.min.y)*bytesperline(r, depth);
697dd7cddfSDavid du Colombier for(x=r.min.x; x<r.max.x; x++){
707dd7cddfSDavid du Colombier pix = (data[i]>>depth*((xmask-x)&xmask))&pmask;
717dd7cddfSDavid du Colombier if(((x+1)&xmask) == 0)
727dd7cddfSDavid du Colombier i++;
737dd7cddfSDavid du Colombier col += Bprint(fd, "%d ", pix);
747dd7cddfSDavid du Colombier if(col >= MAXLINE-(2+1)){
757dd7cddfSDavid du Colombier Bprint(fd, "\n");
767dd7cddfSDavid du Colombier col = 0;
777dd7cddfSDavid du Colombier }else
787dd7cddfSDavid du Colombier col += Bprint(fd, " ");
797dd7cddfSDavid du Colombier }
807dd7cddfSDavid du Colombier }
817dd7cddfSDavid du Colombier break;
827dd7cddfSDavid du Colombier case GREY8:
837dd7cddfSDavid du Colombier for(i=0; i<ndata; i++){
847dd7cddfSDavid du Colombier col += Bprint(fd, "%d ", data[i]);
857dd7cddfSDavid du Colombier if(col >= MAXLINE-(4+1)){
867dd7cddfSDavid du Colombier Bprint(fd, "\n");
877dd7cddfSDavid du Colombier col = 0;
887dd7cddfSDavid du Colombier }else
897dd7cddfSDavid du Colombier col += Bprint(fd, " ");
907dd7cddfSDavid du Colombier }
917dd7cddfSDavid du Colombier break;
927dd7cddfSDavid du Colombier case RGB24:
937dd7cddfSDavid du Colombier for(i=0; i<ndata; i+=3){
949a747e4fSDavid du Colombier col += Bprint(fd, "%d %d %d", data[i+2], data[i+1], data[i]);
957dd7cddfSDavid du Colombier if(col >= MAXLINE-(4+4+4+1)){
967dd7cddfSDavid du Colombier Bprint(fd, "\n");
977dd7cddfSDavid du Colombier col = 0;
987dd7cddfSDavid du Colombier }else
997dd7cddfSDavid du Colombier col += Bprint(fd, " ");
1007dd7cddfSDavid du Colombier }
1017dd7cddfSDavid du Colombier break;
1027dd7cddfSDavid du Colombier default:
1037dd7cddfSDavid du Colombier return "WritePPM: can't handle channel type";
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier return nil;
1077dd7cddfSDavid du Colombier }
1087dd7cddfSDavid du Colombier
1097dd7cddfSDavid du Colombier static
1107dd7cddfSDavid du Colombier char*
writeppm0(Biobuf * fd,Image * image,Memimage * memimage,Rectangle r,int chan,char * comment)1117dd7cddfSDavid du Colombier writeppm0(Biobuf *fd, Image *image, Memimage *memimage, Rectangle r, int chan, char *comment)
1127dd7cddfSDavid du Colombier {
1137dd7cddfSDavid du Colombier char *err;
1147dd7cddfSDavid du Colombier
1157dd7cddfSDavid du Colombier switch(chan){
1167dd7cddfSDavid du Colombier case GREY1:
1177dd7cddfSDavid du Colombier Bprint(fd, "P1\n");
1187dd7cddfSDavid du Colombier break;
1197dd7cddfSDavid du Colombier case GREY2:
1207dd7cddfSDavid du Colombier case GREY4:
1217dd7cddfSDavid du Colombier case GREY8:
1227dd7cddfSDavid du Colombier Bprint(fd, "P2\n");
1237dd7cddfSDavid du Colombier break;
1247dd7cddfSDavid du Colombier case RGB24:
1257dd7cddfSDavid du Colombier Bprint(fd, "P3\n");
1267dd7cddfSDavid du Colombier break;
1277dd7cddfSDavid du Colombier default:
1287dd7cddfSDavid du Colombier return "WritePPM: can't handle channel type";
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier
1317dd7cddfSDavid du Colombier if(comment!=nil && comment[0]!='\0'){
1327dd7cddfSDavid du Colombier Bprint(fd, "# %s", comment);
1337dd7cddfSDavid du Colombier if(comment[strlen(comment)-1] != '\n')
1347dd7cddfSDavid du Colombier Bprint(fd, "\n");
1357dd7cddfSDavid du Colombier }
1367dd7cddfSDavid du Colombier Bprint(fd, "%d %d\n", Dx(r), Dy(r));
1377dd7cddfSDavid du Colombier
1387dd7cddfSDavid du Colombier /* maximum pixel value */
1397dd7cddfSDavid du Colombier switch(chan){
1407dd7cddfSDavid du Colombier case GREY2:
1417dd7cddfSDavid du Colombier Bprint(fd, "%d\n", 3);
1427dd7cddfSDavid du Colombier break;
1437dd7cddfSDavid du Colombier case GREY4:
1447dd7cddfSDavid du Colombier Bprint(fd, "%d\n", 15);
1457dd7cddfSDavid du Colombier break;
1467dd7cddfSDavid du Colombier case GREY8:
1477dd7cddfSDavid du Colombier case RGB24:
1487dd7cddfSDavid du Colombier Bprint(fd, "%d\n", 255);
1497dd7cddfSDavid du Colombier break;
1507dd7cddfSDavid du Colombier }
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier err = writedata(fd, image, memimage);
1537dd7cddfSDavid du Colombier
1547dd7cddfSDavid du Colombier Bprint(fd, "\n");
1557dd7cddfSDavid du Colombier Bflush(fd);
1567dd7cddfSDavid du Colombier return err;
1577dd7cddfSDavid du Colombier }
1587dd7cddfSDavid du Colombier
1597dd7cddfSDavid du Colombier char*
writeppm(Biobuf * fd,Image * image,char * comment)1607dd7cddfSDavid du Colombier writeppm(Biobuf *fd, Image *image, char *comment)
1617dd7cddfSDavid du Colombier {
1627dd7cddfSDavid du Colombier return writeppm0(fd, image, nil, image->r, image->chan, comment);
1637dd7cddfSDavid du Colombier }
1647dd7cddfSDavid du Colombier
1657dd7cddfSDavid du Colombier char*
memwriteppm(Biobuf * fd,Memimage * memimage,char * comment)1667dd7cddfSDavid du Colombier memwriteppm(Biobuf *fd, Memimage *memimage, char *comment)
1677dd7cddfSDavid du Colombier {
1687dd7cddfSDavid du Colombier return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment);
1697dd7cddfSDavid du Colombier }
170