This commit is contained in:
rsc 2004-04-21 22:19:33 +00:00
parent a01e58366c
commit 28994509cc
82 changed files with 13293 additions and 0 deletions

210
src/cmd/jpg/bmp.c Normal file
View File

@ -0,0 +1,210 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <event.h>
#include "imagefile.h"
int cflag = 0;
int dflag = 0;
int eflag = 0;
int nineflag = 0;
int threeflag = 0;
int output = 0;
ulong outchan = CMAP8;
int defaultcolor = 1;
Image *image;
enum{
Border = 2,
Edge = 5
};
char *show(int, char*);
Rawimage** readbmp(int fd, int colorspace);
void
eresized(int new)
{
Rectangle r;
if(new && getwindow(display, Refnone) < 0){
fprint(2, "bmp: can't reattach to window\n");
exits("resize");
}
if(image == nil)
return;
r = insetrect(screen->clipr, Edge+Border);
r.max.x = r.min.x+Dx(image->r);
r.max.y = r.min.y+Dy(image->r);
border(screen, r, -Border, nil, ZP);
draw(screen, r, image, nil, image->r.min);
flushimage(display, 1);
}
void
main(int argc, char *argv[])
{
int fd, i;
char *err;
ARGBEGIN{
case '3': /* produce encoded, compressed, three-color bitmap file; no display by default */
threeflag++;
/* fall through */
case 't': /* produce encoded, compressed, true-color bitmap file; no display by default */
cflag++;
dflag++;
output++;
defaultcolor = 0;
outchan = RGB24;
break;
case 'c': /* produce encoded, compressed, bitmap file; no display by default */
cflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
case 'd': /* suppress display of image */
dflag++;
break;
case 'e': /* disable floyd-steinberg error diffusion */
eflag++;
break;
case 'k': /* force black and white */
defaultcolor = 0;
outchan = GREY8;
break;
case 'v': /* force RGBV */
defaultcolor = 0;
outchan = CMAP8;
break;
case '9': /* produce plan 9, uncompressed, bitmap file; no display by default */
nineflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
default:
fprint(2, "usage: bmp -39cdektv [file.bmp ...]\n");
exits("usage");
}ARGEND;
err = nil;
if(argc == 0)
err = show(0, "<stdin>");
else{
for(i=0; i<argc; i++){
fd = open(argv[i], OREAD);
if(fd < 0){
fprint(2, "bmp: can't open %s: %r\n", argv[i]);
err = "open";
}else{
err = show(fd, argv[i]);
close(fd);
}
if((nineflag || cflag) && argc>1 && err==nil){
fprint(2, "bmp: exiting after one file\n");
break;
}
}
}
exits(err);
}
int
init(void)
{
static int inited;
if(inited == 0){
if(initdraw(0, 0, 0) < 0){
fprint(2, "bmp: initdraw failed: %r");
return -1;
}
einit(Ekeyboard|Emouse);
inited++;
}
return 1;
}
char*
show(int fd, char *name)
{
Rawimage **array, *r, *c;
Image *i;
int j, ch;
char buf[32];
array = readbmp(fd, CRGB);
if(array == nil || array[0]==nil){
fprint(2, "bmp: decode %s failed: %r\n", name);
return "decode";
}
if(!dflag){
if(init() < 0)
return "initdraw";
if(defaultcolor && screen->depth>8)
outchan = RGB24;
}
r = array[0];
if(outchan == CMAP8)
c = torgbv(r, !eflag);
else{
if(outchan==GREY8 || (r->chandesc==CY && threeflag==0))
c = totruecolor(r, CY);
else
c = totruecolor(r, CRGB24);
}
if(c == nil){
fprint(2, "bmp: converting %s to local format failed: %r\n", name);
return "torgbv";
}
if(!dflag){
if(r->chandesc == CY)
i = allocimage(display, c->r, GREY8, 0, 0);
else
i = allocimage(display, c->r, outchan, 0, 0);
if(i == nil){
fprint(2, "bmp: allocimage %s failed: %r\n", name);
return "allocimage";
}
if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
fprint(2, "bmp: loadimage %s failed: %r\n", name);
return "loadimage";
}
image = i;
eresized(0);
if((ch=ekbd())=='q' || ch==0x7F || ch==0x04)
exits(nil);
draw(screen, screen->clipr, display->white, nil, ZP);
image = nil;
freeimage(i);
}
if(nineflag){
chantostr(buf, outchan);
print("%11s %11d %11d %11d %11d ", buf,
c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y);
if(write(1, c->chans[0], c->chanlen) != c->chanlen){
fprint(2, "bmp: %s: write error %r\n", name);
return "write";
}
}else if(cflag){
if(writerawimage(1, c) < 0){
fprint(2, "bmp: %s: write error: %r\n", name);
return "write";
}
}
for(j=0; j<r->nchans; j++)
free(r->chans[j]);
free(r);
free(array);
if(c){
free(c->chans[0]);
free(c);
}
return nil;
}

37
src/cmd/jpg/bmp.h Normal file
View File

@ -0,0 +1,37 @@
#define BMP_RGB 0
#define BMP_RLE8 1
#define BMP_RLE4 2
#define BMP_BITFIELDS 3
typedef struct {
uchar red;
uchar green;
uchar blue;
uchar alpha;
} Rgb;
typedef struct {
short type;
long size;
short reserved1;
short reserved2;
long offbits;
} Filehdr;
typedef struct {
long size; /* Size of the Bitmap-file */
long lReserved; /* Reserved */
long dataoff; /* Picture data location */
long hsize; /* Header-Size */
long width; /* Picture width (pixels) */
long height; /* Picture height (pixels) */
short planes; /* Planes (must be 1) */
short bpp; /* Bits per pixel (1, 4, 8 or 24) */
long compression; /* Compression mode */
long imagesize; /* Image size (bytes) */
long hres; /* Horizontal Resolution (pels/meter) */
long vres; /* Vertical Resolution (pels/meter) */
long colours; /* Used Colours (Col-Table index) */
long impcolours; /* Important colours (Col-Table index) */
} Infohdr;

121
src/cmd/jpg/close.c Normal file
View File

@ -0,0 +1,121 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
float c1 = 1.402;
float c2 = 0.34414;
float c3 = 0.71414;
float c4 = 1.772;
int
closest(int Y, int Cb, int Cr)
{
double r, g, b;
double diff, min;
int rgb, R, G, B, v, i;
int y1, cb1, cr1;
Cb -= 128;
Cr -= 128;
r = Y+c1*Cr;
g = Y-c2*Cb-c3*Cr;
b = Y+c4*Cb;
//print("YCbCr: %d %d %d, RGB: %g %g %g\n", Y, Cb, Cr, r, g, b);
min = 1000000.;
v = 1000;
for(i=0; i<256; i++){
rgb = cmap2rgb(i);
R = (rgb >> 16) & 0xFF;
G = (rgb >> 8) & 0xFF;
B = (rgb >> 0) & 0xFF;
diff = (R-r)*(R-r) + (G-g)*(G-g) + (B-b)*(B-b);
// y1 = 0.5870*G + 0.114*B + 0.299*R;
// cb1 = (B-y1)/1.772;
// cr1 = (R-y1)/1.402;
if(diff < min){
// if(Y==0 && y1!=0)
// continue;
// if(Y==256-16 && y1<256-16)
// continue;
// if(Cb==0 && cb1!=0)
// continue;
// if(Cb==256-16 && cb1<256-16)
// continue;
// if(Cr==0 && cr1!=0)
// continue;
// if(Cr==256-16 && cr1<256-16)
// continue;
//print("%d %d %d\n", R, G, B);
min = diff;
v = i;
}
}
if(v > 255)
abort();
return v;
}
#define SHIFT 5
#define INC (1<<SHIFT)
typedef struct Color Color;
struct Color
{
int col;
Color *next;
};
Color *col[INC*INC*INC];
void
add(int c, int y, int cb, int cr)
{
Color *cp;
y >>= 8-SHIFT;
cb >>= 8-SHIFT;
cr >>= 8-SHIFT;
cp = col[cr+INC*(cb+INC*y)];
while(cp != nil){
if(cp->col == c)
return;
cp = cp->next;
}
cp = malloc(sizeof(Color));
cp->col = c;
cp->next = col[cr+INC*(cb+INC*y)];
col[cr+INC*(cb+INC*y)] = cp;
}
void
main(void)
{
int y, cb, cr, n;
Color *cp;
for(y=0; y<256; y++){
for(cb=0; cb<256; cb++)
for(cr=0;cr<256;cr++)
add(closest(y, cb, cr), y, cb, cr);
fprint(2, "%d done\n", y);
}
for(y=0; y<INC*INC*INC; y++){
n = 0;
cp = col[y];
while(cp != nil){
n++;
cp = cp->next;
}
cp = col[y];
while(cp != nil){
n++;
print("%d ", cp->col);
cp = cp->next;
}
print("\n");
}
}

421
src/cmd/jpg/gif.c Normal file
View File

@ -0,0 +1,421 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <event.h>
#include "imagefile.h"
int cflag = 0;
int dflag = 0;
int eflag = 0;
int nineflag = 0;
int threeflag = 0;
int output = 0;
ulong outchan = CMAP8;
Image **allims;
Image **allmasks;
int which;
int defaultcolor = 1;
enum{
Border = 2,
Edge = 5
};
char *show(int, char*);
Rectangle
imager(void)
{
Rectangle r;
if(allims==nil || allims[0]==nil)
return screen->r;
r = insetrect(screen->clipr, Edge+Border);
r.max.x = r.min.x+Dx(allims[0]->r);
r.max.y = r.min.y+Dy(allims[0]->r);
return r;
}
void
eresized(int new)
{
Rectangle r;
if(new && getwindow(display, Refnone) < 0){
fprint(2, "gif: can't reattach to window\n");
exits("resize");
}
if(allims==nil || allims[which]==nil)
return;
r = imager();
border(screen, r, -Border, nil, ZP);
r.min.x += allims[which]->r.min.x - allims[0]->r.min.x;
r.min.y += allims[which]->r.min.y - allims[0]->r.min.y;
drawop(screen, r, allims[which], allmasks[which], allims[which]->r.min, S);
flushimage(display, 1);
}
void
main(int argc, char *argv[])
{
int fd, i;
char *err;
ARGBEGIN{
case '3': /* produce encoded, compressed, three-color bitmap file; no display by default */
threeflag++;
/* fall through */
case 't': /* produce encoded, compressed, true-color bitmap file; no display by default */
cflag++;
dflag++;
output++;
defaultcolor = 0;
outchan = RGB24;
break;
case 'c': /* produce encoded, compressed, bitmap file; no display by default */
cflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
case 'd': /* suppress display of image */
dflag++;
break;
case 'e': /* disable floyd-steinberg error diffusion */
eflag++;
break;
case 'k': /* force black and white */
defaultcolor = 0;
outchan = GREY8;
break;
case 'v': /* force RGBV */
defaultcolor = 0;
outchan = CMAP8;
break;
case '9': /* produce plan 9, uncompressed, bitmap file; no display by default */
nineflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
default:
fprint(2, "usage: gif -39cdektv [file.gif ...]\n");
exits("usage");
}ARGEND;
err = nil;
if(argc == 0)
err = show(0, "<stdin>");
else{
for(i=0; i<argc; i++){
fd = open(argv[i], OREAD);
if(fd < 0){
fprint(2, "gif: can't open %s: %r\n", argv[i]);
err = "open";
}else{
err = show(fd, argv[i]);
close(fd);
}
if(output && argc>1 && err==nil){
fprint(2, "gif: exiting after one file\n");
break;
}
}
}
exits(err);
}
Image*
transparency(Rawimage *r, char *name)
{
Image *i;
int j, index;
uchar *pic, *mpic, *mask;
if((r->gifflags&TRANSP) == 0)
return nil;
i = allocimage(display, r->r, GREY8, 0, 0);
if(i == nil){
fprint(2, "gif: allocimage for mask of %s failed: %r\n", name);
return nil;
}
pic = r->chans[0];
mask = malloc(r->chanlen);
if(mask == nil){
fprint(2, "gif: malloc for mask of %s failed: %r\n", name);
freeimage(i);
return nil;
}
index = r->giftrindex;
mpic = mask;
for(j=0; j<r->chanlen; j++)
if(*pic++ == index)
*mpic++ = 0;
else
*mpic++ = 0xFF;
if(loadimage(i, i->r, mask, r->chanlen) < 0){
fprint(2, "gif: loadimage for mask of %s failed: %r\n", name);
free(mask);
freeimage(i);
return nil;
}
free(mask);
return i;
}
/* interleave alpha values of 0xFF in data stream. alpha value comes first, then b g r */
uchar*
expand(uchar *u, int chanlen, int nchan)
{
int j, k;
uchar *v, *up, *vp;
v = malloc(chanlen*(nchan+1));
if(v == nil){
fprint(2, "gif: malloc fails: %r\n");
exits("malloc");
}
up = u;
vp = v;
for(j=0; j<chanlen; j++){
*vp++ = 0xFF;
for(k=0; k<nchan; k++)
*vp++ = *up++;
}
return v;
}
void
addalpha(Rawimage *i)
{
char buf[32];
switch(outchan){
case CMAP8:
i->chans[0] = expand(i->chans[0], i->chanlen/1, 1);
i->chanlen = 2*(i->chanlen/1);
i->chandesc = CRGBVA16;
outchan = CHAN2(CMap, 8, CAlpha, 8);
break;
case GREY8:
i->chans[0] = expand(i->chans[0], i->chanlen/1, 1);
i->chanlen = 2*(i->chanlen/1);
i->chandesc = CYA16;
outchan = CHAN2(CGrey, 8, CAlpha, 8);
break;
case RGB24:
i->chans[0] = expand(i->chans[0], i->chanlen/3, 3);
i->chanlen = 4*(i->chanlen/3);
i->chandesc = CRGBA32;
outchan = RGBA32;
break;
default:
chantostr(buf, outchan);
fprint(2, "gif: can't add alpha to type %s\n", buf);
exits("err");
}
}
/*
* Called only when writing output. If the output is RGBA32,
* we must write four bytes per pixel instead of two.
* There's always at least two: data plus alpha.
* r is used only for reference; the image is already in c.
*/
void
whiteout(Rawimage *r, Rawimage *c)
{
int i, trindex;
uchar *rp, *cp;
rp = r->chans[0];
cp = c->chans[0];
trindex = r->giftrindex;
if(outchan == RGBA32)
for(i=0; i<r->chanlen; i++){
if(*rp == trindex){
*cp++ = 0x00;
*cp++ = 0xFF;
*cp++ = 0xFF;
*cp++ = 0xFF;
}else{
*cp++ = 0xFF;
cp += 3;
}
rp++;
}
else
for(i=0; i<r->chanlen; i++){
if(*rp == trindex){
*cp++ = 0x00;
*cp++ = 0xFF;
}else{
*cp++ = 0xFF;
cp++;
}
rp++;
}
}
int
init(void)
{
static int inited;
if(inited == 0){
if(initdraw(0, 0, 0) < 0){
fprint(2, "gif: initdraw failed: %r\n");
return -1;
}
einit(Ekeyboard|Emouse);
inited++;
}
return 1;
}
char*
show(int fd, char *name)
{
Rawimage **images, **rgbv;
Image **ims, **masks;
int j, k, n, ch, nloop, loopcount, dt;
char *err;
char buf[32];
err = nil;
images = readgif(fd, CRGB);
if(images == nil){
fprint(2, "gif: decode %s failed: %r\n", name);
return "decode";
}
for(n=0; images[n]; n++)
;
ims = malloc((n+1)*sizeof(Image*));
masks = malloc((n+1)*sizeof(Image*));
rgbv = malloc((n+1)*sizeof(Rawimage*));
if(masks==nil || rgbv==nil || ims==nil){
fprint(2, "gif: malloc of masks for %s failed: %r\n", name);
err = "malloc";
goto Return;
}
memset(masks, 0, (n+1)*sizeof(Image*));
memset(ims, 0, (n+1)*sizeof(Image*));
memset(rgbv, 0, (n+1)*sizeof(Rawimage*));
if(!dflag){
if(init() < 0){
err = "initdraw";
goto Return;
}
if(defaultcolor && screen->depth>8)
outchan = RGB24;
}
for(k=0; k<n; k++){
if(outchan == CMAP8)
rgbv[k] = torgbv(images[k], !eflag);
else{
if(outchan==GREY8 || (images[k]->chandesc==CY && threeflag==0))
rgbv[k] = totruecolor(images[k], CY);
else
rgbv[k] = totruecolor(images[k], CRGB24);
}
if(rgbv[k] == nil){
fprint(2, "gif: converting %s to local format failed: %r\n", name);
err = "torgbv";
goto Return;
}
if(!dflag){
masks[k] = transparency(images[k], name);
if(rgbv[k]->chandesc == CY)
ims[k] = allocimage(display, rgbv[k]->r, GREY8, 0, 0);
else
ims[k] = allocimage(display, rgbv[k]->r, outchan, 0, 0);
if(ims[k] == nil){
fprint(2, "gif: allocimage %s failed: %r\n", name);
err = "allocimage";
goto Return;
}
if(loadimage(ims[k], ims[k]->r, rgbv[k]->chans[0], rgbv[k]->chanlen) < 0){
fprint(2, "gif: loadimage %s failed: %r\n", name);
err = "loadimage";
goto Return;
}
}
}
allims = ims;
allmasks = masks;
loopcount = images[0]->gifloopcount;
if(!dflag){
nloop = 0;
do{
for(k=0; k<n; k++){
which = k;
eresized(0);
dt = images[k]->gifdelay*10;
if(dt < 50)
dt = 50;
while(n==1 || ecankbd()){
if((ch=ekbd())=='q' || ch==0x7F || ch==0x04) /* an odd, democratic list */
exits(nil);
if(ch == '\n')
goto Out;
}sleep(dt);
}
/* loopcount -1 means no loop (this code's rule), loopcount 0 means loop forever (netscape's rule)*/
}while(loopcount==0 || ++nloop<loopcount);
/* loop count has run out */
ekbd();
Out:
drawop(screen, screen->clipr, display->white, nil, ZP, S);
}
if(n>1 && output)
fprint(2, "gif: warning: only writing first image in %d-image GIF %s\n", n, name);
if(nineflag){
if(images[0]->gifflags&TRANSP){
addalpha(rgbv[0]);
whiteout(images[0], rgbv[0]);
}
chantostr(buf, outchan);
print("%11s %11d %11d %11d %11d ", buf,
rgbv[0]->r.min.x, rgbv[0]->r.min.y, rgbv[0]->r.max.x, rgbv[0]->r.max.y);
if(write(1, rgbv[0]->chans[0], rgbv[0]->chanlen) != rgbv[0]->chanlen){
fprint(2, "gif: %s: write error %r\n", name);
return "write";
}
}else if(cflag){
if(images[0]->gifflags&TRANSP){
addalpha(rgbv[0]);
whiteout(images[0], rgbv[0]);
}
if(writerawimage(1, rgbv[0]) < 0){
fprint(2, "gif: %s: write error: %r\n", name);
return "write";
}
}
Return:
allims = nil;
allmasks = nil;
for(k=0; images[k]; k++){
for(j=0; j<images[k]->nchans; j++)
free(images[k]->chans[j]);
free(images[k]->cmap);
if(rgbv[k])
free(rgbv[k]->chans[0]);
freeimage(ims[k]);
freeimage(masks[k]);
free(images[k]);
free(rgbv[k]);
}
free(images);
free(masks);
free(ims);
return err;
}

506
src/cmd/jpg/ico.c Normal file
View File

@ -0,0 +1,506 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <event.h>
#include <cursor.h>
typedef struct Icon Icon;
struct Icon
{
Icon *next;
uchar w; /* icon width */
uchar h; /* icon height */
ushort ncolor; /* number of colors */
ushort nplane; /* number of bit planes */
ushort bits; /* bits per pixel */
ulong len; /* length of data */
ulong offset; /* file offset to data */
Image *img;
Image *mask;
Rectangle r; /* relative */
Rectangle sr; /* abs */
};
typedef struct Header Header;
struct Header
{
uint n;
Icon *first;
Icon *last;
};
int debug;
Mouse mouse;
Header h;
Image *background;
ushort
gets(uchar *p)
{
return p[0] | (p[1]<<8);
}
ulong
getl(uchar *p)
{
return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
}
int
Bgetheader(Biobuf *b, Header *h)
{
Icon *icon;
int i;
uchar buf[40];
memset(h, 0, sizeof(*h));
if(Bread(b, buf, 6) != 6)
goto eof;
if(gets(&buf[0]) != 0)
goto header;
if(gets(&buf[2]) != 1)
goto header;
h->n = gets(&buf[4]);
for(i = 0; i < h->n; i++){
icon = mallocz(sizeof(*icon), 1);
if(icon == nil)
sysfatal("malloc: %r");
if(Bread(b, buf, 16) != 16)
goto eof;
icon->w = buf[0];
icon->h = buf[1];
icon->ncolor = buf[2] == 0 ? 256 : buf[2];
if(buf[3] != 0)
goto header;
icon->nplane = gets(&buf[4]);
icon->bits = gets(&buf[6]);
icon->len = getl(&buf[8]);
icon->offset = getl(&buf[12]);
if(i == 0)
h->first = icon;
else
h->last->next = icon;
h->last = icon;
}
return 0;
eof:
werrstr("unexpected EOF");
return -1;
header:
werrstr("unknown header format");
return -1;
}
uchar*
transcmap(Icon *icon, uchar *map)
{
uchar *m, *p;
int i;
p = m = malloc(sizeof(int)*(1<<icon->bits));
for(i = 0; i < icon->ncolor; i++){
*p++ = rgb2cmap(map[2], map[1], map[0]);
map += 4;
}
return m;
}
Image*
xor2img(Icon *icon, uchar *xor, uchar *map)
{
uchar *data;
Image *img;
int inxlen;
uchar *from, *to;
int s, byte, mask;
int x, y;
inxlen = 4*((icon->bits*icon->w+31)/32);
to = data = malloc(icon->w*icon->h);
/* rotate around the y axis, go to 8 bits, and convert color */
mask = (1<<icon->bits)-1;
for(y = 0; y < icon->h; y++){
s = -1;
byte = 0;
from = xor + (icon->h - 1 - y)*inxlen;
for(x = 0; x < icon->w; x++){
if(s < 0){
byte = *from++;
s = 8-icon->bits;
}
*to++ = map[(byte>>s) & mask];
s -= icon->bits;
}
}
/* stick in an image */
img = allocimage(display, Rect(0,0,icon->w,icon->h), CMAP8, 0, DNofill);
loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w);
free(data);
return img;
}
Image*
and2img(Icon *icon, uchar *and)
{
uchar *data;
Image *img;
int inxlen;
int outxlen;
uchar *from, *to;
int x, y;
inxlen = 4*((icon->w+31)/32);
to = data = malloc(inxlen*icon->h);
/* rotate around the y axis and invert bits */
outxlen = (icon->w+7)/8;
for(y = 0; y < icon->h; y++){
from = and + (icon->h - 1 - y)*inxlen;
for(x = 0; x < outxlen; x++){
*to++ = ~(*from++);
}
}
/* stick in an image */
img = allocimage(display, Rect(0,0,icon->w,icon->h), GREY1, 0, DNofill);
loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*outxlen);
free(data);
return img;
}
int
Bgeticon(Biobuf *b, Icon *icon)
{
ulong l;
ushort s;
uchar *xor;
uchar *and;
uchar *cm;
uchar *buf;
uchar *map2map;
Image *img;
Bseek(b, icon->offset, 0);
buf = malloc(icon->len);
if(buf == nil)
return -1;
if(Bread(b, buf, icon->len) != icon->len){
werrstr("unexpected EOF");
return -1;
}
/* this header's info takes precedence over previous one */
if(getl(buf) != 40){
werrstr("bad icon header");
return -1;
}
l = getl(buf+4);
if(l != icon->w)
icon->w = l;
l = getl(buf+8);
if(l>>1 != icon->h)
icon->h = l>>1;
s = gets(buf+12);
if(s != icon->nplane)
icon->nplane = s;
s = gets(buf+14);
if(s != icon->bits)
icon->bits = s;
/* limit what we handle */
switch(icon->bits){
case 1:
case 2:
case 4:
case 8:
break;
default:
werrstr("don't support %d bit pixels", icon->bits);
return -1;
}
if(icon->nplane != 1){
werrstr("don't support %d planes", icon->nplane);
return -1;
}
cm = buf + 40;
xor = cm + 4*icon->ncolor;
and = xor + icon->h*4*((icon->bits*icon->w+31)/32);
/* translate the color map to a plan 9 one */
map2map = transcmap(icon, cm);
/* convert the images */
icon->img = xor2img(icon, xor, map2map);
icon->mask = and2img(icon, and);
/* so that we save an image with a white background */
img = allocimage(display, icon->img->r, CMAP8, 0, DWhite);
draw(img, icon->img->r, icon->img, icon->mask, ZP);
icon->img = img;
free(buf);
free(map2map);
return 0;
}
void
usage(void)
{
fprint(2, "usage: %s [file]\n", argv0);
exits("usage");
}
enum
{
Mimage,
Mmask,
Mexit,
Up= 1,
Down= 0,
};
char *menu3str[] = {
[Mimage] "write image",
[Mmask] "write mask",
[Mexit] "exit",
0,
};
Menu menu3 = {
menu3str
};
Cursor sight = {
{-7, -7},
{0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF,
0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF,
0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8,},
{0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84,
0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE,
0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00,}
};
void
buttons(int ud)
{
while((mouse.buttons==0) != ud)
mouse = emouse();
}
void
mesg(char *fmt, ...)
{
va_list arg;
char buf[1024];
static char obuf[1024];
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
string(screen, screen->r.min, background, ZP, font, obuf);
string(screen, screen->r.min, display->white, ZP, font, buf);
strcpy(obuf, buf);
}
void
doimage(Icon *icon)
{
int rv;
char file[256];
int fd;
rv = -1;
snprint(file, sizeof(file), "%dx%d.img", icon->w, icon->h);
fd = create(file, OWRITE, 0664);
if(fd >= 0){
rv = writeimage(fd, icon->img, 0);
close(fd);
}
if(rv < 0)
mesg("error writing %s: %r", file);
else
mesg("created %s", file);
}
void
domask(Icon *icon)
{
int rv;
char file[64];
int fd;
rv = -1;
snprint(file, sizeof(file), "%dx%d.mask", icon->w, icon->h);
fd = create(file, OWRITE, 0664);
if(fd >= 0){
rv = writeimage(fd, icon->mask, 0);
close(fd);
}
if(rv < 0)
mesg("error writing %s: %r", file);
else
mesg("created %s", file);
}
void
apply(void (*f)(Icon*))
{
Icon *icon;
esetcursor(&sight);
buttons(Down);
if(mouse.buttons == 4)
for(icon = h.first; icon; icon = icon->next)
if(ptinrect(mouse.xy, icon->sr)){
buttons(Up);
f(icon);
break;
}
buttons(Up);
esetcursor(0);
}
void
menu(void)
{
int sel;
sel = emenuhit(3, &mouse, &menu3);
switch(sel){
case Mimage:
apply(doimage);
break;
case Mmask:
apply(domask);
break;
case Mexit:
exits(0);
break;
}
}
void
mousemoved(void)
{
Icon *icon;
for(icon = h.first; icon; icon = icon->next)
if(ptinrect(mouse.xy, icon->sr)){
mesg("%dx%d", icon->w, icon->h);
return;
}
mesg("");
}
enum
{
BORDER= 1,
};
void
eresized(int new)
{
Icon *icon;
Rectangle r;
if(new && getwindow(display, Refnone) < 0)
sysfatal("can't reattach to window");
draw(screen, screen->clipr, background, nil, ZP);
r.max.x = screen->r.min.x;
r.min.y = screen->r.min.y + font->height + 2*BORDER;
for(icon = h.first; icon != nil; icon = icon->next){
r.min.x = r.max.x + BORDER;
r.max.x = r.min.x + Dx(icon->img->r);
r.max.y = r.min.y + Dy(icon->img->r);
draw(screen, r, icon->img, nil, ZP);
border(screen, r, -BORDER, display->black, ZP);
icon->sr = r;
}
flushimage(display, 1);
}
void
main(int argc, char **argv)
{
Biobuf in;
Icon *icon;
int fd;
Rectangle r;
Event e;
ARGBEGIN{
case 'd':
debug = 1;
break;
}ARGEND;
fd = -1;
switch(argc){
case 0:
fd = 0;
break;
case 1:
fd = open(argv[0], OREAD);
if(fd < 0)
sysfatal("opening: %r");
break;
default:
usage();
break;
}
Binit(&in, fd, OREAD);
if(Bgetheader(&in, &h) < 0)
sysfatal("reading header: %r");
initdraw(nil, nil, "ico");
background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, (128<<24)|(128<<16)|(128<<8)|0xFF);
einit(Emouse|Ekeyboard);
r.min = Pt(4, 4);
for(icon = h.first; icon != nil; icon = icon->next){
if(Bgeticon(&in, icon) < 0){
fprint(2, "bad rectangle: %r\n");
continue;
}
if(debug)
fprint(2, "w %ud h %ud ncolor %ud bits %ud len %lud offset %lud\n",
icon->w, icon->h, icon->ncolor, icon->bits, icon->len, icon->offset);
r.max = addpt(r.min, Pt(icon->w, icon->h));
icon->r = r;
r.min.x += r.max.x;
}
eresized(0);
for(;;)
switch(event(&e)){
case Ekeyboard:
break;
case Emouse:
mouse = e.mouse;
if(mouse.buttons & 4)
menu();
else
mousemoved();
break;
}
exits(0);
}

82
src/cmd/jpg/imagefile.h Normal file
View File

@ -0,0 +1,82 @@
typedef struct Rawimage Rawimage;
struct Rawimage
{
Rectangle r;
uchar *cmap;
int cmaplen;
int nchans;
uchar *chans[4];
int chandesc;
int chanlen;
int fields; /* defined by format */
int gifflags; /* gif only; graphics control extension flag word */
int gifdelay; /* gif only; graphics control extension delay in cs */
int giftrindex; /* gif only; graphics control extension transparency index */
int gifloopcount; /* number of times to loop in animation; 0 means forever */
};
enum
{
/* Channel descriptors */
CRGB = 0, /* three channels, no map */
CYCbCr = 1, /* three channels, no map, level-shifted 601 color space */
CY = 2, /* one channel, luminance */
CRGB1 = 3, /* one channel, map present */
CRGBV = 4, /* one channel, map is RGBV, understood */
CRGB24 = 5, /* one channel in correct data order for loadimage(RGB24) */
CRGBA32 = 6, /* one channel in correct data order for loadimage(RGBA32) */
CYA16 = 7, /* one channel in correct data order for loadimage(Grey8+Alpha8) */
CRGBVA16= 8, /* one channel in correct data order for loadimage(CMAP8+Alpha8) */
/* GIF flags */
TRANSP = 1,
INPUT = 2,
DISPMASK = 7<<2
};
enum{ /* PNG flags */
II_GAMMA = 1 << 0,
II_COMMENT = 1 << 1,
};
typedef struct ImageInfo {
ulong fields_set;
double gamma;
char *comment;
} ImageInfo;
Rawimage** readjpg(int, int);
Rawimage** Breadjpg(Biobuf *b, int);
Rawimage** readpng(int, int);
Rawimage** Breadpng(Biobuf *b, int);
Rawimage** readgif(int, int);
Rawimage** readpixmap(int, int);
Rawimage* torgbv(Rawimage*, int);
Rawimage* totruecolor(Rawimage*, int);
int writerawimage(int, Rawimage*);
void* _remaperror(char*, ...);
#ifndef _MEMDRAW_H_
typedef struct Memimage Memimage; /* avoid necessity to include memdraw.h */
#endif
char* startgif(Biobuf*, Image*, int);
char* writegif(Biobuf*, Image*, char*, int, int);
void endgif(Biobuf*);
char* memstartgif(Biobuf*, Memimage*, int);
char* memwritegif(Biobuf*, Memimage*, char*, int, int);
void memendgif(Biobuf*);
Image* onechan(Image*);
Memimage* memonechan(Memimage*);
char* writeppm(Biobuf*, Image*, char*);
char* memwriteppm(Biobuf*, Memimage*, char*);
Image* multichan(Image*);
Memimage* memmultichan(Memimage*);
char* memwritepng(Biobuf*, Memimage*, ImageInfo*);
extern int drawlog2[];

