Why not?
This commit is contained in:
parent
a01e58366c
commit
28994509cc
210
src/cmd/jpg/bmp.c
Normal file
210
src/cmd/jpg/bmp.c
Normal 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
37
src/cmd/jpg/bmp.h
Normal 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
121
src/cmd/jpg/close.c
Normal 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
421
src/cmd/jpg/gif.c
Normal 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
506
src/cmd/jpg/ico.c
Normal 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
82
src/cmd/jpg/imagefile.h
Normal 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
346
src/cmd/jpg/jpegdump.c
Normal 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
342
src/cmd/jpg/jpg.c
Normal 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
52
src/cmd/jpg/mkfile
Normal 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
60
src/cmd/jpg/multichan.c
Normal 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
229
src/cmd/jpg/onechan.c
Normal 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
224
src/cmd/jpg/png.c
Normal 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
209
src/cmd/jpg/ppm.c
Normal 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
626
src/cmd/jpg/readbmp.c
Normal 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
535
src/cmd/jpg/readgif.c
Normal 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
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
334
src/cmd/jpg/readpng.c
Normal 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
238
src/cmd/jpg/readppm.c
Normal 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
190
src/cmd/jpg/readyuv.c
Normal 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
69
src/cmd/jpg/rgbrgbv.c
Normal 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
120
src/cmd/jpg/rgbycc.c
Normal 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
147
src/cmd/jpg/togif.c
Normal 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
322
src/cmd/jpg/toico.c
Normal 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
70
src/cmd/jpg/topng.c
Normal 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
90
src/cmd/jpg/toppm.c
Normal 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
299
src/cmd/jpg/torgbv.c
Normal 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
163
src/cmd/jpg/totruecolor.c
Normal 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
568
src/cmd/jpg/writegif.c
Normal 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
220
src/cmd/jpg/writepng.c
Normal 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
164
src/cmd/jpg/writeppm.c
Normal 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
206
src/cmd/jpg/writerawimage.c
Normal 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
211
src/cmd/jpg/yuv.c
Normal 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
88
src/cmd/map/index.c
Normal 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
51
src/cmd/map/iplot.h
Normal 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)
|
||||||
26
src/cmd/map/libmap/aitoff.c
Normal file
26
src/cmd/map/libmap/aitoff.c
Normal 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
117
src/cmd/map/libmap/albers.c
Normal 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;
|
||||||
|
}
|
||||||
19
src/cmd/map/libmap/azequalarea.c
Normal file
19
src/cmd/map/libmap/azequalarea.c
Normal 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);
|
||||||
|
}
|
||||||
19
src/cmd/map/libmap/azequidist.c
Normal file
19
src/cmd/map/libmap/azequidist.c
Normal 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);
|
||||||
|
}
|
||||||
25
src/cmd/map/libmap/bicentric.c
Normal file
25
src/cmd/map/libmap/bicentric.c
Normal 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,¢er);
|
||||||
|
return(Xbicentric);
|
||||||
|
}
|
||||||
36
src/cmd/map/libmap/bonne.c
Normal file
36
src/cmd/map/libmap/bonne.c
Normal 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);
|
||||||
|
}
|
||||||
13
src/cmd/map/libmap/ccubrt.c
Normal file
13
src/cmd/map/libmap/ccubrt.c
Normal 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);
|
||||||
|
}
|
||||||
85
src/cmd/map/libmap/complex.c
Normal file
85
src/cmd/map/libmap/complex.c
Normal 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);
|
||||||
|
}
|
||||||
27
src/cmd/map/libmap/conic.c
Normal file
27
src/cmd/map/libmap/conic.c
Normal 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);
|
||||||
|
}
|
||||||
30
src/cmd/map/libmap/cubrt.c
Normal file
30
src/cmd/map/libmap/cubrt.c
Normal 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
39
src/cmd/map/libmap/cuts.c
Normal 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;
|
||||||
|
}
|
||||||
24
src/cmd/map/libmap/cylequalarea.c
Normal file
24
src/cmd/map/libmap/cylequalarea.c
Normal 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);
|
||||||
|
}
|
||||||
19
src/cmd/map/libmap/cylindrical.c
Normal file
19
src/cmd/map/libmap/cylindrical.c
Normal 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
132
src/cmd/map/libmap/elco2.c
Normal 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);
|
||||||
|
}
|
||||||
35
src/cmd/map/libmap/elliptic.c
Normal file
35
src/cmd/map/libmap/elliptic.c
Normal 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,¢er);
|
||||||
|
return(Xelliptic);
|
||||||
|
}
|
||||||
26
src/cmd/map/libmap/fisheye.c
Normal file
26
src/cmd/map/libmap/fisheye.c
Normal 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
29
src/cmd/map/libmap/gall.c
Normal 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;
|
||||||
|
}
|
||||||
51
src/cmd/map/libmap/gilbert.c
Normal file
51
src/cmd/map/libmap/gilbert.c
Normal 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
101
src/cmd/map/libmap/guyou.c
Normal 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);
|
||||||
|
}
|
||||||
40
src/cmd/map/libmap/harrison.c
Normal file
40
src/cmd/map/libmap/harrison.c
Normal 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
122
src/cmd/map/libmap/hex.c
Normal 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
121
src/cmd/map/libmap/homing.c
Normal 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;
|
||||||
|
}
|
||||||
30
src/cmd/map/libmap/lagrange.c
Normal file
30
src/cmd/map/libmap/lagrange.c
Normal 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);
|
||||||
|
}
|
||||||
46
src/cmd/map/libmap/lambert.c
Normal file
46
src/cmd/map/libmap/lambert.c
Normal 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
24
src/cmd/map/libmap/laue.c
Normal 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
62
src/cmd/map/libmap/lune.c
Normal 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;
|
||||||
|
}
|
||||||
36
src/cmd/map/libmap/mercator.c
Normal file
36
src/cmd/map/libmap/mercator.c
Normal 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
50
src/cmd/map/libmap/mkfile
Normal 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]
|
||||||
25
src/cmd/map/libmap/mollweide.c
Normal file
25
src/cmd/map/libmap/mollweide.c
Normal 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);
|
||||||
|
}
|
||||||
28
src/cmd/map/libmap/newyorker.c
Normal file
28
src/cmd/map/libmap/newyorker.c
Normal 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);
|
||||||
|
}
|
||||||
35
src/cmd/map/libmap/orthographic.c
Normal file
35
src/cmd/map/libmap/orthographic.c
Normal 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;
|
||||||
|
}
|
||||||
84
src/cmd/map/libmap/perspective.c
Normal file
84
src/cmd/map/libmap/perspective.c
Normal 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;
|
||||||
|
}
|
||||||
28
src/cmd/map/libmap/polyconic.c
Normal file
28
src/cmd/map/libmap/polyconic.c
Normal 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);
|
||||||
|
}
|
||||||
22
src/cmd/map/libmap/rectangular.c
Normal file
22
src/cmd/map/libmap/rectangular.c
Normal 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);
|
||||||
|
}
|
||||||
34
src/cmd/map/libmap/simpleconic.c
Normal file
34
src/cmd/map/libmap/simpleconic.c
Normal 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;
|
||||||
|
}
|
||||||
17
src/cmd/map/libmap/sinusoidal.c
Normal file
17
src/cmd/map/libmap/sinusoidal.c
Normal 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
206
src/cmd/map/libmap/tetra.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
30
src/cmd/map/libmap/trapezoidal.c
Normal file
30
src/cmd/map/libmap/trapezoidal.c
Normal 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;
|
||||||
|
}
|
||||||
80
src/cmd/map/libmap/twocirc.c
Normal file
80
src/cmd/map/libmap/twocirc.c
Normal 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
143
src/cmd/map/libmap/zcoord.c
Normal 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
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
147
src/cmd/map/map.h
Normal 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
103
src/cmd/map/map.rc
Executable 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
83
src/cmd/map/mapdemo.rc
Executable 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
32
src/cmd/map/mkfile
Normal 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
131
src/cmd/map/route.c
Normal 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
52
src/cmd/map/sqrt.c
Normal 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
192
src/cmd/map/symbol.c
Normal 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;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user