/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <draw.h>#include <memdraw.h>#include <bio.h> #define MAXLINE 70 /* imported from libdraw/arith.c to permit an extern log2 function */static int log2[] = { -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5}; /* * Write data */staticchar*writedata(Biobuf *fd, Image *image, Memimage *memimage){ char *err; uchar *data; int i, x, y, ndata, depth, col, pix, xmask, pmask; ulong chan; Rectangle r; if(memimage != nil){ r = memimage->r; depth = memimage->depth; chan = memimage->chan; }else{ r = image->r; depth = image->depth; chan = image->chan; } /* * Read image data into memory * potentially one extra byte on each end of each scan line */ ndata = Dy(r)*(2+Dx(r)*depth/8); data = malloc(ndata); if(data == nil) return "WritePPM: malloc failed"; if(memimage != nil) ndata = unloadmemimage(memimage, r, data, ndata); else ndata = unloadimage(image, r, data, ndata); if(ndata < 0){ err = malloc(ERRMAX); if(err == nil) return "WritePPM: malloc failed"; snprint(err, ERRMAX, "WriteGIF: %r"); free(data); return err; } /* Encode and emit the data */ col = 0; switch(chan){ case GREY1: case GREY2: case GREY4: pmask = (1<<depth)-1; xmask = 7>>log2[depth]; for(y=r.min.y; y<r.max.y; y++){ i = (y-r.min.y)*bytesperline(r, depth); for(x=r.min.x; x<r.max.x; x++){ pix = (data[i]>>depth*((xmask-x)&xmask))&pmask; if(((x+1)&xmask) == 0) i++; col += Bprint(fd, "%d ", pix); if(col >= MAXLINE-(2+1)){ Bprint(fd, "\n"); col = 0; }else col += Bprint(fd, " "); } } break; case GREY8: for(i=0; i<ndata; i++){ col += Bprint(fd, "%d ", data[i]); if(col >= MAXLINE-(4+1)){ Bprint(fd, "\n"); col = 0; }else col += Bprint(fd, " "); } break; case RGB24: for(i=0; i<ndata; i+=3){ col += Bprint(fd, "%d %d %d", data[i+2], data[i+1], data[i]); if(col >= MAXLINE-(4+4+4+1)){ Bprint(fd, "\n"); col = 0; }else col += Bprint(fd, " "); } break; default: return "WritePPM: can't handle channel type"; } return nil;} staticchar*writeppm0(Biobuf *fd, Image *image, Memimage *memimage, Rectangle r, int chan, char *comment){ char *err; switch(chan){ case GREY1: Bprint(fd, "P1\n"); break; case GREY2: case GREY4: case GREY8: Bprint(fd, "P2\n"); break; case RGB24: Bprint(fd, "P3\n"); break; default: return "WritePPM: can't handle channel type"; } if(comment!=nil && comment[0]!='\0'){ Bprint(fd, "# %s", comment); if(comment[strlen(comment)-1] != '\n') Bprint(fd, "\n"); } Bprint(fd, "%d %d\n", Dx(r), Dy(r)); /* maximum pixel value */ switch(chan){ case GREY2: Bprint(fd, "%d\n", 3); break; case GREY4: Bprint(fd, "%d\n", 15); break; case GREY8: case RGB24: Bprint(fd, "%d\n", 255); break; } err = writedata(fd, image, memimage); Bprint(fd, "\n"); Bflush(fd); return err;} char*writeppm(Biobuf *fd, Image *image, char *comment){ return writeppm0(fd, image, nil, image->r, image->chan, comment);} char*memwriteppm(Biobuf *fd, Memimage *memimage, char *comment){ return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment);}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <bio.h>
#define MAXLINE 70
/* imported from libdraw/arith.c to permit an extern log2 function */
static int log2[] = {
-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
};
/*
* Write data
*/
static
char*
writedata(Biobuf *fd, Image *image, Memimage *memimage)
{
char *err;
uchar *data;
int i, x, y, ndata, depth, col, pix, xmask, pmask;
ulong chan;
Rectangle r;
if(memimage != nil){
r = memimage->r;
depth = memimage->depth;
chan = memimage->chan;
}else{
r = image->r;
depth = image->depth;
chan = image->chan;
}
/*
* Read image data into memory
* potentially one extra byte on each end of each scan line
*/
ndata = Dy(r)*(2+Dx(r)*depth/8);
data = malloc(ndata);
if(data == nil)
return "WritePPM: malloc failed";
if(memimage != nil)
ndata = unloadmemimage(memimage, r, data, ndata);
else
ndata = unloadimage(image, r, data, ndata);
if(ndata < 0){
err = malloc(ERRMAX);
if(err == nil)
return "WritePPM: malloc failed";
snprint(err, ERRMAX, "WriteGIF: %r");
free(data);
return err;
}
/* Encode and emit the data */
col = 0;
switch(chan){
case GREY1:
case GREY2:
case GREY4:
pmask = (1<<depth)-1;
xmask = 7>>log2[depth];
for(y=r.min.y; y<r.max.y; y++){
i = (y-r.min.y)*bytesperline(r, depth);
for(x=r.min.x; x<r.max.x; x++){
pix = (data[i]>>depth*((xmask-x)&xmask))&pmask;
if(((x+1)&xmask) == 0)
i++;
col += Bprint(fd, "%d ", pix);
if(col >= MAXLINE-(2+1)){
Bprint(fd, "\n");
col = 0;
}else
col += Bprint(fd, " ");
}
}
break;
case GREY8:
for(i=0; i<ndata; i++){
col += Bprint(fd, "%d ", data[i]);
if(col >= MAXLINE-(4+1)){
Bprint(fd, "\n");
col = 0;
}else
col += Bprint(fd, " ");
}
break;
case RGB24:
for(i=0; i<ndata; i+=3){
col += Bprint(fd, "%d %d %d", data[i+2], data[i+1], data[i]);
if(col >= MAXLINE-(4+4+4+1)){
Bprint(fd, "\n");
col = 0;
}else
col += Bprint(fd, " ");
}
break;
default:
return "WritePPM: can't handle channel type";
}
return nil;
}
static
char*
writeppm0(Biobuf *fd, Image *image, Memimage *memimage, Rectangle r, int chan, char *comment)
{
char *err;
switch(chan){
case GREY1:
Bprint(fd, "P1\n");
break;
case GREY2:
case GREY4:
case GREY8:
Bprint(fd, "P2\n");
break;
case RGB24:
Bprint(fd, "P3\n");
break;
default:
return "WritePPM: can't handle channel type";
}
if(comment!=nil && comment[0]!='\0'){
Bprint(fd, "# %s", comment);
if(comment[strlen(comment)-1] != '\n')
Bprint(fd, "\n");
}
Bprint(fd, "%d %d\n", Dx(r), Dy(r));
/* maximum pixel value */
switch(chan){
case GREY2:
Bprint(fd, "%d\n", 3);
break;
case GREY4:
Bprint(fd, "%d\n", 15);
break;
case GREY8:
case RGB24:
Bprint(fd, "%d\n", 255);
break;
}
err = writedata(fd, image, memimage);
Bprint(fd, "\n");
Bflush(fd);
return err;
}
char*
writeppm(Biobuf *fd, Image *image, char *comment)
{
return writeppm0(fd, image, nil, image->r, image->chan, comment);
}
char*
memwriteppm(Biobuf *fd, Memimage *memimage, char *comment)
{
return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment);
}