346
src/cmd/jpg/jpegdump.c Normal file
View File

@ -0,0 +1,346 @@
/* jpeg parser by tom szymanski */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
/* subroutines done by macros */
#define min(A,B) ((A)<(B) ? (A) : (B))
#define max(A,B) ((A)>(B) ? (A) : (B))
#define maxeql(A,B) if (A < (B)) A = (B);
#define mineql(A,B) if (A > (B)) A = (B);
#define eatarg0 (argc--, argv++)
#define arrayLength(A) ((sizeof A)/ (sizeof A[0]))
FILE *infile;
char *fname;
/* Routines to print error messages of varying severity */
/* externally visible variables */
int warncnt;
char *myname;
void getname (char *arg) {
/* Save name of invoking program for use by error routines */
register char *p;
p = strrchr (arg, '/');
if (p == NULL)
myname = arg;
else
myname = ++p;
}
static void introduction (void) {
warncnt++;
fflush (stdout);
if (myname != NULL)
fprintf (stderr, "%s: ", myname);
}
void warn (char *fmt, ...) {
va_list args;
introduction ();
va_start (args, fmt);
vfprintf (stderr, fmt, args);
va_end (args);
fputc ('\n', stderr);
fflush (stderr);
}
void quit (char *fmt, ...) {
va_list args;
introduction ();
va_start (args, fmt);
vfprintf (stderr, fmt, args);
va_end (args);
fputc ('\n', stderr);
fflush (stderr);
exit (1);
}
void fatal (char *fmt, ...) {
va_list args;
introduction ();
va_start (args, fmt);
vfprintf (stderr, fmt, args);
va_end (args);
fprintf (stderr, "\nbetter get help!\n");
fflush (stderr);
abort ();
}
int toption = 0;
int dqt[16][64];
int get1 (void) {
unsigned char x;
if (fread(&x, 1, 1, infile) == 0)
quit ("unexpected EOF");
return x;
}
int get2 (void) {
int x;
x = get1() << 8;
return x | get1();
}
void eatmarker (int kind) {
int l, c;
l = get2();
printf ("%02x len=%d\n", kind, l);
for (l -= 2; l > 0; l--)
get1();
}
char *sofName[16] = {
"Baseline sequential DCT - Huffman coding",
"Extended sequential DCT - Huffman coding",
"Progressive DCT - Huffman coding",
"Lossless - Huffman coding",
"4 is otherwise used",
"Sequential DCT - differential Huffman coding",
"Progressive DCT - differential Huffman coding",
"Lossless - differential Huffman coding",
"8 is reserved",
"Extended Sequential DCT - arithmetic coding",
"Progressive DCT - arithmetic coding",
"Lossless - arithmetic coding",
"c is otherwise used",
"Sequential DCT - differential arithmetic coding",
"Progressive DCT - differential arithmetic coding",
"Lossless - differential arithmetic coding",
};
void get_sof (int kind) {
int i, length, height, width, precision, ncomponents;
int id, sf, tab;
length = get2();
precision = get1();
height = get2();
width = get2();
ncomponents = get1();
printf ("SOF%d:\t%s\n", kind - 0xc0, sofName[kind - 0xc0]);
printf ("\t%d wide, %d high, %d deep, %d components\n",
width, height, precision, ncomponents);
for (i = 0; i < ncomponents; i++) {
id = get1();
sf = get1();
tab = get1();
printf ("\tcomponent %d: %d hsample, %d vsample, quantization table %d\n",
id, sf >> 4, sf & 0xf, tab);
}
}
void get_com (int kind) {
int l, c;
l = get2();
printf ("COM len=%d '", l);
for (l -= 2; l > 0; l--)
putchar (c = get1());
printf ("'\n");
}
void get_app (int kind) {
int l, c, first;
char buf[6];
int nbuf, nok;
l = get2();
printf ("APP%d len=%d\n", kind - 0xe0, l);
nbuf = 0;
nok = 0;
first = 1;
/* dump printable strings in comment */
for (l -= 2; l > 0; l--){
c = get1();
if(isprint(c)){
if(nbuf >= sizeof buf){
if(!first && nbuf == nok)
printf(" ");
printf("%.*s", nbuf, buf);
nbuf = 0;
first = 0;
}
buf[nbuf++] = c;
nok++;
}else{
if(nok >= sizeof buf)
if(nbuf > 0)
printf("%.*s", nbuf, buf);
nbuf = 0;
nok = 0;
}
}
if(nok >= sizeof buf)
if(nbuf > 0){
if(!first && nbuf == nok)
printf(" ");
printf("%.*s", nbuf, buf);
}
}
void get_dac (int kind) {
eatmarker (kind);
}
int get1dqt (void) {
int t, p, i, *tab;
t = get1();
p = t >> 4;
t = t & 0xf;
printf ("DQT:\tp = %d, table = %d\n", p, t);
tab = &dqt[t][0];
for (i = 0; i < 64; i++)
tab[i] = p ? get2() : get1();
if (toption) {
for (i = 0; i < 64; i++)
printf ("\t%q[%02d] = %d\n", i, tab[i]);
}
return p ? 65 : 129;
}
void get_dqt (int kind) {
int length;
length = get2() - 2;
while (length > 0)
length -= get1dqt();
}
int get1dht (void) {
int l, tcth, p, i, j, v[16], vv[16][256];
tcth = get1();
printf ("DHT:\tclass = %d, table = %d\n", tcth >> 4, tcth & 0xf);
for (i = 0; i < 16; i++)
v[i] = get1();
l = 17;
for (i = 0; i < 16; i++)
for (j = 0; j < v[i]; j++) {
vv[i][j] = get1();
l += 1;
}
if (toption) {
for (i = 0; i < 16; i++)
printf ("\t%l[%02d] = %d\n", i+1, v[i]);
for (i = 0; i < 16; i++)
for (j = 0; j < v[i]; j++)
printf ("\t%v[%02d,%02d] = %d\n", i+1, j+1, vv[i][j]);
}
return l;
}
void get_dht (int kind) {
int length;
length = get2() - 2;
while (length > 0)
length -= get1dht();
}
void get_sos (int kind) {
int i, length, ncomponents, id, dcac, ahal;
length = get2();
ncomponents = get1();
printf ("SOS:\t%d components\n", ncomponents);
for (i = 0; i < ncomponents; i++) {
id = get1();
dcac = get1();
printf ("\tcomponent %d: %d DC, %d AC\n", id, dcac >> 4, dcac & 0xf);
}
printf ("\tstart spectral %d\n", get1());
printf ("\tend spectral %d\n", get1());
ahal = get1();
printf ("\tah = %d, al = %d\n", ahal >> 4, ahal &0xf);
}
main (int argc, char *argv[]) {
int l, stuff, i, j, c;
while (argc > 1 && argv[1][0] == '-') {
switch (argv[1][1]) {
case 't':
toption = 1;
break;
default:
warn ("bad option '%c'", argv[1][1]);
}
eatarg0;
}
fname = argv[1];
infile = fopen (fname, "r");
if (infile == NULL)
quit ("can't open %s\n", fname);
Start:
// if (get1() != 0xff || get1() != 0xd8)
// quit ("not JFIF");
// printf ("SOI\n");
// get_app (0xe0);
for (;;) {
c = get1();
if (c != 0xff)
quit ("expected marker, got %2x", c);
do {
c = get1();
} while (c == 0xff);
marker:
switch (c) {
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
case 0xc5: case 0xc6: case 0xc7:
case 0xc8: case 0xc9: case 0xca: case 0xcb:
case 0xcd: case 0xce: case 0xcf:
get_sof (c);
break;
case 0xc4:
get_dht (c);
break;
case 0xcc:
get_dac (c);
break;
case 0xd8:
printf ("SOI\n");
break;
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
case 0xe8: case 0xe9: case 0xea: case 0xeb:
case 0xec: case 0xed: case 0xee: case 0xef:
get_app(c);
break;
case 0xda:
get_sos (c);
goto newentropy;
case 0xdb:
get_dqt (c);
break;
case 0xfe:
get_com (c);
break;
case 0xd9:
printf ("EOI\n");
if((c=getc(infile)) == EOF)
exit(0);
ungetc(c, infile);
goto Start;
default:
eatmarker (c);
}
continue;
newentropy:
l = stuff = 0;
entropy:
while ((c = get1()) != 0xff)
l += 1;
while (c == 0xff)
c = get1();
if (c == 0) {
stuff += 1;
goto entropy;
}
printf ("sequence length %d with %d stuffs\n", l, stuff);
if (0xd0 <= c && c <= 0xd7) {
printf ("restart %d\n", c - 0xd0);
goto newentropy;
}
goto marker;
}
}

342
src/cmd/jpg/jpg.c Normal file
View File

@ -0,0 +1,342 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <event.h>
#include "imagefile.h"
int cflag = 0;
int dflag = 0;
int eflag = 0;
int jflag = 0;
int fflag = 0;
int Fflag = 0;
int nineflag = 0;
int threeflag = 0;
int colorspace = CYCbCr; /* default for 8-bit displays: combine color rotation with dither */
int output = 0;
ulong outchan = CMAP8;
Image *image;
int defaultcolor = 1;
enum{
Border = 2,
Edge = 5
};
char *show(int, char*, int);
void
eresized(int new)
{
Rectangle r;
if(new && getwindow(display, Refnone) < 0){
fprint(2, "jpg: can't reattach to window\n");
exits("resize");
}
if(image == nil)
return;
r = insetrect(screen->clipr, Edge+Border);
r.max.x = r.min.x+Dx(image->r);
r.max.y = r.min.y+Dy(image->r);
border(screen, r, -Border, nil, ZP);
draw(screen, r, image, nil, image->r.min);
flushimage(display, 1);
}
void
main(int argc, char *argv[])
{
int fd, i, yflag;
char *err;
char buf[12+1];
yflag = 0;
ARGBEGIN{
case 'c': /* produce encoded, compressed, bitmap file; no display by default */
cflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
case 'd': /* suppress display of image */
dflag++;
break;
case 'e': /* disable floyd-steinberg error diffusion */
eflag++;
break;
case 'F':
Fflag++; /* make a movie */
fflag++; /* merge two fields per image */
break;
case 'f':
fflag++; /* merge two fields per image */
break;
case 'J': /* decode jpeg only; no display or remap (for debugging, etc.) */
jflag++;
break;
case 'k': /* force black and white */
defaultcolor = 0;
outchan = GREY8;
break;
case 'r':
colorspace = CRGB;
break;
case '3': /* produce encoded, compressed, three-color bitmap file; no display by default */
threeflag++;
/* fall through */
case 't': /* produce encoded, compressed, true-color bitmap file; no display by default */
cflag++;
dflag++;
output++;
defaultcolor = 0;
outchan = RGB24;
break;
case 'v': /* force RGBV */
defaultcolor = 0;
outchan = CMAP8;
break;
case 'y': /* leave it in CYCbCr; for debugging only */
yflag = 1;
colorspace = CYCbCr;
break;
case '9': /* produce plan 9, uncompressed, bitmap file; no display by default */
nineflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
default:
fprint(2, "usage: jpg -39cdefFkJrtv [file.jpg ...]\n");
exits("usage");
}ARGEND;
if(yflag==0 && dflag==0 && colorspace==CYCbCr){ /* see if we should convert right to RGB */
fd = open("/dev/screen", OREAD);
if(fd > 0){
buf[12] = '\0';
if(read(fd, buf, 12)==12 && chantodepth(strtochan(buf))>8)
colorspace = CRGB;
close(fd);
}
}
err = nil;
if(argc == 0)
err = show(0, "<stdin>", outchan);
else{
for(i=0; i<argc; i++){
fd = open(argv[i], OREAD);
if(fd < 0){
fprint(2, "jpg: can't open %s: %r\n", argv[i]);
err = "open";
}else{
err = show(fd, argv[i], outchan);
close(fd);
}
if((nineflag || cflag) && argc>1 && err==nil){
fprint(2, "jpg: exiting after one file\n");
break;
}
}
}
exits(err);
}
Rawimage**
vidmerge(Rawimage **aa1, Rawimage **aa2)
{
Rawimage **aao, *ao, *a1, *a2;
int i, c, row, col;
aao = nil;
for (i = 0; aa1[i]; i++) {
a1 = aa1[i];
a2 = aa2[i];
if (a2 == nil){
fprint(2, "jpg: vidmerge: unequal lengths\n");
return nil;
}
aao = realloc(aao, (i+2)*sizeof(Rawimage *));
if (aao == nil){
fprint(2, "jpg: vidmerge: realloc\n");
return nil;
}
aao[i+1] = nil;
ao = aao[i] = malloc(sizeof(Rawimage));
if (ao == nil){
fprint(2, "jpg: vidmerge: realloc\n");
return nil;
}
memcpy(ao, a1, sizeof(Rawimage));
if (!eqrect(a1->r , a2->r)){
fprint(2, "jpg: vidmerge: rects different in img %d\n", i);
return nil;
}
if (a1->cmaplen != a2->cmaplen){
fprint(2, "jpg: vidmerge: cmaplen different in img %d\n", i);
return nil;
}
if (a1->nchans != a2->nchans){
fprint(2, "jpg: vidmerge: nchans different in img %d\n", i);
return nil;
}
if (a1->fields != a2->fields){
fprint(2, "jpg: vidmerge: fields different in img %d\n", i);
return nil;
}
ao->r.max.y += Dy(ao->r);
ao->chanlen += ao->chanlen;
if (ao->chanlen != Dx(ao->r)*Dy(ao->r)){
fprint(2, "jpg: vidmerge: chanlen wrong %d != %d*%d\n",
ao->chanlen, Dx(ao->r), Dy(ao->r));
return nil;
}
row = Dx(a1->r);
for (c = 0; c < ao->nchans; c++) {
uchar *po, *p1, *p2;
ao->chans[c] = malloc(ao->chanlen);
po = ao->chans[c];
p1 = a1->chans[c];
p2 = a2->chans[c];
for (col = 0; col < Dy(a1->r); col++) {
memcpy(po, p1, row);
po += row, p1 += row;
memcpy(po, p2, row);
po += row, p2 += row;
}
free(a1->chans[c]);
free(a2->chans[c]);
}
if(a2->cmap != nil)
free(a2->cmap);
free(a1);
free(a2);
}
if (aa2[i] != nil)
fprint(2, "jpg: vidmerge: unequal lengths\n");
free(aa1);
free(aa2);
return aao;
}
char*
show(int fd, char *name, int outc)
{
Rawimage **array, *r, *c;
static int inited;
Image *i;
int j, ch, outchan;
Biobuf b;
char buf[32];
if(Binit(&b, fd, OREAD) < 0)
return nil;
outchan = outc;
rpt: array = Breadjpg(&b, colorspace);
if(array == nil || array[0]==nil){
fprint(2, "jpg: decode %s failed: %r\n", name);
return "decode";
}
if (fflag) {
Rawimage **a;
a = Breadjpg(&b, colorspace);
if(a == nil || a[0]==nil){
fprint(2, "jpg: decode %s-2 failed: %r\n", name);
return "decode";
}
array = vidmerge(a, array);
} else
Bterm(&b);
r = array[0];
c = nil;
if(jflag)
goto Return;
if(!dflag && !inited){
if(initdraw(0, 0, 0) < 0){
fprint(2, "jpg: initdraw failed: %r\n");
return "initdraw";
}
if(Fflag == 0)
einit(Ekeyboard|Emouse);
if(defaultcolor && screen->depth>8 && outchan==CMAP8)
outchan = RGB24;
inited++;
}
if(outchan == CMAP8)
c = torgbv(r, !eflag);
else{
if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)){
c = totruecolor(r, CY);
outchan = GREY8;
}else
c = totruecolor(r, CRGB24);
}
if(c == nil){
fprint(2, "jpg: conversion of %s failed: %r\n", name);
return "torgbv";
}
if(!dflag){
if(c->chandesc == CY)
i = allocimage(display, c->r, GREY8, 0, 0);
else
i = allocimage(display, c->r, outchan, 0, 0);
if(i == nil){
fprint(2, "jpg: allocimage %s failed: %r\n", name);
return "allocimage";
}
if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
fprint(2, "jpg: loadimage %s failed: %r\n", name);
return "loadimage";
}
image = i;
eresized(0);
if (Fflag) {
freeimage(i);
for(j=0; j<r->nchans; j++)
free(r->chans[j]);
free(r->cmap);
free(r);
free(array);
goto rpt;
}
if((ch=ekbd())=='q' || ch==0x7F || ch==0x04)
exits(nil);
draw(screen, screen->clipr, display->white, nil, ZP);
image = nil;
freeimage(i);
}
if(nineflag){
chantostr(buf, outchan);
print("%11s %11d %11d %11d %11d ", buf,
c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y);
if(write(1, c->chans[0], c->chanlen) != c->chanlen){
fprint(2, "jpg: %s: write error %r\n", name);
return "write";
}
}else if(cflag){
if(writerawimage(1, c) < 0){
fprint(2, "jpg: %s: write error: %r\n", name);
return "write";
}
}
Return:
for(j=0; j<r->nchans; j++)
free(r->chans[j]);
free(r->cmap);
free(r);
free(array);
if(c){
free(c->chans[0]);
free(c);
}
if (Fflag) goto rpt;
return nil;
}

52
src/cmd/jpg/mkfile Normal file
View File

@ -0,0 +1,52 @@
<$PLAN9/src/mkhdr
TARG=jpg\
gif\
togif\
ppm\
toppm\
png\
topng\
yuv\
ico\
toico\
bmp\
IMFILES=\
torgbv.$O\
totruecolor.$O\
writerawimage.$O\
HFILES=imagefile.h\
SHORTLIB=draw flate bio 9
LDFLAGS=$LDFLAGS -L$X11/lib -lX11
<$PLAN9/src/mkmany
$O.jpg: $IMFILES readjpg.$O jpg.$O
$O.gif: $IMFILES readgif.$O gif.$O
$O.togif: writegif.$O onechan.$O togif.$O torgbv.$O multichan.$O
$O.ppm: $IMFILES readppm.$O ppm.$O
$O.toppm: writeppm.$O multichan.$O toppm.$O
$O.png: $IMFILES readpng.$O png.$O multichan.$O
$O.topng: writepng.$O topng.$O
$O.yuv: $IMFILES readyuv.$O yuv.$O
$O.bmp: $IMFILES readbmp.$O bmp.$O
torgbv.$O: ycbcr.h rgbv.h
ycbcr.h: rgbycc.c
9c rgbycc.c
9l -o o.rgbycc rgbycc.c
./o.rgbycc >ycbcr.h
rgbv.h: rgbrgbv.c
9c rgbrgbv.c
9l -o o.rgbrgbv rgbrgbv.c
./o.rgbrgbv >rgbv.h
nuke:V: nuke-headers
nuke-headers:V:
rm -f rgbv.h ycbcr.h

60
src/cmd/jpg/multichan.c Normal file
View File

@ -0,0 +1,60 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <bio.h>
#include "imagefile.h"
/* Separate colors, if not a grey scale or bitmap, into one byte per color per pixel, no alpha or X */
/* Result is GREY[1248] or RGB24 */
int drawlog2[] = {
0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5
};
static
int
notrans(ulong chan)
{
switch(chan){
case GREY1:
case GREY2:
case GREY4:
case GREY8:
case RGB24:
return 1;
}
return 0;
}
Image*
multichan(Image *i)
{
Image *ni;
if(notrans(i->chan))
return i;
ni = allocimage(display, i->r, RGB24, 0, DNofill);
if(ni == nil)
return ni;
draw(ni, ni->r, i, nil, i->r.min);
return ni;
}
Memimage*
memmultichan(Memimage *i)
{
Memimage *ni;
if(notrans(i->chan))
return i;
ni = allocmemimage(i->r, RGB24);
if(ni == nil)
return ni;
memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
return ni;
}

229
src/cmd/jpg/onechan.c Normal file
View File

@ -0,0 +1,229 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <bio.h>
#include "imagefile.h"
/* Convert image to a single channel, one byte per pixel */
static
int
notrans(ulong chan)
{
switch(chan){
case GREY1:
case GREY2:
case GREY4:
case CMAP8:
case GREY8:
return 1;
}
return 0;
}
static
int
easycase(ulong chan)
{
switch(chan){
case RGB16:
case RGB24:
case RGBA32:
case ARGB32:
return 1;
}
return 0;
}
/*
* Convert to one byte per pixel, RGBV or grey, depending
*/
static
uchar*
load(Image *image, Memimage *memimage)
{
uchar *data, *p, *q0, *q1, *q2;
uchar *rgbv;
int depth, ndata, dx, dy, i, v;
ulong chan, pixel;
Rectangle r;
Rawimage ri, *nri;
if(memimage == nil){
r = image->r;
depth = image->depth;
chan = image->chan;
}else{
r = memimage->r;
depth = memimage->depth;
chan = memimage->chan;
}
dx = Dx(r);
dy = Dy(r);
/*
* Read image data into memory
* potentially one extra byte on each end of each scan line.
*/
ndata = dy*(2+bytesperline(r, depth));
data = malloc(ndata);
if(data == nil)
return nil;
if(memimage != nil)
ndata = unloadmemimage(memimage, r, data, ndata);
else
ndata = unloadimage(image, r, data, ndata);
if(ndata < 0){
werrstr("onechan: %r");
free(data);
return nil;
}
/*
* Repack
*/
memset(&ri, 0, sizeof(ri));
ri.r = r;
ri.cmap = nil;
ri.cmaplen = 0;
ri.nchans = 3;
ri.chanlen = dx*dy;
ri.chans[0] = malloc(ri.chanlen);
ri.chans[1] = malloc(ri.chanlen);
ri.chans[2] = malloc(ri.chanlen);
if(ri.chans[0]==nil || ri.chans[1]==nil || ri.chans[2]==nil){
Err:
free(ri.chans[0]);
free(ri.chans[1]);
free(ri.chans[2]);
free(data);
return nil;
}
ri.chandesc = CRGB;
p = data;
q0 = ri.chans[0];
q1 = ri.chans[1];
q2 = ri.chans[2];
switch(chan){
default:
werrstr("can't handle image type 0x%lux", chan);
goto Err;
case RGB16:
for(i=0; i<ri.chanlen; i++, p+=2){
pixel = (p[1]<<8)|p[0]; /* rrrrrggg gggbbbbb */
v = (pixel & 0xF800) >> 8;
*q0++ = v | (v>>5);
v = (pixel & 0x07E0) >> 3;
*q1++ = v | (v>>6);
v = (pixel & 0x001F) << 3;
*q2++ = v | (v>>5);
}
break;
case RGB24:
for(i=0; i<ri.chanlen; i++){
*q2++ = *p++;
*q1++ = *p++;
*q0++ = *p++;
}
break;
case RGBA32:
for(i=0; i<ri.chanlen; i++){
*q2++ = *p++;
*q1++ = *p++;
*q0++ = *p++;
p++;
}
break;
case ARGB32:
for(i=0; i<ri.chanlen; i++){
p++;
*q2++ = *p++;
*q1++ = *p++;
*q0++ = *p++;
}
break;
}
rgbv = nil;
nri = torgbv(&ri, 1);
if(nri != nil){
rgbv = nri->chans[0];
free(nri);
}
free(ri.chans[0]);
free(ri.chans[1]);
free(ri.chans[2]);
free(data);
return rgbv;
}
Image*
onechan(Image *i)
{
uchar *data;
Image *ni;
if(notrans(i->chan))
return i;
if(easycase(i->chan))
data = load(i, nil);
else{
ni = allocimage(display, i->r, RGB24, 0, DNofill);
if(ni == nil)
return ni;
draw(ni, ni->r, i, nil, i->r.min);
data = load(ni, nil);
freeimage(ni);
}
if(data == nil)
return nil;
ni = allocimage(display, i->r, CMAP8, 0, DNofill);
if(ni != nil)
if(loadimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){
freeimage(ni);
ni = nil;
}
free(data);
return ni;
}
Memimage*
memonechan(Memimage *i)
{
uchar *data;
Memimage *ni;
if(notrans(i->chan))
return i;
if(easycase(i->chan))
data = load(nil, i);
else{
ni = allocmemimage(i->r, RGB24);
if(ni == nil)
return ni;
memimagedraw(ni, ni->r, i, i->r.min, nil, ZP, S);
data = load(nil, ni);
freememimage(ni);
}
if(data == nil)
return nil;
ni = allocmemimage(i->r, CMAP8);
if(ni != nil)
if(loadmemimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){
freememimage(ni);
ni = nil;
}
free(data);
return ni;
}

224
src/cmd/jpg/png.c Normal file
View File

@ -0,0 +1,224 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <event.h>
#include "imagefile.h"
extern int debug;
int cflag = 0;
int dflag = 0;
int eflag = 0;
int nineflag = 0;
int threeflag = 0;
int colorspace = CRGB;
int output = 0;
ulong outchan = CMAP8;
Image *image;
int defaultcolor = 1;
enum{
Border = 2,
Edge = 5
};
char *show(int, char*, int);
void
eresized(int new)
{
Rectangle r;
if(new && getwindow(display, Refnone) < 0){
fprint(2, "png: can't reattach to window\n");
exits("resize");
}
if(image == nil)
return;
r = insetrect(screen->clipr, Edge+Border);
r.max.x = r.min.x+Dx(image->r);
r.max.y = r.min.y+Dy(image->r);
border(screen, r, -Border, nil, ZP);
draw(screen, r, image, nil, image->r.min);
flushimage(display, 1);
}
void
main(int argc, char *argv[])
{
int fd, i;
char *err;
char buf[12+1];
ARGBEGIN{
case 'c': /* produce encoded, compressed, bitmap file; no display by default */
cflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
case 'D':
debug++;
break;
case 'd': /* suppress display of image */
dflag++;
break;
case 'e': /* disable floyd-steinberg error diffusion */
eflag++;
break;
case 'k': /* force black and white */
defaultcolor = 0;
outchan = GREY8;
break;
case 'r':
colorspace = CRGB;
break;
case '3': /* produce encoded, compressed, three-color bitmap file; no display by default */
threeflag++;
/* fall through */
case 't': /* produce encoded, compressed, true-color bitmap file; no display by default */
cflag++;
dflag++;
output++;
defaultcolor = 0;
outchan = RGB24;
break;
case 'v': /* force RGBV */
defaultcolor = 0;
outchan = CMAP8;
break;
case '9': /* produce plan 9, uncompressed, bitmap file; no display by default */
nineflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
default:
fprint(2, "usage: png -39cdekrtv [file.png ...]\n");
exits("usage");
}ARGEND;
if(dflag==0 && colorspace==CYCbCr){ /* see if we should convert right to RGB */
fd = open("/dev/screen", OREAD);
if(fd > 0){
buf[12] = '\0';
if(read(fd, buf, 12)==12 && chantodepth(strtochan(buf))>8)
colorspace = CRGB;
close(fd);
}
}
err = nil;
if(argc == 0)
err = show(0, "<stdin>", outchan);
else{
for(i=0; i<argc; i++){
fd = open(argv[i], OREAD);
if(fd < 0){
fprint(2, "png: can't open %s: %r\n", argv[i]);
err = "open";
}else{
err = show(fd, argv[i], outchan);
close(fd);
}
if((nineflag || cflag) && argc>1 && err==nil){
fprint(2, "png: exiting after one file\n");
break;
}
}
}
exits(err);
}
char*
show(int fd, char *name, int outc)
{
Rawimage **array, *r, *c;
static int inited;
Image *i;
int j, ch, outchan;
Biobuf b;
char buf[32];
if(Binit(&b, fd, OREAD) < 0)
return nil;
outchan = outc;
array = Breadpng(&b, colorspace);
if(array == nil || array[0]==nil){
fprint(2, "png: decode %s failed: %r\n", name);
return "decode";
}
Bterm(&b);
r = array[0];
if(!dflag && !inited){
if(initdraw(0, 0, 0) < 0){
fprint(2, "png: initdraw failed: %r\n");
return "initdraw";
}
einit(Ekeyboard|Emouse);
if(defaultcolor && screen->depth>8 && outchan==CMAP8)
outchan = RGB24;
inited++;
}
if(outchan == CMAP8)
c = torgbv(r, !eflag);
else{
if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)){
c = totruecolor(r, CY);
outchan = GREY8;
}else
c = totruecolor(r, CRGB24);
}
if(c == nil){
fprint(2, "png: conversion of %s failed: %r\n", name);
return "torgbv";
}
if(!dflag){
if(c->chandesc == CY)
i = allocimage(display, c->r, GREY8, 0, 0);
else
i = allocimage(display, c->r, outchan, 0, 0);
if(i == nil){
fprint(2, "png: allocimage %s failed: %r\n", name);
return "allocimage";
}
if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
fprint(2, "png: loadimage %s failed: %r\n", name);
return "loadimage";
}
image = i;
eresized(0);
if((ch=ekbd())=='q' || ch==0x7F || ch==0x04)
exits(nil);
draw(screen, screen->clipr, display->white, nil, ZP);
image = nil;
freeimage(i);
}
if(nineflag){
chantostr(buf, outchan);
print("%11s %11d %11d %11d %11d ", buf,
c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y);
if(write(1, c->chans[0], c->chanlen) != c->chanlen){
fprint(2, "png: %s: write error %r\n", name);
return "write";
}
}else if(cflag){
if(writerawimage(1, c) < 0){
fprint(2, "png: %s: write error: %r\n", name);
return "write";
}
}
for(j=0; j<r->nchans; j++)
free(r->chans[j]);
free(r->cmap);
free(r);
free(array);
if(c){
free(c->chans[0]);
free(c);
}
return nil;
}

209
src/cmd/jpg/ppm.c Normal file
View File

@ -0,0 +1,209 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <event.h>
#include "imagefile.h"
int cflag = 0;
int dflag = 0;
int eflag = 0;
int nineflag = 0;
int threeflag = 0;
int output = 0;
ulong outchan = CMAP8;
int defaultcolor = 1;
Image *image;
enum{
Border = 2,
Edge = 5
};
char *show(int, char*);
void
eresized(int new)
{
Rectangle r;
if(new && getwindow(display, Refnone) < 0){
fprint(2, "ppm: can't reattach to window\n");
exits("resize");
}
if(image == nil)
return;
r = insetrect(screen->clipr, Edge+Border);
r.max.x = r.min.x+Dx(image->r);
r.max.y = r.min.y+Dy(image->r);
border(screen, r, -Border, nil, ZP);
draw(screen, r, image, nil, image->r.min);
flushimage(display, 1);
}
void
main(int argc, char *argv[])
{
int fd, i;
char *err;
ARGBEGIN{
case '3': /* produce encoded, compressed, three-color bitmap file; no display by default */
threeflag++;
/* fall through */
case 't': /* produce encoded, compressed, true-color bitmap file; no display by default */
cflag++;
dflag++;
output++;
defaultcolor = 0;
outchan = RGB24;
break;
case 'c': /* produce encoded, compressed, bitmap file; no display by default */
cflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
case 'd': /* suppress display of image */
dflag++;
break;
case 'e': /* disable floyd-steinberg error diffusion */
eflag++;
break;
case 'k': /* force black and white */
defaultcolor = 0;
outchan = GREY8;
break;
case 'v': /* force RGBV */
defaultcolor = 0;
outchan = CMAP8;
break;
case '9': /* produce plan 9, uncompressed, bitmap file; no display by default */
nineflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
default:
fprint(2, "usage: ppm -39cdektv [file.ppm ...]\n");
exits("usage");
}ARGEND;
err = nil;
if(argc == 0)
err = show(0, "<stdin>");
else{
for(i=0; i<argc; i++){
fd = open(argv[i], OREAD);
if(fd < 0){
fprint(2, "ppm: can't open %s: %r\n", argv[i]);
err = "open";
}else{
err = show(fd, argv[i]);
close(fd);
}
if((nineflag || cflag) && argc>1 && err==nil){
fprint(2, "ppm: exiting after one file\n");
break;
}
}
}
exits(err);
}
int
init(void)
{
static int inited;
if(inited == 0){
if(initdraw(0, 0, 0) < 0){
fprint(2, "ppm: initdraw failed: %r");
return -1;
}
einit(Ekeyboard|Emouse);
inited++;
}
return 1;
}
char*
show(int fd, char *name)
{
Rawimage **array, *r, *c;
Image *i;
int j, ch;
char buf[32];
array = readpixmap(fd, CRGB);
if(array == nil || array[0]==nil){
fprint(2, "ppm: decode %s failed: %r\n", name);
return "decode";
}
if(!dflag){
if(init() < 0)
return "initdraw";
if(defaultcolor && screen->depth>8)
outchan = RGB24;
}
r = array[0];
if(outchan == CMAP8)
c = torgbv(r, !eflag);
else{
if(outchan==GREY8 || (r->chandesc==CY && threeflag==0))
c = totruecolor(r, CY);
else
c = totruecolor(r, CRGB24);
}
if(c == nil){
fprint(2, "ppm: converting %s to local format failed: %r\n", name);
return "torgbv";
}
if(!dflag){
if(r->chandesc == CY)
i = allocimage(display, c->r, GREY8, 0, 0);
else
i = allocimage(display, c->r, outchan, 0, 0);
if(i == nil){
fprint(2, "ppm: allocimage %s failed: %r\n", name);
return "allocimage";
}
if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
fprint(2, "ppm: loadimage %s failed: %r\n", name);
return "loadimage";
}
image = i;
eresized(0);
if((ch=ekbd())=='q' || ch==0x7F || ch==0x04)
exits(nil);
draw(screen, screen->clipr, display->white, nil, ZP);
image = nil;
freeimage(i);
}
if(nineflag){
chantostr(buf, outchan);
print("%11s %11d %11d %11d %11d ", buf,
c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y);
if(write(1, c->chans[0], c->chanlen) != c->chanlen){
fprint(2, "ppm: %s: write error %r\n", name);
return "write";
}
}else if(cflag){
if(writerawimage(1, c) < 0){
fprint(2, "ppm: %s: write error: %r\n", name);
return "write";
}
}
for(j=0; j<r->nchans; j++)
free(r->chans[j]);
free(r->cmap);
free(r);
free(array);
if(c){
free(c->chans[0]);
free(c);
}
return nil;
}

626
src/cmd/jpg/readbmp.c Normal file
View File

@ -0,0 +1,626 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include "imagefile.h"
#include "bmp.h"
/*
MS-BMP file reader
(c) 2003, I.P.Keller
aims to decode *all* valid bitmap formats, although some of the
flavours couldn't be verified due to lack of suitable test-files.
the following flavours are supported:
Bit/Pix Orientation Compression Tested?
1 top->bottom n/a yes
1 bottom->top n/a yes
4 top->bottom no yes
4 bottom->top no yes
4 top->bottom RLE4 yes, but not with displacement
8 top->bottom no yes
8 bottom->top no yes
8 top->bottom RLE8 yes, but not with displacement
16 top->bottom no no
16 bottom->top no no
16 top->bottom BITMASK no
16 bottom->top BITMASK no
24 top->bottom n/a yes
24 bottom->top n/a yes
32 top->bottom no no
32 bottom->top no no
32 top->bottom BITMASK no
32 bottom->top BITMASK no
OS/2 1.x bmp files are recognised as well, but testing was very limited.
verifying was done with a number of test files, generated by
different tools. nevertheless, the tests were in no way exhaustive
enough to guarantee bug-free decoding. caveat emptor!
*/
static short
r16(Biobuf*b)
{
short s;
s = Bgetc(b);
s |= ((short)Bgetc(b)) << 8;
return s;
}
static long
r32(Biobuf*b)
{
long l;
l = Bgetc(b);
l |= ((long)Bgetc(b)) << 8;
l |= ((long)Bgetc(b)) << 16;
l |= ((long)Bgetc(b)) << 24;
return l;
}
/* get highest bit set */
static int
msb(ulong x)
{
int i;
for(i = 32; i; i--, x <<= 1)
if(x & 0x80000000L)
return i;
return 0;
}
/* Load a 1-Bit encoded BMP file (uncompressed) */
static int
load_1T(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
{
long ix, iy, i = 0, step_up = 0, padded_width = ((width + 31) / 32) * 32;
int val = 0, n;
if(height > 0) { /* bottom-up */
i = (height - 1) * width;
step_up = -2 * width;
} else
height = -height;
for(iy = height; iy; iy--, i += step_up)
for(ix = 0, n = 0; ix < padded_width; ix++, n--) {
if(!n) {
val = Bgetc(b);
n = 8;
}
if(ix < width) {
buf[i] = clut[val & 0x80 ? 1 : 0];
i++;
}
val <<= 1;
}
return 0;
}
/* Load a 4-Bit encoded BMP file (uncompressed) */
static int
load_4T(Biobuf* b, long width, long height, Rgb* buf, Rgb* clut)
{
long ix, iy, i = 0, step_up = 0, skip = (4 - (((width % 8) + 1) / 2)) & 3;
uint valH, valL;
if(height > 0) { /* bottom-up */
i = (height - 1) * width;
step_up = -2 * width;
} else
height = -height;
for(iy = height; iy; iy--, i += step_up) {
for(ix = 0; ix < width; ) {
valH = valL = Bgetc(b) & 0xff;
valH >>= 4;
buf[i] = clut[valH];
i++; ix++;
if(ix < width) {
valL &= 0xf;
buf[i] = clut[valL];
i++; ix++;
}
}
Bseek(b, skip, 1);
}
return 0;
}
/* Load a 4-Bit encoded BMP file (RLE4-compressed) */
static int
load_4C(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
{
long ix, iy = height -1;
uint val, valS, skip;
Rgb* p;
while(iy >= 0) {
ix = 0;
while(ix < width) {
val = Bgetc(b);
if(0 != val) {
valS = (uint)Bgetc(b);
p = &buf[ix + iy * width];
while(val--) {
*p = clut[0xf & (valS >> 4)];
p++;
ix++;
if(0 < val) {
*p = clut[0xf & valS];
p++;
ix++;
val--;
}
}
} else {
/* Special modes... */
val = Bgetc(b);
switch(val) {
case 0: /* End-Of-Line detected */
ix = width;
iy--;
break;
case 1: /* End-Of-Picture detected -->> abort */
ix = width;
iy = -1;
break;
case 2: /* Position change detected */
val = Bgetc(b);
ix += val;
val = Bgetc(b);
iy -= val;
break;
default:/* Transparent data sequence detected */
p = &buf[ix + iy * width];
if((1 == (val & 3)) || (2 == (val & 3)))
skip = 1;
else
skip = 0;
while(val--) {
valS = (uint)Bgetc(b);
*p = clut[0xf & (valS >> 4)];
p++;
ix++;
if(0 < val) {
*p = clut[0xf & valS];
p++;
ix++;
val--;
}
}
if(skip)
Bgetc(b);
break;
}
}
}
}
return 0;
}
/* Load a 8-Bit encoded BMP file (uncompressed) */
static int
load_8T(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
{
long ix, iy, i = 0, step_up = 0, skip = (4 - (width % 4)) & 3;
if(height > 0) { /* bottom-up */
i = (height - 1) * width;
step_up = -2 * width;
} else
height = -height;
for(iy = height; iy; iy--, i += step_up) {
for(ix = 0; ix < width; ix++, i++)
buf[i] = clut[Bgetc(b) & 0xff];
Bseek(b, skip, 1);
}
return 0;
}
/* Load a 8-Bit encoded BMP file (RLE8-compressed) */
static int
load_8C(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
{
long ix, iy = height -1;
int val, valS, skip;
Rgb* p;
while(iy >= 0) {
ix = 0;
while(ix < width) {
val = Bgetc(b);
if(0 != val) {
valS = Bgetc(b);
p = &buf[ix + iy * width];
while(val--) {
*p = clut[valS];
p++;
ix++;
}
} else {
/* Special modes... */
val = Bgetc(b);
switch(val) {
case 0: /* End-Of-Line detected */
ix = width;
iy--;
break;
case 1: /* End-Of-Picture detected */
ix = width;
iy = -1;
break;
case 2: /* Position change detected */
val = Bgetc(b);
ix += val;
val = Bgetc(b);
iy -= val;
break;
default: /* Transparent (not compressed) sequence detected */
p = &buf[ix + iy * width];
if(val & 1)
skip = 1;
else
skip = 0;
while(val--) {
valS = Bgetc(b);
*p = clut[valS];
p++;
ix++;
}
if(skip)
/* Align data stream */
Bgetc(b);
break;
}
}
}
}
return 0;
}
/* Load a 16-Bit encoded BMP file (uncompressed) */
static int
load_16(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
{
uchar c[2];
long ix, iy, i = 0, step_up = 0;
if(height > 0) { /* bottom-up */
i = (height - 1) * width;
step_up = -2 * width;
} else
height = -height;
if(clut) {
unsigned mask_blue = (unsigned)clut[0].blue +
((unsigned)clut[0].green << 8);
unsigned mask_green = (unsigned)clut[1].blue +
((unsigned)clut[1].green << 8);
unsigned mask_red = (unsigned)clut[2].blue +
((unsigned)clut[2].green << 8);
int shft_blue = msb((ulong)mask_blue) - 8;
int shft_green = msb((ulong)mask_green) - 8;
int shft_red = msb((ulong)mask_red) - 8;
for(iy = height; iy; iy--, i += step_up)
for(ix = 0; ix < width; ix++, i++) {
unsigned val;
Bread(b, c, sizeof(c));
val = (unsigned)c[0] + ((unsigned)c[1] << 8);
buf[i].alpha = 0;
if(shft_blue >= 0)
buf[i].blue = (uchar)((val & mask_blue) >> shft_blue);
else
buf[i].blue = (uchar)((val & mask_blue) << -shft_blue);
if(shft_green >= 0)
buf[i].green = (uchar)((val & mask_green) >> shft_green);
else
buf[i].green = (uchar)((val & mask_green) << -shft_green);
if(shft_red >= 0)
buf[i].red = (uchar)((val & mask_red) >> shft_red);
else
buf[i].red = (uchar)((val & mask_red) << -shft_red);
}
} else
for(iy = height; iy; iy--, i += step_up)
for(ix = 0; ix < width; ix++, i++) {
Bread(b, c, sizeof(c));
buf[i].blue = (uchar)((c[0] << 3) & 0xf8);
buf[i].green = (uchar)(((((unsigned)c[1] << 6) +
(((unsigned)c[0]) >> 2))) & 0xf8);
buf[i].red = (uchar)((c[1] << 1) & 0xf8);
}
return 0;
}
/* Load a 24-Bit encoded BMP file (uncompressed) */
static int
load_24T(Biobuf* b, long width, long height, Rgb* buf)
{
long ix, iy, i = 0, step_up = 0, skip = (4 - ((width * 3) % 4)) & 3;
if(height > 0) { /* bottom-up */
i = (height - 1) * width;
step_up = -2 * width;
} else
height = -height;
for(iy = height; iy; iy--, i += step_up) {
for(ix = 0; ix < width; ix++, i++) {
buf[i].alpha = 0;
buf[i].blue = Bgetc(b);
buf[i].green = Bgetc(b);
buf[i].red = Bgetc(b);
}
Bseek(b, skip, 1);
}
return 0;
}
/* Load a 32-Bit encoded BMP file (uncompressed) */
static int
load_32(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
{
uchar c[4];
long ix, iy, i = 0, step_up = 0;
if(height > 0) { /* bottom-up */
i = (height - 1) * width;
step_up = -2 * width;
} else
height = -height;
if(clut) {
ulong mask_blue = (ulong)clut[0].blue +
((ulong)clut[0].green << 8) +
((ulong)clut[0].red << 16) +
((ulong)clut[0].alpha << 24);
ulong mask_green = (ulong)clut[1].blue +
((ulong)clut[1].green << 8) +
((ulong)clut[1].red << 16) +
((ulong)clut[1].alpha << 24);
ulong mask_red = (ulong)clut[2].blue +
((ulong)clut[2].green << 8) +
((ulong)clut[2].red << 16) +
((ulong)clut[2].alpha << 24);
int shft_blue = msb(mask_blue) - 8;
int shft_green = msb(mask_green) - 8;
int shft_red = msb(mask_red) - 8;
for(iy = height; iy; iy--, i += step_up)
for(ix = 0; ix < width; ix++, i++) {
ulong val;
Bread(b, c, sizeof(c));
val = (ulong)c[0] + ((ulong)c[1] << 8) +
((ulong)c[2] << 16) + ((ulong)c[1] << 24);
buf[i].alpha = 0;
if(shft_blue >= 0)
buf[i].blue = (uchar)((val & mask_blue) >> shft_blue);
else
buf[i].blue = (uchar)((val & mask_blue) << -shft_blue);
if(shft_green >= 0)
buf[i].green = (uchar)((val & mask_green) >> shft_green);
else
buf[i].green = (uchar)((val & mask_green) << -shft_green);
if(shft_red >= 0)
buf[i].red = (uchar)((val & mask_red) >> shft_red);
else
buf[i].red = (uchar)((val & mask_red) << -shft_red);
}
} else
for(iy = height; iy; iy--, i += step_up)
for(ix = 0; ix < width; ix++, i++) {
Bread(b, c, nelem(c));
buf[i].blue = c[0];
buf[i].green = c[1];
buf[i].red = c[2];
}
return 0;
}
static Rgb*
ReadBMP(Biobuf *b, int *width, int *height)
{
int colours, num_coltab = 0;
Filehdr bmfh;
Infohdr bmih;
Rgb clut[256];
Rgb* buf;
bmfh.type = r16(b);
if(bmfh.type != 0x4d42) /* signature must be 'BM' */
sysfatal("bad magic number, not a BMP file");
bmfh.size = r32(b);
bmfh.reserved1 = r16(b);
bmfh.reserved2 = r16(b);
bmfh.offbits = r32(b);
memset(&bmih, 0, sizeof(bmih));
bmih.size = r32(b);
if(bmih.size == 0x0c) { /* OS/2 1.x version */
bmih.width = r16(b);
bmih.height = r16(b);
bmih.planes = r16(b);
bmih.bpp = r16(b);
bmih.compression = BMP_RGB;
} else { /* Windows */
bmih.width = r32(b);
bmih.height = r32(b);
bmih.planes = r16(b);
bmih.bpp = r16(b);
bmih.compression = r32(b);
bmih.imagesize = r32(b);
bmih.hres = r32(b);
bmih.vres = r32(b);
bmih.colours = r32(b);
bmih.impcolours = r32(b);
}
if(bmih.bpp < 16) {
/* load colour table */
if(bmih.impcolours)
num_coltab = (int)bmih.impcolours;
else
num_coltab = 1 << bmih.bpp;
} else if(bmih.compression == BMP_BITFIELDS &&
(bmih.bpp == 16 || bmih.bpp == 32))
/* load bitmasks */
num_coltab = 3;
if(num_coltab) {
int i;
Bseek(b, bmih.size + sizeof(Infohdr), 0);
for(i = 0; i < num_coltab; i++) {
clut[i].blue = (uchar)Bgetc(b);
clut[i].green = (uchar)Bgetc(b);
clut[i].red = (uchar)Bgetc(b);
clut[i].alpha = (uchar)Bgetc(b);
}
}
*width = bmih.width;
*height = bmih.height;
colours = bmih.bpp;
Bseek(b, bmfh.offbits, 0);
if ((buf = calloc(sizeof(Rgb), *width * abs(*height))) == nil)
sysfatal("no memory");
switch(colours) {
case 1:
load_1T(b, *width, *height, buf, clut);
break;
case 4:
if(bmih.compression == BMP_RLE4)
load_4C(b, *width, *height, buf, clut);
else
load_4T(b, *width, *height, buf, clut);
break;
case 8:
if(bmih.compression == BMP_RLE8)
load_8C(b, *width, *height, buf, clut);
else
load_8T(b, *width, *height, buf, clut);
break;
case 16:
load_16(b, *width, *height, buf,
bmih.compression == BMP_BITFIELDS ? clut : nil);
break;
case 24:
load_24T(b, *width, *height, buf);
break;
case 32:
load_32(b, *width, *height, buf,
bmih.compression == BMP_BITFIELDS ? clut : nil);
break;
}
return buf;
}
Rawimage**
Breadbmp(Biobuf *bp, int colourspace)
{
Rawimage *a, **array;
int c, width, height;
uchar *r, *g, *b;
Rgb *s, *e;
Rgb *bmp;
char ebuf[128];
a = nil;
bmp = nil;
array = nil;
USED(a);
USED(bmp);
if (colourspace != CRGB) {
errstr(ebuf, sizeof ebuf); /* throw it away */
werrstr("ReadRGB: unknown colour space %d", colourspace);
return nil;
}
if ((bmp = ReadBMP(bp, &width, &height)) == nil)
return nil;
if ((a = calloc(sizeof(Rawimage), 1)) == nil)
goto Error;
for (c = 0; c < 3; c++)
if ((a->chans[c] = calloc(width, height)) == nil)
goto Error;
if ((array = calloc(sizeof(Rawimage *), 2)) == nil)
goto Error;
array[0] = a;
array[1] = nil;
a->nchans = 3;
a->chandesc = CRGB;
a->chanlen = width * height;
a->r = Rect(0, 0, width, height);
s = bmp;
e = s + width * height;
r = a->chans[0];
g = a->chans[1];
b = a->chans[2];
do {
*r++ = s->red;
*g++ = s->green;
*b++ = s->blue;
}while(++s < e);
free(bmp);
return array;
Error:
if (a)
for (c = 0; c < 3; c++)
if (a->chans[c])
free(a->chans[c]);
if (a)
free(a);
if (array)
free(array);
if (bmp)
free(bmp);
return nil;
}
Rawimage**
readbmp(int fd, int colorspace)
{
Rawimage * *a;
Biobuf b;
if (Binit(&b, fd, OREAD) < 0)
return nil;
a = Breadbmp(&b, colorspace);
Bterm(&b);
return a;
}

535
src/cmd/jpg/readgif.c Normal file
View File

@ -0,0 +1,535 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include "imagefile.h"
typedef struct Entry Entry;
typedef struct Header Header;
struct Entry{
int prefix;
int exten;
};
struct Header{
Biobuf *fd;
char err[256];
jmp_buf errlab;
uchar buf[3*256];
char vers[8];
uchar *globalcmap;
int screenw;
int screenh;
int fields;
int bgrnd;
int aspect;
int flags;
int delay;
int trindex;
int loopcount;
Entry tbl[4096];
Rawimage **array;
Rawimage *new;
uchar *pic;
};
static char readerr[] = "ReadGIF: read error: %r";
static char extreaderr[] = "ReadGIF: can't read extension: %r";
static char memerr[] = "ReadGIF: malloc failed: %r";
static Rawimage** readarray(Header*);
static Rawimage* readone(Header*);
static void readheader(Header*);
static void skipextension(Header*);
static uchar* readcmap(Header*, int);
static uchar* decode(Header*, Rawimage*, Entry*);
static void interlace(Header*, Rawimage*);
static
void
clear(void *pp)
{
void **p = (void**)pp;
if(*p){
free(*p);
*p = nil;
}
}
static
void
giffreeall(Header *h, int freeimage)
{
int i;
if(h->fd){
Bterm(h->fd);
h->fd = nil;
}
clear(&h->pic);
if(h->new){
clear(&h->new->cmap);
clear(&h->new->chans[0]);
clear(&h->new);
}
clear(&h->globalcmap);
if(freeimage && h->array!=nil){
for(i=0; h->array[i]; i++){
clear(&h->array[i]->cmap);
clear(&h->array[i]->chans[0]);
}
clear(&h->array);
}
}
static
void
giferror(Header *h, char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vseprint(h->err, h->err+sizeof h->err, fmt, arg);
va_end(arg);
werrstr(h->err);
giffreeall(h, 1);
longjmp(h->errlab, 1);
}
Rawimage**
readgif(int fd, int colorspace)
{
Rawimage **a;
Biobuf b;
Header *h;
char buf[ERRMAX];
buf[0] = '\0';
USED(colorspace);
if(Binit(&b, fd, OREAD) < 0)
return nil;
h = malloc(sizeof(Header));
if(h == nil){
Bterm(&b);
return nil;
}
memset(h, 0, sizeof(Header));
h->fd = &b;
errstr(buf, sizeof buf); /* throw it away */
if(setjmp(h->errlab))
a = nil;
else
a = readarray(h);
giffreeall(h, 0);
free(h);
return a;
}
static
void
inittbl(Header *h)
{
int i;
Entry *tbl;
tbl = h->tbl;
for(i=0; i<258; i++) {
tbl[i].prefix = -1;
tbl[i].exten = i;
}
}
static
Rawimage**
readarray(Header *h)
{
Entry *tbl;
Rawimage *new, **array;
int c, nimages;
tbl = h->tbl;
readheader(h);
if(h->fields & 0x80)
h->globalcmap = readcmap(h, (h->fields&7)+1);
array = malloc(sizeof(Rawimage**));
if(array == nil)
giferror(h, memerr);
nimages = 0;
array[0] = nil;
h->array = array;
for(;;){
switch(c = Bgetc(h->fd)){
case Beof:
goto Return;
case 0x21: /* Extension (ignored) */
skipextension(h);
break;
case 0x2C: /* Image Descriptor */
inittbl(h);
new = readone(h);
if(new->fields & 0x80){
new->cmaplen = 3*(1<<((new->fields&7)+1));
new->cmap = readcmap(h, (new->fields&7)+1);
}else{
new->cmaplen = 3*(1<<((h->fields&7)+1));
new->cmap = malloc(new->cmaplen);
memmove(new->cmap, h->globalcmap, new->cmaplen);
}
h->new = new;
new->chans[0] = decode(h, new, tbl);
if(new->fields & 0x40)
interlace(h, new);
new->gifflags = h->flags;
new->gifdelay = h->delay;
new->giftrindex = h->trindex;
new->gifloopcount = h->loopcount;
array = realloc(h->array, (nimages+2)*sizeof(Rawimage*));
if(array == nil)
giferror(h, memerr);
array[nimages++] = new;
array[nimages] = nil;
h->array = array;
h->new = nil;
break;
case 0x3B: /* Trailer */
goto Return;
default:
fprint(2, "ReadGIF: unknown block type: 0x%.2x\n", c);
goto Return;
}
}
Return:
if(array[0]==nil || array[0]->chans[0] == nil)
giferror(h, "ReadGIF: no picture in file");
return array;
}
static
void
readheader(Header *h)
{
if(Bread(h->fd, h->buf, 13) != 13)
giferror(h, "ReadGIF: can't read header: %r");
memmove(h->vers, h->buf, 6);
if(strcmp(h->vers, "GIF87a")!=0 && strcmp(h->vers, "GIF89a")!=0)
giferror(h, "ReadGIF: can't recognize format %s", h->vers);
h->screenw = h->buf[6]+(h->buf[7]<<8);
h->screenh = h->buf[8]+(h->buf[9]<<8);
h->fields = h->buf[10];
h->bgrnd = h->buf[11];
h->aspect = h->buf[12];
h->flags = 0;
h->delay = 0;
h->trindex = 0;
h->loopcount = -1;
}
static
uchar*
readcmap(Header *h, int size)
{
uchar *map;
if(size > 8)
giferror(h, "ReadGIF: can't handles %d bits per pixel", size);
size = 3*(1<<size);
if(Bread(h->fd, h->buf, size) != size)
giferror(h, "ReadGIF: short read on color map");
map = malloc(size);
if(map == nil)
giferror(h, memerr);
memmove(map, h->buf, size);
return map;
}
static
Rawimage*
readone(Header *h)
{
Rawimage *i;
int left, top, width, height;
if(Bread(h->fd, h->buf, 9) != 9)
giferror(h, "ReadGIF: can't read image descriptor: %r");
i = malloc(sizeof(Rawimage));
if(i == nil)
giferror(h, memerr);
left = h->buf[0]+(h->buf[1]<<8);
top = h->buf[2]+(h->buf[3]<<8);
width = h->buf[4]+(h->buf[5]<<8);
height = h->buf[6]+(h->buf[7]<<8);
i->fields = h->buf[8];
i->r.min.x = left;
i->r.min.y = top;
i->r.max.x = left+width;
i->r.max.y = top+height;
i->nchans = 1;
i->chandesc = CRGB1;
return i;
}
static
int
readdata(Header *h, uchar *data)
{
int nbytes, n;
nbytes = Bgetc(h->fd);
if(nbytes < 0)
giferror(h, "ReadGIF: can't read data: %r");
if(nbytes == 0)
return 0;
n = Bread(h->fd, data, nbytes);
if(n < 0)
giferror(h, "ReadGIF: can't read data: %r");
if(n != nbytes)
fprint(2, "ReadGIF: short data subblock\n");
return n;
}
static
void
graphiccontrol(Header *h)
{
if(Bread(h->fd, h->buf, 5+1) != 5+1)
giferror(h, readerr);
h->flags = h->buf[1];
h->delay = h->buf[2]+(h->buf[3]<<8);
h->trindex = h->buf[4];
}
static
void
skipextension(Header *h)
{
int type, hsize, hasdata, n;
uchar data[256];
hsize = 0;
hasdata = 0;
type = Bgetc(h->fd);
switch(type){
case Beof:
giferror(h, extreaderr);
break;
case 0x01: /* Plain Text Extension */
hsize = 13;
hasdata = 1;
break;
case 0xF9: /* Graphic Control Extension */
graphiccontrol(h);
return;
case 0xFE: /* Comment Extension */
hasdata = 1;
break;
case 0xFF: /* Application Extension */
hsize = Bgetc(h->fd);
/* standard says this must be 11, but Adobe likes to put out 10-byte ones,
* so we pay attention to the field. */
hasdata = 1;
break;
default:
giferror(h, "ReadGIF: unknown extension");
}
if(hsize>0 && Bread(h->fd, h->buf, hsize) != hsize)
giferror(h, extreaderr);
if(!hasdata){
if(h->buf[hsize-1] != 0)
giferror(h, "ReadGIF: bad extension format");
return;
}
/* loop counter: Application Extension with NETSCAPE2.0 as string and 1 <loop.count> in data */
if(type == 0xFF && hsize==11 && memcmp(h->buf, "NETSCAPE2.0", 11)==0){
n = readdata(h, data);
if(n == 0)
return;
if(n==3 && data[0]==1)
h->loopcount = data[1] | (data[2]<<8);
}
while(readdata(h, data) != 0)
;
}
static
uchar*
decode(Header *h, Rawimage *i, Entry *tbl)
{
int c, incode, codesize, CTM, EOD, pici, datai, stacki, nbits, sreg, fc, code, piclen;
int csize, nentry, maxentry, first, ocode, ndata, nb;
uchar *pic;
uchar stack[4096], data[256];
if(Bread(h->fd, h->buf, 1) != 1)
giferror(h, "ReadGIF: can't read data: %r");
codesize = h->buf[0];
if(codesize>8 || 0>codesize)
giferror(h, "ReadGIF: can't handle codesize %d", codesize);
if(i->cmap!=nil && i->cmaplen!=3*(1<<codesize)
&& (codesize!=2 || i->cmaplen!=3*2)) /* peculiar GIF bitmap files... */
giferror(h, "ReadGIF: codesize %d doesn't match color map 3*%d", codesize, i->cmaplen/3);
CTM =1<<codesize;
EOD = CTM+1;
piclen = (i->r.max.x-i->r.min.x)*(i->r.max.y-i->r.min.y);
i->chanlen = piclen;
pic = malloc(piclen);
if(pic == nil)
giferror(h, memerr);
h->pic = pic;
pici = 0;
ndata = 0;
datai = 0;
nbits = 0;
sreg = 0;
fc = 0;
Loop:
for(;;){
csize = codesize+1;
nentry = EOD+1;
maxentry = (1<<csize)-1;
first = 1;
ocode = -1;
for(;; ocode = incode) {
while(nbits < csize) {
if(datai == ndata){
ndata = readdata(h, data);
if(ndata == 0)
goto Return;
datai = 0;
}
c = data[datai++];
sreg |= c<<nbits;
nbits += 8;
}
code = sreg & ((1<<csize) - 1);
sreg >>= csize;
nbits -= csize;
if(code == EOD){
ndata = readdata(h, data);
if(ndata != 0)
fprint(2, "ReadGIF: unexpected data past EOD");
goto Return;
}
if(code == CTM)
goto Loop;
stacki = (sizeof stack)-1;
incode = code;
/* special case for KwKwK */
if(code == nentry) {
stack[stacki--] = fc;
code = ocode;
}
if(code > nentry)
giferror(h, "ReadGIF: bad code %x %x", code, nentry);
for(c=code; c>=0; c=tbl[c].prefix)
stack[stacki--] = tbl[c].exten;
nb = (sizeof stack)-(stacki+1);
if(pici+nb > piclen){
/* this common error is harmless
* we have to keep reading to keep the blocks in sync */
;
}else{
memmove(pic+pici, stack+stacki+1, sizeof stack - (stacki+1));
pici += nb;
}
fc = stack[stacki+1];
if(first){
first = 0;
continue;
}
#define early 0 /* peculiar tiff feature here for reference */
if(nentry == maxentry-early) {
if(csize >= 12)
continue;
csize++;
maxentry = (1<<csize);
if(csize < 12)
maxentry--;
}
tbl[nentry].prefix = ocode;
tbl[nentry].exten = fc;
nentry++;
}
}
Return:
h->pic = nil;
return pic;
}
static
void
interlace(Header *h, Rawimage *image)
{
uchar *pic;
Rectangle r;
int dx, yy, y;
uchar *ipic;
pic = image->chans[0];
r = image->r;
dx = r.max.x-r.min.x;
ipic = malloc(dx*(r.max.y-r.min.y));
if(ipic == nil)
giferror(h, nil);
/* Group 1: every 8th row, starting with row 0 */
yy = 0;
for(y=r.min.y; y<r.max.y; y+=8){
memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx);
yy++;
}
/* Group 2: every 8th row, starting with row 4 */
for(y=r.min.y+4; y<r.max.y; y+=8){
memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx);
yy++;
}
/* Group 3: every 4th row, starting with row 2 */
for(y=r.min.y+2; y<r.max.y; y+=4){
memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx);
yy++;
}
/* Group 4: every 2nd row, starting with row 1 */
for(y=r.min.y+1; y<r.max.y; y+=2){
memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx);
yy++;
}
free(image->chans[0]);
image->chans[0] = ipic;
}

1661
src/cmd/jpg/readjpg.c Normal file

File diff suppressed because it is too large Load Diff

334
src/cmd/jpg/readpng.c Normal file
View File

@ -0,0 +1,334 @@
// work in progress... this version only good enough to read
// non-interleaved, 24bit RGB images
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <bio.h>
#include <flate.h>
#include <draw.h>
#include "imagefile.h"
int debug;
enum{ IDATSIZE=1000000,
/* filtering algorithms, supposedly increase compression */
FilterNone = 0, /* new[x][y] = buf[x][y] */
FilterSub = 1, /* new[x][y] = buf[x][y] + new[x-1][y] */
FilterUp = 2, /* new[x][y] = buf[x][y] + new[x][y-1] */
FilterAvg = 3, /* new[x][y] = buf[x][y] + (new[x-1][y]+new[x][y-1])/2 */
FilterPaeth= 4, /* new[x][y] = buf[x][y] + paeth(new[x-1][y],new[x][y-1],new[x-1][y-1]) */
FilterLast = 5,
PropertyBit = 1<<5,
};
typedef struct ZlibR{
Biobuf *bi;
uchar *buf;
uchar *b; // next byte to decompress
uchar *e; // past end of buf
} ZlibR;
typedef struct ZlibW{
uchar *r, *g, *b; // Rawimage channels
int chan; // next channel to write
int col; // column index of current pixel
// -1 = one-byte pseudo-column for filter spec
int row; // row index of current pixel
int ncol, nrow; // image width, height
int filter; // algorithm for current scanline
} ZlibW;
static ulong *crctab;
static uchar PNGmagic[] = {137,80,78,71,13,10,26,10};
static char memerr[] = "ReadPNG: malloc failed: %r";
static ulong
get4(uchar *a)
{
return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
}
static
void
pnginit(void)
{
static int inited;
if(inited)
return;
inited = 1;
crctab = mkcrctab(0xedb88320);
if(crctab == nil)
sysfatal("mkcrctab error");
inflateinit();
}
static
void*
pngmalloc(ulong n, int clear)
{
void *p;
p = malloc(n);
if(p == nil)
sysfatal(memerr);
if(clear)
memset(p, 0, n);
return p;
}
static int
getchunk(Biobuf *b, char *type, uchar *d, int m)
{
uchar buf[8];
ulong crc = 0, crc2;
int n, nr;
if(Bread(b, buf, 8) != 8)
return -1;
n = get4(buf);
memmove(type, buf+4, 4);
type[4] = 0;
if(n > m)
sysfatal("getchunk needed %d, had %d", n, m);
nr = Bread(b, d, n);
if(nr != n)
sysfatal("getchunk read %d, expected %d", nr, n);
crc = blockcrc(crctab, crc, type, 4);
crc = blockcrc(crctab, crc, d, n);
if(Bread(b, buf, 4) != 4)
sysfatal("getchunk tlr failed");
crc2 = get4(buf);
if(crc != crc2)
sysfatal("getchunk crc failed");
return n;
}
static int
zread(void *va)
{
ZlibR *z = va;
char type[5];
int n;
if(z->b >= z->e){
refill_buffer:
z->b = z->buf;
n = getchunk(z->bi, type, z->b, IDATSIZE);
if(n < 0 || strcmp(type, "IEND") == 0)
return -1;
z->e = z->b + n;
if(type[0] & PropertyBit)
goto refill_buffer; /* skip auxiliary chunks for now */
if(strcmp(type,"IDAT") != 0)
sysfatal("unrecognized mandatory chunk %s", type);
}
return *z->b++;
}
static uchar
paeth(uchar a, uchar b, uchar c)
{
int p, pa, pb, pc;
p = (int)a + (int)b - (int)c;
pa = abs(p - (int)a);
pb = abs(p - (int)b);
pc = abs(p - (int)c);
if(pa <= pb && pa <= pc)
return a;
else if(pb <= pc)
return b;
return c;
}
static void
unfilter(int alg, uchar *buf, uchar *ebuf, int up)
{
switch(alg){
case FilterSub:
while (++buf < ebuf)
*buf += buf[-1];
break;
case FilterUp:
if (up != 0)
do
*buf += buf[up];
while (++buf < ebuf);
break;
case FilterAvg:
if (up == 0)
while (++buf < ebuf)
*buf += buf[-1]/2;
else{
*buf += buf[up]/2;
while (++buf < ebuf)
*buf += (buf[-1]+buf[up])/2;
}
break;
case FilterPaeth:
if (up == 0)
while (++buf < ebuf)
*buf += buf[-1];
else{
*buf += paeth(0, buf[up], 0);
while (++buf < ebuf)
*buf += paeth(buf[-1], buf[up], buf[up-1]);
}
break;
}
}
static int
zwrite(void *va, void *vb, int n)
{
ZlibW *z = va;
uchar *buf = vb;
int i, up;
for(i=0; i<n; i++){
if(z->col == -1){
// set filter byte
z->filter = *buf++;
if (z->filter >= FilterLast)
sysfatal("unknown filter algorithm %d for row %d", z->row, z->filter);
z->col++;
continue;
}
switch(z->chan){
case 0:
*z->r++ = *buf++;
z->chan = 1;
break;
case 1:
*z->g++ = *buf++;
z->chan = 2;
break;
case 2:
*z->b++ = *buf++;
z->chan = 0;
z->col++;
if(z->col == z->ncol){
if (z->filter){
if(z->row == 0)
up = 0;
else
up = -z->ncol;
unfilter(z->filter, z->r - z->col, z->r, up);
unfilter(z->filter, z->g - z->col, z->g, up);
unfilter(z->filter, z->b - z->col, z->b, up);
}
z->col = -1;
z->row++;
if((z->row >= z->nrow) && (i < n-1) )
sysfatal("header said %d rows; data goes further", z->nrow);
}
break;
}
}
return n;
}
static Rawimage*
readslave(Biobuf *b)
{
ZlibR zr;
ZlibW zw;
Rawimage *image;
char type[5];
uchar *buf, *h;
int k, n, nrow, ncol, err;
buf = pngmalloc(IDATSIZE, 0);
Bread(b, buf, sizeof PNGmagic);
if(memcmp(PNGmagic, buf, sizeof PNGmagic) != 0)
sysfatal("bad PNGmagic");
n = getchunk(b, type, buf, IDATSIZE);
if(n < 13 || strcmp(type,"IHDR") != 0)
sysfatal("missing IHDR chunk");
h = buf;
ncol = get4(h); h += 4;
nrow = get4(h); h += 4;
if(ncol <= 0 || nrow <= 0)
sysfatal("impossible image size nrow=%d ncol=%d", nrow, ncol);
if(debug)
fprint(2, "readpng nrow=%d ncol=%d\n", nrow, ncol);
if(*h++ != 8)
sysfatal("only 24 bit per pixel supported for now [%d]", h[-1]);
if(*h++ != 2)
sysfatal("only rgb supported for now [%d]", h[-1]);
if(*h++ != 0)
sysfatal("only deflate supported for now [%d]", h[-1]);
if(*h++ != FilterNone)
sysfatal("only FilterNone supported for now [%d]", h[-1]);
if(*h != 0)
sysfatal("only non-interlaced supported for now [%d]", h[-1]);
image = pngmalloc(sizeof(Rawimage), 1);
image->r = Rect(0, 0, ncol, nrow);
image->cmap = nil;
image->cmaplen = 0;
image->chanlen = ncol*nrow;
image->fields = 0;
image->gifflags = 0;
image->gifdelay = 0;
image->giftrindex = 0;
image->chandesc = CRGB;
image->nchans = 3;
for(k=0; k<3; k++)
image->chans[k] = pngmalloc(ncol*nrow, 0);
zr.bi = b;
zr.buf = buf;
zr.b = zr.e = buf + IDATSIZE;
zw.r = image->chans[0];
zw.g = image->chans[1];
zw.b = image->chans[2];
zw.chan = 0;
zw.col = -1;
zw.row = 0;
zw.ncol = ncol;
zw.nrow = nrow;
err = inflatezlib(&zw, zwrite, &zr, zread);
if(err)
sysfatal("inflatezlib %s\n", flateerr(err));
free(buf);
return image;
}
Rawimage**
Breadpng(Biobuf *b, int colorspace)
{
Rawimage *r, **array;
char buf[ERRMAX];
buf[0] = '\0';
if(colorspace != CRGB){
errstr(buf, sizeof buf); /* throw it away */
werrstr("ReadPNG: unknown color space %d", colorspace);
return nil;
}
pnginit();
array = malloc(2*sizeof(*array));
if(array==nil)
return nil;
errstr(buf, sizeof buf); /* throw it away */
r = readslave(b);
array[0] = r;
array[1] = nil;
return array;
}
Rawimage**
readpng(int fd, int colorspace)
{
Rawimage** a;
Biobuf b;
if(Binit(&b, fd, OREAD) < 0)
return nil;
a = Breadpng(&b, colorspace);
Bterm(&b);
return a;
}

238
src/cmd/jpg/readppm.c Normal file
View File

@ -0,0 +1,238 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <ctype.h>
#include "imagefile.h"
Rawimage *readppm(Biobuf*, Rawimage*);
/*
* fetch a non-comment character.
*/
static
int
Bgetch(Biobuf *b)
{
int c;
for(;;) {
c = Bgetc(b);
if(c == '#') {
while((c = Bgetc(b)) != Beof && c != '\n')
;
}
return c;
}
}
/*
* fetch a nonnegative decimal integer.
*/
static
int
Bgetint(Biobuf *b)
{
int c;
int i;
while((c = Bgetch(b)) != Beof && !isdigit(c))
;
if(c == Beof)
return -1;
i = 0;
do {
i = i*10 + (c-'0');
} while((c = Bgetch(b)) != Beof && isdigit(c));
return i;
}
static
int
Bgetdecimalbit(Biobuf *b)
{
int c;
while((c = Bgetch(b)) != Beof && c != '0' && c != '1')
;
if(c == Beof)
return -1;
return c == '1';
}
static int bitc, nbit;
static
int
Bgetbit(Biobuf *b)
{
if(nbit == 0) {
nbit = 8;
bitc = Bgetc(b);
if(bitc == -1)
return -1;
}
nbit--;
return (bitc >> (nbit-1)) & 0x1;
}
static
void
Bflushbit(Biobuf *b)
{
USED(b);
nbit = 0;
}
Rawimage**
readpixmap(int fd, int colorspace)
{
Rawimage **array, *a;
Biobuf b;
char buf[ERRMAX];
int i;
char *e;
USED(colorspace);
if(Binit(&b, fd, OREAD) < 0)
return nil;
werrstr("");
e = "out of memory";
if((array = malloc(sizeof *array)) == nil)
goto Error;
if((array[0] = malloc(sizeof *array[0])) == nil)
goto Error;
memset(array[0], 0, sizeof *array[0]);
for(i=0; i<3; i++)
array[0]->chans[i] = nil;
e = "bad file format";
switch(Bgetc(&b)) {
case 'P':
Bungetc(&b);
a = readppm(&b, array[0]);
break;
default:
a = nil;
break;
}
if(a == nil)
goto Error;
array[0] = a;
return array;
Error:
if(array)
free(array[0]);
free(array);
errstr(buf, sizeof buf);
if(buf[0] == 0)
strcpy(buf, e);
errstr(buf, sizeof buf);
return nil;
}
typedef struct Pix Pix;
struct Pix {
char magic;
int maxcol;
int (*fetch)(Biobuf*);
int nchan;
int chandesc;
int invert;
void (*flush)(Biobuf*);
};
static Pix pix[] = {
{ '1', 1, Bgetdecimalbit, 1, CY, 1, nil }, /* portable bitmap */
{ '4', 1, Bgetbit, 1, CY, 1, Bflushbit }, /* raw portable bitmap */
{ '2', 0, Bgetint, 1, CY, 0, nil }, /* portable greymap */
{ '5', 0, Bgetc, 1, CY, 0, nil }, /* raw portable greymap */
{ '3', 0, Bgetint, 3, CRGB, 0, nil }, /* portable pixmap */
{ '6', 0, Bgetc, 3, CRGB, 0, nil }, /* raw portable pixmap */
{ 0 },
};
Rawimage*
readppm(Biobuf *b, Rawimage *a)
{
int i, ch, wid, ht, r, c;
int maxcol, nchan, invert;
int (*fetch)(Biobuf*);
uchar *rgb[3];
char buf[ERRMAX];
char *e;
Pix *p;
e = "bad file format";
if(Bgetc(b) != 'P')
goto Error;
c = Bgetc(b);
for(p=pix; p->magic; p++)
if(p->magic == c)
break;
if(p->magic == 0)
goto Error;
wid = Bgetint(b);
ht = Bgetint(b);
if(wid <= 0 || ht <= 0)
goto Error;
a->r = Rect(0,0,wid,ht);
maxcol = p->maxcol;
if(maxcol == 0) {
maxcol = Bgetint(b);
if(maxcol <= 0)
goto Error;
}
e = "out of memory";
for(i=0; i<p->nchan; i++)
if((rgb[i] = a->chans[i] = malloc(wid*ht)) == nil)
goto Error;
a->nchans = p->nchan;
a->chanlen = wid*ht;
a->chandesc = p->chandesc;
e = "error reading file";
fetch = p->fetch;
nchan = p->nchan;
invert = p->invert;
for(r=0; r<ht; r++) {
for(c=0; c<wid; c++) {
for(i=0; i<nchan; i++) {
if((ch = (*fetch)(b)) < 0)
goto Error;
if(invert)
ch = maxcol - ch;
*rgb[i]++ = (ch * 255)/maxcol;
}
}
if(p->flush)
(*p->flush)(b);
}
return a;
Error:
errstr(buf, sizeof buf);
if(buf[0] == 0)
strcpy(buf, e);
errstr(buf, sizeof buf);
for(i=0; i<3; i++)
free(a->chans[i]);
free(a->cmap);
return nil;
}

190
src/cmd/jpg/readyuv.c Normal file
View File

@ -0,0 +1,190 @@
/* readyuv.c - read an Abekas A66 style image file. Steve Simon, 2003 */
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <ctype.h>
#include "imagefile.h"
/*
* ITU/CCIR Rec601 states:
*
* R = y + 1.402 * Cr
* B = Y + 1.77305 * Cb
* G = Y - 0.72414 * Cr - 0.34414 * Cb
*
* using 8 bit traffic
* Y = 16 + 219 * Y
* Cr = 128 + 224 * Cr
* Cb = 128 + 224 * Cb
* or, if 10bit is used
* Y = 64 + 876 * Y
* Cr = 512 + 896 * Cr
* Cb = 512 + 896 * Cb
*/
enum {
PAL = 576, NTSC = 486 };
static int lsbtab[] = { 6, 4, 2, 0};
static int
clip(int x)
{
x >>= 18;
if (x > 255)
return 0xff;
if (x <= 0)
return 0;
return x;
}
Rawimage**
Breadyuv(Biobuf *bp, int colourspace)
{
Dir * d;
Rawimage * a, **array;
char *e, ebuf[128];
ushort * mux, *end, *frm;
uchar buf[720 * 2], *r, *g, *b;
int y1, y2, cb, cr, sz, c, l, w, base, bits, lines;
frm = 0;
if (colourspace != CYCbCr) {
errstr(ebuf, sizeof ebuf); /* throw it away */
werrstr("ReadYUV: unknown colour space %d", colourspace);
return nil;
}
if ((a = calloc(sizeof(Rawimage), 1)) == nil)
sysfatal("no memory");
if ((array = calloc(sizeof(Rawimage * ), 2)) == nil)
sysfatal("no memory");
array[0] = a;
array[1] = nil;
if ((d = dirfstat(Bfildes(bp))) != nil) {
sz = d->length;
free(d);
} else {
fprint(2, "cannot stat input, assuming 720x576x10bit\n");
sz = 720 * PAL * 2L + (720 * PAL / 2L);
}
switch (sz) {
case 720 * PAL * 2: // 625 x 8bit
bits = 8;
lines = PAL;
break;
case 720 * NTSC * 2: // 525 x 8bit
bits = 8;
lines = NTSC;
break;
case 720 * PAL * 2 + (720 * PAL / 2) : // 625 x 10bit
bits = 10;
lines = PAL;
break;
case 720 * NTSC * 2 + (720 * NTSC / 2) : // 525 x 10bit
bits = 10;
lines = NTSC;
break;
default:
e = "unknown file size";
goto Error;
}
// print("bits=%d pixels=%d lines=%d\n", bits, 720, lines);
//
a->nchans = 3;
a->chandesc = CRGB;
a->chanlen = 720 * lines;
a->r = Rect(0, 0, 720, lines);
e = "no memory";
if ((frm = malloc(720 * 2 * lines * sizeof(ushort))) == nil)
goto Error;
for (c = 0; c < 3; c++)
if ((a->chans[c] = malloc(720 * lines)) == nil)
goto Error;
e = "read file";
for (l = 0; l < lines; l++) {
if (Bread(bp, buf, 720 * 2) == -1)
goto Error;
base = l * 720 * 2;
for (w = 0; w < 720 * 2; w++)
frm[base + w] = ((ushort)buf[w]) << 2;
}
if (bits == 10)
for (l = 0; l < lines; l++) {
if (Bread(bp, buf, 720 / 2) == -1)
goto Error;
base = l * 720 * 2;
for (w = 0; w < 720 * 2; w++)
frm[base + w] |= buf[w / 4] >> lsbtab[w % 4];
}
mux = frm;
end = frm + 720 * lines * 2;
r = a->chans[0];
g = a->chans[1];
b = a->chans[2];
while (mux < end) {
cb = *mux++ - 512;
y1 = (*mux++ - 64) * 76310;
cr = *mux++ - 512;
y2 = (*mux++ - 64) * 76310;
*r++ = clip((104635 * cr) + y1);
*g++ = clip((-25690 * cb + -53294 * cr) + y1);
*b++ = clip((132278 * cb) + y1);
*r++ = clip((104635 * cr) + y2);
*g++ = clip((-25690 * cb + -53294 * cr) + y2);
*b++ = clip((132278 * cb) + y2);
}
free(frm);
return array;
Error:
errstr(ebuf, sizeof ebuf);
if (ebuf[0] == 0)
strcpy(ebuf, e);
errstr(ebuf, sizeof ebuf);
for (c = 0; c < 3; c++)
free(a->chans[c]);
free(a->cmap);
free(array[0]);
free(array);
free(frm);
return nil;
}
Rawimage**
readyuv(int fd, int colorspace)
{
Rawimage * *a;
Biobuf b;
if (Binit(&b, fd, OREAD) < 0)
return nil;
a = Breadyuv(&b, colorspace);
Bterm(&b);
return a;
}

69
src/cmd/jpg/rgbrgbv.c Normal file
View File

@ -0,0 +1,69 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
/*
* This version of closest() is now (feb 20, 2001) installed as rgb2cmap in libdraw
*/
int
closest(int cr, int cg, int cb)
{
int i, r, g, b, sq;
ulong rgb;
int best, bestsq;
best = 0;
bestsq = 0x7FFFFFFF;
for(i=0; i<256; i++){
rgb = cmap2rgb(i);
r = (rgb>>16) & 0xFF;
g = (rgb>>8) & 0xFF;
b = (rgb>>0) & 0xFF;
sq = (r-cr)*(r-cr)+(g-cg)*(g-cg)+(b-cb)*(b-cb);
if(sq < bestsq){
bestsq = sq;
best = i;
}
}
return best;
}
void
main(int argc, char *argv[])
{
int i, rgb;
int r, g, b;
uchar close[16*16*16];
/* rgbmap */
print("uint rgbmap[256] = {\n");
for(i=0; i<256; i++){
if(i%8 == 0)
print("\t");
rgb = cmap2rgb(i);
r = (rgb>>16) & 0xFF;
g = (rgb>>8) & 0xFF;
b = (rgb>>0) & 0xFF;
print("0x%.6ulX, ", (r<<16) | (g<<8) | b);
if(i%8 == 7)
print("\n");
}
print("};\n\n");
/* closestrgb */
print("uchar closestrgb[16*16*16] = {\n");
for(r=0; r<256; r+=16)
for(g=0; g<256; g+=16)
for(b=0; b<256; b+=16)
close[(b/16)+16*((g/16)+16*(r/16))] = closest(r+8, g+8, b+8);
for(i=0; i<16*16*16; i++){
if(i%16 == 0)
print("\t");
print("%d,", close[i]);
if(i%16 == 15)
print("\n");
}
print("};\n\n");
exits(nil);
}

120
src/cmd/jpg/rgbycc.c Normal file
View File

@ -0,0 +1,120 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
float c1 = 1.402;
float c2 = 0.34414;
float c3 = 0.71414;
float c4 = 1.772;
int
closest(int Y, int Cb, int Cr)
{
double r, g, b;
double diff, min;
int rgb, R, G, B, v, i;
int y1, cb1, cr1;
Cb -= 128;
Cr -= 128;
r = Y+c1*Cr;
g = Y-c2*Cb-c3*Cr;
b = Y+c4*Cb;
//print("YCbCr: %d %d %d, RGB: %g %g %g\n", Y, Cb, Cr, r, g, b);
min = 1000000.;
v = 1000;
for(i=0; i<256; i++){
rgb = cmap2rgb(i);
R = (rgb >> 16) & 0xFF;
G = (rgb >> 8) & 0xFF;
B = (rgb >> 0) & 0xFF;
diff = (R-r)*(R-r) + (G-g)*(G-g) + (B-b)*(B-b);
y1 = 0.5870*G + 0.114*B + 0.299*R;
cb1 = (B-y1)/1.772;
cr1 = (R-y1)/1.402;
if(diff < min){
// if(Y==0 && y1!=0)
// continue;
if(Y==256-16 && y1<256-16)
continue;
// if(Cb==0 && cb1!=0)
// continue;
if(Cb==256-16 && cb1<256-16)
continue;
// if(Cr==0 && cr1!=0)
// continue;
if(Cr==256-16 && cr1<256-16)
continue;
//print("%d %d %d\n", R, G, B);
min = diff;
v = i;
}
}
if(v > 255)
abort();
return v;
}
void
main(int argc, char *argv[])
{
int i, rgb;
int r, g, b;
double Y, Cr, Cb;
int y, cb, cr;
uchar close[16*16*16];
//print("%d\n", closest(atoi(argv[1]), atoi(argv[2]), atoi(argv[3])));
//exits("X");
/* ycbcrmap */
print("uint ycbcrmap[256] = {\n");
for(i=0; i<256; i++){
if(i%8 == 0)
print("\t");
rgb = cmap2rgb(i);
r = (rgb>>16) & 0xFF;
g = (rgb>>8) & 0xFF;
b = (rgb>>0) & 0xFF;
Y = 0.5870*g + 0.114*b + 0.299*r;
Cr = (r-Y)/1.402 + 128.;
Cb = (b-Y)/1.772 + 128.;
if(Y<0. || Y>=256. || Cr<0. || Cr>=256. || Cb<0. || Cb>=256.)
print("bad at %d: %d %d %d; %g %g %g\n", i, r, g, b, Y, Cb, Cr);
r = Y;
g = Cb;
b = Cr;
print("0x%.6ulX, ", (r<<16) | (g<<8) | b);
if(i%8 == 7)
print("\n");
}
print("};\n\n");
/* closestycbcr */
print("uchar closestycbcr[16*16*16] = {\n");
for(y=0; y<256; y+=16)
for(cb=0; cb<256; cb+=16)
for(cr=0; cr<256; cr+=16)
close[(cr/16)+16*((cb/16)+16*(y/16))] = closest(y, cb, cr);
if(0){
/*weird: set white for nearly white */
for(cb=128-32; cb<=128+32; cb+=16)
for(cr=128-32; cr<=128+32; cr+=16)
close[(cr/16)+16*((cb/16)+16*(255/16))] = 0;
/*weird: set black for nearly black */
for(cb=128-32; cb<=128+32; cb+=16)
for(cr=128-32; cr<=128+32; cr+=16)
close[(cr/16)+16*((cb/16)+16*(0/16))] = 255;
}
for(i=0; i<16*16*16; i++){
if(i%16 == 0)
print("\t");
print("%d,", close[i]);
if(i%16 == 15)
print("\n");
}
print("};\n\n");
exits(nil);
}

147
src/cmd/jpg/togif.c Normal file
View File

@ -0,0 +1,147 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <ctype.h>
#include <bio.h>
#include "imagefile.h"
void
usage(void)
{
fprint(2, "usage: togif [-l loopcount] [-c 'comment'] [-d Δt (ms)] [-t transparency-index] [file ... [-d Δt] file ...]\n");
exits("usage");
}
#define UNSET (-12345678)
void
main(int argc, char *argv[])
{
Biobuf bout;
Memimage *i, *ni;
int fd, j, dt, trans, loop;
char buf[256];
char *err, *comment, *s;
comment = nil;
dt = -1;
trans = -1;
loop = UNSET;
ARGBEGIN{
case 'l':
s = ARGF();
if(s==nil || (!isdigit(s[0]) && s[0]!='-'))
usage();
loop = atoi(s);
break;
case 'c':
comment = ARGF();
if(comment == nil)
usage();
break;
case 'd':
s = ARGF();
if(s==nil || !isdigit(s[0]))
usage();
dt = atoi(s);
break;
case 't':
s = ARGF();
if(s==nil || !isdigit(s[0]))
usage();
trans = atoi(s);
if(trans > 255)
usage();
break;
default:
usage();
}ARGEND
if(Binit(&bout, 1, OWRITE) < 0)
sysfatal("Binit failed: %r");
memimageinit();
err = nil;
if(argc == 0){
i = readmemimage(0);
if(i == nil)
sysfatal("reading input: %r");
ni = memonechan(i);
if(ni == nil)
sysfatal("converting image to RGBV: %r");
if(i != ni){
freememimage(i);
i = ni;
}
err = memstartgif(&bout, i, -1);
if(err == nil){
if(comment)
err = memwritegif(&bout, i, comment, dt, trans);
else{
snprint(buf, sizeof buf, "Converted by Plan 9 from <stdin>");
err = memwritegif(&bout, i, buf, dt, trans);
}
}
}else{
if(loop == UNSET){
if(argc == 1)
loop = -1; /* no loop for single image */
else
loop = 0; /* the default case: 0 means infinite loop */
}
for(j=0; j<argc; j++){
if(argv[j][0] == '-' && argv[j][1]=='d'){
/* time change */
if(argv[j][2] == '\0'){
s = argv[++j];
if(j == argc)
usage();
}else
s = &argv[j][2];
if(!isdigit(s[0]))
usage();
dt = atoi(s);
if(j == argc-1) /* last argument must be file */
usage();
continue;
}
fd = open(argv[j], OREAD);
if(fd < 0)
sysfatal("can't open %s: %r", argv[j]);
i = readmemimage(fd);
if(i == nil)
sysfatal("can't readimage %s: %r", argv[j]);
close(fd);
ni = memonechan(i);
if(ni == nil)
sysfatal("converting image to RGBV: %r");
if(i != ni){
freememimage(i);
i = ni;
}
if(j == 0){
err = memstartgif(&bout, i, loop);
if(err != nil)
break;
}
if(comment)
err = memwritegif(&bout, i, comment, dt, trans);
else{
snprint(buf, sizeof buf, "Converted by Plan 9 from %s", argv[j]);
err = memwritegif(&bout, i, buf, dt, trans);
}
if(err != nil)
break;
freememimage(i);
comment = nil;
}
}
memendgif(&bout);
if(err != nil)
fprint(2, "togif: %s\n", err);
exits(err);
}

322
src/cmd/jpg/toico.c Normal file
View File

@ -0,0 +1,322 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
enum
{
FileHdrLen= 6,
IconDescrLen= 16,
IconHdrLen= 40,
};
typedef struct Icon Icon;
struct Icon
{
Icon *next;
char *file;
uchar w; /* icon width */
uchar h; /* icon height */
ushort ncolor; /* number of colors */
ushort nplane; /* number of bit planes */
ushort bits; /* bits per pixel */
ulong len; /* length of data */
ulong offset; /* file offset to data */
uchar map[4*256]; /* color map */
Image *img;
uchar *xor;
int xorlen;
uchar *and;
int andlen;
};
typedef struct Header Header;
struct Header
{
uint n;
Icon *first;
Icon *last;
};
void
Bputs(Biobuf *b, ushort x)
{
Bputc(b, x&0xff);
Bputc(b, x>>8);
}
void
Bputl(Biobuf *b, ulong x)
{
Bputs(b, x&0xffff);
Bputs(b, x>>16);
}
Header h;
void* emalloc(int);
void mk8bit(Icon*, int);
void mkxorand(Icon*, int);
void readicon(char*);
void
main(int argc, char **argv)
{
int i;
Biobuf *b, out;
Icon *icon;
ulong offset;
ulong len;
ARGBEGIN{
}ARGEND;
/* read in all the images */
initdraw(nil, nil, nil);
if(argc < 1){
readicon("/fd/0");
} else {
for(i = 0; i < argc; i++)
readicon(argv[i]);
}
/* create the .ico file */
b = &out;
Binit(b, 1, OWRITE);
/* offset to first icon */
offset = FileHdrLen + h.n*IconDescrLen;
/* file header is */
Bputs(b, 0);
Bputs(b, 1);
Bputs(b, h.n);
/* icon description */
for(icon = h.first; icon != nil; icon = icon->next){
Bputc(b, icon->w);
Bputc(b, icon->h);
Bputc(b, icon->ncolor);
Bputc(b, 0);
Bputs(b, icon->nplane);
Bputs(b, icon->bits);
len = IconHdrLen + icon->ncolor*4 + icon->xorlen + icon->andlen;
Bputl(b, len);
Bputl(b, offset);
offset += len;
}
/* icons */
for(icon = h.first; icon != nil; icon = icon->next){
/* icon header (BMP like) */
Bputl(b, IconHdrLen);
Bputl(b, icon->w);
Bputl(b, 2*icon->h);
Bputs(b, icon->nplane);
Bputs(b, icon->bits);
Bputl(b, 0); /* compression info */
Bputl(b, 0);
Bputl(b, 0);
Bputl(b, 0);
Bputl(b, 0);
Bputl(b, 0);
/* color map */
if(Bwrite(b, icon->map, 4*icon->ncolor) < 0)
sysfatal("writing color map: %r");
/* xor bits */
if(Bwrite(b, icon->xor, icon->xorlen) < 0)
sysfatal("writing xor bits: %r");
/* and bits */
if(Bwrite(b, icon->and, icon->andlen) < 0)
sysfatal("writing and bits: %r");
}
Bterm(b);
exits(0);
}
void
readicon(char *file)
{
int fd;
Icon *icon;
fd = open(file, OREAD);
if(fd < 0)
sysfatal("opening %s: %r", file);
icon = emalloc(sizeof(Icon));
icon->img = readimage(display, fd, 0);
if(icon->img == nil)
sysfatal("reading image %s: %r", file);
close(fd);
if(h.first)
h.last->next = icon;
else
h.first = icon;
h.last = icon;
h.n++;
icon->h = Dy(icon->img->r);
icon->w = Dx(icon->img->r);
icon->bits = 1<<icon->img->depth;
icon->nplane = 1;
/* convert to 8 bits per pixel */
switch(icon->img->chan){
case GREY8:
case CMAP8:
break;
case GREY1:
case GREY2:
case GREY4:
mk8bit(icon, 1);
break;
default:
mk8bit(icon, 0);
break;
}
icon->bits = 8;
icon->file = file;
/* create xor/and masks, minimizing bits per pixel */
mkxorand(icon, icon->img->chan == GREY8);
}
void*
emalloc(int len)
{
void *x;
x = mallocz(len, 1);
if(x == nil)
sysfatal("memory: %r");
return x;
}
/* convert to 8 bit */
void
mk8bit(Icon *icon, int grey)
{
Image *img;
img = allocimage(display, icon->img->r, grey ? GREY8 : CMAP8, 0, DNofill);
if(img == nil)
sysfatal("can't allocimage: %r");
draw(img, img->r, icon->img, nil, ZP);
freeimage(icon->img);
icon->img = img;
}
/* make xor and and mask */
void
mkxorand(Icon *icon, int grey)
{
int i, x, y, s, sa;
uchar xx[256];
uchar *data, *p, *e;
int ndata;
uchar *mp;
int ncolor;
ulong color;
int bits;
uchar andbyte, xorbyte;
uchar *ato, *xto;
int xorrl, andrl;
ndata = icon->h * icon->w;
data = emalloc(ndata);
if(unloadimage(icon->img, icon->img->r, data, ndata) < 0)
sysfatal("can't unload %s: %r", icon->file);
e = data + ndata;
/* find colors used */
memset(xx, 0, sizeof xx);
for(p = data; p < e; p++)
xx[*p]++;
/* count the colors and create a mapping from plan 9 */
mp = icon->map;
ncolor = 0;
for(i = 0; i < 256; i++){
if(xx[i] == 0)
continue;
if(grey){
*mp++ = i;
*mp++ = i;
*mp++ = i;
*mp++ = 0;
} else {
color = cmap2rgb(i);
*mp++ = color;
*mp++ = color>>8;
*mp++ = color>>16;
*mp++ = 0;
}
xx[i] = ncolor;
ncolor++;
}
/* get minimum number of pixels per bit (with a color map) */
if(ncolor <= 2){
ncolor = 2;
bits = 1;
} else if(ncolor <= 4){
ncolor = 4;
bits = 2;
} else if(ncolor <= 16){
ncolor = 16;
bits = 4;
} else {
ncolor = 256;
bits = 8;
}
icon->bits = bits;
icon->ncolor = ncolor;
/* the xor mask rows are justified to a 32 bit boundary */
/* the and mask is 1 bit grey */
xorrl = 4*((bits*icon->w + 31)/32);
andrl = 4*((icon->w + 31)/32);
icon->xor = emalloc(xorrl * icon->h);
icon->and = emalloc(andrl * icon->h);
icon->xorlen = xorrl*icon->h;
icon->andlen = andrl*icon->h;
/* make both masks. they're upside down relative to plan9 ones */
p = data;
for(y = 0; y < icon->h; y++){
andbyte = 0;
xorbyte = 0;
sa = s = 0;
xto = icon->xor + (icon->h-1-y)*xorrl;
ato = icon->and + (icon->h-1-y)*andrl;
for(x = 0; x < icon->w; x++){
xorbyte <<= bits;
xorbyte |= xx[*p];
s += bits;
if(s == 8){
*xto++ = xorbyte;
xorbyte = 0;
s = 0;
}
andbyte <<= 1;
if(*p == 0xff)
andbyte |= 1;
sa++;
if(sa == 0){
*ato++ = andbyte;
sa = 0;
andbyte = 0;
}
p++;
}
}
free(data);
}

70
src/cmd/jpg/topng.c Normal file
View File

@ -0,0 +1,70 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <ctype.h>
#include <bio.h>
#include <flate.h>
#include "imagefile.h"
void
usage(void)
{
fprint(2, "usage: topng [-c 'comment'] [-g 'gamma'] [file]\n");
exits("usage");
}
void
main(int argc, char *argv[])
{
Biobuf bout;
Memimage *i;
int fd;
char *err, *filename;
ImageInfo II;
ARGBEGIN{
case 'c':
II.comment = ARGF();
if(II.comment == nil)
usage();
II.fields_set |= II_COMMENT;
break;
case 'g':
II.gamma = atof(ARGF());
if(II.gamma == 0.)
usage();
II.fields_set |= II_GAMMA;
break;
case 't':
break;
default:
usage();
}ARGEND
if(Binit(&bout, 1, OWRITE) < 0)
sysfatal("Binit failed: %r");
memimageinit();
if(argc == 0){
fd = 0;
filename = "<stdin>";
}else{
fd = open(argv[0], OREAD);
if(fd < 0)
sysfatal("can't open %s: %r", argv[0]);
filename = argv[0];
}
i = readmemimage(fd);
if(i == nil)
sysfatal("can't readimage %s: %r", filename);
close(fd);
err = memwritepng(&bout, i, &II);
freememimage(i);
if(err != nil)
fprint(2, "topng: %s\n", err);
exits(err);
}

90
src/cmd/jpg/toppm.c Normal file
View File

@ -0,0 +1,90 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <ctype.h>
#include <bio.h>
#include "imagefile.h"
void
usage(void)
{
fprint(2, "usage: toppm [-c 'comment'] [file]\n");
exits("usage");
}
void
main(int argc, char *argv[])
{
Biobuf bout;
Memimage *i, *ni;
int fd;
char buf[256];
char *err, *comment;
comment = nil;
ARGBEGIN{
case 'c':
comment = ARGF();
if(comment == nil)
usage();
if(strchr(comment, '\n') != nil){
fprint(2, "ppm: comment cannot contain newlines\n");
usage();
}
break;
default:
usage();
}ARGEND
if(argc > 1)
usage();
if(Binit(&bout, 1, OWRITE) < 0)
sysfatal("Binit failed: %r");
memimageinit();
err = nil;
if(argc == 0){
i = readmemimage(0);
if(i == nil)
sysfatal("reading input: %r");
ni = memmultichan(i);
if(ni == nil)
sysfatal("converting image to RGBV: %r");
if(i != ni){
freememimage(i);
i = ni;
}
if(err == nil)
err = memwriteppm(&bout, i, comment);
}else{
fd = open(argv[0], OREAD);
if(fd < 0)
sysfatal("can't open %s: %r", argv[0]);
i = readmemimage(fd);
if(i == nil)
sysfatal("can't readimage %s: %r", argv[0]);
close(fd);
ni = memmultichan(i);
if(ni == nil)
sysfatal("converting image to RGBV: %r");
if(i != ni){
freememimage(i);
i = ni;
}
if(comment)
err = memwriteppm(&bout, i, comment);
else{
snprint(buf, sizeof buf, "Converted by Plan 9 from %s", argv[0]);
err = memwriteppm(&bout, i, buf);
}
freememimage(i);
}
if(err != nil)
fprint(2, "toppm: %s\n", err);
exits(err);
}

299
src/cmd/jpg/torgbv.c Normal file
View File

@ -0,0 +1,299 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include "imagefile.h"
#include "rgbv.h"
#include "ycbcr.h"
#define CLAMPOFF 128
static int clamp[CLAMPOFF+256+CLAMPOFF];
static int inited;
void*
_remaperror(char *fmt, ...)
{
va_list arg;
char buf[256];
va_start(arg, fmt);
vseprint(buf, buf+sizeof buf, fmt, arg);
va_end(arg);
werrstr(buf);
return nil;
}
Rawimage*
torgbv(Rawimage *i, int errdiff)
{
int j, k, rgb, x, y, er, eg, eb, col, t;
int r, g, b, r1, g1, b1;
int *ered, *egrn, *eblu, *rp, *gp, *bp;
uint *map3;
uchar *closest;
Rawimage *im;
int dx, dy;
char err[ERRMAX];
uchar *cmap, *cm, *in, *out, *inp, *outp, cmap1[3*256], map[256], *rpic, *bpic, *gpic;
err[0] = '\0';
errstr(err, sizeof err); /* throw it away */
im = malloc(sizeof(Rawimage));
if(im == nil)
return nil;
memset(im, 0, sizeof(Rawimage));
im->chans[0] = malloc(i->chanlen);
if(im->chans[0] == nil){
free(im);
return nil;
}
im->r = i->r;
im->nchans = 1;
im->chandesc = CRGBV;
im->chanlen = i->chanlen;
dx = i->r.max.x-i->r.min.x;
dy = i->r.max.y-i->r.min.y;
cmap = i->cmap;
if(inited == 0){
inited = 1;
for(j=0; j<CLAMPOFF; j++)
clamp[j] = 0;
for(j=0; j<256; j++)
clamp[CLAMPOFF+j] = (j>>4);
for(j=0; j<CLAMPOFF; j++)
clamp[CLAMPOFF+256+j] = (255>>4);
}
in = i->chans[0];
inp = in;
out = im->chans[0];
outp = out;
ered = malloc((dx+1)*sizeof(int));
egrn = malloc((dx+1)*sizeof(int));
eblu = malloc((dx+1)*sizeof(int));
if(ered==nil || egrn==nil || eblu==nil){
free(im->chans[0]);
free(im);
free(ered);
free(egrn);
free(eblu);
return _remaperror("remap: malloc failed: %r");
}
memset(ered, 0, (dx+1)*sizeof(int));
memset(egrn, 0, (dx+1)*sizeof(int));
memset(eblu, 0, (dx+1)*sizeof(int));
switch(i->chandesc){
default:
return _remaperror("remap: can't recognize channel type %d", i->chandesc);
case CRGB1:
if(cmap == nil)
return _remaperror("remap: image has no color map");
if(i->nchans != 1)
return _remaperror("remap: can't handle nchans %d", i->nchans);
for(j=1; j<=8; j++)
if(i->cmaplen == 3*(1<<j))
break;
if(j > 8)
return _remaperror("remap: can't do colormap size 3*%d", i->cmaplen/3);
if(i->cmaplen != 3*256){
/* to avoid a range check in inner loop below, make a full-size cmap */
memmove(cmap1, cmap, i->cmaplen);
cmap = cmap1;
}
if(errdiff == 0){
k = 0;
for(j=0; j<256; j++){
r = cmap[k]>>4;
g = cmap[k+1]>>4;
b = cmap[k+2]>>4;
k += 3;
map[j] = closestrgb[b+16*(g+16*r)];
}
for(j=0; j<i->chanlen; j++)
out[j] = map[in[j]];
}else{
/* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
for(y=0; y<dy; y++){
er = 0;
eg = 0;
eb = 0;
rp = ered;
gp = egrn;
bp = eblu;
for(x=0; x<dx; x++){
cm = &cmap[3 * *inp++];
r = cm[0] +*rp;
g = cm[1] +*gp;
b = cm[2] +*bp;
/* sanity checks are new */
if(r >= 256+CLAMPOFF)
r = 0;
if(g >= 256+CLAMPOFF)
g = 0;
if(b >= 256+CLAMPOFF)
b = 0;
r1 = clamp[r+CLAMPOFF];
g1 = clamp[g+CLAMPOFF];
b1 = clamp[b+CLAMPOFF];
if(r1 >= 16 || g1 >= 16 || b1 >= 16)
col = 0;
else
col = closestrgb[b1+16*(g1+16*r1)];
*outp++ = col;
rgb = rgbmap[col];
r -= (rgb>>16) & 0xFF;
t = (3*r)>>4;
*rp++ = t+er;
*rp += t;
er = r-3*t;
g -= (rgb>>8) & 0xFF;
t = (3*g)>>4;
*gp++ = t+eg;
*gp += t;
eg = g-3*t;
b -= rgb & 0xFF;
t = (3*b)>>4;
*bp++ = t+eb;
*bp += t;
eb = b-3*t;
}
}
}
break;
case CYCbCr:
closest = closestycbcr;
map3 = ycbcrmap;
goto Threecolor;
case CRGB:
closest = closestrgb;
map3 = rgbmap;
Threecolor:
if(i->nchans != 3)
return _remaperror("remap: RGB image has %d channels", i->nchans);
rpic = i->chans[0];
gpic = i->chans[1];
bpic = i->chans[2];
if(errdiff == 0){
for(j=0; j<i->chanlen; j++){
r = rpic[j]>>4;
g = gpic[j]>>4;
b = bpic[j]>>4;
out[j] = closest[b+16*(g+16*r)];
}
}else{
/* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
for(y=0; y<dy; y++){
er = 0;
eg = 0;
eb = 0;
rp = ered;
gp = egrn;
bp = eblu;
for(x=0; x<dx; x++){
r = *rpic++ + *rp;
g = *gpic++ + *gp;
b = *bpic++ + *bp;
/*
* Errors can be uncorrectable if converting from YCbCr,
* since we can't guarantee that an extremal value of one of
* the components selects a color with an extremal value.
* If we don't, the errors accumulate without bound. This
* doesn't happen in RGB because the closest table can guarantee
* a color on the edge of the gamut, producing a zero error in
* that component. For the rotation YCbCr space, there may be
* no color that can guarantee zero error at the edge.
* Therefore we must clamp explicitly rather than by assuming
* an upper error bound of CLAMPOFF. The performance difference
* is miniscule anyway.
*/
if(r < 0)
r = 0;
else if(r > 255)
r = 255;
if(g < 0)
g = 0;
else if(g > 255)
g = 255;
if(b < 0)
b = 0;
else if(b > 255)
b = 255;
r1 = r>>4;
g1 = g>>4;
b1 = b>>4;
col = closest[b1+16*(g1+16*r1)];
*outp++ = col;
rgb = map3[col];
r -= (rgb>>16) & 0xFF;
t = (3*r)>>4;
*rp++ = t+er;
*rp += t;
er = r-3*t;
g -= (rgb>>8) & 0xFF;
t = (3*g)>>4;
*gp++ = t+eg;
*gp += t;
eg = g-3*t;
b -= rgb & 0xFF;
t = (3*b)>>4;
*bp++ = t+eb;
*bp += t;
eb = b-3*t;
}
}
}
break;
case CY:
if(i->nchans != 1)
return _remaperror("remap: Y image has %d chans", i->nchans);
rpic = i->chans[0];
if(errdiff == 0){
for(j=0; j<i->chanlen; j++){
r = rpic[j]>>4;
*outp++ = closestrgb[r+16*(r+16*r)];
}
}else{
/* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
for(y=0; y<dy; y++){
er = 0;
rp = ered;
for(x=0; x<dx; x++){
r = *inp++ + *rp;
r1 = clamp[r+CLAMPOFF];
col = closestrgb[r1+16*(r1+16*r1)];
*outp++ = col;
rgb = rgbmap[col];
r -= (rgb>>16) & 0xFF;
t = (3*r)>>4;
*rp++ = t+er;
*rp += t;
er = r-3*t;
}
}
}
break;
}
free(ered);
free(egrn);
free(eblu);
return im;
}

163
src/cmd/jpg/totruecolor.c Normal file
View File

@ -0,0 +1,163 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include "imagefile.h"
enum {
c1 = 2871, /* 1.402 * 2048 */
c2 = 705, /* 0.34414 * 2048 */
c3 = 1463, /* 0.71414 * 2048 */
c4 = 3629, /* 1.772 * 2048 */
};
Rawimage*
totruecolor(Rawimage *i, int chandesc)
{
int j, k;
Rawimage *im;
char err[ERRMAX];
uchar *rp, *gp, *bp, *cmap, *inp, *outp, cmap1[3*256];
int r, g, b, Y, Cr, Cb;
if(chandesc!=CY && chandesc!=CRGB24)
return _remaperror("remap: can't convert to chandesc %d", chandesc);
err[0] = '\0';
errstr(err, sizeof err); /* throw it away */
im = malloc(sizeof(Rawimage));
if(im == nil)
return nil;
memset(im, 0, sizeof(Rawimage));
if(chandesc == CY)
im->chanlen = i->chanlen;
else
im->chanlen = 3*i->chanlen;
im->chandesc = chandesc;
im->chans[0] = malloc(im->chanlen);
if(im->chans[0] == nil){
free(im);
return nil;
}
im->r = i->r;
im->nchans = 1;
cmap = i->cmap;
outp = im->chans[0];
switch(i->chandesc){
default:
return _remaperror("remap: can't recognize channel type %d", i->chandesc);
case CY:
if(i->nchans != 1)
return _remaperror("remap: Y image has %d chans", i->nchans);
if(chandesc == CY){
memmove(im->chans[0], i->chans[0], i->chanlen);
break;
}
/* convert to three color */
inp = i->chans[0];
for(j=0; j<i->chanlen; j++){
k = *inp++;
*outp++ = k;
*outp++ = k;
*outp++ = k;
}
break;
case CRGB1:
if(cmap == nil)
return _remaperror("remap: image has no color map");
if(i->nchans != 1)
return _remaperror("remap: can't handle nchans %d", i->nchans);
for(j=1; j<=8; j++)
if(i->cmaplen == 3*(1<<j))
break;
if(j > 8)
return _remaperror("remap: can't do colormap size 3*%d", i->cmaplen/3);
if(i->cmaplen != 3*256){
/* to avoid a range check in loop below, make a full-size cmap */
memmove(cmap1, cmap, i->cmaplen);
cmap = cmap1;
}
inp = i->chans[0];
if(chandesc == CY){
for(j=0; j<i->chanlen; j++){
k = *inp++;
r = cmap[3*k+2];
g = cmap[3*k+1];
b = cmap[3*k+0];
r = (2125*r + 7154*g + 721*b)/10000; /* Poynton page 84 */
*outp++ = r;
}
}else{
for(j=0; j<i->chanlen; j++){
k = *inp++;
*outp++ = cmap[3*k+2];
*outp++ = cmap[3*k+1];
*outp++ = cmap[3*k+0];
}
}
break;
case CRGB:
if(i->nchans != 3)
return _remaperror("remap: can't handle nchans %d", i->nchans);
rp = i->chans[0];
gp = i->chans[1];
bp = i->chans[2];
if(chandesc == CY){
for(j=0; j<i->chanlen; j++){
r = *bp++;
g = *gp++;
b = *rp++;
r = (2125*r + 7154*g + 721*b)/10000; /* Poynton page 84 */
*outp++ = r;
}
}else
for(j=0; j<i->chanlen; j++){
*outp++ = *bp++;
*outp++ = *gp++;
*outp++ = *rp++;
}
break;
case CYCbCr:
if(i->nchans != 3)
return _remaperror("remap: can't handle nchans %d", i->nchans);
rp = i->chans[0];
gp = i->chans[1];
bp = i->chans[2];
for(j=0; j<i->chanlen; j++){
Y = *rp++ << 11;
Cb = *gp++ - 128;
Cr = *bp++ - 128;
r = (Y+c1*Cr) >> 11;
g = (Y-c2*Cb-c3*Cr) >> 11;
b = (Y+c4*Cb) >> 11;
if(r < 0)
r = 0;
if(r > 255)
r = 255;
if(g < 0)
g = 0;
if(g > 255)
g = 255;
if(b < 0)
b = 0;
if(b > 255)
b = 255;
if(chandesc == CY){
r = (2125*r + 7154*g + 721*b)/10000;
*outp++ = r;
}else{
*outp++ = b;
*outp++ = g;
*outp++ = r;
}
}
break;
}
return im;
}

568
src/cmd/jpg/writegif.c Normal file
View File

@ -0,0 +1,568 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <bio.h>
#include "imagefile.h"
enum
{
Nhash = 4001,
Nbuf = 300,
};
typedef struct Entry Entry;
typedef struct IO IO;
struct Entry
{
int index;
int prefix;
int exten;
Entry *next;
};
struct IO
{
Biobuf *fd;
uchar buf[Nbuf];
int i;
int nbits; /* bits in right side of shift register */
int sreg; /* shift register */
};
static Rectangle mainrect;
static Entry tbl[4096];
static uchar *colormap[5]; /* one for each ldepth: GREY1 GREY2 GREY4 CMAP8=rgbv plus GREY8 */
#define GREYMAP 4
static int colormapsize[] = { 2, 4, 16, 256, 256 }; /* 2 for zero is an odd property of GIF */
static void writeheader(Biobuf*, Rectangle, int, ulong, int);
static void writedescriptor(Biobuf*, Rectangle);
static char* writedata(Biobuf*, Image*, Memimage*);
static void writecomment(Biobuf *fd, char*);
static void writegraphiccontrol(Biobuf *fd, int, int);
static void* gifmalloc(ulong);
static void encode(Biobuf*, Rectangle, int, uchar*, uint);
static
char*
startgif0(Biobuf *fd, ulong chan, Rectangle r, int depth, int loopcount)
{
int i;
for(i=0; i<nelem(tbl); i++)
tbl[i] = (Entry){i, -1, i, nil};
switch(chan){
case GREY1:
case GREY2:
case GREY4:
case CMAP8:
case GREY8:
break;
default:
return "WriteGIF: can't handle channel type";
}
mainrect = r;
writeheader(fd, r, depth, chan, loopcount);
return nil;
}
char*
startgif(Biobuf *fd, Image *image, int loopcount)
{
return startgif0(fd, image->chan, image->r, image->depth, loopcount);
}
char*
memstartgif(Biobuf *fd, Memimage *memimage, int loopcount)
{
return startgif0(fd, memimage->chan, memimage->r, memimage->depth, loopcount);
}
static
char*
writegif0(Biobuf *fd, Image *image, Memimage *memimage, ulong chan, Rectangle r, char *comment, int dt, int trans)
{
char *err;
switch(chan){
case GREY1:
case GREY2:
case GREY4:
case CMAP8:
case GREY8:
break;
default:
return "WriteGIF: can't handle channel type";
}
writecomment(fd, comment);
writegraphiccontrol(fd, dt, trans);
writedescriptor(fd, r);
err = writedata(fd, image, memimage);
if(err != nil)
return err;
return nil;
}
char*
writegif(Biobuf *fd, Image *image, char *comment, int dt, int trans)
{
return writegif0(fd, image, nil, image->chan, image->r, comment, dt, trans);
}
char*
memwritegif(Biobuf *fd, Memimage *memimage, char *comment, int dt, int trans)
{
return writegif0(fd, nil, memimage, memimage->chan, memimage->r, comment, dt, trans);
}
/*
* Write little-endian 16-bit integer
*/
static
void
put2(Biobuf *fd, int i)
{
Bputc(fd, i);
Bputc(fd, i>>8);
}
/*
* Get color map for all ldepths, in format suitable for writing out
*/
static
void
getcolormap(void)
{
int i, col;
ulong rgb;
uchar *c;
if(colormap[0] != nil)
return;
for(i=0; i<nelem(colormap); i++)
colormap[i] = gifmalloc(3* colormapsize[i]);
c = colormap[GREYMAP]; /* GREY8 */
for(i=0; i<256; i++){
c[3*i+0] = i; /* red */
c[3*i+1] = i; /* green */
c[3*i+2] = i; /* blue */
}
c = colormap[3]; /* RGBV */
for(i=0; i<256; i++){
rgb = cmap2rgb(i);
c[3*i+0] = (rgb>>16) & 0xFF; /* red */
c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
}
c = colormap[2]; /* GREY4 */
for(i=0; i<16; i++){
col = (i<<4)|i;
rgb = cmap2rgb(col);
c[3*i+0] = (rgb>>16) & 0xFF; /* red */
c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
}
c = colormap[1]; /* GREY2 */
for(i=0; i<4; i++){
col = (i<<6)|(i<<4)|(i<<2)|i;
rgb = cmap2rgb(col);
c[3*i+0] = (rgb>>16) & 0xFF; /* red */
c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
}
c = colormap[0]; /* GREY1 */
for(i=0; i<2; i++){
if(i == 0)
col = 0;
else
col = 0xFF;
rgb = cmap2rgb(col);
c[3*i+0] = (rgb>>16) & 0xFF; /* red */
c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
}
}
/*
* Write header, logical screen descriptor, and color map
*/
static
void
writeheader(Biobuf *fd, Rectangle r, int depth, ulong chan, int loopcount)
{
/* Header */
Bprint(fd, "%s", "GIF89a");
/* Logical Screen Descriptor */
put2(fd, Dx(r));
put2(fd, Dy(r));
/* Color table present, 4 bits per color (for RGBV best case), size of color map */
Bputc(fd, (1<<7)|(3<<4)|(depth-1)); /* not right for GREY8, but GIF doesn't let us specify enough bits */
Bputc(fd, 0xFF); /* white background (doesn't matter anyway) */
Bputc(fd, 0); /* pixel aspect ratio - unused */
/* Global Color Table */
getcolormap();
if(chan == GREY8)
depth = GREYMAP;
else
depth = drawlog2[depth];
Bwrite(fd, colormap[depth], 3*colormapsize[depth]);
if(loopcount >= 0){ /* hard-to-discover way to force cycled animation */
/* Application Extension with (1 loopcountlo loopcounthi) as data */
Bputc(fd, 0x21);
Bputc(fd, 0xFF);
Bputc(fd, 11);
Bwrite(fd, "NETSCAPE2.0", 11);
Bputc(fd, 3);
Bputc(fd, 1);
put2(fd, loopcount);
Bputc(fd, 0);
}
}
/*
* Write optional comment block
*/
static
void
writecomment(Biobuf *fd, char *comment)
{
int n;
if(comment==nil || comment[0]=='\0')
return;
/* Comment extension and label */
Bputc(fd, 0x21);
Bputc(fd, 0xFE);
/* Comment data */
n = strlen(comment);
if(n > 255)
n = 255;
Bputc(fd, n);
Bwrite(fd, comment, n);
/* Block terminator */
Bputc(fd, 0x00);
}
/*
* Write optional control block (sets Delay Time)
*/
static
void
writegraphiccontrol(Biobuf *fd, int dt, int trans)
{
if(dt < 0 && trans < 0)
return;
/* Comment extension and label and block size*/
Bputc(fd, 0x21);
Bputc(fd, 0xF9);
Bputc(fd, 0x04);
/* Disposal method and other flags (none) */
if(trans >= 0)
Bputc(fd, 0x01);
else
Bputc(fd, 0x00);
/* Delay time, in centisec (argument is millisec for sanity) */
if(dt < 0)
dt = 0;
else if(dt < 10)
dt = 1;
else
dt = (dt+5)/10;
put2(fd, dt);
/* Transparency index */
if(trans < 0)
trans = 0;
Bputc(fd, trans);
/* Block terminator */
Bputc(fd, 0x00);
}
/*
* Write image descriptor
*/
static
void
writedescriptor(Biobuf *fd, Rectangle r)
{
/* Image Separator */
Bputc(fd, 0x2C);
/* Left, top, width, height */
put2(fd, r.min.x-mainrect.min.x);
put2(fd, r.min.y-mainrect.min.y);
put2(fd, Dx(r));
put2(fd, Dy(r));
/* no special processing */
Bputc(fd, 0);
}
/*
* Write data
*/
static
char*
writedata(Biobuf *fd, Image *image, Memimage *memimage)
{
char *err;
uchar *data;
int ndata, depth;
Rectangle r;
if(memimage != nil){
r = memimage->r;
depth = memimage->depth;
}else{
r = image->r;
depth = image->depth;
}
/* LZW Minimum code size */
if(depth == 1)
Bputc(fd, 2);
else
Bputc(fd, depth);
/*
* Read image data into memory
* potentially one extra byte on each end of each scan line
*/
ndata = Dy(r)*(2+(Dx(r)>>(3-drawlog2[depth])));
data = gifmalloc(ndata);
if(memimage != nil)
ndata = unloadmemimage(memimage, r, data, ndata);
else
ndata = unloadimage(image, r, data, ndata);
if(ndata < 0){
err = gifmalloc(ERRMAX);
snprint(err, ERRMAX, "WriteGIF: %r");
free(data);
return err;
}
/* Encode and emit the data */
encode(fd, r, depth, data, ndata);
free(data);
/* Block Terminator */
Bputc(fd, 0);
return nil;
}
/*
* Write trailer
*/
void
endgif(Biobuf *fd)
{
Bputc(fd, 0x3B);
Bflush(fd);
}
void
memendgif(Biobuf *fd)
{
endgif(fd);
}
/*
* Put n bits of c into output at io.buf[i];
*/
static
void
output(IO *io, int c, int n)
{
if(c < 0){
if(io->nbits != 0)
io->buf[io->i++] = io->sreg;
Bputc(io->fd, io->i);
Bwrite(io->fd, io->buf, io->i);
io->nbits = 0;
return;
}
if(io->nbits+n >= 31){
fprint(2, "panic: WriteGIF sr overflow\n");
exits("WriteGIF panic");
}
io->sreg |= c<<io->nbits;
io->nbits += n;
while(io->nbits >= 8){
io->buf[io->i++] = io->sreg;
io->sreg >>= 8;
io->nbits -= 8;
}
if(io->i >= 255){
Bputc(io->fd, 255);
Bwrite(io->fd, io->buf, 255);
memmove(io->buf, io->buf+255, io->i-255);
io->i -= 255;
}
}
/*
* LZW encoder
*/
static
void
encode(Biobuf *fd, Rectangle r, int depth, uchar *data, uint ndata)
{
int i, c, h, csize, prefix, first, sreg, nbits, bitsperpixel;
int CTM, EOD, codesize, ld0, datai, x, ld, pm;
int nentry, maxentry, early;
Entry *e, *oe;
IO *io;
Entry **hash;
first = 1;
ld = drawlog2[depth];
/* ldepth 0 must generate codesize 2 with values 0 and 1 (see the spec.) */
ld0 = ld;
if(ld0 == 0)
ld0 = 1;
codesize = (1<<ld0);
CTM = 1<<codesize;
EOD = CTM+1;
io = gifmalloc(sizeof(IO));
io->fd = fd;
sreg = 0;
nbits = 0;
bitsperpixel = 1<<ld;
pm = (1<<bitsperpixel)-1;
datai = 0;
x = r.min.x;
hash = gifmalloc(Nhash*sizeof(Entry*));
Init:
memset(hash, 0, Nhash*sizeof(Entry*));
csize = codesize+1;
nentry = EOD+1;
maxentry = (1<<csize);
for(i = 0; i<nentry; i++){
e = &tbl[i];
h = (e->prefix<<24) | (e->exten<<8);
h %= Nhash;
if(h < 0)
h += Nhash;
e->next = hash[h];
hash[h] = e;
}
prefix = -1;
if(first)
output(io, CTM, csize);
first = 0;
/*
* Scan over pixels. Because of partially filled bytes on ends of scan lines,
* which must be ignored in the data stream passed to GIF, this is more
* complex than we'd like.
*/
Next:
for(;;){
if(ld != 3){
/* beginning of scan line is difficult; prime the shift register */
if(x == r.min.x){
if(datai == ndata)
break;
sreg = data[datai++];
nbits = 8-((x&(7>>ld))<<ld);
}
x++;
if(x == r.max.x)
x = r.min.x;
}
if(nbits == 0){
if(datai == ndata)
break;
sreg = data[datai++];
nbits = 8;
}
nbits -= bitsperpixel;
c = sreg>>nbits & pm;
h = prefix<<24 | c<<8;
h %= Nhash;
if(h < 0)
h += Nhash;
oe = nil;
for(e = hash[h]; e!=nil; e=e->next){
if(e->prefix == prefix && e->exten == c){
if(oe != nil){
oe->next = e->next;
e->next = hash[h];
hash[h] = e;
}
prefix = e->index;
goto Next;
}
oe = e;
}
output(io, prefix, csize);
early = 0; /* peculiar tiff feature here for reference */
if(nentry == maxentry-early){
if(csize == 12){
nbits += bitsperpixel; /* unget pixel */
x--;
if(ld != 3 && x == r.min.x)
datai--;
output(io, CTM, csize);
goto Init;
}
csize++;
maxentry = (1<<csize);
}
e = &tbl[nentry];
e->prefix = prefix;
e->exten = c;
e->next = hash[h];
hash[h] = e;
prefix = c;
nentry++;
}
output(io, prefix, csize);
output(io, EOD, csize);
output(io, -1, csize);
free(io);
free(hash);
}
static
void*
gifmalloc(ulong sz)
{
void *v;
v = malloc(sz);
if(v == nil) {
fprint(2, "WriteGIF: out of memory allocating %ld\n", sz);
abort();
exits("mem");
}
memset(v, 0, sz);
return v;
}

220
src/cmd/jpg/writepng.c Normal file
View File

@ -0,0 +1,220 @@
// based on PNG 1.2 specification, July 1999 (see also rfc2083)
// Alpha is not supported yet because of lack of industry acceptance and
// because Plan9 Image uses premultiplied alpha, so png can't be lossless.
// Only 24bit color supported, because 8bit may as well use GIF.
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <ctype.h>
#include <bio.h>
#include <flate.h>
#include "imagefile.h"
enum{ IDATSIZE = 20000,
FilterNone = 0,
};
typedef struct ZlibR{
uchar *data;
int width;
int nrow, ncol;
int row, col; // next pixel to send
} ZlibR;
typedef struct ZlibW{
Biobuf *bo;
uchar *buf;
uchar *b; // next place to write
uchar *e; // past end of buf
} ZlibW;
static ulong *crctab;
static uchar PNGmagic[] = {137,80,78,71,13,10,26,10};
static void
put4(uchar *a, ulong v)
{
a[0] = v>>24;
a[1] = v>>16;
a[2] = v>>8;
a[3] = v;
}
static void
chunk(Biobuf *bo, char *type, uchar *d, int n)
{
uchar buf[4];
ulong crc = 0;
if(strlen(type) != 4)
return;
put4(buf, n);
Bwrite(bo, buf, 4);
Bwrite(bo, type, 4);
Bwrite(bo, d, n);
crc = blockcrc(crctab, crc, type, 4);
crc = blockcrc(crctab, crc, d, n);
put4(buf, crc);
Bwrite(bo, buf, 4);
}
static int
zread(void *va, void *buf, int n)
{
ZlibR *z = va;
int nrow = z->nrow;
int ncol = z->ncol;
uchar *b = buf, *e = b+n, *img;
int i, pixels; // number of pixels in row that can be sent now
while(b+3 <= e){ // loop over image rows
if(z->row >= nrow)
break;
if(z->col==0)
*b++ = FilterNone;
pixels = (e-b)/3;
if(pixels > ncol - z->col)
pixels = ncol - z->col;
img = z->data + z->width * z->row + 3 * z->col;
// Plan 9 image format is BGR?!!!
// memmove(b, img, 3*pixels);
// b += 3*pixels;
for(i=0; i<pixels; i++, img += 3){
*b++ = img[2];
*b++ = img[1];
*b++ = img[0];
}
z->col += pixels;
if(z->col >= ncol){
z->col = 0;
z->row++;
}
}
return b - (uchar*)buf;
}
static void
IDAT(ZlibW *z)
{
chunk(z->bo, "IDAT", z->buf, z->b - z->buf);
z->b = z->buf;
}
static int
zwrite(void *va, void *buf, int n)
{
ZlibW *z = va;
uchar *b = buf, *e = b+n;
int m;
while(b < e){ // loop over IDAT chunks
m = z->e - z->b;
if(m > e - b)
m = e - b;
memmove(z->b, b, m);
z->b += m;
b += m;
if(z->b >= z->e)
IDAT(z);
}
return n;
}
static Memimage*
memRGB(Memimage *i)
{
Memimage *ni;
if(i->chan == RGB24)
return i;
ni = allocmemimage(i->r, RGB24);
if(ni == nil)
return ni;
memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
return ni;
}
char*
memwritepng(Biobuf *bo, Memimage *r, ImageInfo *II)
{
uchar buf[200], *h;
ulong vgamma;
int err, n;
ZlibR zr;
ZlibW zw;
int nrow = r->r.max.y - r->r.min.y;
int ncol = r->r.max.x - r->r.min.x;
Tm *tm;
Memimage *rgb;
rgb = memRGB(r);
if(rgb == nil)
return "allocmemimage nil";
crctab = mkcrctab(0xedb88320);
if(crctab == nil)
sysfatal("mkcrctab error");
deflateinit();
Bwrite(bo, PNGmagic, sizeof PNGmagic);
// IHDR chunk
h = buf;
put4(h, ncol); h += 4;
put4(h, nrow); h += 4;
*h++ = 8; // bit depth = 24 bit per pixel
*h++ = 2; // color type = rgb
*h++ = 0; // compression method = deflate
*h++ = 0; // filter method
*h++ = 0; // interlace method = no interlace
chunk(bo, "IHDR", buf, h-buf);
tm = gmtime(time(0));
h = buf;
*h++ = (tm->year + 1900)>>8;
*h++ = (tm->year + 1900)&0xff;
*h++ = tm->mon + 1;
*h++ = tm->mday;
*h++ = tm->hour;
*h++ = tm->min;
*h++ = tm->sec;
chunk(bo, "tIME", buf, h-buf);
if(II->fields_set & II_GAMMA){
vgamma = II->gamma*100000;
put4(buf, vgamma);
chunk(bo, "gAMA", buf, 4);
}
if(II->fields_set & II_COMMENT){
strncpy((char*)buf, "Comment", sizeof buf);
n = strlen((char*)buf)+1; // leave null between Comment and text
strncpy((char*)(buf+n), II->comment, sizeof buf - n);
chunk(bo, "tEXt", buf, n+strlen((char*)buf+n));
}
// image chunks
zr.nrow = nrow;
zr.ncol = ncol;
zr.width = rgb->width * sizeof(ulong);
zr.data = rgb->data->bdata;
zr.row = zr.col = 0;
zw.bo = bo;
zw.buf = malloc(IDATSIZE);
zw.b = zw.buf;
zw.e = zw.b + IDATSIZE;
err = deflatezlib(&zw, zwrite, &zr, zread, 6, 0);
if(zw.b > zw.buf)
IDAT(&zw);
free(zw.buf);
if(err)
sysfatal("deflatezlib %s\n", flateerr(err));
chunk(bo, "IEND", nil, 0);
if(r != rgb)
freememimage(rgb);
return nil;
}

164
src/cmd/jpg/writeppm.c Normal file
View File

@ -0,0 +1,164 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <bio.h>
#include "imagefile.h"
#define MAXLINE 70
/*
* 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>>drawlog2[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);
}

206
src/cmd/jpg/writerawimage.c Normal file
View File

@ -0,0 +1,206 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include "imagefile.h"
/*
* Hacked version for writing from Rawimage to file.
* Assumes 8 bits per component.
*/
#define HSHIFT 3 /* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */
#define NHASH (1<<(HSHIFT*NMATCH))
#define HMASK (NHASH-1)
#define hupdate(h, c) ((((h)<<HSHIFT)^(c))&HMASK)
typedef struct Hlist Hlist;
struct Hlist{
uchar *s;
Hlist *next, *prev;
};
int
writerawimage(int fd, Rawimage *i)
{
uchar *outbuf, *outp, *eout; /* encoded data, pointer, end */
uchar *loutp; /* start of encoded line */
Hlist *hash; /* heads of hash chains of past strings */
Hlist *chain, *hp; /* hash chain members, pointer */
Hlist *cp; /* next Hlist to fall out of window */
int h; /* hash value */
uchar *line, *eline; /* input line, end pointer */
uchar *data, *edata; /* input buffer, end pointer */
ulong n; /* length of input buffer */
int bpl; /* input line length */
int offs, runlen; /* offset, length of consumed data */
uchar dumpbuf[NDUMP]; /* dump accumulator */
int ndump; /* length of dump accumulator */
int ncblock; /* size of buffer */
Rectangle r;
uchar *p, *q, *s, *es, *t;
char hdr[11+5*12+1], buf[16];
ulong desc;
r = i->r;
switch(i->chandesc){
default:
werrstr("can't handle chandesc %d", i->chandesc);
return -1;
case CY:
bpl = Dx(r);
desc = GREY8;
break;
case CYA16:
bpl = 2*Dx(r);
desc = CHAN2(CGrey, 8, CAlpha, 8);
break;
case CRGBV:
bpl = Dx(r);
desc = CMAP8;
break;
case CRGBVA16:
bpl = 2*Dx(r);
desc = CHAN2(CMap, 8, CAlpha, 8);
break;
case CRGB24:
bpl = 3*Dx(r);
desc = RGB24;
break;
case CRGBA32:
bpl = 4*Dx(r);
desc = RGBA32;
break;
}
ncblock = _compblocksize(r, bpl/Dx(r));
outbuf = malloc(ncblock);
hash = malloc(NHASH*sizeof(Hlist));
chain = malloc(NMEM*sizeof(Hlist));
if(outbuf == 0 || hash == 0 || chain == 0){
ErrOut:
free(outbuf);
free(hash);
free(chain);
return -1;
}
n = Dy(r)*bpl;
data = i->chans[0];
sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ",
chantostr(buf, desc), r.min.x, r.min.y, r.max.x, r.max.y);
if(write(fd, hdr, 11+5*12) != 11+5*12){
werrstr("i/o error writing header");
goto ErrOut;
}
edata = data+n;
eout = outbuf+ncblock;
line = data;
r.max.y = r.min.y;
while(line != edata){
memset(hash, 0, NHASH*sizeof(Hlist));
memset(chain, 0, NMEM*sizeof(Hlist));
cp = chain;
h = 0;
outp = outbuf;
for(n = 0; n != NMATCH; n++)
h = hupdate(h, line[n]);
loutp = outbuf;
while(line != edata){
ndump = 0;
eline = line+bpl;
for(p = line; p != eline; ){
if(eline-p < NRUN)
es = eline;
else
es = p+NRUN;
q = 0;
runlen = 0;
for(hp = hash[h].next; hp; hp = hp->next){
s = p + runlen;
if(s >= es)
continue;
t = hp->s + runlen;
for(; s >= p; s--)
if(*s != *t--)
goto matchloop;
t += runlen+2;
s += runlen+2;
for(; s < es; s++)
if(*s != *t++)
break;
n = s-p;
if(n > runlen){
runlen = n;
q = hp->s;
if(n == NRUN)
break;
}
matchloop: ;
}
if(runlen < NMATCH){
if(ndump == NDUMP){
if(eout-outp < ndump+1)
goto Bfull;
*outp++ = ndump-1+128;
memmove(outp, dumpbuf, ndump);
outp += ndump;
ndump = 0;
}
dumpbuf[ndump++] = *p;
runlen = 1;
}
else{
if(ndump != 0){
if(eout-outp < ndump+1)
goto Bfull;
*outp++ = ndump-1+128;
memmove(outp, dumpbuf, ndump);
outp += ndump;
ndump = 0;
}
offs = p-q-1;
if(eout-outp < 2)
goto Bfull;
*outp++ = ((runlen-NMATCH)<<2) + (offs>>8);
*outp++ = offs&255;
}
for(q = p+runlen; p != q; p++){
if(cp->prev)
cp->prev->next = 0;
cp->next = hash[h].next;
cp->prev = &hash[h];
if(cp->next)
cp->next->prev = cp;
cp->prev->next = cp;
cp->s = p;
if(++cp == &chain[NMEM])
cp = chain;
if(edata-p > NMATCH)
h = hupdate(h, p[NMATCH]);
}
}
if(ndump != 0){
if(eout-outp < ndump+1)
goto Bfull;
*outp++ = ndump-1+128;
memmove(outp, dumpbuf, ndump);
outp += ndump;
}
line = eline;
loutp = outp;
r.max.y++;
}
Bfull:
if(loutp == outbuf){
werrstr("compressor out of sync");
goto ErrOut;
}
n = loutp-outbuf;
sprint(hdr, "%11d %11ld ", r.max.y, n);
write(fd, hdr, 2*12);
write(fd, outbuf, n);
r.min.y = r.max.y;
}
free(outbuf);
free(hash);
free(chain);
return 0;
}

211
src/cmd/jpg/yuv.c Normal file
View File

@ -0,0 +1,211 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <event.h>
#include "imagefile.h"
int cflag = 0;
int dflag = 0;
int eflag = 0;
int nineflag = 0;
int threeflag = 0;
int output = 0;
ulong outchan = CMAP8;
int defaultcolor = 1;
Image *image;
enum{
Border = 2,
Edge = 5
};
char *show(int, char*);
Rawimage** readyuv(int fd, int colorspace);
void
eresized(int new)
{
Rectangle r;
if(new && getwindow(display, Refnone) < 0){
fprint(2, "yuv: can't reattach to window\n");
exits("resize");
}
if(image == nil)
return;
r = insetrect(screen->clipr, Edge+Border);
r.max.x = r.min.x+Dx(image->r);
r.max.y = r.min.y+Dy(image->r);
border(screen, r, -Border, nil, ZP);
draw(screen, r, image, nil, image->r.min);
flushimage(display, 1);
}
void
main(int argc, char *argv[])
{
int fd, i;
char *err;
ARGBEGIN{
case '3': /* produce encoded, compressed, three-color bitmap file; no display by default */
threeflag++;
/* fall through */
case 't': /* produce encoded, compressed, true-color bitmap file; no display by default */
cflag++;
dflag++;
output++;
defaultcolor = 0;
outchan = RGB24;
break;
case 'c': /* produce encoded, compressed, bitmap file; no display by default */
cflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
case 'd': /* suppress display of image */
dflag++;
break;
case 'e': /* disable floyd-steinberg error diffusion */
eflag++;
break;
case 'k': /* force black and white */
defaultcolor = 0;
outchan = GREY8;
break;
case 'v': /* force RGBV */
defaultcolor = 0;
outchan = CMAP8;
break;
case '9': /* produce plan 9, uncompressed, bitmap file; no display by default */
nineflag++;
dflag++;
output++;
if(defaultcolor)
outchan = CMAP8;
break;
default:
fprint(2, "usage: yuv -39cdektv [file.yuv ...]\n");
exits("usage");
}ARGEND;
err = nil;
if(argc == 0)
err = show(0, "<stdin>");
else{
for(i=0; i<argc; i++){
fd = open(argv[i], OREAD);
if(fd < 0){
fprint(2, "yuv: can't open %s: %r\n", argv[i]);
err = "open";
}else{
err = show(fd, argv[i]);
close(fd);
}
if((nineflag || cflag) && argc>1 && err==nil){
fprint(2, "yuv: exiting after one file\n");
break;
}
}
}
exits(err);
}
int
init(void)
{
static int inited;
if(inited == 0){
if(initdraw(0, 0, 0) < 0){
fprint(2, "yuv: initdraw failed: %r");
return -1;
}
einit(Ekeyboard|Emouse);
inited++;
}
return 1;
}
char*
show(int fd, char *name)
{
Rawimage **array, *r, *c;
Image *i;
int j, ch;
char buf[32];
array = readyuv(fd, CYCbCr);
if(array == nil || array[0]==nil){
fprint(2, "yuv: decode %s failed: %r\n", name);
return "decode";
}
if(!dflag){
if(init() < 0)
return "initdraw";
if(defaultcolor && screen->depth>8)
outchan = RGB24;
}
r = array[0];
if(outchan == CMAP8)
c = torgbv(r, !eflag);
else{
if(outchan==GREY8 || (r->chandesc==CY && threeflag==0))
c = totruecolor(r, CY);
else
c = totruecolor(r, CRGB24);
}
if(c == nil){
fprint(2, "yuv: converting %s to local format failed: %r\n", name);
return "torgbv";
}
if(!dflag){
if(r->chandesc == CY)
i = allocimage(display, c->r, GREY8, 0, 0);
else
i = allocimage(display, c->r, outchan, 0, 0);
if(i == nil){
fprint(2, "yuv: allocimage %s failed: %r\n", name);
return "allocimage";
}
if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
fprint(2, "yuv: loadimage %s failed: %r\n", name);
return "loadimage";
}
image = i;
eresized(0);
if((ch=ekbd())=='q' || ch==0x7F || ch==0x04)
exits(nil);
draw(screen, screen->clipr, display->white, nil, ZP);
image = nil;
freeimage(i);
}
if(nineflag){
chantostr(buf, outchan);
print("%11s %11d %11d %11d %11d ", buf,
c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y);
if(write(1, c->chans[0], c->chanlen) != c->chanlen){
fprint(2, "yuv: %s: write error %r\n", name);
return "write";
}
}else if(cflag){
if(writerawimage(1, c) < 0){
fprint(2, "yuv: %s: write error: %r\n", name);
return "write";
}
}
for(j=0; j<r->nchans; j++)
free(r->chans[j]);
free(r->cmap);
free(r);
free(array);
if(c){
free(c->chans[0]);
free(c);
}
return nil;
}

88
src/cmd/map/index.c Normal file
View File

@ -0,0 +1,88 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static proj Yaitoff(double p0, double p1){USED(p0); USED(p1); return aitoff();}
static proj Yalbers(double p0,double p1){USED(p0); USED(p1); return albers(p0,p1);}
static proj Yazequalarea(double p0, double p1){USED(p0); USED(p1); return azequalarea();}
static proj Yazequidistant(double p0, double p1){USED(p0); USED(p1); return azequidistant();}
static proj Ybicentric(double p0,double p1){USED(p0); USED(p1); return bicentric(p0);}
static proj Ybonne(double p0,double p1){USED(p0); USED(p1); return bonne(p0);}
static proj Yconic(double p0,double p1){USED(p0); USED(p1); return conic(p0);}
static proj Ycylequalarea(double p0,double p1){USED(p0); USED(p1); return cylequalarea(p0);}
static proj Ycylindrical(double p0, double p1){USED(p0); USED(p1); return cylindrical();}
static proj Yelliptic(double p0,double p1){USED(p0); USED(p1); return elliptic(p0);}
static proj Yfisheye(double p0,double p1){USED(p0); USED(p1); return fisheye(p0);}
static proj Ygall(double p0,double p1){USED(p0); USED(p1); return gall(p0);}
static proj Ygilbert(double p0, double p1){USED(p0); USED(p1); return gilbert();}
static proj Yglobular(double p0, double p1){USED(p0); USED(p1); return globular();}
static proj Ygnomonic(double p0, double p1){USED(p0); USED(p1); return gnomonic();}
static proj Yguyou(double p0, double p1){USED(p0); USED(p1); return guyou();}
static proj Yharrison(double p0,double p1){USED(p0); USED(p1); return harrison(p0,p1);}
static proj Yhex(double p0, double p1){USED(p0); USED(p1); return hex();}
static proj Yhoming(double p0,double p1){USED(p0); USED(p1); return homing(p0);}
static proj Ylagrange(double p0, double p1){USED(p0); USED(p1); return lagrange();}
static proj Ylambert(double p0,double p1){USED(p0); USED(p1); return lambert(p0,p1);}
static proj Ylaue(double p0, double p1){USED(p0); USED(p1); return laue();}
static proj Ylune(double p0,double p1){USED(p0); USED(p1); return lune(p0,p1);}
static proj Ymecca(double p0, double p1){USED(p0); USED(p1); return mecca(p0);}
static proj Ymercator(double p0, double p1){USED(p0); USED(p1); return mercator();}
static proj Ymollweide(double p0, double p1){USED(p0); USED(p1); return mollweide();}
static proj Ynewyorker(double p0,double p1){USED(p0); USED(p1); return newyorker(p0);}
static proj Yorthographic(double p0, double p1){USED(p0); USED(p1); return orthographic();}
static proj Yperspective(double p0,double p1){USED(p0); USED(p1); return perspective(p0);}
static proj Ypolyconic(double p0, double p1){USED(p0); USED(p1); return polyconic();}
static proj Yrectangular(double p0,double p1){USED(p0); USED(p1); return rectangular(p0);}
static proj Ysimpleconic(double p0,double p1){USED(p0); USED(p1); return simpleconic(p0,p1);}
static proj Ysinusoidal(double p0, double p1){USED(p0); USED(p1); return sinusoidal();}
static proj Ysp_albers(double p0,double p1){USED(p0); USED(p1); return sp_albers(p0,p1);}
static proj Ysp_mercator(double p0, double p1){USED(p0); USED(p1); return sp_mercator();}
static proj Ysquare(double p0, double p1){USED(p0); USED(p1); return square();}
static proj Ystereographic(double p0, double p1){USED(p0); USED(p1); return stereographic();}
static proj Ytetra(double p0, double p1){USED(p0); USED(p1); return tetra();}
static proj Ytrapezoidal(double p0,double p1){USED(p0); USED(p1); return trapezoidal(p0,p1);}
static proj Yvandergrinten(double p0, double p1){USED(p0); USED(p1); return vandergrinten();}
struct index index[] = {
{"aitoff", Yaitoff, 0, picut, 0, 0, 0},
{"albers", Yalbers, 2, picut, 3, 0, 0},
{"azequalarea", Yazequalarea, 0, nocut, 1, 0, 0},
{"azequidistant", Yazequidistant, 0, nocut, 1, 0, 0},
{"bicentric", Ybicentric, 1, nocut, 0, 0, 0},
{"bonne", Ybonne, 1, picut, 0, 0, 0},
{"conic", Yconic, 1, picut, 0, 0, 0},
{"cylequalarea", Ycylequalarea, 1, picut, 3, 0, 0},
{"cylindrical", Ycylindrical, 0, picut, 0, 0, 0},
{"elliptic", Yelliptic, 1, picut, 0, 0, 0},
{"fisheye", Yfisheye, 1, nocut, 0, 0, 0},
{"gall", Ygall, 1, picut, 3, 0, 0},
{"gilbert", Ygilbert, 0, picut, 0, 0, 0},
{"globular", Yglobular, 0, picut, 0, 0, 0},
{"gnomonic", Ygnomonic, 0, nocut, 0, 0, plimb},
{"guyou", Yguyou, 0, guycut, 0, 0, 0},
{"harrison", Yharrison, 2, nocut, 0, 0, plimb},
{"hex", Yhex, 0, hexcut, 0, 0, 0},
{"homing", Yhoming, 1, nocut, 3, 0, hlimb},
{"lagrange", Ylagrange,0,picut,0, 0, 0},
{"lambert", Ylambert, 2, picut, 0, 0, 0},
{"laue", Ylaue, 0, nocut, 0, 0, 0},
{"lune", Ylune, 2, nocut, 0, 0, 0},
{"mecca", Ymecca, 1, picut, 3, 0, mlimb},
{"mercator", Ymercator, 0, picut, 3, 0, 0},
{"mollweide", Ymollweide, 0, picut, 0, 0, 0},
{"newyorker", Ynewyorker, 1, nocut, 0, 0, 0},
{"orthographic", Yorthographic, 0, nocut, 0, 0, olimb},
{"perspective", Yperspective, 1, nocut, 0, 0, plimb},
{"polyconic", Ypolyconic, 0, picut, 0, 0, 0},
{"rectangular", Yrectangular, 1, picut, 3, 0, 0},
{"simpleconic", Ysimpleconic, 2, picut, 3, 0, 0},
{"sinusoidal", Ysinusoidal, 0, picut, 0, 0, 0},
{"sp_albers", Ysp_albers, 2, picut, 3, 1, 0},
{"sp_mercator", Ysp_mercator, 0, picut, 0, 1, 0},
{"square", Ysquare, 0, picut, 0, 0, 0},
{"stereographic", Ystereographic, 0, nocut, 0, 0, 0},
{"tetra", Ytetra, 0, tetracut, 0, 0, 0},
{"trapezoidal", Ytrapezoidal, 2, picut, 3, 0, 0},
{"vandergrinten", Yvandergrinten, 0, picut, 0, 0, 0},
0
};

51
src/cmd/map/iplot.h Normal file
View File

@ -0,0 +1,51 @@
/* Plotting functions for v8 and v9 systems */
/* This file is an alternative to plot.h */
/* open the plotting output */
#define openpl() print("o\n")
/* close the plotting output */
#define closepl() print("cl\n")
/* make sure the page or screen is clear */
#define erase() print("e\n")
/* plot a point at _x,_y, which becomes current */
#define point(_x,_y) print("poi %d %d\n", _x,_y)
/* coordinates to be assigned to lower left and upper right
corners of (square) plotting area */
#define range(_x,_y,_X,_Y) print("ra %d %d %d %d\n", _x,_y,_X,_Y)
/* place text, first letter at current point, which does not change */
#define text(_s) {if(*(_s) == ' ')print("t \"%s\"\n",_s); else print("t %s\n", _s); }
/* draw line from current point to _x,_y, which becomes current */
#define vec(_x,_y) print("v %d %d\n", _x,_y)
/* _x,_y becomes current point */
#define move(_x, _y) print("m %d %d\n", _x, _y)
/* specify style for drawing lines */
#define SOLID "solid"
#define DOTTED "dotted"
#define DASHED "dashed"
#define DOTDASH "dotdash"
#define pen(_s) print("pe %s\n", _s)
#define BLACK "z"
#define RED "r"
#define YELLOW "y"
#define GREEN "g"
#define BLUE "b"
#define CYAN "c"
#define MAGENTA "m"
#define WHITE "w"
#define colorcode(_s) ((strcmp(_s,"black")==0)?BLACK:_s)
#define colorx(_s) print("co %s\n", _s); /* funny name is all ken's fault */
#define comment(s,f)

View File

@ -0,0 +1,26 @@
#include <u.h>
#include <libc.h>
#include "map.h"
#define Xaitwist Xaitpole.nlat
static struct place Xaitpole;
static int
Xaitoff(struct place *place, double *x, double *y)
{
struct place p;
copyplace(place,&p);
p.wlon.l /= 2.;
sincos(&p.wlon);
norm(&p,&Xaitpole,&Xaitwist);
Xazequalarea(&p,x,y);
*x *= 2.;
return(1);
}
proj
aitoff(void)
{
latlon(0.,0.,&Xaitpole);
return(Xaitoff);
}

117
src/cmd/map/libmap/albers.c Normal file
View File

@ -0,0 +1,117 @@
#include <u.h>
#include <libc.h>
#include "map.h"
/* For Albers formulas see Deetz and Adams "Elements of Map Projection", */
/* USGS Special Publication No. 68, GPO 1921 */
static double r0sq, r1sq, d2, n, den, sinb1, sinb2;
static struct coord plat1, plat2;
static int southpole;
static double num(double s)
{
if(d2==0)
return(1);
s = d2*s*s;
return(1+s*(2./3+s*(3./5+s*(4./7+s*5./9))));
}
/* Albers projection for a spheroid, good only when N pole is fixed */
static int
Xspalbers(struct place *place, double *x, double *y)
{
double r = sqrt(r0sq-2*(1-d2)*place->nlat.s*num(place->nlat.s)/n);
double t = n*place->wlon.l;
*y = r*cos(t);
*x = -r*sin(t);
if(!southpole)
*y = -*y;
else
*x = -*x;
return(1);
}
/* lat1, lat2: std parallels; e2: squared eccentricity */
static proj albinit(double lat1, double lat2, double e2)
{
double r1;
double t;
for(;;) {
if(lat1 < -90)
lat1 = -180 - lat1;
if(lat2 > 90)
lat2 = 180 - lat2;
if(lat1 <= lat2)
break;
t = lat1; lat1 = lat2; lat2 = t;
}
if(lat2-lat1 < 1) {
if(lat1 > 89)
return(azequalarea());
return(0);
}
if(fabs(lat2+lat1) < 1)
return(cylequalarea(lat1));
d2 = e2;
den = num(1.);
deg2rad(lat1,&plat1);
deg2rad(lat2,&plat2);
sinb1 = plat1.s*num(plat1.s)/den;
sinb2 = plat2.s*num(plat2.s)/den;
n = (plat1.c*plat1.c/(1-e2*plat1.s*plat1.s) -
plat2.c*plat2.c/(1-e2*plat2.s*plat2.s)) /
(2*(1-e2)*den*(sinb2-sinb1));
r1 = plat1.c/(n*sqrt(1-e2*plat1.s*plat1.s));
r1sq = r1*r1;
r0sq = r1sq + 2*(1-e2)*den*sinb1/n;
southpole = lat1<0 && plat2.c>plat1.c;
return(Xspalbers);
}
proj
sp_albers(double lat1, double lat2)
{
return(albinit(lat1,lat2,EC2));
}
proj
albers(double lat1, double lat2)
{
return(albinit(lat1,lat2,0.));
}
static double scale = 1;
static double twist = 0;
void
albscale(double x, double y, double lat, double lon)
{
struct place place;
double alat, alon, x1,y1;
scale = 1;
twist = 0;
invalb(x,y,&alat,&alon);
twist = lon - alon;
deg2rad(lat,&place.nlat);
deg2rad(lon,&place.wlon);
Xspalbers(&place,&x1,&y1);
scale = sqrt((x1*x1+y1*y1)/(x*x+y*y));
}
void
invalb(double x, double y, double *lat, double *lon)
{
int i;
double sinb_den, sinp;
x *= scale;
y *= scale;
*lon = atan2(-x,fabs(y))/(RAD*n) + twist;
sinb_den = (r0sq - x*x - y*y)*n/(2*(1-d2));
sinp = sinb_den;
for(i=0; i<5; i++)
sinp = sinb_den/num(sinp);
*lat = asin(sinp)/RAD;
}

View File

@ -0,0 +1,19 @@
#include <u.h>
#include <libc.h>
#include "map.h"
int
Xazequalarea(struct place *place, double *x, double *y)
{
double r;
r = sqrt(1. - place->nlat.s);
*x = - r * place->wlon.s;
*y = - r * place->wlon.c;
return(1);
}
proj
azequalarea(void)
{
return(Xazequalarea);
}

View File

@ -0,0 +1,19 @@
#include <u.h>
#include <libc.h>
#include "map.h"
int
Xazequidistant(struct place *place, double *x, double *y)
{
double colat;
colat = PI/2 - place->nlat.l;
*x = -colat * place->wlon.s;
*y = -colat * place->wlon.c;
return(1);
}
proj
azequidistant(void)
{
return(Xazequidistant);
}

View File

@ -0,0 +1,25 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static struct coord center;
static int
Xbicentric(struct place *place, double *x, double *y)
{
if(place->wlon.c<=.01||place->nlat.c<=.01)
return(-1);
*x = -center.c*place->wlon.s/place->wlon.c;
*y = place->nlat.s/(place->nlat.c*place->wlon.c);
return(*x**x+*y**y<=9);
}
proj
bicentric(double l)
{
l = fabs(l);
if(l>89)
return(0);
deg2rad(l,&center);
return(Xbicentric);
}

View File

@ -0,0 +1,36 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static struct coord stdpar;
static double r0;
static int
Xbonne(struct place *place, double *x, double *y)
{
double r, alpha;
r = r0 - place->nlat.l;
if(r<.001)
if(fabs(stdpar.c)<1e-10)
alpha = place->wlon.l;
else if(fabs(place->nlat.c)==0)
alpha = 0;
else
alpha = place->wlon.l/(1+
stdpar.c*stdpar.c*stdpar.c/place->nlat.c/3);
else
alpha = place->wlon.l * place->nlat.c / r;
*x = - r*sin(alpha);
*y = - r*cos(alpha);
return(1);
}
proj
bonne(double par)
{
if(fabs(par*RAD) < .01)
return(Xsinusoidal);
deg2rad(par, &stdpar);
r0 = stdpar.c/stdpar.s + stdpar.l;
return(Xbonne);
}

View File

@ -0,0 +1,13 @@
#include <u.h>
#include <libc.h>
#include "map.h"
void
ccubrt(double zr, double zi, double *wr, double *wi)
{
double r, theta;
theta = atan2(zi,zr);
r = cubrt(hypot(zr,zi));
*wr = r*cos(theta/3);
*wi = r*sin(theta/3);
}

View File

@ -0,0 +1,85 @@
#include <u.h>
#include <libc.h>
#include "map.h"
/*complex divide, defensive against overflow from
* * and /, but not from + and -
* assumes underflow yields 0.0
* uses identities:
* (a + bi)/(c + di) = ((a + bd/c) + (b - ad/c)i)/(c + dd/c)
* (a + bi)/(c + di) = (b - ai)/(d - ci)
*/
void
cdiv(double a, double b, double c, double d, double *u, double *v)
{
double r,t;
if(fabs(c)<fabs(d)) {
t = -c; c = d; d = t;
t = -a; a = b; b = t;
}
r = d/c;
t = c + r*d;
*u = (a + r*b)/t;
*v = (b - r*a)/t;
}
void
cmul(double c1, double c2, double d1, double d2, double *e1, double *e2)
{
*e1 = c1*d1 - c2*d2;
*e2 = c1*d2 + c2*d1;
}
void
csq(double c1, double c2, double *e1, double *e2)
{
*e1 = c1*c1 - c2*c2;
*e2 = c1*c2*2;
}
/* complex square root
* assumes underflow yields 0.0
* uses these identities:
* sqrt(x+_iy) = sqrt(r(cos(t)+_isin(t))
* = sqrt(r)(cos(t/2)+_isin(t/2))
* cos(t/2) = sin(t)/2sin(t/2) = sqrt((1+cos(t)/2)
* sin(t/2) = sin(t)/2cos(t/2) = sqrt((1-cos(t)/2)
*/
void
csqrt(double c1, double c2, double *e1, double *e2)
{
double r,s;
double x,y;
x = fabs(c1);
y = fabs(c2);
if(x>=y) {
if(x==0) {
*e1 = *e2 = 0;
return;
}
r = x;
s = y/x;
} else {
r = y;
s = x/y;
}
r *= sqrt(1+ s*s);
if(c1>0) {
*e1 = sqrt((r+c1)/2);
*e2 = c2/(2* *e1);
} else {
*e2 = sqrt((r-c1)/2);
if(c2<0)
*e2 = -*e2;
*e1 = c2/(2* *e2);
}
}
void cpow(double c1, double c2, double *d1, double *d2, double pwr)
{
double theta = pwr*atan2(c2,c1);
double r = pow(hypot(c1,c2), pwr);
*d1 = r*cos(theta);
*d2 = r*sin(theta);
}

View File

@ -0,0 +1,27 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static struct coord stdpar;
static int
Xconic(struct place *place, double *x, double *y)
{
double r;
if(fabs(place->nlat.l-stdpar.l) > 80.*RAD)
return(-1);
r = stdpar.c/stdpar.s - tan(place->nlat.l - stdpar.l);
*x = - r*sin(place->wlon.l * stdpar.s);
*y = - r*cos(place->wlon.l * stdpar.s);
if(r>3) return(0);
return(1);
}
proj
conic(double par)
{
if(fabs(par) <.1)
return(Xcylindrical);
deg2rad(par, &stdpar);
return(Xconic);
}

View File

@ -0,0 +1,30 @@
#include <u.h>
#include <libc.h>
#include "map.h"
double
cubrt(double a)
{
double x,y,x1;
if(a==0)
return(0.);
y = 1;
if(a<0) {
y = -y;
a = -a;
}
while(a<1) {
a *= 8;
y /= 2;
}
while(a>1) {
a /= 8;
y *= 2;
}
x = 1;
do {
x1 = x;
x = (2*x1+a/(x1*x1))/3;
} while(fabs(x-x1)>10.e-15);
return(x*y);
}

39
src/cmd/map/libmap/cuts.c Normal file
View File

@ -0,0 +1,39 @@
#include <u.h>
#include <libc.h>
#include "map.h"
extern void abort(void);
/* these routines duplicate names found in map.c. they are
called from routines in hex.c, guyou.c, and tetra.c, which
are in turn invoked directly from map.c. this bad organization
arises from data hiding; only these three files know stuff
that's necessary for the proper handling of the unusual cuts
involved in these projections.
the calling routines are not advertised as part of the library,
and the library duplicates should never get loaded, however they
are included to make the libary self-standing.*/
int
picut(struct place *g, struct place *og, double *cutlon)
{
g; og; cutlon;
abort();
return 0;
}
int
ckcut(struct place *g1, struct place *g2, double lon)
{
g1; g2; lon;
abort();
return 0;
}
double
reduce(double x)
{
x;
abort();
return 0;
}

View File

@ -0,0 +1,24 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static double a;
static int
Xcylequalarea(struct place *place, double *x, double *y)
{
*x = - place->wlon.l * a;
*y = place->nlat.s;
return(1);
}
proj
cylequalarea(double par)
{
struct coord stdp0;
if(par > 89.0)
return(0);
deg2rad(par, &stdp0);
a = stdp0.c*stdp0.c;
return(Xcylequalarea);
}

View File

@ -0,0 +1,19 @@
#include <u.h>
#include <libc.h>
#include "map.h"
int
Xcylindrical(struct place *place, double *x, double *y)
{
if(fabs(place->nlat.l) > 80.*RAD)
return(-1);
*x = - place->wlon.l;
*y = place->nlat.s / place->nlat.c;
return(1);
}
proj
cylindrical(void)
{
return(Xcylindrical);
}

132
src/cmd/map/libmap/elco2.c Normal file
View File

@ -0,0 +1,132 @@
#include <u.h>
#include <libc.h>
#include "map.h"
/* elliptic integral routine, R.Bulirsch,
* Numerische Mathematik 7(1965) 78-90
* calculate integral from 0 to x+iy of
* (a+b*t^2)/((1+t^2)*sqrt((1+t^2)*(1+kc^2*t^2)))
* yields about D valid figures, where CC=10e-D
* for a*b>=0, except at branchpoints x=0,y=+-i,+-i/kc;
* there the accuracy may be reduced.
* fails for kc=0 or x<0
* return(1) for success, return(0) for fail
*
* special case a=b=1 is equivalent to
* standard elliptic integral of first kind
* from 0 to atan(x+iy) of
* 1/sqrt(1-k^2*(sin(t))^2) where k^2=1-kc^2
*/
#define ROOTINF 10.e18
#define CC 1.e-6
int
elco2(double x, double y, double kc, double a, double b, double *u, double *v)
{
double c,d,dn1,dn2,e,e1,e2,f,f1,f2,h,k,m,m1,m2,sy;
double d1[13],d2[13];
int i,l;
if(kc==0||x<0)
return(0);
sy = y>0? 1: y==0? 0: -1;
y = fabs(y);
csq(x,y,&c,&e2);
d = kc*kc;
k = 1-d;
e1 = 1+c;
cdiv2(1+d*c,d*e2,e1,e2,&f1,&f2);
f2 = -k*x*y*2/f2;
csqr(f1,f2,&dn1,&dn2);
if(f1<0) {
f1 = dn1;
dn1 = -dn2;
dn2 = -f1;
}
if(k<0) {
dn1 = fabs(dn1);
dn2 = fabs(dn2);
}
c = 1+dn1;
cmul(e1,e2,c,dn2,&f1,&f2);
cdiv(x,y,f1,f2,&d1[0],&d2[0]);
h = a-b;
d = f = m = 1;
kc = fabs(kc);
e = a;
a += b;
l = 4;
for(i=1;;i++) {
m1 = (kc+m)/2;
m2 = m1*m1;
k *= f/(m2*4);
b += e*kc;
e = a;
cdiv2(kc+m*dn1,m*dn2,c,dn2,&f1,&f2);
csqr(f1/m1,k*dn2*2/f2,&dn1,&dn2);
cmul(dn1,dn2,x,y,&f1,&f2);
x = fabs(f1);
y = fabs(f2);
a += b/m1;
l *= 2;
c = 1 +dn1;
d *= k/2;
cmul(x,y,x,y,&e1,&e2);
k *= k;
cmul(c,dn2,1+e1*m2,e2*m2,&f1,&f2);
cdiv(d*x,d*y,f1,f2,&d1[i],&d2[i]);
if(k<=CC)
break;
kc = sqrt(m*kc);
f = m2;
m = m1;
}
f1 = f2 = 0;
for(;i>=0;i--) {
f1 += d1[i];
f2 += d2[i];
}
x *= m1;
y *= m1;
cdiv2(1-y,x,1+y,-x,&e1,&e2);
e2 = x*2/e2;
d = a/(m1*l);
*u = atan2(e2,e1);
if(*u<0)
*u += PI;
a = d*sy/2;
*u = d*(*u) + f1*h;
*v = (-1-log(e1*e1+e2*e2))*a + f2*h*sy + a;
return(1);
}
void
cdiv2(double c1, double c2, double d1, double d2, double *e1, double *e2)
{
double t;
if(fabs(d2)>fabs(d1)) {
t = d1, d1 = d2, d2 = t;
t = c1, c1 = c2, c2 = t;
}
if(fabs(d1)>ROOTINF)
*e2 = ROOTINF*ROOTINF;
else
*e2 = d1*d1 + d2*d2;
t = d2/d1;
*e1 = (c1+t*c2)/(d1+t*d2); /* (c1*d1+c2*d2)/(d1*d1+d2*d2) */
}
/* complex square root of |x|+iy */
void
csqr(double c1, double c2, double *e1, double *e2)
{
double r2;
r2 = c1*c1 + c2*c2;
if(r2<=0) {
*e1 = *e2 = 0;
return;
}
*e1 = sqrt((sqrt(r2) + fabs(c1))/2);
*e2 = c2/(*e1*2);
}

View File

@ -0,0 +1,35 @@
#include <u.h>
#include <libc.h>
#include "map.h"
struct coord center;
static int
Xelliptic(struct place *place, double *x, double *y)
{
double r1,r2;
r1 = acos(place->nlat.c*(place->wlon.c*center.c
- place->wlon.s*center.s));
r2 = acos(place->nlat.c*(place->wlon.c*center.c
+ place->wlon.s*center.s));
*x = -(r1*r1 - r2*r2)/(4*center.l);
*y = (r1*r1+r2*r2)/2 - (center.l*center.l+*x**x);
if(*y < 0)
*y = 0;
*y = sqrt(*y);
if(place->nlat.l<0)
*y = -*y;
return(1);
}
proj
elliptic(double l)
{
l = fabs(l);
if(l>89)
return(0);
if(l<1)
return(Xazequidistant);
deg2rad(l,&center);
return(Xelliptic);
}

View File

@ -0,0 +1,26 @@
#include <u.h>
#include <libc.h>
#include "map.h"
/* refractive fisheye, not logarithmic */
static double n;
static int
Xfisheye(struct place *place, double *x, double *y)
{
double r;
double u = sin(PI/4-place->nlat.l/2)/n;
if(fabs(u) > .97)
return -1;
r = tan(asin(u));
*x = -r*place->wlon.s;
*y = -r*place->wlon.c;
return 1;
}
proj
fisheye(double par)
{
n = par;
return n<.1? 0: Xfisheye;
}

29
src/cmd/map/libmap/gall.c Normal file
View File

@ -0,0 +1,29 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static double scale;
static int
Xgall(struct place *place, double *x, double *y)
{
/* two ways to compute tan(place->nlat.l/2) */
if(fabs(place->nlat.s)<.1)
*y = sin(place->nlat.l/2)/cos(place->nlat.l/2);
else
*y = (1-place->nlat.c)/place->nlat.s;
*x = -scale*place->wlon.l;
return 1;
}
proj
gall(double par)
{
double coshalf;
if(fabs(par)>80)
return 0;
par *= RAD;
coshalf = cos(par/2);
scale = cos(par)/(2*coshalf*coshalf);
return Xgall;
}

View File

@ -0,0 +1,51 @@
#include <u.h>
#include <libc.h>
#include "map.h"
int
Xgilbert(struct place *p, double *x, double *y)
{
/* the interesting part - map the sphere onto a hemisphere */
struct place q;
q.nlat.s = tan(0.5*(p->nlat.l));
if(q.nlat.s > 1) q.nlat.s = 1;
if(q.nlat.s < -1) q.nlat.s = -1;
q.nlat.c = sqrt(1 - q.nlat.s*q.nlat.s);
q.wlon.l = p->wlon.l/2;
sincos(&q.wlon);
/* the dull part: present the hemisphere orthogrpahically */
*y = q.nlat.s;
*x = -q.wlon.s*q.nlat.c;
return(1);
}
proj
gilbert(void)
{
return(Xgilbert);
}
/* derivation of the interesting part:
map the sphere onto the plane by stereographic projection;
map the plane onto a half plane by sqrt;
map the half plane back to the sphere by stereographic
projection
n,w are original lat and lon
r is stereographic radius
primes are transformed versions
r = cos(n)/(1+sin(n))
r' = sqrt(r) = cos(n')/(1+sin(n'))
r'^2 = (1-sin(n')^2)/(1+sin(n')^2) = cos(n)/(1+sin(n))
this is a linear equation for sin n', with solution
sin n' = (1+sin(n)-cos(n))/(1+sin(n)+cos(n))
use standard formula: tan x/2 = (1-cos x)/sin x = sin x/(1+cos x)
to show that the right side of the last equation is tan(n/2)
*/

101
src/cmd/map/libmap/guyou.c Normal file
View File

@ -0,0 +1,101 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static struct place gywhem, gyehem;
static struct coord gytwist;
static double gyconst, gykc, gyside;
static void
dosquare(double z1, double z2, double *x, double *y)
{
double w1,w2;
w1 = z1 -1;
if(fabs(w1*w1+z2*z2)>.000001) {
cdiv(z1+1,z2,w1,z2,&w1,&w2);
w1 *= gyconst;
w2 *= gyconst;
if(w1<0)
w1 = 0;
elco2(w1,w2,gykc,1.,1.,x,y);
} else {
*x = gyside;
*y = 0;
}
}
int
Xguyou(struct place *place, double *x, double *y)
{
int ew; /*which hemisphere*/
double z1,z2;
struct place pl;
ew = place->wlon.l<0;
copyplace(place,&pl);
norm(&pl,ew?&gyehem:&gywhem,&gytwist);
Xstereographic(&pl,&z1,&z2);
dosquare(z1/2,z2/2,x,y);
if(!ew)
*x -= gyside;
return(1);
}
proj
guyou(void)
{
double junk;
gykc = 1/(3+2*sqrt(2.));
gyconst = -(1+sqrt(2.));
elco2(-gyconst,0.,gykc,1.,1.,&gyside,&junk);
gyside *= 2;
latlon(0.,90.,&gywhem);
latlon(0.,-90.,&gyehem);
deg2rad(0.,&gytwist);
return(Xguyou);
}
int
guycut(struct place *g, struct place *og, double *cutlon)
{
int c;
c = picut(g,og,cutlon);
if(c!=1)
return(c);
*cutlon = 0.;
if(g->nlat.c<.7071||og->nlat.c<.7071)
return(ckcut(g,og,0.));
return(1);
}
static int
Xsquare(struct place *place, double *x, double *y)
{
double z1,z2;
double r, theta;
struct place p;
copyplace(place,&p);
if(place->nlat.l<0) {
p.nlat.l = -p.nlat.l;
p.nlat.s = -p.nlat.s;
}
if(p.nlat.l<FUZZ && fabs(p.wlon.l)>PI-FUZZ){
*y = -gyside/2;
*x = p.wlon.l>0?0:gyside;
return(1);
}
Xstereographic(&p,&z1,&z2);
r = sqrt(sqrt(hypot(z1,z2)/2));
theta = atan2(z1,-z2)/4;
dosquare(r*sin(theta),-r*cos(theta),x,y);
if(place->nlat.l<0)
*y = -gyside - *y;
return(1);
}
proj
square(void)
{
guyou();
return(Xsquare);
}

View File

@ -0,0 +1,40 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static double v3,u2,u3,a,b; /*v=view,p=obj,u=unit.y*/
static int
Xharrison(struct place *place, double *x, double *y)
{
double p1 = -place->nlat.c*place->wlon.s;
double p2 = -place->nlat.c*place->wlon.c;
double p3 = place->nlat.s;
double d = b + u3*p2 - u2*p3;
double t;
if(d < .01)
return -1;
t = a/d;
if(v3*place->nlat.s < 1.)
return -1;
*y = t*p2*u2 + (v3-t*(v3-p3))*u3;
*x = t*p1;
if(t < 0)
return 0;
if(*x * *x + *y * *y > 16)
return -1;
return 1;
}
proj
harrison(double r, double alpha)
{
u2 = cos(alpha*RAD);
u3 = sin(alpha*RAD);
v3 = r;
b = r*u2;
a = 1 + b;
if(r<1.001 || a<sqrt(r*r-1))
return 0;
return Xharrison;
}

122
src/cmd/map/libmap/hex.c Normal file
View File

@ -0,0 +1,122 @@
#include <u.h>
#include <libc.h>
#include "map.h"
#define BIG 1.e15
#define HFUZZ .0001
static double hcut[3] ;
static double kr[3] = { .5, -1., .5 };
static double ki[3] = { -1., 0., 1. }; /*to multiply by sqrt(3)/2*/
static double cr[3];
static double ci[3];
static struct place hem;
static struct coord twist;
static double rootroot3, hkc;
static double w2;
static double rootk;
static void
reflect(int i, double wr, double wi, double *x, double *y)
{
double pr,pi,l;
pr = cr[i]-wr;
pi = ci[i]-wi;
l = 2*(kr[i]*pr + ki[i]*pi);
*x = wr + l*kr[i];
*y = wi + l*ki[i];
}
static int
Xhex(struct place *place, double *x, double *y)
{
int ns;
int i;
double zr,zi;
double sr,si,tr,ti,ur,ui,vr,vi,yr,yi;
struct place p;
copyplace(place,&p);
ns = place->nlat.l >= 0;
if(!ns) {
p.nlat.l = -p.nlat.l;
p.nlat.s = -p.nlat.s;
}
if(p.nlat.l<HFUZZ) {
for(i=0;i<3;i++)
if(fabs(reduce(p.wlon.l-hcut[i]))<HFUZZ) {
if(i==2) {
*x = 2*cr[0] - cr[1];
*y = 0;
} else {
*x = cr[1];
*y = 2*ci[2*i];
}
return(1);
}
p.nlat.l = HFUZZ;
sincos(&p.nlat);
}
norm(&p,&hem,&twist);
Xstereographic(&p,&zr,&zi);
zr /= 2;
zi /= 2;
cdiv(1-zr,-zi,1+zr,zi,&sr,&si);
csq(sr,si,&tr,&ti);
ccubrt(1+3*tr,3*ti,&ur,&ui);
csqrt(ur-1,ui,&vr,&vi);
cdiv(rootroot3+vr,vi,rootroot3-vr,-vi,&yr,&yi);
yr /= rootk;
yi /= rootk;
elco2(fabs(yr),yi,hkc,1.,1.,x,y);
if(yr < 0)
*x = w2 - *x;
if(!ns) reflect(hcut[0]>place->wlon.l?0:
hcut[1]>=place->wlon.l?1:
2,*x,*y,x,y);
return(1);
}
proj
hex(void)
{
int i;
double t;
double root3;
double c,d;
struct place p;
hcut[2] = PI;
hcut[1] = hcut[2]/3;
hcut[0] = -hcut[1];
root3 = sqrt(3.);
rootroot3 = sqrt(root3);
t = 15 -8*root3;
hkc = t*(1-sqrt(1-1/(t*t)));
elco2(BIG,0.,hkc,1.,1.,&w2,&t);
w2 *= 2;
rootk = sqrt(hkc);
latlon(90.,90.,&hem);
latlon(90.,0.,&p);
Xhex(&p,&c,&t);
latlon(0.,0.,&p);
Xhex(&p,&d,&t);
for(i=0;i<3;i++) {
ki[i] *= root3/2;
cr[i] = c + (c-d)*kr[i];
ci[i] = (c-d)*ki[i];
}
deg2rad(0.,&twist);
return(Xhex);
}
int
hexcut(struct place *g, struct place *og, double *cutlon)
{
int t,i;
if(g->nlat.l>=-HFUZZ&&og->nlat.l>=-HFUZZ)
return(1);
for(i=0;i<3;i++) {
t = ckcut(g,og,*cutlon=hcut[i]);
if(t!=1) return(t);
}
return(1);
}

121
src/cmd/map/libmap/homing.c Normal file
View File

@ -0,0 +1,121 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static struct coord p0; /* standard parallel */
int first;
static double
trigclamp(double x)
{
return x>1? 1: x<-1? -1: x;
}
static struct coord az; /* azimuth of p0 seen from place */
static struct coord rad; /* angular dist from place to p0 */
static int
azimuth(struct place *place)
{
if(place->nlat.c < FUZZ) {
az.l = PI/2 + place->nlat.l - place->wlon.l;
sincos(&az);
rad.l = fabs(place->nlat.l - p0.l);
if(rad.l > PI)
rad.l = 2*PI - rad.l;
sincos(&rad);
return 1;
}
rad.c = trigclamp(p0.s*place->nlat.s + /* law of cosines */
p0.c*place->nlat.c*place->wlon.c);
rad.s = sqrt(1 - rad.c*rad.c);
if(fabs(rad.s) < .001) {
az.s = 0;
az.c = 1;
} else {
az.s = trigclamp(p0.c*place->wlon.s/rad.s); /* sines */
az.c = trigclamp((p0.s - rad.c*place->nlat.s)
/(rad.s*place->nlat.c));
}
rad.l = atan2(rad.s, rad.c);
return 1;
}
static int
Xmecca(struct place *place, double *x, double *y)
{
if(!azimuth(place))
return 0;
*x = -place->wlon.l;
*y = fabs(az.s)<.02? -az.c*rad.s/p0.c: *x*az.c/az.s;
return fabs(*y)>2? -1:
rad.c<0? 0:
1;
}
proj
mecca(double par)
{
first = 1;
if(fabs(par)>80.)
return(0);
deg2rad(par,&p0);
return(Xmecca);
}
static int
Xhoming(struct place *place, double *x, double *y)
{
if(!azimuth(place))
return 0;
*x = -rad.l*az.s;
*y = -rad.l*az.c;
return place->wlon.c<0? 0: 1;
}
proj
homing(double par)
{
first = 1;
if(fabs(par)>80.)
return(0);
deg2rad(par,&p0);
return(Xhoming);
}
int
hlimb(double *lat, double *lon, double res)
{
if(first) {
*lon = -90;
*lat = -90;
first = 0;
return 0;
}
*lat += res;
if(*lat <= 90)
return 1;
if(*lon == 90)
return -1;
*lon = 90;
*lat = -90;
return 0;
}
int
mlimb(double *lat, double *lon, double res)
{
int ret = !first;
if(fabs(p0.s) < .01)
return -1;
if(first) {
*lon = -180;
first = 0;
} else
*lon += res;
if(*lon > 180)
return -1;
*lat = atan(-cos(*lon*RAD)/p0.s*p0.c)/RAD;
return ret;
}

View File

@ -0,0 +1,30 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static int
Xlagrange(struct place *place, double *x, double *y)
{
double z1,z2;
double w1,w2,t1,t2;
struct place p;
copyplace(place,&p);
if(place->nlat.l<0) {
p.nlat.l = -p.nlat.l;
p.nlat.s = -p.nlat.s;
}
Xstereographic(&p,&z1,&z2);
csqrt(-z2/2,z1/2,&w1,&w2);
cdiv(w1-1,w2,w1+1,w2,&t1,&t2);
*y = -t1;
*x = t2;
if(place->nlat.l<0)
*y = -*y;
return(1);
}
proj
lagrange(void)
{
return(Xlagrange);
}

View File

@ -0,0 +1,46 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static struct coord stdp0, stdp1;
static double k;
static int
Xlambert(struct place *place, double *x, double *y)
{
double r;
if(place->nlat.l < -80.*RAD)
return(-1);
if(place->nlat.l > 89.*RAD)
r = 0; /* slovenly */
else
r = stdp0.c*exp(0.5*k*log(
(1+stdp0.s)*(1-place->nlat.s)/((1-stdp0.s)*(1+place->nlat.s))));
if(stdp1.l<0.)
r = -r;
*x = - r*sin(k * place->wlon.l);
*y = - r*cos(k * place->wlon.l);
return(1);
}
proj
lambert(double par0, double par1)
{
double temp;
if(fabs(par0)>fabs(par1)){
temp = par0;
par0 = par1;
par1 = temp;
}
deg2rad(par0, &stdp0);
deg2rad(par1, &stdp1);
if(fabs(par1+par0)<.1)
return(mercator());
if(fabs(par1-par0)<.1)
return(perspective(-1.));
if(fabs(par0)>89.5||fabs(par1)>89.5)
return(0);
k = 2*log(stdp1.c/stdp0.c)/log(
(1+stdp0.s)*(1-stdp1.s)/((1-stdp0.s)*(1+stdp1.s)));
return(Xlambert);
}

24
src/cmd/map/libmap/laue.c Normal file
View File

@ -0,0 +1,24 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static int
Xlaue(struct place *place, double *x, double *y)
{
double r;
if(place->nlat.l<PI/4+FUZZ)
return(-1);
r = tan(PI-2*place->nlat.l);
if(r>3)
return(-1);
*x = - r * place->wlon.s;
*y = - r * place->wlon.c;
return(1);
}
proj
laue(void)
{
return(Xlaue);
}

62
src/cmd/map/libmap/lune.c Normal file
View File

@ -0,0 +1,62 @@
#include <u.h>
#include <libc.h>
#include "map.h"
int Xstereographic(struct place *place, double *x, double *y);
static struct place eastpole;
static struct place westpole;
static double eastx, easty;
static double westx, westy;
static double scale;
static double pwr;
/* conformal map w = ((1+z)^A - (1-z)^A)/((1+z)^A + (1-z)^A),
where A<1, maps unit circle onto a convex lune with x= +-1
mapping to vertices of angle A*PI at w = +-1 */
/* there are cuts from E and W poles to S pole,
in absence of a cut routine, error is returned for
points outside a polar cap through E and W poles */
static int Xlune(struct place *place, double *x, double *y)
{
double stereox, stereoy;
double z1x, z1y, z2x, z2y;
double w1x, w1y, w2x, w2y;
double numx, numy, denx, deny;
if(place->nlat.l < eastpole.nlat.l-FUZZ)
return -1;
Xstereographic(place, &stereox, &stereoy);
stereox *= scale;
stereoy *= scale;
z1x = 1 + stereox;
z1y = stereoy;
z2x = 1 - stereox;
z2y = -stereoy;
cpow(z1x,z1y,&w1x,&w1y,pwr);
cpow(z2x,z2y,&w2x,&w2y,pwr);
numx = w1x - w2x;
numy = w1y - w2y;
denx = w1x + w2x;
deny = w1y + w2y;
cdiv(numx, numy, denx, deny, x, y);
return 1;
}
proj
lune(double lat, double theta)
{
deg2rad(lat, &eastpole.nlat);
deg2rad(-90.,&eastpole.wlon);
deg2rad(lat, &westpole.nlat);
deg2rad(90. ,&westpole.wlon);
Xstereographic(&eastpole, &eastx, &easty);
Xstereographic(&westpole, &westx, &westy);
if(fabs(easty)>FUZZ || fabs(westy)>FUZZ ||
fabs(eastx+westx)>FUZZ)
abort();
scale = 1/eastx;
pwr = theta/180;
return Xlune;
}

View File

@ -0,0 +1,36 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static int
Xmercator(struct place *place, double *x, double *y)
{
if(fabs(place->nlat.l) > 80.*RAD)
return(-1);
*x = -place->wlon.l;
*y = 0.5*log((1+place->nlat.s)/(1-place->nlat.s));
return(1);
}
proj
mercator(void)
{
return(Xmercator);
}
static double ecc = ECC;
static int
Xspmercator(struct place *place, double *x, double *y)
{
if(Xmercator(place,x,y) < 0)
return(-1);
*y += 0.5*ecc*log((1-ecc*place->nlat.s)/(1+ecc*place->nlat.s));
return(1);
}
proj
sp_mercator(void)
{
return(Xspmercator);
}

50
src/cmd/map/libmap/mkfile Normal file
View File

@ -0,0 +1,50 @@
<$PLAN9/src/mkhdr
LIB=libmap.a
OFILES=aitoff.$O\
albers.$O\
azequalarea.$O\
azequidist.$O\
bicentric.$O\
bonne.$O\
ccubrt.$O\
complex.$O\
conic.$O\
cubrt.$O\
cylequalarea.$O\
cylindrical.$O\
elco2.$O\
elliptic.$O\
fisheye.$O\
gall.$O\
gilbert.$O\
guyou.$O\
harrison.$O\
hex.$O\
homing.$O\
lagrange.$O\
lambert.$O\
laue.$O\
lune.$O\
mercator.$O\
mollweide.$O\
newyorker.$O\
orthographic.$O\
perspective.$O\
polyconic.$O\
rectangular.$O\
simpleconic.$O\
sinusoidal.$O\
tetra.$O\
trapezoidal.$O\
twocirc.$O\
zcoord.$O\
HFILES=../map.h\
<$PLAN9/src/mklib
CFLAGS=$CFLAGS -I..
nuke:V:
mk clean
rm -f libmap.a[$OS]

View File

@ -0,0 +1,25 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static int
Xmollweide(struct place *place, double *x, double *y)
{
double z;
double w;
z = place->nlat.l;
if(fabs(z)<89.9*RAD)
do { /*newton for 2z+sin2z=pi*sin(lat)*/
w = (2*z+sin(2*z)-PI*place->nlat.s)/(2+2*cos(2*z));
z -= w;
} while(fabs(w)>=.00001);
*y = sin(z);
*x = - (2/PI)*cos(z)*place->wlon.l;
return(1);
}
proj
mollweide(void)
{
return(Xmollweide);
}

View File

@ -0,0 +1,28 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static double a;
static int
Xnewyorker(struct place *place, double *x, double *y)
{
double r = PI/2 - place->nlat.l;
double s;
if(r<.001) /* cheat to plot center */
s = 0;
else if(r<a)
return -1;
else
s = log(r/a);
*x = -s * place->wlon.s;
*y = -s * place->wlon.c;
return(1);
}
proj
newyorker(double a0)
{
a = a0*RAD;
return(Xnewyorker);
}

View File

@ -0,0 +1,35 @@
#include <u.h>
#include <libc.h>
#include "map.h"
int
Xorthographic(struct place *place, double *x, double *y)
{
*x = - place->nlat.c * place->wlon.s;
*y = - place->nlat.c * place->wlon.c;
return(place->nlat.l<0.? 0 : 1);
}
proj
orthographic(void)
{
return(Xorthographic);
}
int
olimb(double *lat, double *lon, double res)
{
static int first = 1;
if(first) {
*lat = 0;
*lon = -180;
first = 0;
return 0;
}
*lon += res;
if(*lon <= 180)
return 1;
first = 1;
return -1;
}

View File

@ -0,0 +1,84 @@
#include <u.h>
#include <libc.h>
#include "map.h"
#define ORTHRAD 1000
static double viewpt;
static int
Xperspective(struct place *place, double *x, double *y)
{
double r;
if(viewpt<=1+FUZZ && fabs(place->nlat.s<=viewpt+.01))
return(-1);
r = place->nlat.c*(viewpt - 1.)/(viewpt - place->nlat.s);
*x = - r*place->wlon.s;
*y = - r*place->wlon.c;
if(r>4.)
return(-1);
if(fabs(viewpt)>1 && place->nlat.s<1/viewpt ||
fabs(viewpt)<=1 && place->nlat.s<viewpt)
return 0;
return(1);
}
proj
perspective(double radius)
{
viewpt = radius;
if(viewpt >= ORTHRAD)
return(Xorthographic);
if(fabs(viewpt-1.)<.0001)
return(0);
return(Xperspective);
}
/* called from various conformal projections,
but not from stereographic itself */
int
Xstereographic(struct place *place, double *x, double *y)
{
double v = viewpt;
int retval;
viewpt = -1;
retval = Xperspective(place, x, y);
viewpt = v;
return retval;
}
proj
stereographic(void)
{
viewpt = -1.;
return(Xperspective);
}
proj
gnomonic(void)
{
viewpt = 0.;
return(Xperspective);
}
int
plimb(double *lat, double *lon, double res)
{
static int first = 1;
if(viewpt >= ORTHRAD)
return olimb(lat, lon, res);
if(first) {
first = 0;
*lon = -180;
if(fabs(viewpt) < .01)
*lat = 0;
else if(fabs(viewpt)<=1)
*lat = asin(viewpt)/RAD;
else
*lat = asin(1/viewpt)/RAD;
} else
*lon += res;
if(*lon <= 180)
return 1;
first = 1;
return -1;
}

View File

@ -0,0 +1,28 @@
#include <u.h>
#include <libc.h>
#include "map.h"
int
Xpolyconic(struct place *place, double *x, double *y)
{
double r, alpha;
double lat2, lon2;
if(fabs(place->nlat.l) > .01) {
r = place->nlat.c / place->nlat.s;
alpha = place->wlon.l * place->nlat.s;
*y = place->nlat.l + r*(1 - cos(alpha));
*x = - r*sin(alpha);
} else {
lon2 = place->wlon.l * place->wlon.l;
lat2 = place->nlat.l * place->nlat.l;
*y = place->nlat.l * (1+(lon2/2)*(1-(8+lon2)*lat2/12));
*x = - place->wlon.l * (1-lat2*(3+lon2)/6);
}
return(1);
}
proj
polyconic(void)
{
return(Xpolyconic);
}

View File

@ -0,0 +1,22 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static double scale;
static int
Xrectangular(struct place *place, double *x, double *y)
{
*x = -scale*place->wlon.l;
*y = place->nlat.l;
return(1);
}
proj
rectangular(double par)
{
scale = cos(par*RAD);
if(scale<.1)
return 0;
return(Xrectangular);
}

View File

@ -0,0 +1,34 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static double r0, a;
static int
Xsimpleconic(struct place *place, double *x, double *y)
{
double r = r0 - place->nlat.l;
double t = a*place->wlon.l;
*x = -r*sin(t);
*y = -r*cos(t);
return 1;
}
proj
simpleconic(double par0, double par1)
{
struct coord lat0;
struct coord lat1;
deg2rad(par0,&lat0);
deg2rad(par1,&lat1);
if(fabs(lat0.l+lat1.l)<.01)
return rectangular(par0);
if(fabs(lat0.l-lat1.l)<.01) {
a = lat0.s/lat0.l;
r0 = lat0.c/lat0.s + lat0.l;
} else {
a = (lat1.c-lat0.c)/(lat0.l-lat1.l);
r0 = ((lat0.c+lat1.c)/a + lat1.l + lat0.l)/2;
}
return Xsimpleconic;
}

View File

@ -0,0 +1,17 @@
#include <u.h>
#include <libc.h>
#include "map.h"
int
Xsinusoidal(struct place *place, double *x, double *y)
{
*x = - place->wlon.l * place->nlat.c;
*y = place->nlat.l;
return(1);
}
proj
sinusoidal(void)
{
return(Xsinusoidal);
}

206
src/cmd/map/libmap/tetra.c Normal file
View File

@ -0,0 +1,206 @@
#include <u.h>
#include <libc.h>
#include "map.h"
/*
* conformal map of earth onto tetrahedron
* the stages of mapping are
* (a) stereo projection of tetrahedral face onto
* isosceles curvilinear triangle with 3 120-degree
* angles and one straight side
* (b) map of this triangle onto half plane cut along
* 3 rays from the roots of unity to infinity
* formula (z^4+2*3^.5*z^2-1)/(z^4-2*3^.5*z^2-1)
* (c) do 3 times for each sector of plane:
* map of |arg z|<=pi/6, cut along z>1 into
* triangle |arg z|<=pi/6, Re z<=const,
* with upper side of cut going into upper half of
* of vertical side of triangle and lowere into lower
* formula int from 0 to z dz/sqrt(1-z^3)
*
* int from u to 1 3^.25*du/sqrt(1-u^3) =
F(acos((rt3-1+u)/(rt3+1-u)),sqrt(1/2+rt3/4))
* int from 1 to u 3^.25*du/sqrt(u^3-1) =
* F(acos((rt3+1-u)/(rt3-1+u)),sqrt(1/2-rt3/4))
* this latter formula extends analytically down to
* u=0 and is the basis of this routine, with the
* argument of complex elliptic integral elco2
* being tan(acos...)
* the formula F(pi-x,k) = 2*F(pi/2,k)-F(x,k) is
* used to cross over into the region where Re(acos...)>pi/2
* f0 and fpi are suitably scaled complete integrals
*/
#define TFUZZ 0.00001
static struct place tpole[4]; /* point of tangency of tetrahedron face*/
static double tpoleinit[4][2] = {
1., 0.,
1., 180.,
-1., 90.,
-1., -90.
};
static struct tproj {
double tlat,tlon; /* center of stereo projection*/
double ttwist; /* rotatn before stereo*/
double trot; /*rotate after projection*/
struct place projpl; /*same as tlat,tlon*/
struct coord projtw; /*same as ttwist*/
struct coord postrot; /*same as trot*/
} tproj[4][4] = {
{/*00*/ {0.},
/*01*/ {90., 0., 90., -90.},
/*02*/ {0., 45., -45., 150.},
/*03*/ {0., -45., -135., 30.}
},
{/*10*/ {90., 0., -90., 90.},
/*11*/ {0.},
/*12*/ {0., 135., -135., -150.},
/*13*/ {0., -135., -45., -30.}
},
{/*20*/ {0., 45., 135., -30.},
/*21*/ {0., 135., 45., -150.},
/*22*/ {0.},
/*23*/ {-90., 0., 180., 90.}
},
{/*30*/ {0., -45., 45., -150.},
/*31*/ {0., -135., 135., -30.},
/*32*/ {-90., 0., 0., 90.},
/*33*/ {0.}
}};
static double tx[4] = { /*where to move facet after final rotation*/
0., 0., -1., 1. /*-1,1 to be sqrt(3)*/
};
static double ty[4] = {
0., 2., -1., -1.
};
static double root3;
static double rt3inv;
static double two_rt3;
static double tkc,tk,tcon;
static double f0r,f0i,fpir,fpii;
static void
twhichp(struct place *g, int *p, int *q)
{
int i,j,k;
double cosdist[4];
struct place *tp;
for(i=0;i<4;i++) {
tp = &tpole[i];
cosdist[i] = g->nlat.s*tp->nlat.s +
g->nlat.c*tp->nlat.c*(
g->wlon.s*tp->wlon.s +
g->wlon.c*tp->wlon.c);
}
j = 0;
for(i=1;i<4;i++)
if(cosdist[i] > cosdist[j])
j = i;
*p = j;
k = j==0?1:0;
for(i=0;i<4;i++)
if(i!=j&&cosdist[i]>cosdist[k])
k = i;
*q = k;
}
int
Xtetra(struct place *place, double *x, double *y)
{
int i,j;
struct place pl;
register struct tproj *tpp;
double vr, vi;
double br, bi;
double zr,zi,z2r,z2i,z4r,z4i,sr,si,tr,ti;
twhichp(place,&i,&j);
copyplace(place,&pl);
norm(&pl,&tproj[i][j].projpl,&tproj[i][j].projtw);
Xstereographic(&pl,&vr,&vi);
zr = vr/2;
zi = vi/2;
if(zr<=TFUZZ)
zr = TFUZZ;
csq(zr,zi,&z2r,&z2i);
csq(z2r,z2i,&z4r,&z4i);
z2r *= two_rt3;
z2i *= two_rt3;
cdiv(z4r+z2r-1,z4i+z2i,z4r-z2r-1,z4i-z2i,&sr,&si);
csqrt(sr-1,si,&tr,&ti);
cdiv(tcon*tr,tcon*ti,root3+1-sr,-si,&br,&bi);
if(br<0) {
br = -br;
bi = -bi;
if(!elco2(br,bi,tk,1.,1.,&vr,&vi))
return 0;
vr = fpir - vr;
vi = fpii - vi;
} else
if(!elco2(br,bi,tk,1.,1.,&vr,&vi))
return 0;
if(si>=0) {
tr = f0r - vi;
ti = f0i + vr;
} else {
tr = f0r + vi;
ti = f0i - vr;
}
tpp = &tproj[i][j];
*x = tr*tpp->postrot.c +
ti*tpp->postrot.s + tx[i];
*y = ti*tpp->postrot.c -
tr*tpp->postrot.s + ty[i];
return(1);
}
int
tetracut(struct place *g, struct place *og, double *cutlon)
{
int i,j,k;
if((g->nlat.s<=-rt3inv&&og->nlat.s<=-rt3inv) &&
(ckcut(g,og,*cutlon=0.)==2||ckcut(g,og,*cutlon=PI)==2))
return(2);
twhichp(g,&i,&k);
twhichp(og,&j,&k);
if(i==j||i==0||j==0)
return(1);
return(0);
}
proj
tetra(void)
{
int i;
int j;
register struct place *tp;
register struct tproj *tpp;
double t;
root3 = sqrt(3.);
rt3inv = 1/root3;
two_rt3 = 2*root3;
tkc = sqrt(.5-.25*root3);
tk = sqrt(.5+.25*root3);
tcon = 2*sqrt(root3);
elco2(tcon/(root3-1),0.,tkc,1.,1.,&f0r,&f0i);
elco2(1.e15,0.,tk,1.,1.,&fpir,&fpii);
fpir *= 2;
fpii *= 2;
for(i=0;i<4;i++) {
tx[i] *= f0r*root3;
ty[i] *= f0r;
tp = &tpole[i];
t = tp->nlat.s = tpoleinit[i][0]/root3;
tp->nlat.c = sqrt(1 - t*t);
tp->nlat.l = atan2(tp->nlat.s,tp->nlat.c);
deg2rad(tpoleinit[i][1],&tp->wlon);
for(j=0;j<4;j++) {
tpp = &tproj[i][j];
latlon(tpp->tlat,tpp->tlon,&tpp->projpl);
deg2rad(tpp->ttwist,&tpp->projtw);
deg2rad(tpp->trot,&tpp->postrot);
}
}
return(Xtetra);
}

View File

@ -0,0 +1,30 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static struct coord stdpar0, stdpar1;
static double k;
static double yeq;
static int
Xtrapezoidal(struct place *place, double *x, double *y)
{
*y = yeq + place->nlat.l;
*x = *y*k*place->wlon.l;
return 1;
}
proj
trapezoidal(double par0, double par1)
{
if(fabs(fabs(par0)-fabs(par1))<.1)
return rectangular(par0);
deg2rad(par0,&stdpar0);
deg2rad(par1,&stdpar1);
if(fabs(par1-par0) < .1)
k = stdpar1.s;
else
k = (stdpar1.c-stdpar0.c)/(stdpar0.l-stdpar1.l);
yeq = -stdpar1.l - stdpar1.c/k;
return Xtrapezoidal;
}

View File

@ -0,0 +1,80 @@
#include <u.h>
#include <libc.h>
#include "map.h"
static double
quadratic(double a, double b, double c)
{
double disc = b*b - 4*a*c;
return disc<0? 0: (-b-sqrt(disc))/(2*a);
}
/* for projections with meridians being circles centered
on the x axis and parallels being circles centered on the y
axis. Find the intersection of the meridian thru (m,0), (90,0),
with the parallel thru (0,p), (p1,p2) */
static int
twocircles(double m, double p, double p1, double p2, double *x, double *y)
{
double a; /* center of meridian circle, a>0 */
double b; /* center of parallel circle, b>0 */
double t,bb;
if(m > 0) {
twocircles(-m,p,p1,p2,x,y);
*x = -*x;
} else if(p < 0) {
twocircles(m,-p,p1,-p2,x,y);
*y = -*y;
} else if(p < .01) {
*x = m;
t = m/p1;
*y = p + (p2-p)*t*t;
} else if(m > -.01) {
*y = p;
*x = m - m*p*p;
} else {
b = p>=1? 1: p>.99? 0.5*(p+1 + p1*p1/(1-p)):
0.5*(p*p-p1*p1-p2*p2)/(p-p2);
a = .5*(m - 1/m);
t = m*m-p*p+2*(b*p-a*m);
bb = b*b;
*x = quadratic(1+a*a/bb, -2*a + a*t/bb,
t*t/(4*bb) - m*m + 2*a*m);
*y = (*x*a+t/2)/b;
}
return 1;
}
static int
Xglobular(struct place *place, double *x, double *y)
{
twocircles(-2*place->wlon.l/PI,
2*place->nlat.l/PI, place->nlat.c, place->nlat.s, x, y);
return 1;
}
proj
globular(void)
{
return Xglobular;
}
static int
Xvandergrinten(struct place *place, double *x, double *y)
{
double t = 2*place->nlat.l/PI;
double abst = fabs(t);
double pval = abst>=1? 1: abst/(1+sqrt(1-t*t));
double p2 = 2*pval/(1+pval);
twocircles(-place->wlon.l/PI, pval, sqrt(1-p2*p2), p2, x, y);
if(t < 0)
*y = -*y;
return 1;
}
proj
vandergrinten(void)
{
return Xvandergrinten;
}

143
src/cmd/map/libmap/zcoord.c Normal file
View File

@ -0,0 +1,143 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
#include "map.h"
static double cirmod(double);
static struct place pole; /* map pole is tilted to here */
static struct coord twist; /* then twisted this much */
static struct place ipole; /* inverse transfrom */
static struct coord itwist;
void
orient(double lat, double lon, double theta)
{
lat = cirmod(lat);
if(lat>90.) {
lat = 180. - lat;
lon -= 180.;
theta -= 180.;
} else if(lat < -90.) {
lat = -180. - lat;
lon -= 180.;
theta -= 180;
}
latlon(lat,lon,&pole);
deg2rad(theta, &twist);
latlon(lat,180.-theta,&ipole);
deg2rad(180.-lon, &itwist);
}
void
latlon(double lat, double lon, struct place *p)
{
lat = cirmod(lat);
if(lat>90.) {
lat = 180. - lat;
lon -= 180.;
} else if(lat < -90.) {
lat = -180. - lat;
lon -= 180.;
}
deg2rad(lat,&p->nlat);
deg2rad(lon,&p->wlon);
}
void
deg2rad(double theta, struct coord *coord)
{
theta = cirmod(theta);
coord->l = theta*RAD;
if(theta==90) {
coord->s = 1;
coord->c = 0;
} else if(theta== -90) {
coord->s = -1;
coord->c = 0;
} else
sincos(coord);
}
static double
cirmod(double theta)
{
while(theta >= 180.)
theta -= 360;
while(theta<-180.)
theta += 360.;
return(theta);
}
void
sincos(struct coord *coord)
{
coord->s = sin(coord->l);
coord->c = cos(coord->l);
}
void
normalize(struct place *gg)
{
norm(gg,&pole,&twist);
}
void
invert(struct place *g)
{
norm(g,&ipole,&itwist);
}
void
norm(struct place *gg, struct place *pp, struct coord *tw)
{
register struct place *g; /*geographic coords */
register struct place *p; /* new pole in old coords*/
struct place m; /* standard map coords*/
g = gg;
p = pp;
if(p->nlat.s == 1.) {
if(p->wlon.l+tw->l == 0.)
return;
g->wlon.l -= p->wlon.l+tw->l;
} else {
if(p->wlon.l != 0) {
g->wlon.l -= p->wlon.l;
sincos(&g->wlon);
}
m.nlat.s = p->nlat.s * g->nlat.s
+ p->nlat.c * g->nlat.c * g->wlon.c;
m.nlat.c = sqrt(1. - m.nlat.s * m.nlat.s);
m.nlat.l = atan2(m.nlat.s, m.nlat.c);
m.wlon.s = g->nlat.c * g->wlon.s;
m.wlon.c = p->nlat.c * g->nlat.s
- p->nlat.s * g->nlat.c * g->wlon.c;
m.wlon.l = atan2(m.wlon.s, - m.wlon.c)
- tw->l;
*g = m;
}
sincos(&g->wlon);
if(g->wlon.l>PI)
g->wlon.l -= 2*PI;
else if(g->wlon.l<-PI)
g->wlon.l += 2*PI;
}
double
tan(double x)
{
return(sin(x)/cos(x));
}
void
printp(struct place *g)
{
printf("%.3f %.3f %.3f %.3f %.3f %.3f\n",
g->nlat.l,g->nlat.s,g->nlat.c,g->wlon.l,g->wlon.s,g->wlon.c);
}
void
copyplace(struct place *g1, struct place *g2)
{
*g2 = *g1;
}

1226
src/cmd/map/map.c Normal file

File diff suppressed because it is too large Load Diff

147
src/cmd/map/map.h Normal file
View File

@ -0,0 +1,147 @@
/*
#pragma lib "/sys/src/cmd/map/libmap/libmap.a$O"
#pragma src "/sys/src/cmd/map/libmap"
*/
#define index index0
#ifndef PI
#define PI 3.1415926535897932384626433832795028841971693993751
#endif
#define TWOPI (2*PI)
#define RAD (PI/180)
double hypot(double, double); /* sqrt(a*a+b*b) */
double tan(double); /* not in K&R library */
#define ECC .08227185422 /* eccentricity of earth */
#define EC2 .006768657997
#define FUZZ .0001
#define UNUSED 0.0 /* a dummy double parameter */
struct coord {
double l; /* lat or lon in radians*/
double s; /* sin */
double c; /* cos */
};
struct place {
struct coord nlat;
struct coord wlon;
};
typedef int (*proj)(struct place *, double *, double *);
struct index { /* index of known projections */
char *name; /* name of projection */
proj (*prog)(double, double);
/* pointer to projection function */
int npar; /* number of params */
int (*cut)(struct place *, struct place *, double *);
/* function that handles cuts--eg longitude 180 */
int poles; /*1 S pole is a line, 2 N pole is, 3 both*/
int spheroid; /* poles must be at 90 deg if nonzero */
int (*limb)(double *lat, double *lon, double resolution);
/* get next place on limb */
/* return -1 if done, 0 at gap, else 1 */
};
proj aitoff(void);
proj albers(double, double);
int Xazequalarea(struct place *, double *, double *);
proj azequalarea(void);
int Xazequidistant(struct place *, double *, double *);
proj azequidistant(void);
proj bicentric(double);
proj bonne(double);
proj conic(double);
proj cylequalarea(double);
int Xcylindrical(struct place *, double *, double *);
proj cylindrical(void);
proj elliptic(double);
proj fisheye(double);
proj gall(double);
proj gilbert(void);
proj globular(void);
proj gnomonic(void);
int guycut(struct place *, struct place *, double *);
int Xguyou(struct place *, double *, double *);
proj guyou(void);
proj harrison(double, double);
int hexcut(struct place *, struct place *, double *);
proj hex(void);
proj homing(double);
int hlimb(double*, double*, double resolution);
proj lagrange(void);
proj lambert(double, double);
proj laue(void);
proj lune(double, double);
proj loxodromic(double); /* not in library */
proj mecca(double);
int mlimb(double*, double*, double resolution);
proj mercator(void);
proj mollweide(void);
proj newyorker(double);
proj ortelius(double, double); /* not in library */
int Xorthographic(struct place *place, double *x, double *y);
proj orthographic(void);
int olimb(double*, double*, double);
proj perspective(double);
int plimb(double*, double*, double resolution);
int Xpolyconic(struct place *, double *, double *);
proj polyconic(void);
proj rectangular(double);
proj simpleconic(double, double);
int Xsinusoidal(struct place *, double *, double *);
proj sinusoidal(void);
proj sp_albers(double, double);
proj sp_mercator(void);
proj square(void);
int Xstereographic(struct place *, double *, double *);
proj stereographic(void);
int Xtetra(struct place *, double *, double *);
int tetracut(struct place *, struct place *, double *);
proj tetra(void);
proj trapezoidal(double, double);
proj vandergrinten(void);
proj wreath(double, double); /* not in library */
void findxy(double, double *, double *);
void albscale(double, double, double, double);
void invalb(double, double, double *, double *);
void cdiv(double, double, double, double, double *, double *);
void cmul(double, double, double, double, double *, double *);
void cpow(double, double, double *, double *, double);
void csq(double, double, double *, double *);
void csqrt(double, double, double *, double *);
void ccubrt(double, double, double *, double *);
double cubrt(double);
int elco2(double, double, double, double, double, double *, double *);
void cdiv2(double, double, double, double, double *, double *);
void csqr(double, double, double *, double *);
void orient(double, double, double);
void latlon(double, double, struct place *);
void deg2rad(double, struct coord *);
void sincos(struct coord *);
void normalize(struct place *);
void invert(struct place *);
void norm(struct place *, struct place *, struct coord *);
void printp(struct place *);
void copyplace(struct place *, struct place *);
int picut(struct place *, struct place *, double *);
int ckcut(struct place *, struct place *, double);
double reduce(double);
void getsyms(char *);
int putsym(struct place *, char *, double, int);
void filerror(char *s, char *f);
void error(char *s);
int doproj(struct place *, int *, int *);
int cpoint(int, int, int);
int plotpt(struct place *, int);
int nocut(struct place *, struct place *, double *);
extern int (*projection)(struct place *, double *, double *);

103
src/cmd/map/map.rc Executable file
View File

@ -0,0 +1,103 @@
#!/bin/rc
rfork en
# F FEATUREs, M map files, A other arguments
FEATURE=no
if (~ $MAPPROG '')
MAPPROG=/bin/aux/mapd
if (~ $MAPDIR '')
MAPDIR=/lib/map
F=(); M=(); A=();
for (i) {
switch ($FEATURE) {
case no
switch ($i) {
case -f
FEATURE=yes
F=($F)
case *
A=($A $i)
}
case yes
switch ($i) {
case -f
case -*
A=($A $i)
FEATURE=no
case riv*2
F=($F 201 202)
case riv*3
F=($F 201 202 203)
case riv*4
F=($F 201 202 203 204)
case riv*
F=($F 201)
case iriv*2
F=($F 206 207)
case iriv*[34]
F=($F 206 207 208)
case iriv*
F=($F 206)
case coast*2 shore*2 lake*2
F=($F 102)
case coast*3 shore*3 lake*3
F=($F 102 103)
case coast*4 shore*4 lake*4
F=($F 102 103 104)
case coast* shore* lake*
case ilake*[234] ishore*[234]
F=($F 106 107)
case ilake* ishore*
F=($F 106)
case reef*
F=($F 108)
case canal*2
F=($F 210 211)
case canal*[34]
F=($F 210 211 212)
case canal*
F=($F 210)
case glacier*
F=($F 115)
case state* province*
F=($F 401)
case countr*2
F=($F 301 302)
case countr*[34]
F=($F 301 302 303)
case countr*
F=($F 301)
case salt*[234]
F=($F 109 110)
case salt*
F=($F 109)
case ice*[234] shel*[234]
F=($F 113 114)
case ice* shel*
F=($F 113)
case *
echo map: unknown feature $i >[1=2]
exits "unknown feature"
}
}
}
for (j in $F) {
if (test -r $MAPDIR/$j)
M=($M $MAPDIR/$j)
}
if (~ $F ?*) {
if (test -r $MAPDIR/101)
M=(101 $M)
M=(-m $M)
}
if (~ $MAP '')
MAP=world
MAP=$MAP MAPDIR=$MAPDIR $MAPPROG $A $M

83
src/cmd/map/mapdemo.rc Executable file
View File

@ -0,0 +1,83 @@
#!/bin/rc
fn demo {proj=$1; shift;
label=$1; shift;
{ echo 'o'
echo 'ra -8192 -8492 8192 8492'
echo 'e'
echo 'm -8192 8192'
echo t $type
echo 'm -8192 -8192'
echo t $proj - $label
MAP=world MAPDIR=/lib/map map $proj $* -s -d 5
}
sleep 5
}
rfork en
{
type='Equatorial projections centered on long. 0. Parallels are straight lines.'
demo mercator 'equally spaced straight meridians, conformal, straight compass courses'
demo sinusoidal 'equally spaced parallels, equal-area, same as bonne(0)'
demo cylequalarea 'equally spaced straight meridians, equal-area, true scale on Eq' 0
demo cylindrical 'central projection on tangent cylinder'
demo rectangular 'equally spaced parallels, equally spaced straight meridians, true scale on Eq' 0
demo gall 'parallels spaced stereographically on prime meridian, equally spaced straight meridians, true scale on Eq' 0
demo mollweide '(homalographic) equal-area, hemisphere is a circle'
demo gilbert 'globe mapped conformally on hemisphere, viewed orthographically'
type='Azimuthal: centered on the North Pole, Parallels are concentric circles, Meridians are equally spaced radial lines'
demo azequidistant 'equally spaced parallels, true distances from pole'
demo azequalarea 'equal area'
demo gnomonic 'central projecton on tangent plane, straight great circles'
demo perspective 'viewed along earth''s axis 2 earth radii from center of earth' 2
demo orthographic 'viewed from infinity'
demo stereographic 'conformal, projected from opposite pole'
demo laue 'radius = tan(2\(mu colatitude ), used in xray crystallography'
demo fisheye 'fisheye view of stereographic map, index of refraction 2' 2 -o 40.75 74
demo newyorker 'New Yorker map from viewing pedestal of radius .5' .5 -o 40.75 74
type='Polar conic projections symmetric about the Prime Meridian. Parallels are segments of concentric circles.'
demo conic 'central projection on cone tangent at 40' 40
demo simpleconic 'equally spaced parallels, true scale on 20 and 50' 20 50
demo lambert 'conformal, true scale on 20 and 50' 20 50
demo albers 'equal-area, true scale on 20 and 50' 20 50
demo bonne 'equally spaced parallels, equal-area, parallel 40 developed from tangent cone' 40
type='Projections with bilateral symmetry about the Prime Meridian and the equator.'
demo polyconic 'parallels developed from tangent cones, equally spaced along Prime Meridian'
demo aitoff 'equal-area projection of globe onto 2-to-1 ellipse, based on azequalarea'
demo lagrange 'conformal, maps whole sphere into a circle'
demo bicentric 'points plotted at true azimuth from two centers on the equator at longitudes +-40, great circles are straight lines' 40
demo elliptic 'points are plotted at true distance from two centers on the equator at longitudes +-40' 40
demo globular 'hemisphere is circle, circular meridians and parallels'
demo vandergrinten 'sphere is circle, meridians as in globular, circular arc parallels resemble mercator'
type='Doubly periodic conformal projections.'
demo guyou 'W and E hemispheres are square'
demo square 'World is square with Poles at diagonally opposite corners'
demo tetra 'map on tetrahedron with edge tangent to Prime Meridian at S Pole, unfolded into equilateral triangle'
demo hex 'world is hexagon centered on N Pole, N and S hemispheres are equilateral
triangles'
type='Retroazimuthal projections. Directions to center are true.'
demo mecca 'equally spaced vertical meridians' 21.4 -o 90 -39.8
demo homing 'distances to Mecca are true' 21.4 -o 90 -39.8
type='Miscellaneous projections.'
demo harrison 'oblique perspective from above the North Pole, 2 earth radii from the earth, looking along the Date Line 40 degrees off vertical' 2 40
demo trapezoidal 'equally spaced parallels, straight meridians equally spaced along parallels, true scale at 20 and 50 on Prime Meridian' 20 50
demo lune 'conformal, polar cap above Eq is 60-degree lune' 0 60
type='Maps based on the spheroid'
demo sp_mercator 'equally spaced straight meridians, conformal'
demo sp_albers 'equal-area, true scale on 20 and 50' 20 50
} | plot

32
src/cmd/map/mkfile Normal file
View File

@ -0,0 +1,32 @@
<$PLAN9/src/mkhdr
TARG=mapd
LIB=libmap/libmap.a
OFILES=map.$O\
symbol.$O\
index.$O\
sqrt.$O\
HFILES=map.h\
iplot.h\
<$PLAN9/src/mkone
$O.out:V: $OFILES $LIB
$LD $LDFLAGS -o $target $prereq
$LIB:V:
cd libmap
mk install
installall:V:
for(objtype in $CPUS)
mk install
cp map.rc /rc/bin/map
cp mapdemo.rc /rc/bin/mapdemo
clean nuke:V:
rm -f *.[$OS] [$OS].out y.tab.? y.debug y.output $TARG
cd libmap; mk clean

131
src/cmd/map/route.c Normal file
View File

@ -0,0 +1,131 @@
#include <u.h>
#include <libc.h>
#include "map.h"
/* Given two lat-lon pairs, find an orientation for the
-o option of "map" that will place those two points
on the equator of a standard projection, equally spaced
about the prime meridian.
-w and -l options are suggested also.
Option -t prints out a series of
coordinates that follows the (great circle) track
in the original coordinate system,
followed by ".
This data is just right for map -t.
Option -i inverts the map top-to-bottom.
*/
struct place pole;
struct coord twist;
int track;
int inv = -1;
extern void doroute(double, double, double, double, double);
void
dorot(double a, double b, double *x, double *y, void (*f)(struct place *))
{
struct place g;
deg2rad(a,&g.nlat);
deg2rad(b,&g.wlon);
(*f)(&g);
*x = g.nlat.l/RAD;
*y = g.wlon.l/RAD;
}
void
rotate(double a, double b, double *x, double *y)
{
dorot(a,b,x,y,normalize);
}
void
rinvert(double a, double b, double *x, double *y)
{
dorot(a,b,x,y,invert);
}
main(int argc, char **argv)
{
#pragma ref argv
double an,aw,bn,bw;
ARGBEGIN {
case 't':
track = 1;
break;
case 'i':
inv = 1;
break;
default:
exits("route: bad option");
} ARGEND;
if (argc<4) {
print("use route [-t] [-i] lat lon lat lon\n");
exits("arg count");
}
an = atof(argv[0]);
aw = atof(argv[1]);
bn = atof(argv[2]);
bw = atof(argv[3]);
doroute(inv*90.,an,aw,bn,bw);
return 0;
}
void
doroute(double dir, double an, double aw, double bn, double bw)
{
double an1,aw1,bn1,bw1,pn,pw;
double theta;
double cn,cw,cn1,cw1;
int i,n;
orient(an,aw,0.);
rotate(bn,bw,&bn1,&bw1);
/* printf("b %f %f\n",bn1,bw1);*/
orient(an,aw,bw1);
rinvert(0.,dir,&pn,&pw);
/* printf("p %f %f\n",pn,pw);*/
orient(pn,pw,0.);
rotate(an,aw,&an1,&aw1);
rotate(bn,bw,&bn1,&bw1);
theta = (aw1+bw1)/2;
/* printf("a %f %f \n",an1,aw1);*/
orient(pn,pw,theta);
rotate(an,aw,&an1,&aw1);
rotate(bn,bw,&bn1,&bw1);
if(fabs(aw1-bw1)>180)
if(theta<0.) theta+=180;
else theta -= 180;
orient(pn,pw,theta);
rotate(an,aw,&an1,&aw1);
rotate(bn,bw,&bn1,&bw1);
if(!track) {
double dlat, dlon, t;
/* printf("A %.4f %.4f\n",an1,aw1); */
/* printf("B %.4f %.4f\n",bn1,bw1); */
cw1 = fabs(bw1-aw1); /* angular difference for map margins */
/* while (aw<0.0)
aw += 360.;
while (bw<0.0)
bw += 360.; */
dlon = fabs(aw-bw);
if (dlon>180)
dlon = 360-dlon;
dlat = fabs(an-bn);
printf("-o %.4f %.4f %.4f -w %.2f %.2f %.2f %.2f \n",
pn,pw,theta, -0.3*cw1, .3*cw1, -.6*cw1, .6*cw1);
} else {
cn1 = 0;
n = 1 + fabs(bw1-aw1)/.2;
for(i=0;i<=n;i++) {
cw1 = aw1 + i*(bw1-aw1)/n;
rinvert(cn1,cw1,&cn,&cw);
printf("%f %f\n",cn,cw);
}
printf("\"\n");
}
}

52
src/cmd/map/sqrt.c Normal file
View File

@ -0,0 +1,52 @@
/*
sqrt returns the square root of its floating
point argument. Newton's method.
calls frexp
*/
#include <u.h>
#include <libc.h>
double
sqrt(double arg)
{
double x, temp;
int exp, i;
if(arg <= 0) {
if(arg < 0)
return 0.;
return 0;
}
x = frexp(arg, &exp);
while(x < 0.5) {
x *= 2;
exp--;
}
/*
* NOTE
* this wont work on 1's comp
*/
if(exp & 1) {
x *= 2;
exp--;
}
temp = 0.5 * (1.0+x);
while(exp > 60) {
temp *= (1L<<30);
exp -= 60;
}
while(exp < -60) {
temp /= (1L<<30);
exp += 60;
}
if(exp >= 0)
temp *= 1L << (exp/2);
else
temp /= 1L << (-exp/2);
for(i=0; i<=4; i++)
temp = 0.5*(temp + arg/temp);
return temp;
}

192
src/cmd/map/symbol.c Normal file
View File

@ -0,0 +1,192 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
#include "map.h"
#include "iplot.h"
#define NSYMBOL 20
enum flag { POINT,ENDSEG,ENDSYM };
struct symb {
double x, y;
char name[10+1];
enum flag flag;
} *symbol[NSYMBOL];
static int nsymbol;
static double halfrange = 1;
extern int halfwidth;
extern int vflag;
static int getrange(FILE *);
static int getsymbol(FILE *, int);
static void setrot(struct place *, double, int);
static void dorot(struct symb *, double *, double *);
void
getsyms(char *file)
{
FILE *sf = fopen(file,"r");
if(sf==0)
filerror("cannot open", file);
while(nsymbol<NSYMBOL-1 && getsymbol(sf,nsymbol))
nsymbol++;
fclose(sf);
}
static int
getsymbol(FILE *sf, int n)
{
double x,y;
char s[2];
int i;
struct symb *sp;
for(;;) {
if(fscanf(sf,"%1s",s)==EOF)
return 0;
switch(s[0]) {
case ':':
break;
case 'o':
case 'c': /* cl */
fscanf(sf,"%*[^\n]");
continue;
case 'r':
if(getrange(sf))
continue;
default:
error("-y file syntax error");
}
break;
}
sp = (struct symb*)malloc(sizeof(struct symb));
symbol[n] = sp;
if(fscanf(sf,"%10s",sp->name)!=1)
return 0;
i = 0;
while(fscanf(sf,"%1s",s)!=EOF) {
switch(s[0]) {
case 'r':
if(!getrange(sf))
break;
continue;
case 'm':
if(i>0)
symbol[n][i-1].flag = ENDSEG;
continue;
case ':':
ungetc(s[0],sf);
break;
default:
ungetc(s[0],sf);
case 'v':
if(fscanf(sf,"%lf %lf",&x,&y)!=2)
break;
sp[i].x = x*halfwidth/halfrange;
sp[i].y = y*halfwidth/halfrange;
sp[i].flag = POINT;
i++;
sp = symbol[n] = (struct symb*)realloc(symbol[n],
(i+1)*sizeof(struct symb));
continue;
}
break;
}
if(i>0)
symbol[n][i-1].flag = ENDSYM;
else
symbol[n] = 0;
return 1;
}
static int
getrange(FILE *sf)
{
double x,y,xmin,ymin;
if(fscanf(sf,"%*s %lf %lf %lf %lf",
&xmin,&ymin,&x,&y)!=4)
return 0;
x -= xmin;
y -= ymin;
halfrange = (x>y? x: y)/2;
if(halfrange<=0)
error("bad ra command in -y file");
return 1;
}
/* r=0 upright;=1 normal;=-1 reverse*/
int
putsym(struct place *p, char *name, double s, int r)
{
int x,y,n;
struct symb *sp;
double dx,dy;
int conn = 0;
for(n=0; symbol[n]; n++)
if(strcmp(name,symbol[n]->name)==0)
break;
sp = symbol[n];
if(sp==0)
return 0;
if(doproj(p,&x,&y)*vflag <= 0)
return 1;
setrot(p,s,r);
for(;;) {
dorot(sp,&dx,&dy);
conn = cpoint(x+(int)dx,y+(int)dy,conn);
switch(sp->flag) {
case ENDSEG:
conn = 0;
case POINT:
sp++;
continue;
case ENDSYM:
break;
}
break;
}
return 1;
}
static double rot[2][2];
static void
setrot(struct place *p, double s, int r)
{
double x0,y0,x1,y1;
struct place up;
up = *p;
up.nlat.l += .5*RAD;
sincos(&up.nlat);
if(r&&(*projection)(p,&x0,&y0)) {
if((*projection)(&up,&x1,&y1)<=0) {
up.nlat.l -= RAD;
sincos(&up.nlat);
if((*projection)(&up,&x1,&y1)<=0)
goto unit;
x1 = x0 - x1;
y1 = y0 - y1;
} else {
x1 -= x0;
y1 -= y0;
}
x1 = r*x1;
s /= hypot(x1,y1);
rot[0][0] = y1*s;
rot[0][1] = x1*s;
rot[1][0] = -x1*s;
rot[1][1] = y1*s;
} else {
unit:
rot[0][0] = rot[1][1] = s;
rot[0][1] = rot[1][0] = 0;
}
}
static void
dorot(struct symb *sp, double *px, double *py)
{
*px = rot[0][0]*sp->x + rot[0][1]*sp->y;
*py = rot[1][0]*sp->x + rot[1][1]*sp->y;
}