cmd/pict: import 9front's graphical tools
This commit is contained in:
parent
890f126abc
commit
e8562ff537
8
sys/src/cmd/pict/README.txt
Normal file
8
sys/src/cmd/pict/README.txt
Normal file
@ -0,0 +1,8 @@
|
||||
These are the graphic tools from 9front as documented at
|
||||
|
||||
http://man.cat-v.org/9front/1/jpg
|
||||
|
||||
The whole pict/ folder should be an external package as it's not
|
||||
actually required for a minimal system.
|
||||
It's included in the main Jehanne's source tree because we don't have
|
||||
a package management system yet.
|
219
sys/src/cmd/pict/bmp.c
Normal file
219
sys/src/cmd/pict/bmp.c
Normal file
@ -0,0 +1,219 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <event.h>
|
||||
#include <keyboard.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
int cflag = 0;
|
||||
int dflag = 0;
|
||||
int eflag = 0;
|
||||
int nineflag = 0;
|
||||
int threeflag = 0;
|
||||
int output = 0;
|
||||
uint32_t outchan = CMAP8;
|
||||
int defaultcolor = 1;
|
||||
Image *image;
|
||||
|
||||
enum{
|
||||
Border = 2,
|
||||
Edge = 5
|
||||
};
|
||||
|
||||
char *show(int, char*);
|
||||
|
||||
Rawimage** readbmp(int fd, int colorspace);
|
||||
|
||||
Rectangle
|
||||
imager(Image *i)
|
||||
{
|
||||
Point p1, p2;
|
||||
|
||||
p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min);
|
||||
p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
|
||||
return rectaddpt(i->r, subpt(p2, p1));
|
||||
}
|
||||
|
||||
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 = imager(image);
|
||||
border(screen, r, -Border, nil, ZP);
|
||||
drawop(screen, r, image, nil, image->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: 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==Kdel || ch==Keof)
|
||||
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;
|
||||
}
|
39
sys/src/cmd/pict/bmp.h
Normal file
39
sys/src/cmd/pict/bmp.h
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
#define BMP_RGB 0
|
||||
#define BMP_RLE8 1
|
||||
#define BMP_RLE4 2
|
||||
#define BMP_BITFIELDS 3
|
||||
|
||||
typedef struct {
|
||||
unsigned char red;
|
||||
unsigned char green;
|
||||
unsigned char blue;
|
||||
unsigned char alpha;
|
||||
} Rgb;
|
||||
|
||||
#define Filehdrsz 14
|
||||
|
||||
typedef struct {
|
||||
short type;
|
||||
long size; /* file size, not structure 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;
|
47
sys/src/cmd/pict/build.json
Normal file
47
sys/src/cmd/pict/build.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"Cmd": {
|
||||
"Include": [
|
||||
"../cmd.json"
|
||||
],
|
||||
"Install": "/arch/$ARCH/cmd/pict/",
|
||||
"SourceFiles": [
|
||||
"torgbv.c",
|
||||
"totruecolor.c",
|
||||
"writerawimage.c",
|
||||
"readjpg.c",
|
||||
"writejpg.c",
|
||||
"multichan.c",
|
||||
"readgif.c",
|
||||
"writegif.c",
|
||||
"onechan.c",
|
||||
"readpng.c",
|
||||
"writepng.c",
|
||||
"readppm.c",
|
||||
"writeppm.c",
|
||||
"readtif.c",
|
||||
"writetif.c",
|
||||
"readyuv.c",
|
||||
"readbmp.c",
|
||||
"readtga.c",
|
||||
"readv210.c"
|
||||
],
|
||||
"SourceFilesCmd": [
|
||||
"jpg.c",
|
||||
"tojpg.c",
|
||||
"gif.c",
|
||||
"togif.c",
|
||||
"ppm.c",
|
||||
"toppm.c",
|
||||
"png.c",
|
||||
"topng.c",
|
||||
"tif.c",
|
||||
"totif.c",
|
||||
"yuv.c",
|
||||
"ico.c",
|
||||
"toico.c",
|
||||
"bmp.c",
|
||||
"tga.c",
|
||||
"v210.c"
|
||||
]
|
||||
}
|
||||
}
|
121
sys/src/cmd/pict/close.c
Normal file
121
sys/src/cmd/pict/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");
|
||||
}
|
||||
}
|
437
sys/src/cmd/pict/gif.c
Normal file
437
sys/src/cmd/pict/gif.c
Normal file
@ -0,0 +1,437 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <event.h>
|
||||
#include <keyboard.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
int cflag = 0;
|
||||
int dflag = 0;
|
||||
int eflag = 0;
|
||||
int nineflag = 0;
|
||||
int threeflag = 0;
|
||||
int output = 0;
|
||||
uint32_t outchan = CMAP8;
|
||||
Image **allims;
|
||||
int which;
|
||||
int defaultcolor = 1;
|
||||
|
||||
enum{
|
||||
Border = 2,
|
||||
Edge = 5
|
||||
};
|
||||
|
||||
char *show(int, char*);
|
||||
|
||||
Rectangle
|
||||
imager(void)
|
||||
{
|
||||
Point p1, p2;
|
||||
|
||||
if(allims==nil || allims[0]==nil)
|
||||
return screen->r;
|
||||
|
||||
p1 = addpt(divpt(subpt(allims[0]->r.max, allims[0]->r.min), 2), allims[0]->r.min);
|
||||
p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
|
||||
return rectaddpt(allims[0]->r, subpt(p2, p1));
|
||||
}
|
||||
|
||||
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);
|
||||
draw(screen, r, allims[which], nil, allims[which]->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: 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;
|
||||
unsigned char *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 */
|
||||
unsigned char*
|
||||
expand(unsigned char *u, int chanlen, int nchan)
|
||||
{
|
||||
int j, k;
|
||||
unsigned char *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
|
||||
blackout(Rawimage *r, Rawimage *c)
|
||||
{
|
||||
int i, trindex;
|
||||
unsigned char *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++ = 0x00;
|
||||
*cp++ = 0x00;
|
||||
*cp++ = 0x00;
|
||||
}else{
|
||||
*cp++ = 0xFF;
|
||||
cp += 3;
|
||||
}
|
||||
rp++;
|
||||
}
|
||||
else
|
||||
for(i=0; i<r->chanlen; i++){
|
||||
if(*rp == trindex){
|
||||
*cp++ = 0x00;
|
||||
*cp++ = 0x00;
|
||||
}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 *tmp, *msk, *img, *dst, **ims;
|
||||
Rectangle r;
|
||||
int j, k, n, ch, nloop, loopcount, dt;
|
||||
char *err;
|
||||
char buf[32];
|
||||
|
||||
err = nil;
|
||||
images = readgif(fd, CRGB, dflag);
|
||||
if(images == nil){
|
||||
fprint(2, "gif: decode %s failed: %r\n", name);
|
||||
return "decode";
|
||||
}
|
||||
for(n=0; images[n]; n++)
|
||||
if(n == 0)
|
||||
r = images[n]->r;
|
||||
else
|
||||
combinerect(&r, images[n]->r);
|
||||
tmp = nil;
|
||||
ims = malloc((n+1)*sizeof(Image*));
|
||||
rgbv = malloc((n+1)*sizeof(Rawimage*));
|
||||
if(rgbv==nil || ims==nil){
|
||||
fprint(2, "gif: malloc of masks for %s failed: %r\n", name);
|
||||
err = "malloc";
|
||||
goto Return;
|
||||
}
|
||||
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){
|
||||
msk = transparency(images[k], name);
|
||||
if(rgbv[k]->chandesc == CY)
|
||||
img = allocimage(display, rgbv[k]->r, GREY8, 0, 0);
|
||||
else
|
||||
img = allocimage(display, rgbv[k]->r, outchan, 0, 0);
|
||||
if(tmp == nil)
|
||||
tmp = allocimage(display, r, img->chan, 0, DWhite);
|
||||
ims[k]= dst = allocimage(display, r, tmp->chan, 0, DWhite);
|
||||
if(tmp == nil || img == nil || dst == nil){
|
||||
fprint(2, "gif: allocimage %s failed: %r\n", name);
|
||||
err = "allocimage";
|
||||
goto Return;
|
||||
}
|
||||
if(loadimage(img, img->r, rgbv[k]->chans[0], rgbv[k]->chanlen) < 0){
|
||||
fprint(2, "gif: loadimage %s failed: %r\n", name);
|
||||
err = "loadimage";
|
||||
goto Return;
|
||||
}
|
||||
switch((images[k]->gifflags>>2)&7){
|
||||
default:
|
||||
draw(tmp, img->r, img, msk, img->r.min);
|
||||
draw(dst, tmp->r, tmp, nil, tmp->r.min);
|
||||
break;
|
||||
case 2:
|
||||
draw(tmp, img->r, display->white, msk, img->r.min);
|
||||
/* no break */
|
||||
case 3:
|
||||
draw(dst, tmp->r, tmp, nil, tmp->r.min);
|
||||
draw(dst, img->r, img, msk, img->r.min);
|
||||
break;
|
||||
}
|
||||
freeimage(msk);
|
||||
freeimage(img);
|
||||
}
|
||||
}
|
||||
if(tmp)
|
||||
freeimage(tmp);
|
||||
|
||||
allims = ims;
|
||||
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()){
|
||||
/* an odd, democratic list */
|
||||
if((ch=ekbd())=='q' || ch==Kdel || ch==Keof)
|
||||
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:
|
||||
draw(screen, screen->clipr, display->white, nil, ZP);
|
||||
}
|
||||
if(nineflag){
|
||||
if(images[0]->gifflags&TRANSP){
|
||||
addalpha(rgbv[0]);
|
||||
blackout(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]);
|
||||
blackout(images[0], rgbv[0]);
|
||||
}
|
||||
if(writerawimage(1, rgbv[0]) < 0){
|
||||
fprint(2, "gif: %s: write error: %r\n", name);
|
||||
return "write";
|
||||
}
|
||||
}
|
||||
|
||||
Return:
|
||||
allims = 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]);
|
||||
free(images[k]);
|
||||
free(rgbv[k]);
|
||||
}
|
||||
free(images);
|
||||
free(ims);
|
||||
return err;
|
||||
}
|
627
sys/src/cmd/pict/ico.c
Normal file
627
sys/src/cmd/pict/ico.c
Normal file
@ -0,0 +1,627 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <event.h>
|
||||
#include <cursor.h>
|
||||
|
||||
#include "imagefile.h"
|
||||
|
||||
typedef struct Icon Icon;
|
||||
struct Icon
|
||||
{
|
||||
Icon *next;
|
||||
|
||||
unsigned char w; /* icon width */
|
||||
unsigned char h; /* icon height */
|
||||
unsigned short ncolor; /* number of colors */
|
||||
unsigned short nplane; /* number of bit planes */
|
||||
unsigned short bits; /* bits per pixel */
|
||||
uint32_t len; /* length of data */
|
||||
uint32_t offset; /* file offset to data */
|
||||
|
||||
Memimage *img;
|
||||
Memimage *mask;
|
||||
|
||||
Rectangle r; /* relative */
|
||||
Rectangle sr; /* abs */
|
||||
};
|
||||
|
||||
typedef struct Header Header;
|
||||
struct Header
|
||||
{
|
||||
uint n;
|
||||
Icon *first;
|
||||
Icon *last;
|
||||
};
|
||||
|
||||
int debug;
|
||||
int cflag;
|
||||
Mouse mouse;
|
||||
Header h;
|
||||
Image *background;
|
||||
|
||||
unsigned short
|
||||
gets(unsigned char *p)
|
||||
{
|
||||
return p[0] | (p[1]<<8);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
getl(unsigned char *p)
|
||||
{
|
||||
return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
|
||||
}
|
||||
|
||||
int
|
||||
Bgetheader(Biobuf *b, Header *h)
|
||||
{
|
||||
unsigned char buf[40];
|
||||
Icon *icon;
|
||||
int i;
|
||||
|
||||
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] == 0 ? 256 : buf[0];
|
||||
icon->h = buf[1] == 0 ? 256 : buf[1];
|
||||
icon->ncolor = buf[2] == 0 ? 256 : buf[2];
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned char*
|
||||
transcmap(Icon *icon, int ncolor, unsigned char *map)
|
||||
{
|
||||
unsigned char *m, *p;
|
||||
int i;
|
||||
|
||||
p = m = mallocz(sizeof(int)*(1<<icon->bits), 1);
|
||||
if(m == nil)
|
||||
sysfatal("malloc: %r");
|
||||
for(i = 0; i < ncolor; i++){
|
||||
*p++ = rgb2cmap(map[2], map[1], map[0]);
|
||||
map += 4;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
Memimage*
|
||||
xor2img(Icon *icon, long chan, unsigned char *xor, unsigned char *map)
|
||||
{
|
||||
unsigned char *data;
|
||||
Memimage *img;
|
||||
int inxlen;
|
||||
unsigned char *from, *to;
|
||||
int s, byte, mask;
|
||||
int x, y;
|
||||
|
||||
inxlen = 4*((icon->bits*icon->w+31)/32);
|
||||
img = allocmemimage(Rect(0,0,icon->w,icon->h), chan);
|
||||
if(img == nil)
|
||||
return nil;
|
||||
|
||||
if(chan != CMAP8){
|
||||
from = xor + icon->h*inxlen;
|
||||
for(y = 0; y < icon->h; y++){
|
||||
from -= inxlen;
|
||||
loadmemimage(img, Rect(0,y,icon->w,y+1), from, inxlen);
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
to = data = malloc(icon->w*icon->h);
|
||||
if(data == nil){
|
||||
freememimage(img);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
loadmemimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w);
|
||||
free(data);
|
||||
return img;
|
||||
}
|
||||
|
||||
Memimage*
|
||||
and2img(Icon *icon, unsigned char *and)
|
||||
{
|
||||
unsigned char *data;
|
||||
Memimage *img;
|
||||
int inxlen;
|
||||
int outxlen;
|
||||
unsigned char *from, *to;
|
||||
int x, y;
|
||||
|
||||
inxlen = 4*((icon->w+31)/32);
|
||||
to = data = malloc(inxlen*icon->h);
|
||||
if(data == nil)
|
||||
return nil;
|
||||
|
||||
/* 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 */
|
||||
if(img = allocmemimage(Rect(0,0,icon->w,icon->h), GREY1))
|
||||
loadmemimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*outxlen);
|
||||
|
||||
free(data);
|
||||
return img;
|
||||
}
|
||||
|
||||
int
|
||||
Bgeticon(Biobuf *b, Icon *icon)
|
||||
{
|
||||
unsigned char *end;
|
||||
unsigned char *xor;
|
||||
unsigned char *and;
|
||||
unsigned char *cm;
|
||||
unsigned char *buf;
|
||||
unsigned char *map2map;
|
||||
Memimage *img;
|
||||
unsigned char magic[4];
|
||||
int ncolor;
|
||||
long chan;
|
||||
|
||||
Bseek(b, icon->offset, 0);
|
||||
if(Bread(b, magic, 4) != 4){
|
||||
werrstr("unexpected EOF");
|
||||
return -1;
|
||||
}
|
||||
if(magic[0] == 137 && memcmp(magic+1, "PNG", 3) == 0){
|
||||
Rawimage **png;
|
||||
|
||||
Bseek(b, -4, 1);
|
||||
png = Breadpng(b, CRGB);
|
||||
if(png == nil || png[0] == nil)
|
||||
return -1;
|
||||
switch(png[0]->chandesc){
|
||||
case CY:
|
||||
chan = GREY8;
|
||||
break;
|
||||
case CYA16:
|
||||
chan = CHAN2(CGrey, 8, CAlpha, 8);
|
||||
break;
|
||||
case CRGB24:
|
||||
chan = RGB24;
|
||||
break;
|
||||
case CRGBA32:
|
||||
chan = RGBA32;
|
||||
break;
|
||||
default:
|
||||
werrstr("bad icon png channel descriptor");
|
||||
return -1;
|
||||
}
|
||||
icon->mask = nil;
|
||||
icon->img = allocmemimage(png[0]->r, chan);
|
||||
loadmemimage(icon->img, icon->img->r, png[0]->chans[0], png[0]->chanlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(getl(magic) != 40){
|
||||
werrstr("bad icon bmp header");
|
||||
return -1;
|
||||
}
|
||||
if(icon->len < 40){
|
||||
werrstr("bad icon bmp header length");
|
||||
return -1;
|
||||
}
|
||||
buf = malloc(icon->len);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
memmove(buf, magic, 4);
|
||||
if(Bread(b, buf+4, icon->len-4) != icon->len-4){
|
||||
werrstr("unexpected EOF");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* this header's info takes precedence over previous one */
|
||||
ncolor = 0;
|
||||
icon->w = getl(buf+4);
|
||||
icon->h = getl(buf+8)>>1;
|
||||
icon->nplane = gets(buf+12);
|
||||
icon->bits = gets(buf+14);
|
||||
|
||||
/* limit what we handle */
|
||||
switch(icon->bits){
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
ncolor = icon->ncolor;
|
||||
if(ncolor > (1<<icon->bits))
|
||||
ncolor = 1<<icon->bits;
|
||||
chan = CMAP8;
|
||||
break;
|
||||
case 15:
|
||||
case 16:
|
||||
chan = RGB16;
|
||||
break;
|
||||
case 24:
|
||||
chan = RGB24;
|
||||
break;
|
||||
case 32:
|
||||
chan = ARGB32;
|
||||
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;
|
||||
}
|
||||
|
||||
xor = cm = buf + 40;
|
||||
if(chan == CMAP8)
|
||||
xor += 4*ncolor;
|
||||
end = xor + icon->h*4*((icon->bits*icon->w+31)/32);
|
||||
if(end < buf || end > buf+icon->len){
|
||||
werrstr("bad icon length %zux != %lux", end - buf, icon->len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* translate the color map to a plan 9 one */
|
||||
map2map = nil;
|
||||
if(chan == CMAP8)
|
||||
map2map = transcmap(icon, ncolor, cm);
|
||||
|
||||
/* convert the images */
|
||||
icon->img = xor2img(icon, chan, xor, map2map);
|
||||
if(icon->img == nil){
|
||||
werrstr("xor2img: %r");
|
||||
return -1;
|
||||
}
|
||||
icon->mask = nil;
|
||||
|
||||
/* check for and mask */
|
||||
and = end;
|
||||
end += icon->h*4*((icon->w+31)/32);
|
||||
if(end <= buf+icon->len)
|
||||
icon->mask = and2img(icon, and);
|
||||
|
||||
/* so that we save an image with a white background */
|
||||
if(img = allocmemimage(icon->img->r, icon->img->chan)){
|
||||
memfillcolor(img, DWhite);
|
||||
memimagedraw(img, icon->img->r, icon->img, ZP, icon->mask, ZP, SoverD);
|
||||
freememimage(icon->img);
|
||||
icon->img = img;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(map2map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [ -c ] [ 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 = writememimage(fd, icon->img);
|
||||
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;
|
||||
|
||||
if(icon->mask == nil)
|
||||
return;
|
||||
|
||||
rv = -1;
|
||||
snprint(file, sizeof(file), "%dx%d.mask", icon->w, icon->h);
|
||||
fd = create(file, OWRITE, 0664);
|
||||
if(fd >= 0){
|
||||
rv = writememimage(fd, icon->mask);
|
||||
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,
|
||||
};
|
||||
|
||||
Image*
|
||||
screenimage(Memimage *m)
|
||||
{
|
||||
Rectangle r;
|
||||
Image *i;
|
||||
|
||||
if(i = allocimage(display, m->r, m->chan, 0, DNofill)){
|
||||
r = m->r;
|
||||
while(r.min.y < m->r.max.y){
|
||||
r.max.y = r.min.y+1;
|
||||
loadimage(i, r, byteaddr(m, r.min), bytesperline(r, m->depth));
|
||||
r.min.y++;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
eresized(int new)
|
||||
{
|
||||
Icon *icon;
|
||||
Image *i;
|
||||
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);
|
||||
if(i = screenimage(icon->img)){
|
||||
draw(screen, r, i, nil, ZP);
|
||||
freeimage(i);
|
||||
}
|
||||
border(screen, r, -BORDER, display->black, ZP);
|
||||
icon->sr = r;
|
||||
}
|
||||
flushimage(display, 1);
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Biobuf in;
|
||||
Icon *icon;
|
||||
int num, fd;
|
||||
Rectangle r;
|
||||
Event e;
|
||||
|
||||
ARGBEGIN{
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'c':
|
||||
cflag = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}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;
|
||||
}
|
||||
|
||||
memimageinit();
|
||||
Binit(&in, fd, OREAD);
|
||||
|
||||
if(Bgetheader(&in, &h) < 0)
|
||||
sysfatal("reading header: %r");
|
||||
|
||||
num = 0;
|
||||
r.min = Pt(4, 4);
|
||||
for(icon = h.first; icon != nil; icon = icon->next){
|
||||
if(Bgeticon(&in, icon) < 0){
|
||||
fprint(2, "%s: read fail: %r\n", argv0);
|
||||
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;
|
||||
if(cflag){
|
||||
writememimage(1, icon->img);
|
||||
exits(0);
|
||||
}
|
||||
r.min.x += r.max.x;
|
||||
num++;
|
||||
}
|
||||
|
||||
if(num == 0 || cflag)
|
||||
sysfatal("no images");
|
||||
|
||||
initdraw(nil, nil, "ico");
|
||||
background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x808080FF);
|
||||
eresized(0);
|
||||
einit(Emouse|Ekeyboard);
|
||||
for(;;)
|
||||
switch(event(&e)){
|
||||
case Ekeyboard:
|
||||
break;
|
||||
case Emouse:
|
||||
mouse = e.mouse;
|
||||
if(mouse.buttons & 4)
|
||||
menu();
|
||||
else
|
||||
mousemoved();
|
||||
break;
|
||||
}
|
||||
/* not reached */
|
||||
}
|
86
sys/src/cmd/pict/imagefile.h
Normal file
86
sys/src/cmd/pict/imagefile.h
Normal file
@ -0,0 +1,86 @@
|
||||
typedef struct Rawimage Rawimage;
|
||||
|
||||
struct Rawimage
|
||||
{
|
||||
Rectangle r;
|
||||
unsigned char *cmap;
|
||||
int cmaplen;
|
||||
int nchans;
|
||||
unsigned char *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 {
|
||||
uint32_t fields_set;
|
||||
double gamma;
|
||||
char *comment;
|
||||
} ImageInfo;
|
||||
|
||||
|
||||
Rawimage** readjpg(int, int);
|
||||
Rawimage** Breadjpg(Biobuf*, int);
|
||||
Rawimage** readpng(int, int);
|
||||
Rawimage** Breadpng(Biobuf*, int);
|
||||
Rawimage** readtif(int, int);
|
||||
Rawimage** Breadtif(Biobuf*, int);
|
||||
Rawimage** readgif(int, int, int);
|
||||
Rawimage** readpixmap(int, int);
|
||||
Rawimage* torgbv(Rawimage*, int);
|
||||
Rawimage* totruecolor(Rawimage*, int);
|
||||
int writerawimage(int, Rawimage*);
|
||||
void* _remaperror(char*, ...);
|
||||
|
||||
typedef struct Memimage Memimage; /* avoid necessity to include memdraw.h */
|
||||
|
||||
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*, int);
|
||||
char* memwriteppm(Biobuf*, Memimage*, char*, int);
|
||||
char* writejpg(Biobuf*, Image*, char*, int, int);
|
||||
char* memwritejpg(Biobuf*, Memimage*, char*, int, int);
|
||||
Image* multichan(Image*);
|
||||
Memimage* memmultichan(Memimage*);
|
||||
|
||||
char* memwritepng(Biobuf*, Memimage*, ImageInfo*);
|
||||
|
||||
char* writetif(Biobuf*, Image*, char*, int, int);
|
||||
char* memwritetif(Biobuf*, Memimage*, char*, int, int);
|
346
sys/src/cmd/pict/jpegdump.c
Normal file
346
sys/src/cmd/pict/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;
|
||||
}
|
||||
}
|
357
sys/src/cmd/pict/jpg.c
Normal file
357
sys/src/cmd/pict/jpg.c
Normal file
@ -0,0 +1,357 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <event.h>
|
||||
#include <keyboard.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;
|
||||
uint32_t outchan = CMAP8;
|
||||
Image *image;
|
||||
int defaultcolor = 1;
|
||||
|
||||
enum{
|
||||
Border = 2,
|
||||
Edge = 5
|
||||
};
|
||||
|
||||
char *show(int, char*, int);
|
||||
|
||||
Rectangle
|
||||
imager(Image *i)
|
||||
{
|
||||
Point p1, p2;
|
||||
|
||||
p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min);
|
||||
p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
|
||||
return rectaddpt(i->r, subpt(p2, p1));
|
||||
}
|
||||
|
||||
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 = imager(image);
|
||||
border(screen, r, -Border, nil, ZP);
|
||||
drawop(screen, r, image, nil, image->r.min, S);
|
||||
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 -39cdefFkJrtvy [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: malloc\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++) {
|
||||
unsigned char *po, *p1, *p2;
|
||||
|
||||
ao->chans[c] = malloc(ao->chanlen);
|
||||
if (ao->chans[c] == nil){
|
||||
fprint(2, "jpg: vidmerge: malloc chan\n");
|
||||
return nil;
|
||||
}
|
||||
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){
|
||||
if (!inited) {
|
||||
if(initdraw(0, 0, 0) < 0){
|
||||
fprint(2, "jpg: initdraw failed: %r\n");
|
||||
return "initdraw";
|
||||
}
|
||||
if(Fflag == 0)
|
||||
einit(Ekeyboard|Emouse);
|
||||
inited++;
|
||||
}
|
||||
if(defaultcolor && screen->depth>8 && outchan==CMAP8)
|
||||
outchan = RGB24;
|
||||
}
|
||||
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==Kdel || ch==Keof)
|
||||
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;
|
||||
}
|
54
sys/src/cmd/pict/multichan.c
Normal file
54
sys/src/cmd/pict/multichan.c
Normal file
@ -0,0 +1,54 @@
|
||||
#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 */
|
||||
|
||||
static
|
||||
int
|
||||
notrans(uint32_t 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
sys/src/cmd/pict/onechan.c
Normal file
229
sys/src/cmd/pict/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(uint32_t chan)
|
||||
{
|
||||
switch(chan){
|
||||
case GREY1:
|
||||
case GREY2:
|
||||
case GREY4:
|
||||
case CMAP8:
|
||||
case GREY8:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
easycase(uint32_t 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
|
||||
unsigned char*
|
||||
load(Image *image, Memimage *memimage)
|
||||
{
|
||||
unsigned char *data, *p, *q0, *q1, *q2;
|
||||
unsigned char *rgbv;
|
||||
int depth, ndata, dx, dy, i, v;
|
||||
uint32_t 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)
|
||||
{
|
||||
unsigned char *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)
|
||||
{
|
||||
unsigned char *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;
|
||||
}
|
250
sys/src/cmd/pict/png.c
Normal file
250
sys/src/cmd/pict/png.c
Normal file
@ -0,0 +1,250 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <event.h>
|
||||
#include <keyboard.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
extern int debug;
|
||||
int cflag = 0;
|
||||
int dflag = 0;
|
||||
int eflag = 0;
|
||||
int nineflag = 0;
|
||||
int threeflag = 0;
|
||||
int output = 0;
|
||||
uint32_t outchan = CMAP8;
|
||||
Image *image;
|
||||
int defaultcolor = 1;
|
||||
|
||||
enum{
|
||||
Border = 2,
|
||||
Edge = 5
|
||||
};
|
||||
|
||||
char *show(int, char*, int);
|
||||
|
||||
Rectangle
|
||||
imager(Image *i)
|
||||
{
|
||||
Point p1, p2;
|
||||
|
||||
p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min);
|
||||
p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
|
||||
return rectaddpt(i->r, subpt(p2, p1));
|
||||
}
|
||||
|
||||
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 = imager(image);
|
||||
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 '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 '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;
|
||||
|
||||
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;
|
||||
Image *i, *i2;
|
||||
int j, ch, outchan;
|
||||
long len;
|
||||
Biobuf b;
|
||||
char buf[32];
|
||||
static int inited;
|
||||
|
||||
if(Binit(&b, fd, OREAD) < 0)
|
||||
return nil;
|
||||
outchan = outc;
|
||||
array = Breadpng(&b, CRGB);
|
||||
if(array == nil || array[0]==nil){
|
||||
fprint(2, "png: decode %s failed: %r\n", name);
|
||||
return "decode";
|
||||
}
|
||||
Bterm(&b);
|
||||
|
||||
r = array[0];
|
||||
if(!dflag){
|
||||
if (!inited) {
|
||||
if(initdraw(0, 0, 0) < 0){
|
||||
fprint(2, "png: initdraw failed: %r\n");
|
||||
return "initdraw";
|
||||
}
|
||||
einit(Ekeyboard|Emouse);
|
||||
inited++;
|
||||
}
|
||||
if(defaultcolor && screen->depth>8 && outchan==CMAP8)
|
||||
outchan = RGB24;
|
||||
}
|
||||
if(outchan == CMAP8)
|
||||
c = torgbv(r, !eflag);
|
||||
else{
|
||||
switch(r->chandesc){
|
||||
case CY:
|
||||
outchan = GREY8;
|
||||
break;
|
||||
case CYA16:
|
||||
outchan = CHAN2(CGrey, 8, CAlpha, 8);
|
||||
break;
|
||||
case CRGB24:
|
||||
outchan = RGB24;
|
||||
break;
|
||||
case CRGBA32:
|
||||
outchan = RGBA32;
|
||||
break;
|
||||
}
|
||||
c = r;
|
||||
}
|
||||
if(c == nil){
|
||||
fprint(2, "png: conversion of %s failed: %r\n", name);
|
||||
return "torgbv";
|
||||
}
|
||||
if(!dflag){
|
||||
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 of %d bytes failed: %r\n",
|
||||
name, c->chanlen);
|
||||
return "loadimage";
|
||||
}
|
||||
i2 = allocimage(display, c->r, outchan, 0, 0);
|
||||
draw(i2, i2->r, display->black, nil, ZP);
|
||||
draw(i2, i2->r, i, nil, i->r.min);
|
||||
image = i2;
|
||||
eresized(0);
|
||||
if((ch=ekbd())=='q' || ch==Kdel || ch==Keof)
|
||||
exits(nil);
|
||||
draw(screen, screen->clipr, display->white, nil, ZP);
|
||||
image = nil;
|
||||
freeimage(i);
|
||||
}
|
||||
if(nineflag){
|
||||
chantostr(buf, outchan);
|
||||
len = (c->r.max.x - c->r.min.x) * (c->r.max.y - c->r.min.y);
|
||||
switch(c->chandesc){
|
||||
case CY:
|
||||
// len *= 1;
|
||||
break;
|
||||
case CYA16:
|
||||
len *= 2;
|
||||
break;
|
||||
case CRGB24:
|
||||
len *= 3;
|
||||
break;
|
||||
case CRGBA32:
|
||||
len *= 4;
|
||||
break;
|
||||
}
|
||||
if(c->chanlen != len)
|
||||
fprint(2, "%s: writing %d bytes for len %ld chan %s\n",
|
||||
argv0, c->chanlen, len, buf);
|
||||
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 && c != r){
|
||||
free(c->chans[0]);
|
||||
free(c);
|
||||
}
|
||||
return nil;
|
||||
}
|
219
sys/src/cmd/pict/ppm.c
Normal file
219
sys/src/cmd/pict/ppm.c
Normal file
@ -0,0 +1,219 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <event.h>
|
||||
#include <keyboard.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
int cflag = 0;
|
||||
int dflag = 0;
|
||||
int eflag = 0;
|
||||
int nineflag = 0;
|
||||
int threeflag = 0;
|
||||
int output = 0;
|
||||
uint32_t outchan = CMAP8;
|
||||
int defaultcolor = 1;
|
||||
Image *image;
|
||||
|
||||
enum{
|
||||
Border = 2,
|
||||
Edge = 5
|
||||
};
|
||||
|
||||
char *show(int, char*);
|
||||
|
||||
Rectangle
|
||||
imager(Image *i)
|
||||
{
|
||||
Point p1, p2;
|
||||
|
||||
p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min);
|
||||
p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
|
||||
return rectaddpt(i->r, subpt(p2, p1));
|
||||
}
|
||||
|
||||
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 = imager(image);
|
||||
border(screen, r, -Border, nil, ZP);
|
||||
drawop(screen, r, image, nil, image->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: 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)
|
||||
outchan = GREY8;
|
||||
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==Kdel || ch==Keof)
|
||||
exits(nil);
|
||||
draw(screen, screen->clipr, display->white, nil, ZP);
|
||||
image = nil;
|
||||
freeimage(i);
|
||||
}
|
||||
if(nineflag){
|
||||
if(r->chandesc == CY)
|
||||
outchan = GREY8;
|
||||
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
sys/src/cmd/pict/readbmp.c
Normal file
626
sys/src/cmd/pict/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(uint32_t 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 = (uint)Bgetc(b);
|
||||
|
||||
if(0 != val) {
|
||||
valS = (uint)Bgetc(b);
|
||||
p = &buf[ix + iy * width];
|
||||
while(val--) {
|
||||
*p = clut[0xf & (valS >> 4)];
|
||||
p++;
|
||||
ix++;
|
||||
if(val != 0) {
|
||||
*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 = (uint)Bgetc(b);
|
||||
ix += val;
|
||||
val = (uint)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(val != 0) {
|
||||
*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)
|
||||
{
|
||||
unsigned char 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((uint32_t)mask_blue) - 8;
|
||||
int shft_green = msb((uint32_t)mask_green) - 8;
|
||||
int shft_red = msb((uint32_t)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 = (unsigned char)((val & mask_blue) >> shft_blue);
|
||||
else
|
||||
buf[i].blue = (unsigned char)((val & mask_blue) << -shft_blue);
|
||||
if(shft_green >= 0)
|
||||
buf[i].green = (unsigned char)((val & mask_green) >> shft_green);
|
||||
else
|
||||
buf[i].green = (unsigned char)((val & mask_green) << -shft_green);
|
||||
if(shft_red >= 0)
|
||||
buf[i].red = (unsigned char)((val & mask_red) >> shft_red);
|
||||
else
|
||||
buf[i].red = (unsigned char)((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 = (unsigned char)((c[0] << 3) & 0xf8);
|
||||
buf[i].green = (unsigned char)(((((unsigned)c[1] << 6) +
|
||||
(((unsigned)c[0]) >> 2))) & 0xf8);
|
||||
buf[i].red = (unsigned char)((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)
|
||||
{
|
||||
unsigned char 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) {
|
||||
uint32_t mask_blue = (uint32_t)clut[0].blue +
|
||||
((uint32_t)clut[0].green << 8) +
|
||||
((uint32_t)clut[0].red << 16) +
|
||||
((uint32_t)clut[0].alpha << 24);
|
||||
uint32_t mask_green = (uint32_t)clut[1].blue +
|
||||
((uint32_t)clut[1].green << 8) +
|
||||
((uint32_t)clut[1].red << 16) +
|
||||
((uint32_t)clut[1].alpha << 24);
|
||||
uint32_t mask_red = (uint32_t)clut[2].blue +
|
||||
((uint32_t)clut[2].green << 8) +
|
||||
((uint32_t)clut[2].red << 16) +
|
||||
((uint32_t)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++) {
|
||||
uint32_t val;
|
||||
Bread(b, c, sizeof(c));
|
||||
val = (uint32_t)c[0] + ((uint32_t)c[1] << 8) +
|
||||
((uint32_t)c[2] << 16) + ((uint32_t)c[1] << 24);
|
||||
|
||||
buf[i].alpha = 0;
|
||||
if(shft_blue >= 0)
|
||||
buf[i].blue = (unsigned char)((val & mask_blue) >> shft_blue);
|
||||
else
|
||||
buf[i].blue = (unsigned char)((val & mask_blue) << -shft_blue);
|
||||
if(shft_green >= 0)
|
||||
buf[i].green = (unsigned char)((val & mask_green) >> shft_green);
|
||||
else
|
||||
buf[i].green = (unsigned char)((val & mask_green) << -shft_green);
|
||||
if(shft_red >= 0)
|
||||
buf[i].red = (unsigned char)((val & mask_red) >> shft_red);
|
||||
else
|
||||
buf[i].red = (unsigned char)((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 + Filehdrsz, 0);
|
||||
|
||||
for(i = 0; i < num_coltab; i++) {
|
||||
clut[i].blue = (unsigned char)Bgetc(b);
|
||||
clut[i].green = (unsigned char)Bgetc(b);
|
||||
clut[i].red = (unsigned char)Bgetc(b);
|
||||
clut[i].alpha = (unsigned char)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;
|
||||
unsigned char *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;
|
||||
}
|
||||
|
||||
|
545
sys/src/cmd/pict/readgif.c
Normal file
545
sys/src/cmd/pict/readgif.c
Normal file
@ -0,0 +1,545 @@
|
||||
#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;
|
||||
unsigned char buf[3*256];
|
||||
char vers[8];
|
||||
unsigned char *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;
|
||||
|
||||
unsigned char *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*, int);
|
||||
static Rawimage* readone(Header*);
|
||||
static void readheader(Header*);
|
||||
static void skipextension(Header*);
|
||||
static unsigned char* readcmap(Header*, int);
|
||||
static unsigned char* decode(Header*, Rawimage*, Entry*);
|
||||
static void interlace(Header*, Rawimage*);
|
||||
|
||||
static
|
||||
void
|
||||
_clear(void **p)
|
||||
{
|
||||
if(*p){
|
||||
free(*p);
|
||||
*p = nil;
|
||||
}
|
||||
}
|
||||
#define clear(p) _clear((void**)p)
|
||||
|
||||
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("%s", h->err);
|
||||
giffreeall(h, 1);
|
||||
longjmp(h->errlab, 1);
|
||||
}
|
||||
|
||||
|
||||
Rawimage**
|
||||
readgif(int fd, int colorspace, int justone)
|
||||
{
|
||||
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, justone);
|
||||
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, int justone)
|
||||
{
|
||||
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{
|
||||
if(h->globalcmap == nil)
|
||||
giferror(h, "ReadGIF: globalcmap missing");
|
||||
new->cmaplen = 3*(1<<((h->fields&7)+1));
|
||||
new->cmap = malloc(new->cmaplen);
|
||||
if(new->cmap == nil)
|
||||
giferror(h, memerr);
|
||||
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;
|
||||
if(justone)
|
||||
goto Return;
|
||||
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
|
||||
unsigned char*
|
||||
readcmap(Header *h, int size)
|
||||
{
|
||||
unsigned char *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;
|
||||
memset(i->chans, 0, sizeof(i->chans));
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int
|
||||
readdata(Header *h, unsigned char *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;
|
||||
unsigned char 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){
|
||||
/*
|
||||
* This code used to check h->buf[hsize-1] != 0
|
||||
* and giferror if so, but if !hasdata, hsize == 0.
|
||||
*/
|
||||
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
|
||||
unsigned char*
|
||||
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;
|
||||
unsigned char clip, *p, *pic;
|
||||
unsigned char 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);
|
||||
|
||||
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\n");
|
||||
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){
|
||||
fprint(2, "ReadGIF: GIF invalid, code out of range, %x > %x\n", code, nentry);
|
||||
code = nentry;
|
||||
}
|
||||
for(c=code; stacki>0 && 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:
|
||||
if(i->cmap!=nil && i->cmaplen!=3*256){
|
||||
clip = (i->cmaplen/3)-1;
|
||||
for(p = pic; p < pic+piclen; p++)
|
||||
if(*p > clip)
|
||||
*p = clip;
|
||||
}
|
||||
h->pic = nil;
|
||||
return pic;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
interlace(Header *h, Rawimage *image)
|
||||
{
|
||||
unsigned char *pic;
|
||||
Rectangle r;
|
||||
int dx, yy, y;
|
||||
unsigned char *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;
|
||||
}
|
1659
sys/src/cmd/pict/readjpg.c
Normal file
1659
sys/src/cmd/pict/readjpg.c
Normal file
File diff suppressed because it is too large
Load Diff
531
sys/src/cmd/pict/readpng.c
Normal file
531
sys/src/cmd/pict/readpng.c
Normal file
@ -0,0 +1,531 @@
|
||||
#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 = 8*1024*1024,
|
||||
|
||||
/* filtering algorithms */
|
||||
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 ZlibR;
|
||||
typedef struct ZlibW ZlibW;
|
||||
|
||||
struct ZlibW
|
||||
{
|
||||
unsigned char *data; /* Rawimage data */
|
||||
int ndata;
|
||||
int noutchan;
|
||||
int chandesc;
|
||||
int nchan;
|
||||
|
||||
unsigned char *scan; /* new scanline */
|
||||
unsigned char *lastscan; /* previous scan line */
|
||||
int scanlen; /* scan line length */
|
||||
int scanpos; /* scan position */
|
||||
|
||||
int dx; /* width of image */
|
||||
int dy; /* height of image */
|
||||
int bpc; /* bits per channel (per pixel) */
|
||||
int y; /* current scan line */
|
||||
int pass; /* adam7 pass#; 0 means no adam7 */
|
||||
unsigned char palette[3*256]; /* color palette */
|
||||
int palsize; /* number of palette entries */
|
||||
};
|
||||
|
||||
struct ZlibR
|
||||
{
|
||||
Biobuf *io; /* input buffer */
|
||||
unsigned char *buf; /* malloc'ed staging buffer */
|
||||
unsigned char *p; /* next byte to decompress */
|
||||
unsigned char *e; /* end of buffer */
|
||||
ZlibW *w;
|
||||
};
|
||||
|
||||
static uint32_t *crctab;
|
||||
static unsigned char PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
|
||||
|
||||
static uint32_t
|
||||
get4(unsigned char *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(uint32_t n, int clear)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = mallocz(n, clear);
|
||||
if(p == nil)
|
||||
sysfatal("malloc: %r");
|
||||
return p;
|
||||
}
|
||||
|
||||
static int
|
||||
getchunk(Biobuf *b, char *type, unsigned char *d, int m)
|
||||
{
|
||||
unsigned char buf[8];
|
||||
uint32_t 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->p >= z->e){
|
||||
Again:
|
||||
z->p = z->buf;
|
||||
z->e = z->p;
|
||||
n = getchunk(z->io, type, z->p, IDATSIZE);
|
||||
if(n < 0 || strcmp(type, "IEND") == 0)
|
||||
return -1;
|
||||
z->e = z->p + n;
|
||||
if(!strcmp(type,"PLTE")){
|
||||
if(n < 3 || n > 3*256 || n%3)
|
||||
sysfatal("invalid PLTE chunk len %d", n);
|
||||
memcpy(z->w->palette, z->p, n);
|
||||
z->w->palsize = 256;
|
||||
goto Again;
|
||||
}
|
||||
if(type[0] & PropertyBit)
|
||||
goto Again; /* skip auxiliary chunks fornow */
|
||||
if(strcmp(type,"IDAT")){
|
||||
sysfatal("unrecognized mandatory chunk %s", type);
|
||||
goto Again;
|
||||
}
|
||||
}
|
||||
return *z->p++;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
paeth(unsigned char a, unsigned char b, unsigned char c)
|
||||
{
|
||||
int p, pa, pb, pc;
|
||||
|
||||
p = a + b - c;
|
||||
pa = abs(p - a);
|
||||
pb = abs(p - b);
|
||||
pc = abs(p - c);
|
||||
|
||||
if(pa <= pb && pa <= pc)
|
||||
return a;
|
||||
else if(pb <= pc)
|
||||
return b;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
unfilter(int alg, unsigned char *buf, unsigned char *up, int len, int bypp)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch(alg){
|
||||
default:
|
||||
fprint(2, "unknown filtering scheme %d\n", alg);
|
||||
case FilterNone:
|
||||
break;
|
||||
|
||||
case FilterSub:
|
||||
for(i = bypp; i < len; ++i)
|
||||
buf[i] += buf[i-bypp];
|
||||
break;
|
||||
|
||||
case FilterUp:
|
||||
for(i = 0; i < len; ++i)
|
||||
buf[i] += up[i];
|
||||
break;
|
||||
|
||||
case FilterAvg:
|
||||
for(i = 0; i < bypp; ++i)
|
||||
buf[i] += (0+up[i])/2;
|
||||
for(; i < len; ++i)
|
||||
buf[i] += (buf[i-bypp]+up[i])/2;
|
||||
break;
|
||||
|
||||
case FilterPaeth:
|
||||
for(i = 0; i < bypp; ++i)
|
||||
buf[i] += paeth(0, up[i], 0);
|
||||
for(; i < len; ++i)
|
||||
buf[i] += paeth(buf[i-bypp], up[i], up[i-bypp]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct {
|
||||
int x;
|
||||
int y;
|
||||
int dx;
|
||||
int dy;
|
||||
} adam7[] = {
|
||||
{0,0,1,1}, /* eve alone */
|
||||
{0,0,8,8}, /* pass 1 */
|
||||
{4,0,8,8}, /* pass 2 */
|
||||
{0,4,4,8}, /* pass 3 */
|
||||
{2,0,4,4}, /* pass 4 */
|
||||
{0,2,2,4}, /* pass 5 */
|
||||
{1,0,2,2}, /* pass 6 */
|
||||
{0,1,1,2}, /* pass 7 */
|
||||
};
|
||||
|
||||
static void
|
||||
scan(int len, ZlibW *z)
|
||||
{
|
||||
int chan, i, j, nbit, off, val;
|
||||
unsigned char pixel[4], *p, *w;
|
||||
|
||||
unfilter(z->scan[0], z->scan+1, z->lastscan+1, len-1, (z->nchan*z->bpc+7)/8);
|
||||
|
||||
/*
|
||||
* loop over raw bits extracting pixel values and converting to 8-bit
|
||||
*/
|
||||
nbit = 0;
|
||||
chan = 0;
|
||||
val = 0;
|
||||
off = z->y*z->dx + adam7[z->pass].x;
|
||||
w = z->data + z->noutchan*off;
|
||||
p = z->scan+1; /* skip alg byte */
|
||||
len--;
|
||||
for(i=0; i<len*8; i++){
|
||||
val <<= 1;
|
||||
if(p[i>>3] & (1<<(7-(i&7))))
|
||||
val++;
|
||||
if(++nbit == z->bpc){
|
||||
/* finished the value */
|
||||
pixel[chan++] = (val*255)/((1<<z->bpc)-1);
|
||||
val = 0;
|
||||
nbit = 0;
|
||||
if(chan == z->nchan){
|
||||
/* finished the pixel */
|
||||
if(off < z->dx*z->dy){
|
||||
if(z->nchan < 3 && z->palsize){
|
||||
j = pixel[0];
|
||||
if(z->bpc < 8)
|
||||
j >>= 8-z->bpc;
|
||||
if(j >= z->palsize)
|
||||
sysfatal("index %d >= palette size %d", j, z->palsize);
|
||||
pixel[3] = pixel[1]; /* alpha */
|
||||
pixel[0] = z->palette[3*j];
|
||||
pixel[1] = z->palette[3*j+1];
|
||||
pixel[2] = z->palette[3*j+2];
|
||||
}
|
||||
switch(z->chandesc){
|
||||
case CYA16:
|
||||
// print("%.2x%.2x ", pixel[0], pixel[1]);
|
||||
*w++ = pixel[1];
|
||||
*w++ += (pixel[0]*pixel[1])/255;
|
||||
break;
|
||||
case CRGBA32:
|
||||
// print("%.2x%.2x%.2x%.2x ", pixel[0], pixel[1], pixel[2], pixel[3]);
|
||||
*w++ += pixel[3];
|
||||
*w++ += (pixel[2]*pixel[3])/255;
|
||||
*w++ += (pixel[1]*pixel[3])/255;
|
||||
*w++ += (pixel[0]*pixel[3])/255;
|
||||
break;
|
||||
case CRGB24:
|
||||
*w++ = pixel[2];
|
||||
*w++ = pixel[1];
|
||||
case CY:
|
||||
*w++ = pixel[0];
|
||||
break;
|
||||
}
|
||||
w += (adam7[z->pass].dx-1)*z->noutchan;
|
||||
}
|
||||
off += adam7[z->pass].dx;
|
||||
if(off >= (z->y+1)*z->dx){
|
||||
/* finished the line */
|
||||
return;
|
||||
}
|
||||
chan = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
sysfatal("scan line too short");
|
||||
}
|
||||
|
||||
static int
|
||||
scanbytes(ZlibW *z)
|
||||
{
|
||||
int bits, n, adx, dx;
|
||||
|
||||
if(adam7[z->pass].y >= z->dy || adam7[z->pass].x >= z->dx)
|
||||
return 0;
|
||||
adx = adam7[z->pass].dx;
|
||||
dx = z->dx - adam7[z->pass].x;
|
||||
if(dx <= 0)
|
||||
n = 1;
|
||||
else
|
||||
n = (dx+adx-1)/adx;
|
||||
if(n != 1 + (z->dx - (adam7[z->pass].x+1)) / adam7[z->pass].dx){
|
||||
fprint(2, "%d/%d != 1+(%d-1)/%d = %d\n",
|
||||
z->dx - adam7[z->pass].x - 1 + adx, adx,
|
||||
z->dx - (adam7[z->pass].x+1), adam7[z->pass].dx,
|
||||
1 + (z->dx - (adam7[z->pass].x+1)) / adam7[z->pass].dx);
|
||||
}
|
||||
bits = n*z->bpc*z->nchan;
|
||||
return 1 + (bits+7)/8;
|
||||
}
|
||||
|
||||
static int
|
||||
nextpass(ZlibW *z)
|
||||
{
|
||||
int len;
|
||||
|
||||
memset(z->lastscan, 0, z->scanlen);
|
||||
do{
|
||||
z->pass = (z->pass+1)%8;
|
||||
z->y = adam7[z->pass].y;
|
||||
len = scanbytes(z);
|
||||
}while(len < 2);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
zwrite(void *vz, void *vbuf, int n)
|
||||
{
|
||||
int oldn, m, len;
|
||||
unsigned char *buf, *t;
|
||||
ZlibW *z;
|
||||
|
||||
z = vz;
|
||||
buf = vbuf;
|
||||
oldn = n;
|
||||
|
||||
len = scanbytes(z);
|
||||
if(len < 2)
|
||||
len = nextpass(z);
|
||||
|
||||
while(n > 0){
|
||||
m = len - z->scanpos;
|
||||
if(m > n){
|
||||
/* save final partial line */
|
||||
memmove(z->scan+z->scanpos, buf, n);
|
||||
z->scanpos += n;
|
||||
break;
|
||||
}
|
||||
|
||||
/* fill line */
|
||||
memmove(z->scan+z->scanpos, buf, m);
|
||||
buf += m;
|
||||
n -= m;
|
||||
|
||||
/* process line */
|
||||
scan(len, z);
|
||||
t = z->scan;
|
||||
z->scan = z->lastscan;
|
||||
z->lastscan = t;
|
||||
|
||||
z->scanpos = 0;
|
||||
z->y += adam7[z->pass].dy;
|
||||
if(z->y >= z->dy)
|
||||
len = nextpass(z);
|
||||
}
|
||||
return oldn;
|
||||
}
|
||||
|
||||
static Rawimage*
|
||||
readslave(Biobuf *b)
|
||||
{
|
||||
char type[5];
|
||||
int bpc, colorfmt, dx, dy, err, n, nchan, nout, useadam7;
|
||||
unsigned char *buf, *h;
|
||||
Rawimage *image;
|
||||
ZlibR zr;
|
||||
ZlibW zw;
|
||||
|
||||
buf = pngmalloc(IDATSIZE, 0);
|
||||
if(Bread(b, buf, sizeof PNGmagic) != sizeof PNGmagic
|
||||
|| 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;
|
||||
dx = get4(h);
|
||||
h += 4;
|
||||
dy = get4(h);
|
||||
h += 4;
|
||||
if(dx <= 0 || dy <= 0)
|
||||
sysfatal("impossible image size %dx%d", dx, dy);
|
||||
if(debug)
|
||||
fprint(2, "readpng %dx%d\n", dx, dy);
|
||||
|
||||
bpc = *h++;
|
||||
colorfmt = *h++;
|
||||
nchan = 0;
|
||||
if(*h++ != 0)
|
||||
sysfatal("only deflate supported for now [%d]", h[-1]);
|
||||
if(*h++ != FilterNone)
|
||||
sysfatal("only FilterNone supported for now [%d]", h[-1]);
|
||||
useadam7 = *h++;
|
||||
USED(h);
|
||||
|
||||
image = pngmalloc(sizeof(Rawimage), 1);
|
||||
image->r = Rect(0, 0, dx, dy);
|
||||
nout = 0;
|
||||
switch(colorfmt){
|
||||
case 0: /* grey */
|
||||
if(bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8 && bpc != 16)
|
||||
sysfatal("invalid greyscale bpc %d", bpc);
|
||||
image->nchans = 1;
|
||||
image->chandesc = CY;
|
||||
nout = 1;
|
||||
nchan = 1;
|
||||
break;
|
||||
case 2: /* rgb */
|
||||
if(bpc != 8 && bpc != 16)
|
||||
sysfatal("invalid rgb bpc %d", bpc);
|
||||
image->nchans = 1;
|
||||
image->chandesc = CRGB24;
|
||||
nout = 3;
|
||||
nchan = 3;
|
||||
break;
|
||||
case 3: /* indexed rgb with PLTE */
|
||||
if(bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8)
|
||||
sysfatal("invalid indexed rgb bpc %d", bpc);
|
||||
image->nchans = 1;
|
||||
image->chandesc = CRGB24;
|
||||
nout = 3;
|
||||
nchan = 1;
|
||||
break;
|
||||
case 4: /* grey+alpha */
|
||||
if(bpc != 8 && bpc != 16)
|
||||
sysfatal("invalid grey+alpha bpc %d", bpc);
|
||||
image->nchans = 1;
|
||||
image->chandesc = CYA16;
|
||||
nout = 2;
|
||||
nchan = 2;
|
||||
break;
|
||||
case 6: /* rgb+alpha */
|
||||
if(bpc != 8 && bpc != 16)
|
||||
sysfatal("invalid rgb+alpha bpc %d", bpc);
|
||||
image->nchans = 1;
|
||||
image->chandesc = CRGBA32;
|
||||
nout = 4;
|
||||
nchan = 4;
|
||||
break;
|
||||
default:
|
||||
sysfatal("unsupported color scheme %d", h[-1]);
|
||||
}
|
||||
image->chanlen = dx*dy*nout;
|
||||
image->chans[0] = pngmalloc(image->chanlen, 0);
|
||||
memset(image->chans[0], 0, image->chanlen);
|
||||
|
||||
memset(&zr, 0, sizeof zr);
|
||||
zr.w = &zw;
|
||||
zr.io = b;
|
||||
zr.buf = buf;
|
||||
|
||||
memset(&zw, 0, sizeof zw);
|
||||
if(useadam7)
|
||||
zw.pass = 1;
|
||||
zw.data = image->chans[0];
|
||||
zw.ndata = image->chanlen;
|
||||
zw.chandesc = image->chandesc;
|
||||
zw.noutchan = nout;
|
||||
|
||||
zw.dx = dx;
|
||||
zw.dy = dy;
|
||||
zw.scanlen = (nchan*dx*bpc+7)/8+1;
|
||||
zw.scan = pngmalloc(zw.scanlen, 1);
|
||||
zw.lastscan = pngmalloc(zw.scanlen, 1);
|
||||
zw.nchan = nchan;
|
||||
zw.bpc = bpc;
|
||||
|
||||
err = inflatezlib(&zw, zwrite, &zr, zread);
|
||||
|
||||
if(err)
|
||||
sysfatal("inflatezlib %s\n", flateerr(err));
|
||||
|
||||
free(buf);
|
||||
free(zw.scan);
|
||||
free(zw.lastscan);
|
||||
return image;
|
||||
}
|
||||
|
||||
Rawimage**
|
||||
Breadpng(Biobuf *b, int colorspace)
|
||||
{
|
||||
Rawimage **array, *r;
|
||||
|
||||
if(colorspace != CRGB){
|
||||
werrstr("ReadPNG: unknown color space %d", colorspace);
|
||||
return nil;
|
||||
}
|
||||
pnginit();
|
||||
array = malloc(2*sizeof(*array));
|
||||
if(array==nil)
|
||||
return nil;
|
||||
r = readslave(b);
|
||||
array[0] = r;
|
||||
array[1] = nil;
|
||||
return array;
|
||||
}
|
||||
|
||||
Rawimage**
|
||||
readpng(int fd, int colorspace)
|
||||
{
|
||||
Biobuf b;
|
||||
Rawimage **a;
|
||||
|
||||
if(Binit(&b, fd, OREAD) < 0)
|
||||
return nil;
|
||||
a = Breadpng(&b, colorspace);
|
||||
Bterm(&b);
|
||||
return a;
|
||||
}
|
237
sys/src/cmd/pict/readppm.c
Normal file
237
sys/src/cmd/pict/readppm.c
Normal file
@ -0,0 +1,237 @@
|
||||
#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(Biobufhdr *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(Biobufhdr *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(Biobufhdr *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(Biobufhdr *b)
|
||||
{
|
||||
if(nbit == 0) {
|
||||
nbit = 8;
|
||||
bitc = Bgetc(b);
|
||||
if(bitc == -1)
|
||||
return -1;
|
||||
}
|
||||
nbit--;
|
||||
return (bitc >> nbit) & 0x1;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
Bflushbit(Biobufhdr* _)
|
||||
{
|
||||
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)(Biobufhdr*);
|
||||
int nchan;
|
||||
int chandesc;
|
||||
int invert;
|
||||
void (*flush)(Biobufhdr*);
|
||||
};
|
||||
|
||||
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)(Biobufhdr*);
|
||||
unsigned char *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;
|
||||
}
|
510
sys/src/cmd/pict/readtga.c
Normal file
510
sys/src/cmd/pict/readtga.c
Normal file
@ -0,0 +1,510 @@
|
||||
/*
|
||||
* TGA is a fairly dead standard, however in the video industry
|
||||
* it is still used a little for test patterns and the like.
|
||||
*
|
||||
* Thus we ignore any alpha channels.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <ctype.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
enum {
|
||||
HdrLen = 18,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int idlen; /* length of string after header */
|
||||
int cmaptype; /* 1 => datatype = 1 => colourmapped */
|
||||
int datatype; /* see below */
|
||||
int cmaporigin; /* index of first entry in colour map */
|
||||
int cmaplen; /* length of colour map */
|
||||
int cmapbpp; /* bits per pixel of colour map: 16, 24, or 32 */
|
||||
int xorigin; /* source image origin */
|
||||
int yorigin;
|
||||
int width;
|
||||
int height;
|
||||
int bpp; /* bits per pixel of image: 16, 24, or 32 */
|
||||
int descriptor;
|
||||
unsigned char *cmap; /* colour map (optional) */
|
||||
} Tga;
|
||||
|
||||
/*
|
||||
* descriptor:
|
||||
* d0-3 = number of attribute bits per pixel
|
||||
* d4 = reserved, always zero
|
||||
* d6-7 = origin: 0=lower left, 1=upper left, 2=lower right, 3=upper right
|
||||
* d8-9 = interleave: 0=progressive, 1=2 way, 3=4 way, 4=reserved.
|
||||
*/
|
||||
|
||||
char *datatype[] = {
|
||||
[0] "No image data",
|
||||
[1] "Color-mapped",
|
||||
[2] "RGB",
|
||||
[3] "B&W",
|
||||
[9] "RLE color-mapped",
|
||||
[10] "RLE RGB",
|
||||
[11] "RLE B&W",
|
||||
[32] "Compressed color",
|
||||
[33] "Quadtree compressed color",
|
||||
};
|
||||
|
||||
static int
|
||||
Bgeti(Biobuf *bp)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
if((x = Bgetc(bp)) < 0)
|
||||
return -1;
|
||||
if((y = Bgetc(bp)) < 0)
|
||||
return -1;
|
||||
return (y<<8)|x;
|
||||
}
|
||||
|
||||
static int
|
||||
fixcmap(unsigned char *cmap, int *cmapbpp, int cmaplen)
|
||||
{
|
||||
int i;
|
||||
unsigned short x;
|
||||
unsigned char tmp;
|
||||
|
||||
switch(*cmapbpp){
|
||||
case 32:
|
||||
/* swap B with R */
|
||||
for(i = 0; i < cmaplen; i++){
|
||||
tmp = cmap[4*i+0];
|
||||
cmap[4*i+0] = cmap[4*i+2];
|
||||
cmap[4*i+2] = tmp;
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
/* swap B with R */
|
||||
for(i = 0; i < cmaplen; i++){
|
||||
tmp = cmap[3*i+0];
|
||||
cmap[3*i+0] = cmap[3*i+2];
|
||||
cmap[3*i+2] = tmp;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
case 15:
|
||||
/* convert to 24-bit colormap */
|
||||
if((cmap = realloc(cmap, 3*cmaplen)) == nil)
|
||||
return -1;
|
||||
for(i = cmaplen-1; i >= 0; i--){
|
||||
x = (cmap[2*i+1]<<8) | cmap[2*i+0];
|
||||
tmp = (x>>0)&0x1f;
|
||||
cmap[3*i+2] = (tmp<<3) | (tmp>>2);
|
||||
tmp = (x>>5)&0x1f;
|
||||
cmap[3*i+1] = (tmp<<3) | (tmp>>2);
|
||||
tmp = (x>>10)&0x1f;
|
||||
cmap[3*i+0] = (tmp<<3) | (tmp>>2);
|
||||
}
|
||||
*cmapbpp = 24;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Tga *
|
||||
rdhdr(Biobuf *bp)
|
||||
{
|
||||
int n;
|
||||
Tga *h;
|
||||
|
||||
if((h = malloc(sizeof(Tga))) == nil)
|
||||
return nil;
|
||||
if((h->idlen = Bgetc(bp)) == -1)
|
||||
return nil;
|
||||
if((h->cmaptype = Bgetc(bp)) == -1)
|
||||
return nil;
|
||||
if((h->datatype = Bgetc(bp)) == -1)
|
||||
return nil;
|
||||
if((h->cmaporigin = Bgeti(bp)) == -1)
|
||||
return nil;
|
||||
if((h->cmaplen = Bgeti(bp)) == -1)
|
||||
return nil;
|
||||
if((h->cmapbpp = Bgetc(bp)) == -1)
|
||||
return nil;
|
||||
if((h->xorigin = Bgeti(bp)) == -1)
|
||||
return nil;
|
||||
if((h->yorigin = Bgeti(bp)) == -1)
|
||||
return nil;
|
||||
if((h->width = Bgeti(bp)) == -1)
|
||||
return nil;
|
||||
if((h->height = Bgeti(bp)) == -1)
|
||||
return nil;
|
||||
if((h->bpp = Bgetc(bp)) == -1)
|
||||
return nil;
|
||||
if((h->descriptor = Bgetc(bp)) == -1)
|
||||
return nil;
|
||||
|
||||
/* skip over ID, usually empty anyway */
|
||||
if(Bseek(bp, h->idlen, 1) < 0){
|
||||
free(h);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if(h->cmaptype == 0){
|
||||
h->cmap = 0;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* skip over unused color map data */
|
||||
n = (h->cmapbpp/8)*h->cmaporigin;
|
||||
if(Bseek(bp, n, 1) < 0){
|
||||
free(h);
|
||||
return nil;
|
||||
}
|
||||
h->cmaplen -= h->cmaporigin;
|
||||
|
||||
n = (h->cmapbpp/8)*h->cmaplen;
|
||||
if((h->cmap = malloc(n)) == nil){
|
||||
free(h);
|
||||
return nil;
|
||||
}
|
||||
if(Bread(bp, h->cmap, n) != n){
|
||||
free(h);
|
||||
free(h->cmap);
|
||||
return nil;
|
||||
}
|
||||
if(fixcmap(h->cmap, &h->cmapbpp, h->cmaplen) != 0){
|
||||
free(h);
|
||||
free(h->cmap);
|
||||
return nil;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static int
|
||||
cmap(Biobuf *bp, unsigned char *l, int num)
|
||||
{
|
||||
return Bread(bp, l, num);
|
||||
}
|
||||
|
||||
static int
|
||||
luma(Biobuf *bp, int bpp, unsigned char *l, int num)
|
||||
{
|
||||
char tmp[2];
|
||||
int got;
|
||||
|
||||
if(bpp == 8){
|
||||
got = Bread(bp, l, num);
|
||||
}
|
||||
else{
|
||||
for(got = 0; got < num; got++){
|
||||
if(Bread(bp, tmp, 2) != 2)
|
||||
break;
|
||||
*l++ = tmp[0];
|
||||
}
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
||||
static int
|
||||
luma_rle(Biobuf *bp, int bpp, unsigned char *l, int num)
|
||||
{
|
||||
unsigned char len, p;
|
||||
int got;
|
||||
|
||||
for(got = 0; got < num;){
|
||||
if(Bread(bp, &len, 1) != 1)
|
||||
break;
|
||||
if(len & 0x80){
|
||||
len &= 0x7f;
|
||||
if(luma(bp, bpp, &p, 1) != 1)
|
||||
break;
|
||||
for(len++; len > 0 && got < num; len--, got++)
|
||||
*l++ = p;
|
||||
}
|
||||
else{
|
||||
for(len++; len > 0 && got < num; len--, got++)
|
||||
if(luma(bp, bpp, l++, 1) != 1)
|
||||
return got;
|
||||
}
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
||||
static int
|
||||
cmap_rle(Biobuf *bp, unsigned char *l, int num)
|
||||
{
|
||||
return luma_rle(bp, 8, l, num);
|
||||
}
|
||||
|
||||
static int
|
||||
rgba(Biobuf *bp, int bpp, unsigned char *r, unsigned char *g, unsigned char *b, int num)
|
||||
{
|
||||
int i;
|
||||
unsigned char buf[4], tmp;
|
||||
unsigned short x;
|
||||
|
||||
switch(bpp){
|
||||
case 16:
|
||||
case 15:
|
||||
for(i = 0; i < num; i++){
|
||||
if(Bread(bp, buf, 2) != 2)
|
||||
break;
|
||||
x = (buf[1]<<8) | buf[0];
|
||||
tmp = (x>>0)&0x1f;
|
||||
*b++ = (tmp<<3) | (tmp>>2);
|
||||
tmp = (x>>5)&0x1f;
|
||||
*g++ = (tmp<<3) | (tmp>>2);
|
||||
tmp = (x>>10)&0x1f;
|
||||
*r++ = (tmp<<3) | (tmp>>2);
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
for(i = 0; i < num; i++){
|
||||
if(Bread(bp, buf, 3) != 3)
|
||||
break;
|
||||
*b++ = buf[0];
|
||||
*g++ = buf[1];
|
||||
*r++ = buf[2];
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
for(i = 0; i < num; i++){
|
||||
if(Bread(bp, buf, 4) != 4)
|
||||
break;
|
||||
*b++ = buf[0];
|
||||
*g++ = buf[1];
|
||||
*r++ = buf[2];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int
|
||||
rgba_rle(Biobuf *bp, int bpp, unsigned char *r, unsigned char *g, unsigned char *b, int num)
|
||||
{
|
||||
unsigned char len;
|
||||
int i, got;
|
||||
|
||||
for(got = 0; got < num; got += len){
|
||||
if(Bread(bp, &len, 1) != 1)
|
||||
break;
|
||||
if(len & 0x80){
|
||||
len &= 0x7f;
|
||||
len += 1; /* run of zero is meaningless */
|
||||
if(rgba(bp, bpp, r, g, b, 1) != 1)
|
||||
break;
|
||||
for(i = 1; i < len && got+i < num; i++){
|
||||
r[i] = *r;
|
||||
g[i] = *g;
|
||||
b[i] = *b;
|
||||
}
|
||||
len = i;
|
||||
}
|
||||
else{
|
||||
len += 1; /* raw block of zero is meaningless */
|
||||
if(rgba(bp, bpp, r, g, b, len) != len)
|
||||
break;
|
||||
}
|
||||
r += len;
|
||||
g += len;
|
||||
b += len;
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
||||
int
|
||||
flip(Rawimage *ar)
|
||||
{
|
||||
int w, h, c, l;
|
||||
unsigned char *t, *s, *d;
|
||||
|
||||
w = Dx(ar->r);
|
||||
h = Dy(ar->r);
|
||||
if((t = malloc(w)) == nil){
|
||||
werrstr("ReadTGA: no memory - %r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(c = 0; c < ar->nchans; c++){
|
||||
s = ar->chans[c];
|
||||
d = ar->chans[c] + ar->chanlen - w;
|
||||
for(l = 0; l < (h/2); l++){
|
||||
memcpy(t, s, w);
|
||||
memcpy(s, d, w);
|
||||
memcpy(d, t, w);
|
||||
s += w;
|
||||
d -= w;
|
||||
}
|
||||
}
|
||||
free(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
reflect(Rawimage *ar)
|
||||
{
|
||||
int w, h, c, l, p;
|
||||
unsigned char t, *sol, *eol, *s, *d;
|
||||
|
||||
w = Dx(ar->r);
|
||||
h = Dy(ar->r);
|
||||
|
||||
for(c = 0; c < ar->nchans; c++){
|
||||
sol = ar->chans[c];
|
||||
eol = ar->chans[c] +w -1;
|
||||
for(l = 0; l < h; l++){
|
||||
s = sol;
|
||||
d = eol;
|
||||
for(p = 0; p < w/2; p++){
|
||||
t = *s;
|
||||
*s = *d;
|
||||
*d = t;
|
||||
s++;
|
||||
d--;
|
||||
}
|
||||
sol += w;
|
||||
eol += w;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Rawimage**
|
||||
Breadtga(Biobuf *bp)
|
||||
{
|
||||
Tga *h;
|
||||
int n, c, num;
|
||||
unsigned char *r, *g, *b;
|
||||
Rawimage *ar, **array;
|
||||
|
||||
if((h = rdhdr(bp)) == nil){
|
||||
werrstr("ReadTGA: bad header %r");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if(0){
|
||||
fprint(2, "idlen=%d\n", h->idlen);
|
||||
fprint(2, "cmaptype=%d\n", h->cmaptype);
|
||||
fprint(2, "datatype=%s\n", datatype[h->datatype]);
|
||||
fprint(2, "cmaporigin=%d\n", h->cmaporigin);
|
||||
fprint(2, "cmaplen=%d\n", h->cmaplen);
|
||||
fprint(2, "cmapbpp=%d\n", h->cmapbpp);
|
||||
fprint(2, "xorigin=%d\n", h->xorigin);
|
||||
fprint(2, "yorigin=%d\n", h->yorigin);
|
||||
fprint(2, "width=%d\n", h->width);
|
||||
fprint(2, "height=%d\n", h->height);
|
||||
fprint(2, "bpp=%d\n", h->bpp);
|
||||
fprint(2, "descriptor=%d\n", h->descriptor);
|
||||
}
|
||||
|
||||
array = nil;
|
||||
if((ar = calloc(1, sizeof(Rawimage))) == nil){
|
||||
werrstr("ReadTGA: no memory - %r\n");
|
||||
goto Error;
|
||||
}
|
||||
|
||||
if((array = calloc(2, sizeof(Rawimage *))) == nil){
|
||||
werrstr("ReadTGA: no memory - %r\n");
|
||||
goto Error;
|
||||
}
|
||||
array[0] = ar;
|
||||
array[1] = nil;
|
||||
|
||||
if(h->datatype == 3 || h->datatype == 11){
|
||||
ar->nchans = 1;
|
||||
ar->chandesc = CY;
|
||||
}
|
||||
else if(h->datatype == 1){
|
||||
ar->nchans = 1;
|
||||
ar->chandesc = CRGB1;
|
||||
}
|
||||
else if(h->datatype == 9){
|
||||
ar->nchans = 1;
|
||||
ar->chandesc = (h->cmapbpp == 32) ? CRGBV : CRGB1;
|
||||
}
|
||||
else{
|
||||
ar->nchans = 3;
|
||||
ar->chandesc = CRGB;
|
||||
}
|
||||
|
||||
ar->cmap = h->cmap;
|
||||
ar->cmaplen = (h->cmapbpp/8)*h->cmaplen;
|
||||
ar->chanlen = h->width*h->height;
|
||||
ar->r = Rect(0, 0, h->width, h->height);
|
||||
for(c = 0; c < ar->nchans; c++)
|
||||
if((ar->chans[c] = malloc(h->width*h->height)) == nil){
|
||||
werrstr("ReadTGA: no memory - %r\n");
|
||||
goto Error;
|
||||
}
|
||||
r = ar->chans[0];
|
||||
g = ar->chans[1];
|
||||
b = ar->chans[2];
|
||||
|
||||
num = h->width*h->height;
|
||||
switch(h->datatype){
|
||||
case 1:
|
||||
n = cmap(bp, r, num);
|
||||
break;
|
||||
case 2:
|
||||
n = rgba(bp, h->bpp, r, g, b, num);
|
||||
break;
|
||||
case 3:
|
||||
n = luma(bp, h->bpp, r, num);
|
||||
break;
|
||||
case 9:
|
||||
n = cmap_rle(bp, r, num);
|
||||
break;
|
||||
case 10:
|
||||
n = rgba_rle(bp, h->bpp, r, g, b, num);
|
||||
break;
|
||||
case 11:
|
||||
n = luma_rle(bp, h->bpp, r, num);
|
||||
break;
|
||||
default:
|
||||
werrstr("ReadTGA: type=%d (%s) unsupported\n", h->datatype, datatype[h->datatype]);
|
||||
goto Error;
|
||||
}
|
||||
|
||||
if(n != num){
|
||||
werrstr("ReadTGA: decode fail (%d!=%d) - %r\n", n, num);
|
||||
goto Error;
|
||||
}
|
||||
if((h->descriptor&(1<<4)) != 0)
|
||||
reflect(ar);
|
||||
if((h->descriptor&(1<<5)) == 0)
|
||||
flip(ar);
|
||||
|
||||
free(h);
|
||||
return array;
|
||||
Error:
|
||||
|
||||
if(ar)
|
||||
for (c = 0; c < ar->nchans; c++)
|
||||
free(ar->chans[c]);
|
||||
free(ar);
|
||||
free(array);
|
||||
free(h->cmap);
|
||||
free(h);
|
||||
return nil;
|
||||
}
|
||||
|
||||
Rawimage**
|
||||
readtga(int fd)
|
||||
{
|
||||
Rawimage * *a;
|
||||
Biobuf b;
|
||||
|
||||
if(Binit(&b, fd, OREAD) < 0)
|
||||
return nil;
|
||||
a = Breadtga(&b);
|
||||
Bterm(&b);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
1862
sys/src/cmd/pict/readtif.c
Normal file
1862
sys/src/cmd/pict/readtif.c
Normal file
File diff suppressed because it is too large
Load Diff
203
sys/src/cmd/pict/readv210.c
Normal file
203
sys/src/cmd/pict/readv210.c
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* readV210.c - read single uncompressed Quicktime YUV image.
|
||||
* http://developer.apple.com/quicktime/icefloe/dispatch019.html#v210
|
||||
* Steve Simon, 2009
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <ctype.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
enum {
|
||||
Pixels = 720,
|
||||
R601pal = 576,
|
||||
R601ntsc = 486,
|
||||
Shift = 13
|
||||
};
|
||||
|
||||
static int
|
||||
looksize(char *file, long size, int *pixels, int *lines, int *chunk)
|
||||
{
|
||||
Biobuf *bp;
|
||||
unsigned long l, p, c;
|
||||
char *s, *a[12];
|
||||
|
||||
/*
|
||||
* This may not always work, there could be an alias between file
|
||||
* sizes of different standards stored in 8bits and 10 bits.
|
||||
*/
|
||||
if((bp = Bopen(file, OREAD)) == nil)
|
||||
return -1;
|
||||
while((s = Brdstr(bp, '\n', 1)) != nil){
|
||||
if(tokenize(s, a, nelem(a)) < 3)
|
||||
continue;
|
||||
if(a[0][0] == '#')
|
||||
continue;
|
||||
p = atoll(a[3]);
|
||||
l = atoll(a[5]);
|
||||
l += atoll(a[7]);
|
||||
c = 128 * ceil(p/48);
|
||||
if(l*c == size){
|
||||
*pixels = p;
|
||||
*lines = l;
|
||||
*chunk = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Bterm(bp);
|
||||
if(s == nil)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
clip(int x)
|
||||
{
|
||||
x >>= Shift + 2; /* +2 as we assume all input images are 10 bit */
|
||||
if(x > 255)
|
||||
return 0xff;
|
||||
if(x <= 0)
|
||||
return 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
Rawimage**
|
||||
BreadV210(Biobuf *bp, int colourspace)
|
||||
{
|
||||
Dir *d;
|
||||
unsigned long sz;
|
||||
Rawimage *a, **array;
|
||||
unsigned short *mux, *end, *frm, *wr;
|
||||
unsigned char *buf, *r, *g, *b;
|
||||
uint i, t;
|
||||
int y1, y2, cb, cr, c, l, rd;
|
||||
int chunk, lines, pixels;
|
||||
int F1, F2, F3, F4;
|
||||
|
||||
buf = nil;
|
||||
if(colourspace != CYCbCr){
|
||||
werrstr("BreadV210: unknown colour space %d", colourspace);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if((d = dirfstat(Bfildes(bp))) != nil){
|
||||
sz = d->length;
|
||||
free(d);
|
||||
}
|
||||
else {
|
||||
fprint(2, "cannot stat input, assuming pixelsx576x10bit\n");
|
||||
sz = Pixels * R601pal * 2L + (pixels * R601pal / 2L);
|
||||
}
|
||||
|
||||
if(looksize("/lib/video.specs", sz, &pixels, &lines, &chunk) == -1){
|
||||
werrstr("file spec not in /lib/video.specs\n");
|
||||
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;
|
||||
|
||||
a->nchans = 3;
|
||||
a->chandesc = CRGB;
|
||||
a->chanlen = pixels * lines;
|
||||
a->r = Rect(0, 0, pixels, lines);
|
||||
|
||||
if((frm = malloc(pixels*2*lines*sizeof(unsigned short))) == nil)
|
||||
goto Error;
|
||||
|
||||
for(c = 0; c < 3; c++)
|
||||
if((a->chans[c] = malloc(pixels*lines)) == nil)
|
||||
goto Error;
|
||||
|
||||
if((buf = malloc(chunk)) == nil)
|
||||
goto Error;
|
||||
|
||||
for(l = 0; l < lines; l++){
|
||||
if(Bread(bp, buf, chunk) == -1)
|
||||
goto Error;
|
||||
|
||||
rd = 0;
|
||||
wr = &frm[l*pixels*2];
|
||||
end = &frm[(l+1)*pixels*2];
|
||||
while(wr < end){
|
||||
t = 0;
|
||||
for(i = 0; i < 4; i++)
|
||||
t += buf[rd+i] << 8*i;
|
||||
*wr++ = t & 0x3ff;
|
||||
*wr++ = t>>10 & 0x3ff;
|
||||
*wr++ = t>>20 & 0x3ff;
|
||||
rd += 4;
|
||||
}
|
||||
}
|
||||
|
||||
mux = frm;
|
||||
end = frm + pixels * lines * 2;
|
||||
r = a->chans[0];
|
||||
g = a->chans[1];
|
||||
b = a->chans[2];
|
||||
|
||||
if(pixels == Pixels && lines != R601pal){ // 625
|
||||
F1 = floor(1.402 * (1 << Shift));
|
||||
F2 = floor(0.34414 * (1 << Shift));
|
||||
F3 = floor(0.71414 * (1 << Shift));
|
||||
F4 = floor(1.772 * (1 << Shift));
|
||||
}
|
||||
else{ // 525 and HD
|
||||
F1 = floor(1.5748 * (1 << Shift));
|
||||
F2 = floor(0.1874 * (1 << Shift));
|
||||
F3 = floor(0.4681 * (1 << Shift));
|
||||
F4 = floor(1.8560 * (1 << Shift));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fixme: fixed colourspace conversion at present
|
||||
*/
|
||||
while(mux < end){
|
||||
|
||||
cb = *mux++ - 512;
|
||||
y1 = (int)*mux++ << Shift;
|
||||
cr = *mux++ - 512;
|
||||
y2 = (int)*mux++ << Shift;
|
||||
|
||||
*r++ = clip(y1 + F1*cr);
|
||||
*g++ = clip(y1 - F2*cb - F3*cr);
|
||||
*b++ = clip((y1 + F4*cb));
|
||||
|
||||
*r++ = clip(y2 + F1*cr);
|
||||
*g++ = clip(y2 - F2*cb - F3*cr);
|
||||
*b++ = clip((y2 + F4*cb));
|
||||
}
|
||||
free(frm);
|
||||
free(buf);
|
||||
return array;
|
||||
|
||||
Error:
|
||||
for(c = 0; c < 3; c++)
|
||||
free(a->chans[c]);
|
||||
free(a->cmap);
|
||||
free(array[0]);
|
||||
free(array);
|
||||
free(frm);
|
||||
free(buf);
|
||||
return nil;
|
||||
}
|
||||
|
||||
Rawimage**
|
||||
readV210(int fd, int colorspace)
|
||||
{
|
||||
Rawimage * *a;
|
||||
Biobuf b;
|
||||
|
||||
if(Binit(&b, fd, OREAD) < 0)
|
||||
return nil;
|
||||
a = BreadV210(&b, colorspace);
|
||||
Bterm(&b);
|
||||
return a;
|
||||
}
|
215
sys/src/cmd/pict/readyuv.c
Normal file
215
sys/src/cmd/pict/readyuv.c
Normal file
@ -0,0 +1,215 @@
|
||||
/* 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"
|
||||
|
||||
|
||||
enum {
|
||||
Pixels = 720,
|
||||
R601pal = 576,
|
||||
R601ntsc = 486,
|
||||
Shift = 13
|
||||
};
|
||||
|
||||
|
||||
static int lsbtab[] = { 6, 4, 2, 0};
|
||||
|
||||
static int
|
||||
looksize(char *file, long size, int *pixels, int *lines, int *bits)
|
||||
{
|
||||
Biobuf *bp;
|
||||
unsigned long l, p;
|
||||
char *s, *a[12];
|
||||
|
||||
/*
|
||||
* This may not always work, there could be an alias between file
|
||||
* sizes of different standards stored in 8bits and 10 bits.
|
||||
*/
|
||||
if ((bp = Bopen(file, OREAD)) == nil)
|
||||
return -1;
|
||||
while((s = Brdstr(bp, '\n', 1)) != nil){
|
||||
if (tokenize(s, a, nelem(a)) < 3)
|
||||
continue;
|
||||
if (a[0][0] == '#')
|
||||
continue;
|
||||
p = atoll(a[3]);
|
||||
l = atoll(a[5]);
|
||||
l += atoll(a[7]);
|
||||
if (l*p*2 == size){
|
||||
*pixels = p;
|
||||
*lines = l;
|
||||
*bits = 8;
|
||||
break;
|
||||
}
|
||||
if ((l*p*20)/8 == size){
|
||||
*pixels = p;
|
||||
*lines = l;
|
||||
*bits = 10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Bterm(bp);
|
||||
if (s == nil)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
clip(int x)
|
||||
{
|
||||
x >>= (Shift+2); // +2 as we assume all input images are 10 bit
|
||||
|
||||
if (x > 255)
|
||||
return 0xff;
|
||||
if (x <= 0)
|
||||
return 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
Rawimage**
|
||||
Breadyuv(Biobuf *bp, int colourspace)
|
||||
{
|
||||
Dir *d;
|
||||
unsigned long sz;
|
||||
Rawimage *a, **array;
|
||||
unsigned short * mux, *end, *frm;
|
||||
unsigned char *buf, *r, *g, *b;
|
||||
int y1, y2, cb, cr, c, l, w, base;
|
||||
int bits, lines, pixels;
|
||||
int F1, F2, F3, F4;
|
||||
|
||||
if ((d = dirfstat(Bfildes(bp))) != nil){
|
||||
sz = d->length;
|
||||
free(d);
|
||||
}
|
||||
else{
|
||||
fprint(2, "cannot stat input, assuming pixelsx576x10bit\n");
|
||||
sz = Pixels * R601pal * 2L + (Pixels * R601pal / 2L);
|
||||
}
|
||||
|
||||
if (looksize("/lib/video.specs", sz, &pixels, &lines, &bits) == -1){
|
||||
werrstr("file size not listed in /lib/video.specs");
|
||||
return nil;
|
||||
}
|
||||
|
||||
buf = nil;
|
||||
if (colourspace != CYCbCr) {
|
||||
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;
|
||||
|
||||
a->nchans = 3;
|
||||
a->chandesc = CRGB;
|
||||
a->chanlen = pixels * lines;
|
||||
a->r = Rect(0, 0, pixels, lines);
|
||||
|
||||
if ((frm = malloc(pixels*2*lines*sizeof(unsigned short))) == nil)
|
||||
goto Error;
|
||||
|
||||
for (c = 0; c < 3; c++)
|
||||
if ((a->chans[c] = malloc(pixels*lines)) == nil)
|
||||
goto Error;
|
||||
|
||||
if ((buf = malloc(pixels*2)) == nil)
|
||||
goto Error;
|
||||
|
||||
for (l = 0; l < lines; l++) {
|
||||
if (Bread(bp, buf, pixels *2) == -1)
|
||||
goto Error;
|
||||
|
||||
base = l*pixels*2;
|
||||
for (w = 0; w < pixels *2; w++)
|
||||
frm[base + w] = ((unsigned short)buf[w]) << 2;
|
||||
}
|
||||
|
||||
|
||||
if (bits == 10)
|
||||
for (l = 0; l < lines; l++) {
|
||||
if (Bread(bp, buf, pixels / 2) == -1)
|
||||
goto Error;
|
||||
|
||||
|
||||
base = l * pixels * 2;
|
||||
for (w = 0; w < pixels * 2; w++)
|
||||
frm[base + w] |= (buf[w / 4] >> lsbtab[w % 4]) & 3;
|
||||
}
|
||||
|
||||
mux = frm;
|
||||
end = frm + pixels * lines * 2;
|
||||
r = a->chans[0];
|
||||
g = a->chans[1];
|
||||
b = a->chans[2];
|
||||
|
||||
if(pixels == Pixels && lines != R601pal){ // 625
|
||||
F1 = floor(1.402 * (1 << Shift));
|
||||
F2 = floor(0.34414 * (1 << Shift));
|
||||
F3 = floor(0.71414 * (1 << Shift));
|
||||
F4 = floor(1.772 * (1 << Shift));
|
||||
}
|
||||
else{ // 525
|
||||
F1 = floor(1.5748 * (1 << Shift));
|
||||
F2 = floor(0.1874 * (1 << Shift));
|
||||
F3 = floor(0.4681 * (1 << Shift));
|
||||
F4 = floor(1.8560 * (1 << Shift));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fixme: fixed colourspace conversion at present
|
||||
*/
|
||||
while (mux < end) {
|
||||
|
||||
cb = *mux++ - 512;
|
||||
y1 = (int)*mux++ << Shift;
|
||||
cr = *mux++ - 512;
|
||||
y2 = (int)*mux++ << Shift;
|
||||
|
||||
*r++ = clip(y1 + F1*cr);
|
||||
*g++ = clip(y1 - F2*cb - F3*cr);
|
||||
*b++ = clip((y1 + F4*cb));
|
||||
|
||||
*r++ = clip(y2 + F1*cr);
|
||||
*g++ = clip(y2 - F2*cb - F3*cr);
|
||||
*b++ = clip((y2 + F4*cb));
|
||||
}
|
||||
free(frm);
|
||||
free(buf);
|
||||
return array;
|
||||
|
||||
Error:
|
||||
for (c = 0; c < 3; c++)
|
||||
free(a->chans[c]);
|
||||
free(a->cmap);
|
||||
free(array[0]);
|
||||
free(array);
|
||||
free(frm);
|
||||
free(buf);
|
||||
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;
|
||||
}
|
||||
|
||||
|
70
sys/src/cmd/pict/rgbrgbv.c
Normal file
70
sys/src/cmd/pict/rgbrgbv.c
Normal file
@ -0,0 +1,70 @@
|
||||
#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;
|
||||
uint32_t 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;
|
||||
unsigned char close[16*16*16];
|
||||
|
||||
print("/* This file has been generated by rgbrgbv */\n");
|
||||
/* rgbmap */
|
||||
print("unsigned int 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("unsigned char 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);
|
||||
}
|
295
sys/src/cmd/pict/rgbv.h
Normal file
295
sys/src/cmd/pict/rgbv.h
Normal file
@ -0,0 +1,295 @@
|
||||
/* This file has been generated by rgbrgbv */
|
||||
unsigned int rgbmap[256] = {
|
||||
0x000000, 0x000044, 0x000088, 0x0000CC, 0x004400, 0x004444, 0x004488, 0x0044CC,
|
||||
0x008800, 0x008844, 0x008888, 0x0088CC, 0x00CC00, 0x00CC44, 0x00CC88, 0x00CCCC,
|
||||
0x00DDDD, 0x111111, 0x000055, 0x000099, 0x0000DD, 0x005500, 0x005555, 0x004C99,
|
||||
0x0049DD, 0x009900, 0x00994C, 0x009999, 0x0093DD, 0x00DD00, 0x00DD49, 0x00DD93,
|
||||
0x00EE9E, 0x00EEEE, 0x222222, 0x000066, 0x0000AA, 0x0000EE, 0x006600, 0x006666,
|
||||
0x0055AA, 0x004FEE, 0x00AA00, 0x00AA55, 0x00AAAA, 0x009EEE, 0x00EE00, 0x00EE4F,
|
||||
0x00FF55, 0x00FFAA, 0x00FFFF, 0x333333, 0x000077, 0x0000BB, 0x0000FF, 0x007700,
|
||||
0x007777, 0x005DBB, 0x0055FF, 0x00BB00, 0x00BB5D, 0x00BBBB, 0x00AAFF, 0x00FF00,
|
||||
0x440044, 0x440088, 0x4400CC, 0x444400, 0x444444, 0x444488, 0x4444CC, 0x448800,
|
||||
0x448844, 0x448888, 0x4488CC, 0x44CC00, 0x44CC44, 0x44CC88, 0x44CCCC, 0x440000,
|
||||
0x550000, 0x550055, 0x4C0099, 0x4900DD, 0x555500, 0x555555, 0x4C4C99, 0x4949DD,
|
||||
0x4C9900, 0x4C994C, 0x4C9999, 0x4993DD, 0x49DD00, 0x49DD49, 0x49DD93, 0x49DDDD,
|
||||
0x4FEEEE, 0x660000, 0x660066, 0x5500AA, 0x4F00EE, 0x666600, 0x666666, 0x5555AA,
|
||||
0x4F4FEE, 0x55AA00, 0x55AA55, 0x55AAAA, 0x4F9EEE, 0x4FEE00, 0x4FEE4F, 0x4FEE9E,
|
||||
0x55FFAA, 0x55FFFF, 0x770000, 0x770077, 0x5D00BB, 0x5500FF, 0x777700, 0x777777,
|
||||
0x5D5DBB, 0x5555FF, 0x5DBB00, 0x5DBB5D, 0x5DBBBB, 0x55AAFF, 0x55FF00, 0x55FF55,
|
||||
0x880088, 0x8800CC, 0x884400, 0x884444, 0x884488, 0x8844CC, 0x888800, 0x888844,
|
||||
0x888888, 0x8888CC, 0x88CC00, 0x88CC44, 0x88CC88, 0x88CCCC, 0x880000, 0x880044,
|
||||
0x99004C, 0x990099, 0x9300DD, 0x994C00, 0x994C4C, 0x994C99, 0x9349DD, 0x999900,
|
||||
0x99994C, 0x999999, 0x9393DD, 0x93DD00, 0x93DD49, 0x93DD93, 0x93DDDD, 0x990000,
|
||||
0xAA0000, 0xAA0055, 0xAA00AA, 0x9E00EE, 0xAA5500, 0xAA5555, 0xAA55AA, 0x9E4FEE,
|
||||
0xAAAA00, 0xAAAA55, 0xAAAAAA, 0x9E9EEE, 0x9EEE00, 0x9EEE4F, 0x9EEE9E, 0x9EEEEE,
|
||||
0xAAFFFF, 0xBB0000, 0xBB005D, 0xBB00BB, 0xAA00FF, 0xBB5D00, 0xBB5D5D, 0xBB5DBB,
|
||||
0xAA55FF, 0xBBBB00, 0xBBBB5D, 0xBBBBBB, 0xAAAAFF, 0xAAFF00, 0xAAFF55, 0xAAFFAA,
|
||||
0xCC00CC, 0xCC4400, 0xCC4444, 0xCC4488, 0xCC44CC, 0xCC8800, 0xCC8844, 0xCC8888,
|
||||
0xCC88CC, 0xCCCC00, 0xCCCC44, 0xCCCC88, 0xCCCCCC, 0xCC0000, 0xCC0044, 0xCC0088,
|
||||
0xDD0093, 0xDD00DD, 0xDD4900, 0xDD4949, 0xDD4993, 0xDD49DD, 0xDD9300, 0xDD9349,
|
||||
0xDD9393, 0xDD93DD, 0xDDDD00, 0xDDDD49, 0xDDDD93, 0xDDDDDD, 0xDD0000, 0xDD0049,
|
||||
0xEE004F, 0xEE009E, 0xEE00EE, 0xEE4F00, 0xEE4F4F, 0xEE4F9E, 0xEE4FEE, 0xEE9E00,
|
||||
0xEE9E4F, 0xEE9E9E, 0xEE9EEE, 0xEEEE00, 0xEEEE4F, 0xEEEE9E, 0xEEEEEE, 0xEE0000,
|
||||
0xFF0000, 0xFF0055, 0xFF00AA, 0xFF00FF, 0xFF5500, 0xFF5555, 0xFF55AA, 0xFF55FF,
|
||||
0xFFAA00, 0xFFAA55, 0xFFAAAA, 0xFFAAFF, 0xFFFF00, 0xFFFF55, 0xFFFFAA, 0xFFFFFF,
|
||||
};
|
||||
|
||||
unsigned char closestrgb[16*16*16] = {
|
||||
0,17,17,1,1,18,35,52,2,19,36,53,3,20,37,54,
|
||||
17,17,17,1,1,18,35,52,2,19,36,53,3,20,37,54,
|
||||
17,17,34,5,5,5,35,6,6,6,23,7,7,7,24,41,
|
||||
4,4,5,5,5,5,6,6,6,6,23,7,7,7,24,41,
|
||||
4,4,5,5,5,22,22,6,6,23,40,40,7,24,41,41,
|
||||
21,21,5,5,22,22,39,39,6,23,40,57,57,24,41,58,
|
||||
38,38,38,9,22,39,39,56,56,40,40,57,57,57,41,58,
|
||||
55,55,9,9,9,39,56,56,10,10,57,11,11,11,28,58,
|
||||
8,8,9,9,9,9,56,10,10,10,27,11,11,11,28,45,
|
||||
25,25,9,9,26,26,43,10,10,27,27,44,11,28,45,45,
|
||||
42,42,26,26,43,43,43,60,27,27,44,44,61,28,45,62,
|
||||
59,59,13,13,43,60,60,14,14,44,44,61,61,15,45,62,
|
||||
12,12,13,13,13,60,60,14,14,14,61,61,15,15,16,62,
|
||||
29,29,13,13,30,30,60,14,14,31,31,15,15,16,16,33,
|
||||
46,46,30,30,47,47,47,31,31,32,32,32,16,16,33,33,
|
||||
63,63,47,47,47,48,48,48,32,32,49,49,49,33,33,50,
|
||||
17,17,17,1,1,18,35,52,2,19,36,53,3,20,37,54,
|
||||
17,17,34,34,1,18,35,52,2,19,36,53,3,20,37,54,
|
||||
17,34,34,34,51,5,35,6,6,6,23,7,7,7,24,41,
|
||||
4,34,34,51,5,5,6,6,6,6,23,7,7,7,24,41,
|
||||
4,4,51,5,5,22,22,6,6,23,40,40,7,24,41,41,
|
||||
21,21,5,5,22,22,39,39,6,23,40,57,57,24,41,58,
|
||||
38,38,38,9,22,39,39,56,56,40,40,57,57,57,41,58,
|
||||
55,55,9,9,9,39,56,56,10,10,57,11,11,11,28,58,
|
||||
8,8,9,9,9,9,56,10,10,10,27,11,11,11,28,45,
|
||||
25,25,9,9,26,26,43,10,10,27,27,44,11,28,45,45,
|
||||
42,42,26,26,43,43,43,60,27,27,44,44,61,28,45,62,
|
||||
59,59,13,13,43,60,60,14,14,44,44,61,61,15,45,62,
|
||||
12,12,13,13,13,60,60,14,14,14,61,61,15,15,16,62,
|
||||
29,29,13,13,30,30,60,14,14,31,31,15,15,16,16,33,
|
||||
46,46,30,30,47,47,47,31,31,32,32,32,16,16,33,33,
|
||||
63,63,47,47,47,48,48,48,32,32,49,49,49,33,33,50,
|
||||
17,17,34,64,64,64,35,65,65,65,82,66,66,66,83,100,
|
||||
17,34,34,34,51,64,35,65,65,65,82,66,66,66,83,100,
|
||||
34,34,34,51,51,51,69,69,69,69,69,70,70,70,87,87,
|
||||
67,34,51,51,51,68,69,69,69,69,86,70,70,70,87,87,
|
||||
67,51,51,51,68,68,69,69,69,69,86,70,70,70,87,104,
|
||||
67,67,51,68,68,68,39,69,69,69,40,70,70,70,87,58,
|
||||
38,38,72,72,72,39,39,56,73,73,40,57,74,74,87,58,
|
||||
71,71,72,72,72,72,56,73,73,73,73,74,74,74,74,91,
|
||||
71,71,72,72,72,72,73,73,73,73,73,74,74,74,91,91,
|
||||
71,71,72,72,72,72,73,73,73,73,90,74,74,91,91,108,
|
||||
88,88,72,89,89,43,43,73,73,90,44,44,74,91,91,62,
|
||||
75,75,76,76,76,76,60,77,77,77,44,78,78,78,78,62,
|
||||
75,75,76,76,76,76,77,77,77,77,77,78,78,78,78,95,
|
||||
75,75,76,76,76,76,77,77,77,94,94,78,78,78,95,95,
|
||||
92,92,93,93,93,93,93,77,94,94,94,78,78,95,95,96,
|
||||
109,109,93,93,110,48,48,94,94,111,49,49,95,95,96,50,
|
||||
79,79,64,64,64,64,65,65,65,65,82,66,66,66,83,100,
|
||||
79,34,34,51,64,64,65,65,65,65,82,66,66,66,83,100,
|
||||
67,34,51,51,51,68,69,69,69,69,86,70,70,70,87,87,
|
||||
67,51,51,51,68,68,69,69,69,69,86,70,70,70,87,104,
|
||||
67,67,51,68,68,68,69,69,69,69,86,70,70,70,87,104,
|
||||
67,67,68,68,68,85,85,69,69,86,86,70,70,87,87,104,
|
||||
71,71,72,72,72,85,85,73,73,86,103,103,74,87,104,121,
|
||||
71,71,72,72,72,72,73,73,73,73,73,74,74,74,91,91,
|
||||
71,71,72,72,72,72,73,73,73,73,90,74,74,74,91,108,
|
||||
71,71,72,72,72,89,89,73,73,90,90,74,74,91,91,108,
|
||||
88,88,89,89,89,89,106,73,90,90,107,107,91,91,108,108,
|
||||
75,75,76,76,76,76,106,77,77,77,107,78,78,78,108,125,
|
||||
75,75,76,76,76,76,77,77,77,77,94,78,78,78,95,95,
|
||||
75,75,76,76,76,93,93,77,77,94,94,78,78,95,95,95,
|
||||
92,92,93,93,93,93,110,94,94,94,111,111,95,95,95,96,
|
||||
109,109,93,110,110,110,127,94,111,111,111,112,95,95,96,96,
|
||||
79,79,64,64,64,81,81,65,65,82,99,99,66,83,100,100,
|
||||
79,79,51,64,64,81,81,65,65,82,99,99,66,83,100,100,
|
||||
67,51,51,51,68,68,69,69,69,69,86,70,70,70,87,104,
|
||||
67,67,51,68,68,68,69,69,69,69,86,70,70,70,87,104,
|
||||
67,67,68,68,68,85,85,69,69,86,86,70,70,87,87,104,
|
||||
84,84,68,68,85,85,85,69,69,86,103,103,70,87,104,121,
|
||||
84,84,72,72,85,85,85,102,73,86,103,120,120,87,104,121,
|
||||
71,71,72,72,72,72,102,73,73,73,73,74,74,74,91,121,
|
||||
71,71,72,72,72,72,73,73,73,73,90,74,74,91,91,108,
|
||||
88,88,72,72,89,89,89,73,73,90,90,74,74,91,108,108,
|
||||
105,105,89,89,89,106,106,73,90,90,107,107,91,91,108,125,
|
||||
105,105,76,76,76,106,123,77,77,77,107,124,78,78,108,125,
|
||||
75,75,76,76,76,76,123,77,77,77,94,78,78,78,95,125,
|
||||
92,92,76,76,93,93,93,77,94,94,94,78,78,95,95,96,
|
||||
109,109,93,93,93,110,110,94,94,111,111,111,95,95,96,96,
|
||||
109,109,110,110,110,127,127,127,111,111,112,112,112,96,96,96,
|
||||
80,80,64,64,81,81,98,98,65,82,99,116,116,83,100,117,
|
||||
80,80,64,64,81,81,98,98,65,82,99,116,116,83,100,117,
|
||||
67,67,51,68,68,68,98,69,69,69,99,70,70,70,87,117,
|
||||
67,67,68,68,68,85,85,69,69,86,86,70,70,87,87,104,
|
||||
84,84,68,68,85,85,85,69,69,86,103,103,70,87,104,121,
|
||||
84,84,68,85,85,85,85,102,86,86,103,120,120,87,104,121,
|
||||
101,101,101,85,85,85,102,102,86,103,103,120,120,120,104,121,
|
||||
101,101,72,72,72,102,102,102,73,73,120,120,74,74,91,121,
|
||||
71,71,72,72,72,89,89,73,73,90,90,74,74,91,91,108,
|
||||
88,88,72,89,89,89,106,73,90,90,107,107,74,91,108,108,
|
||||
105,105,105,89,106,106,106,123,90,107,107,107,124,108,108,125,
|
||||
122,122,76,76,106,123,123,123,77,107,107,124,124,124,125,125,
|
||||
122,122,76,76,76,123,123,77,77,77,124,124,124,78,95,125,
|
||||
92,92,76,93,93,93,123,77,94,94,111,124,78,95,95,96,
|
||||
109,109,93,93,110,110,110,94,94,111,111,112,95,95,96,96,
|
||||
126,126,126,110,127,127,127,127,111,111,112,112,112,96,96,113,
|
||||
97,97,97,143,81,98,98,115,115,99,99,116,116,116,100,117,
|
||||
97,97,97,143,81,98,98,115,115,99,99,116,116,116,100,117,
|
||||
97,97,131,131,131,98,98,115,132,132,99,116,133,133,87,117,
|
||||
130,130,131,131,131,85,85,132,132,86,103,103,133,87,104,121,
|
||||
84,84,131,131,85,85,85,102,132,86,103,120,120,87,104,121,
|
||||
101,101,101,85,85,85,102,102,86,103,103,120,120,120,104,121,
|
||||
101,101,101,85,85,102,102,102,119,103,120,120,120,120,121,121,
|
||||
118,118,118,135,102,102,102,119,119,119,120,120,120,137,91,121,
|
||||
118,118,135,135,135,89,119,119,119,90,90,137,137,91,108,108,
|
||||
105,105,135,89,89,106,106,119,90,90,107,107,137,91,108,125,
|
||||
105,105,105,106,106,106,123,123,90,107,107,124,124,108,108,125,
|
||||
122,122,122,106,123,123,123,123,140,107,124,124,124,124,125,125,
|
||||
122,122,139,139,123,123,123,123,140,140,124,124,124,124,95,125,
|
||||
122,122,139,93,93,123,123,140,94,94,111,124,124,95,95,96,
|
||||
109,109,93,110,110,110,127,94,111,111,111,112,95,95,96,96,
|
||||
126,126,126,127,127,127,127,127,111,112,112,112,112,96,96,113,
|
||||
114,114,143,143,143,98,115,115,128,128,116,129,129,129,146,117,
|
||||
114,114,143,143,143,98,115,115,128,128,116,129,129,129,146,117,
|
||||
130,130,131,131,131,131,115,132,132,132,132,133,133,133,133,150,
|
||||
130,130,131,131,131,131,132,132,132,132,132,133,133,133,150,150,
|
||||
130,130,131,131,131,131,102,132,132,132,132,133,133,133,150,121,
|
||||
101,101,131,131,131,102,102,102,132,132,120,120,133,133,150,121,
|
||||
118,118,118,135,102,102,102,119,119,119,120,120,120,137,150,121,
|
||||
118,118,135,135,135,102,119,119,119,136,136,137,137,137,137,154,
|
||||
134,134,135,135,135,135,119,119,136,136,136,137,137,137,154,154,
|
||||
134,134,135,135,135,135,119,136,136,136,153,137,137,137,154,154,
|
||||
122,122,135,135,135,123,123,136,136,153,107,124,124,154,154,125,
|
||||
138,138,139,139,139,123,123,140,140,140,124,124,141,141,141,125,
|
||||
138,138,139,139,139,139,123,140,140,140,124,141,141,141,141,158,
|
||||
138,138,139,139,139,139,140,140,140,140,157,141,141,141,158,158,
|
||||
155,155,139,156,156,156,156,140,157,157,157,141,141,158,158,158,
|
||||
126,126,156,156,127,127,127,157,157,157,112,112,158,158,158,113,
|
||||
142,142,143,143,143,143,115,128,128,128,145,129,129,129,146,163,
|
||||
142,142,143,143,143,143,115,128,128,128,145,129,129,129,146,163,
|
||||
130,130,131,131,131,131,132,132,132,132,132,133,133,133,150,150,
|
||||
130,130,131,131,131,131,132,132,132,132,149,133,133,133,150,167,
|
||||
130,130,131,131,131,131,132,132,132,132,149,133,133,150,150,167,
|
||||
130,130,131,131,131,148,148,132,132,149,149,133,133,150,150,167,
|
||||
118,118,135,135,135,148,119,119,119,149,149,137,137,150,167,167,
|
||||
134,134,135,135,135,135,119,119,136,136,136,137,137,137,154,154,
|
||||
134,134,135,135,135,135,119,136,136,136,153,137,137,137,154,154,
|
||||
134,134,135,135,135,152,152,136,136,153,153,137,137,154,154,171,
|
||||
151,151,135,152,152,152,152,136,153,153,153,170,154,154,171,171,
|
||||
138,138,139,139,139,139,140,140,140,140,170,141,141,141,141,171,
|
||||
138,138,139,139,139,139,140,140,140,140,157,141,141,141,158,158,
|
||||
138,138,139,139,156,156,156,140,140,157,157,141,141,158,158,158,
|
||||
155,155,156,156,156,156,173,157,157,157,174,141,158,158,158,175,
|
||||
172,172,156,173,173,173,173,157,157,174,174,174,158,158,175,175,
|
||||
159,159,143,143,144,144,161,128,128,145,145,162,129,146,163,163,
|
||||
159,159,143,143,144,144,161,128,128,145,145,162,129,146,163,163,
|
||||
130,130,131,131,131,131,132,132,132,132,149,133,133,150,150,167,
|
||||
130,130,131,131,131,148,148,132,132,149,149,133,133,150,150,167,
|
||||
147,147,131,131,148,148,148,132,132,149,149,133,133,150,167,167,
|
||||
147,147,131,148,148,148,165,132,149,149,166,166,133,150,167,167,
|
||||
164,164,135,148,148,165,165,119,149,149,166,166,137,150,167,184,
|
||||
134,134,135,135,135,135,119,136,136,136,153,137,137,137,154,154,
|
||||
134,134,135,135,135,152,152,136,136,153,153,137,137,154,154,171,
|
||||
151,151,135,152,152,152,152,136,153,153,153,170,154,154,171,171,
|
||||
151,151,152,152,152,169,169,153,153,153,170,170,154,154,171,171,
|
||||
168,168,139,139,139,169,169,140,140,170,170,170,141,141,171,188,
|
||||
138,138,139,139,139,139,140,140,140,157,157,141,141,141,158,158,
|
||||
155,155,156,156,156,156,156,140,157,157,157,141,141,158,158,175,
|
||||
172,172,156,156,173,173,173,157,157,174,174,174,158,158,175,175,
|
||||
172,172,173,173,173,173,190,157,174,174,174,191,158,175,175,175,
|
||||
160,160,144,144,161,161,161,178,145,145,162,162,179,146,163,180,
|
||||
160,160,144,144,161,161,161,178,145,145,162,162,179,146,163,180,
|
||||
147,147,131,148,148,161,161,132,132,149,162,162,133,150,150,180,
|
||||
147,147,148,148,148,148,165,132,149,149,166,166,150,150,167,167,
|
||||
164,164,148,148,148,165,165,132,149,149,166,166,150,150,167,184,
|
||||
164,164,164,148,165,165,165,182,149,166,166,166,183,167,167,184,
|
||||
164,164,164,165,165,165,182,182,149,166,166,183,183,167,167,184,
|
||||
181,181,135,135,135,182,182,136,136,153,166,183,183,154,154,184,
|
||||
151,151,135,152,152,152,152,136,153,153,153,170,154,154,171,171,
|
||||
151,151,152,152,152,169,169,153,153,153,170,170,154,154,171,171,
|
||||
168,168,168,169,169,169,169,169,153,170,170,170,187,171,171,188,
|
||||
168,168,168,169,169,169,186,186,170,170,170,187,187,187,188,188,
|
||||
185,185,139,156,156,186,186,186,157,157,187,187,187,158,158,188,
|
||||
155,155,156,156,156,173,173,157,157,157,174,187,158,158,158,175,
|
||||
172,172,156,173,173,173,173,157,174,174,174,191,158,158,175,175,
|
||||
189,189,189,173,190,190,190,190,174,174,191,191,191,175,175,176,
|
||||
177,177,206,206,161,178,178,207,207,162,162,179,179,192,163,180,
|
||||
177,177,206,206,161,178,178,207,207,162,162,179,179,192,163,180,
|
||||
193,193,194,194,194,194,178,195,195,195,162,196,196,196,196,180,
|
||||
193,193,194,194,194,194,165,195,195,195,166,196,196,196,167,184,
|
||||
164,164,194,194,194,165,182,195,195,195,166,183,196,196,167,184,
|
||||
181,181,194,194,165,182,182,182,195,166,166,183,183,183,184,184,
|
||||
181,181,181,165,182,182,182,182,199,166,183,183,183,183,184,184,
|
||||
197,197,198,198,198,182,182,199,199,199,183,183,200,200,200,184,
|
||||
197,197,198,198,198,198,199,199,199,199,170,200,200,200,200,171,
|
||||
168,168,198,198,198,169,169,199,199,170,170,170,200,200,171,188,
|
||||
168,168,168,169,169,169,186,186,170,170,170,187,187,187,188,188,
|
||||
185,185,202,202,186,186,186,186,203,170,187,187,187,187,188,188,
|
||||
185,185,202,202,202,186,186,203,203,203,187,187,187,204,204,188,
|
||||
201,201,202,202,202,186,186,203,203,203,187,187,204,204,175,175,
|
||||
172,172,202,173,173,190,190,203,203,174,191,191,204,175,175,176,
|
||||
189,189,189,190,190,190,190,190,174,191,191,191,191,175,176,176,
|
||||
205,205,206,206,206,178,178,207,207,207,179,179,192,192,209,180,
|
||||
205,205,206,206,206,178,178,207,207,207,179,179,192,192,209,180,
|
||||
193,193,194,194,194,194,195,195,195,195,195,196,196,196,196,213,
|
||||
193,193,194,194,194,194,195,195,195,195,212,196,196,196,213,213,
|
||||
193,193,194,194,194,194,182,195,195,195,212,196,196,196,213,184,
|
||||
181,181,194,194,194,182,182,195,195,195,183,183,183,196,213,184,
|
||||
181,181,198,198,182,182,182,182,199,199,183,183,183,183,213,184,
|
||||
197,197,198,198,198,198,182,199,199,199,183,200,200,200,200,217,
|
||||
197,197,198,198,198,198,199,199,199,199,216,200,200,200,217,217,
|
||||
197,197,198,198,198,198,199,199,199,216,216,200,200,200,217,217,
|
||||
185,185,198,215,215,186,186,186,216,216,187,187,187,217,217,188,
|
||||
185,185,202,202,202,186,186,203,203,203,187,187,187,204,204,188,
|
||||
201,201,202,202,202,186,186,203,203,203,187,187,204,204,204,221,
|
||||
201,201,202,202,202,202,186,203,203,203,220,204,204,204,221,221,
|
||||
218,218,202,219,219,219,219,203,220,220,220,204,204,221,221,221,
|
||||
189,189,219,219,190,190,190,220,220,220,191,191,221,221,221,176,
|
||||
222,222,206,206,223,223,178,207,207,208,208,192,192,209,209,226,
|
||||
222,222,206,206,223,223,178,207,207,208,208,192,192,209,209,226,
|
||||
193,193,194,194,194,194,195,195,195,212,212,196,196,196,213,213,
|
||||
193,193,194,194,194,211,211,195,195,212,212,196,196,213,213,213,
|
||||
210,210,194,194,211,211,211,195,212,212,212,196,196,213,213,230,
|
||||
210,210,194,211,211,211,182,195,212,212,229,183,196,213,213,230,
|
||||
181,181,198,211,211,182,182,199,212,212,229,183,183,213,213,230,
|
||||
197,197,198,198,198,198,199,199,199,199,216,200,200,200,217,217,
|
||||
197,197,198,198,215,215,215,199,199,216,216,200,200,217,217,217,
|
||||
214,214,215,215,215,215,215,199,216,216,216,200,200,217,217,234,
|
||||
214,214,215,215,215,232,232,216,216,216,233,187,217,217,217,234,
|
||||
201,201,202,202,202,186,186,203,203,203,187,187,204,204,234,234,
|
||||
201,201,202,202,202,202,186,203,203,203,220,204,204,204,221,221,
|
||||
218,218,202,219,219,219,219,203,220,220,220,204,204,221,221,221,
|
||||
218,218,219,219,219,219,219,220,220,220,220,237,221,221,221,238,
|
||||
235,235,219,219,236,236,236,220,220,237,237,237,221,221,238,238,
|
||||
239,239,223,223,224,224,224,208,208,225,225,225,209,209,226,226,
|
||||
239,239,223,223,224,224,224,208,208,225,225,225,209,209,226,226,
|
||||
210,210,211,211,211,211,211,195,212,212,212,196,196,213,213,230,
|
||||
210,210,211,211,211,211,228,212,212,212,229,229,213,213,213,230,
|
||||
227,227,211,211,211,228,228,212,212,229,229,229,213,213,230,230,
|
||||
227,227,211,211,228,228,228,212,212,229,229,246,213,213,230,230,
|
||||
227,227,211,228,228,228,245,212,229,229,229,246,213,213,230,230,
|
||||
214,214,198,215,215,215,215,199,216,216,216,200,200,217,217,217,
|
||||
214,214,215,215,215,215,232,216,216,216,233,200,217,217,217,234,
|
||||
231,231,215,215,232,232,232,216,216,233,233,233,217,217,234,234,
|
||||
231,231,215,232,232,232,232,216,233,233,233,250,217,217,234,234,
|
||||
231,231,202,232,232,249,249,203,203,233,250,250,204,234,234,251,
|
||||
218,218,202,219,219,219,219,203,220,220,220,204,204,221,221,221,
|
||||
218,218,219,219,219,219,219,220,220,220,220,237,221,221,221,238,
|
||||
235,235,219,219,236,236,236,220,220,237,237,237,221,221,238,238,
|
||||
235,235,236,236,236,236,236,220,237,237,237,254,221,238,238,238,
|
||||
240,240,224,224,224,241,241,241,225,225,242,242,242,226,226,243,
|
||||
240,240,224,224,224,241,241,241,225,225,242,242,242,226,226,243,
|
||||
227,227,211,211,228,241,241,212,212,229,242,242,213,213,230,243,
|
||||
227,227,211,228,228,228,245,212,229,229,229,246,213,213,230,230,
|
||||
227,227,228,228,228,245,245,245,229,229,246,246,246,230,230,230,
|
||||
244,244,244,228,245,245,245,245,229,229,246,246,246,230,230,247,
|
||||
244,244,244,245,245,245,245,245,229,246,246,246,246,230,230,247,
|
||||
244,244,215,215,245,245,245,216,216,216,246,246,217,217,217,247,
|
||||
231,231,215,232,232,232,232,216,216,233,233,233,217,217,234,234,
|
||||
231,231,232,232,232,232,249,216,233,233,233,250,217,234,234,234,
|
||||
248,248,248,232,249,249,249,249,233,233,250,250,250,234,234,251,
|
||||
248,248,248,249,249,249,249,249,233,250,250,250,250,234,251,251,
|
||||
248,248,219,219,249,249,249,220,220,220,250,250,221,221,221,251,
|
||||
235,235,219,219,236,236,236,220,220,237,237,237,221,221,238,238,
|
||||
235,235,236,236,236,236,236,220,237,237,237,254,221,238,238,238,
|
||||
252,252,252,236,236,253,253,253,237,237,254,254,254,238,238,255,
|
||||
};
|
||||
|
121
sys/src/cmd/pict/rgbycc.c
Normal file
121
sys/src/cmd/pict/rgbycc.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;
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, rgb;
|
||||
int r, g, b;
|
||||
double Y, Cr, Cb;
|
||||
int y, cb, cr;
|
||||
unsigned char close[16*16*16];
|
||||
|
||||
//print("%d\n", closest(atoi(argv[1]), atoi(argv[2]), atoi(argv[3])));
|
||||
//exits("X");
|
||||
|
||||
print("/* This file has been generated by rgbycc */\n");
|
||||
/* 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("unsigned char 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);
|
||||
}
|
223
sys/src/cmd/pict/tga.c
Normal file
223
sys/src/cmd/pict/tga.c
Normal file
@ -0,0 +1,223 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <event.h>
|
||||
#include <keyboard.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
int cflag = 0;
|
||||
int dflag = 0;
|
||||
int eflag = 0;
|
||||
int nineflag = 0;
|
||||
int threeflag = 0;
|
||||
int output = 0;
|
||||
uint32_t outchan = CMAP8;
|
||||
int defaultcolor = 1;
|
||||
Image *image;
|
||||
|
||||
enum{
|
||||
Border = 2,
|
||||
Edge = 5
|
||||
};
|
||||
|
||||
char *show(int, char*);
|
||||
|
||||
Rawimage** readtga(int fd);
|
||||
|
||||
Rectangle
|
||||
imager(Image *i)
|
||||
{
|
||||
Point p1, p2;
|
||||
|
||||
p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min);
|
||||
p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
|
||||
return rectaddpt(i->r, subpt(p2, p1));
|
||||
}
|
||||
|
||||
void
|
||||
eresized(int new)
|
||||
{
|
||||
Rectangle r;
|
||||
|
||||
if(new && getwindow(display, Refnone) < 0){
|
||||
fprint(2, "tga: can't reattach to window\n");
|
||||
exits("resize");
|
||||
}
|
||||
if(image == nil)
|
||||
return;
|
||||
r = imager(image);
|
||||
border(screen, r, -Border, nil, ZP);
|
||||
drawop(screen, r, image, nil, image->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: tga -39cdektv [file ...]\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, "tga: 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, "tga: 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, "tga: 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 = readtga(fd);
|
||||
if(array == nil || array[0]==nil){
|
||||
fprint(2, "tga: 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);
|
||||
outchan = GREY8;
|
||||
}else
|
||||
c = totruecolor(r, CRGB24);
|
||||
}
|
||||
if(c == nil){
|
||||
fprint(2, "tga: 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, "tga: allocimage %s failed: %r\n", name);
|
||||
return "allocimage";
|
||||
}
|
||||
|
||||
if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
|
||||
fprint(2, "tga: loadimage %s failed: %r\n", name);
|
||||
return "loadimage";
|
||||
}
|
||||
image = i;
|
||||
eresized(0);
|
||||
if((ch=ekbd())=='q' || ch==Kdel || ch==Keof)
|
||||
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, "tga: %s: write error %r\n", name);
|
||||
return "write";
|
||||
}
|
||||
}else if(cflag){
|
||||
if(writerawimage(1, c) < 0){
|
||||
fprint(2, "tga: %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;
|
||||
}
|
256
sys/src/cmd/pict/tif.c
Normal file
256
sys/src/cmd/pict/tif.c
Normal file
@ -0,0 +1,256 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <event.h>
|
||||
#include <keyboard.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
int cflag = 0;
|
||||
int dflag = 0;
|
||||
int eflag = 0;
|
||||
int nineflag = 0;
|
||||
int threeflag = 0;
|
||||
int output = 0;
|
||||
Image *image;
|
||||
int defaultcolor = 1;
|
||||
|
||||
enum {
|
||||
Border = 2,
|
||||
Edge = 5
|
||||
};
|
||||
|
||||
int init(void);
|
||||
char *show(int, char *, int);
|
||||
|
||||
Rectangle
|
||||
imager(Image *i)
|
||||
{
|
||||
Point p1, p2;
|
||||
|
||||
p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min);
|
||||
p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
|
||||
return rectaddpt(i->r, subpt(p2, p1));
|
||||
}
|
||||
|
||||
void
|
||||
eresized(int new)
|
||||
{
|
||||
Rectangle r;
|
||||
|
||||
if(new && getwindow(display, Refnone) < 0)
|
||||
sysfatal("getwindow: %r");
|
||||
if(image == nil)
|
||||
return;
|
||||
r = imager(image);
|
||||
border(screen, r, -Border, nil, ZP);
|
||||
drawop(screen, r, image, nil, image->r.min, S);
|
||||
flushimage(display, 1);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [-39cdektv] [file.tif ...]\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd, i;
|
||||
char *err;
|
||||
uint32_t outchan;
|
||||
|
||||
outchan = CMAP8;
|
||||
ARGBEGIN {
|
||||
/*
|
||||
* produce encoded, compressed, bitmap file;
|
||||
* no display by default
|
||||
*/
|
||||
case 'c':
|
||||
cflag++;
|
||||
dflag++;
|
||||
output++;
|
||||
if(defaultcolor)
|
||||
outchan = CMAP8;
|
||||
break;
|
||||
/* suppress display of image */
|
||||
case 'd':
|
||||
dflag++;
|
||||
break;
|
||||
/* disable floyd-steinberg error diffusion */
|
||||
case 'e':
|
||||
eflag++;
|
||||
break;
|
||||
/* force black and white */
|
||||
case 'k':
|
||||
defaultcolor = 0;
|
||||
outchan = GREY8;
|
||||
break;
|
||||
/*
|
||||
* produce encoded, compressed, three-color
|
||||
* bitmap file; no display by default
|
||||
*/
|
||||
case '3':
|
||||
threeflag++;
|
||||
/* fall through */
|
||||
/*
|
||||
* produce encoded, compressed, true-color
|
||||
* bitmap file; no display by default
|
||||
*/
|
||||
case 't':
|
||||
cflag++;
|
||||
dflag++;
|
||||
output++;
|
||||
defaultcolor = 0;
|
||||
outchan = RGB24;
|
||||
break;
|
||||
/* force RGBV */
|
||||
case 'v':
|
||||
defaultcolor = 0;
|
||||
outchan = CMAP8;
|
||||
break;
|
||||
/*
|
||||
* produce plan 9, uncompressed, bitmap file;
|
||||
* no display by default
|
||||
*/
|
||||
case '9':
|
||||
nineflag++;
|
||||
dflag++;
|
||||
output++;
|
||||
if(defaultcolor)
|
||||
outchan = CMAP8;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
} ARGEND
|
||||
|
||||
if(argc <= 0)
|
||||
exits(show(0, "<stdin>", outchan));
|
||||
err = nil;
|
||||
for(i = 0; i < argc; i++) {
|
||||
if((fd = open(argv[i], OREAD)) < 0) {
|
||||
fprint(2, "%s: open %s: %r\n",
|
||||
argv0, argv[i]);
|
||||
err = "open";
|
||||
} else {
|
||||
err = show(fd, argv[i], outchan);
|
||||
close(fd);
|
||||
}
|
||||
if((nineflag || cflag) && argc > 1 && err == nil) {
|
||||
fprint(2, "%s: exiting after one file\n",
|
||||
argv0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
exits(err);
|
||||
}
|
||||
|
||||
int
|
||||
init(void)
|
||||
{
|
||||
static int inited = 0;
|
||||
|
||||
if(!inited) {
|
||||
if(initdraw(0, 0, 0) < 0) {
|
||||
fprint(2, "%s: initdraw: %r", argv0);
|
||||
return -1;
|
||||
}
|
||||
einit(Ekeyboard|Emouse);
|
||||
inited++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
show(int fd, char *name, int outchan)
|
||||
{
|
||||
Rawimage **array, *r, *c;
|
||||
Image *i;
|
||||
int j, ch;
|
||||
Biobuf b;
|
||||
char buf[32];
|
||||
|
||||
if(Binit(&b, fd, OREAD) < 0)
|
||||
return nil;
|
||||
array = Breadtif(&b, CRGB24);
|
||||
if(array == nil || array[0] == nil) {
|
||||
if(array != nil)
|
||||
free(array);
|
||||
fprint(2, "%s: decode %s failed: %r\n",
|
||||
argv0, name);
|
||||
return "decode";
|
||||
}
|
||||
Bterm(&b);
|
||||
if(!dflag) {
|
||||
if(init() < 0)
|
||||
return "initdraw";
|
||||
if(defaultcolor && screen->depth > 8)
|
||||
outchan = RGB24;
|
||||
}
|
||||
r = array[0];
|
||||
if(outchan != CMAP8) {
|
||||
switch(r->chandesc) {
|
||||
case CY:
|
||||
outchan = GREY8;
|
||||
break;
|
||||
case CRGB24:
|
||||
outchan = RGB24;
|
||||
break;
|
||||
}
|
||||
c = r;
|
||||
} else if((c = torgbv(r, !eflag)) == nil) {
|
||||
fprint(2, "%s: conversion of %s failed: %r\n",
|
||||
argv0, name);
|
||||
return "torgbv";
|
||||
}
|
||||
if(!dflag) {
|
||||
i = allocimage(display, c->r, outchan, 0, 0);
|
||||
if(i == nil) {
|
||||
fprint(2, "%s: allocimage %s: %r\n",
|
||||
argv0, name);
|
||||
return "allocimage";
|
||||
}
|
||||
if(loadimage(i, i->r, c->chans[0],
|
||||
c->chanlen) < 0) {
|
||||
fprint(2, "%s: loadimage %s: %r\n",
|
||||
argv0, name);
|
||||
return "loadimage";
|
||||
}
|
||||
image = i;
|
||||
eresized(0);
|
||||
ch = ekbd();
|
||||
if(ch == 'q' || ch == Kdel || ch == Keof)
|
||||
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, "%s: %s: write error: %r\n",
|
||||
argv0, name);
|
||||
return "write";
|
||||
}
|
||||
} else if(cflag && writerawimage(1, c) < 0) {
|
||||
fprint(2, "%s: %s: write error: %r\n",
|
||||
argv0, name);
|
||||
return "write";
|
||||
}
|
||||
if(c != nil && c != r) {
|
||||
free(c->chans[0]);
|
||||
free(c);
|
||||
}
|
||||
for(j = 0; j < r->nchans; j++)
|
||||
free(r->chans[j]);
|
||||
free(r);
|
||||
free(array);
|
||||
return nil;
|
||||
}
|
178
sys/src/cmd/pict/togif.c
Normal file
178
sys/src/cmd/pict/togif.c
Normal file
@ -0,0 +1,178 @@
|
||||
#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 ... | -E]\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
#define UNSET (-12345678)
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
Biobuf bout;
|
||||
Memimage *i, *ni;
|
||||
int fd, j, dt, trans, loop, eof;
|
||||
char buf[256];
|
||||
char *err, *comment, *s;
|
||||
|
||||
comment = nil;
|
||||
dt = -1;
|
||||
trans = -1;
|
||||
loop = UNSET;
|
||||
eof = 0;
|
||||
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;
|
||||
case 'E':
|
||||
eof++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
if(Binit(&bout, 1, OWRITE) < 0)
|
||||
sysfatal("Binit failed: %r");
|
||||
|
||||
memimageinit();
|
||||
|
||||
err = nil;
|
||||
|
||||
if(eof){
|
||||
if(argc != 0) usage();
|
||||
for(j = 0;;j++){
|
||||
i = readmemimage(0);
|
||||
if(i == nil) break;
|
||||
ni = memonechan(i);
|
||||
if(ni == nil)
|
||||
sysfatal("converting image to RGBV: %r");
|
||||
if(i != nil){
|
||||
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 <stdin>");
|
||||
err = memwritegif(&bout, i, buf, dt, trans);
|
||||
}
|
||||
if(err != nil) break;
|
||||
freememimage(i);
|
||||
comment = nil;
|
||||
}
|
||||
}else 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
sys/src/cmd/pict/toico.c
Normal file
322
sys/src/cmd/pict/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;
|
||||
|
||||
unsigned char w; /* icon width */
|
||||
unsigned char h; /* icon height */
|
||||
unsigned short ncolor; /* number of colors */
|
||||
unsigned short nplane; /* number of bit planes */
|
||||
unsigned short bits; /* bits per pixel */
|
||||
uint32_t len; /* length of data */
|
||||
uint32_t offset; /* file offset to data */
|
||||
unsigned char map[4*256]; /* color map */
|
||||
|
||||
Image *img;
|
||||
|
||||
unsigned char *xor;
|
||||
int xorlen;
|
||||
unsigned char *and;
|
||||
int andlen;
|
||||
};
|
||||
|
||||
typedef struct Header Header;
|
||||
struct Header
|
||||
{
|
||||
uint n;
|
||||
Icon *first;
|
||||
Icon *last;
|
||||
};
|
||||
|
||||
void
|
||||
Bputs(Biobuf *b, unsigned short x)
|
||||
{
|
||||
Bputc(b, x&0xff);
|
||||
Bputc(b, x>>8);
|
||||
}
|
||||
|
||||
void
|
||||
Bputl(Biobuf *b, uint32_t 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;
|
||||
uint32_t offset;
|
||||
uint32_t len;
|
||||
|
||||
ARGBEGIN{
|
||||
}ARGEND;
|
||||
|
||||
/* read in all the images */
|
||||
display = initdisplay(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;
|
||||
unsigned char xx[256];
|
||||
unsigned char *data, *p, *e;
|
||||
int ndata;
|
||||
unsigned char *mp;
|
||||
int ncolor;
|
||||
uint32_t color;
|
||||
int bits;
|
||||
unsigned char andbyte, xorbyte;
|
||||
unsigned char *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
sys/src/cmd/pict/tojpg.c
Normal file
70
sys/src/cmd/pict/tojpg.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 "imagefile.h"
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [-c 'comment'] [-ks] [file]\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
Biobuf bout;
|
||||
Memimage *i, *ni;
|
||||
int fd, kflag, sflag;
|
||||
char *err, *file, *com;
|
||||
|
||||
kflag = sflag = 0;
|
||||
com = nil;
|
||||
ARGBEGIN {
|
||||
case 'c':
|
||||
com = EARGF(usage());
|
||||
break;
|
||||
case 'k':
|
||||
kflag = 1;
|
||||
break;
|
||||
case 's':
|
||||
sflag = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
} ARGEND
|
||||
|
||||
if(argc > 1)
|
||||
usage();
|
||||
if(argc == 0) {
|
||||
file = "<stdin>";
|
||||
fd = 0;
|
||||
} else {
|
||||
file = argv[0];
|
||||
if((fd = open(file, OREAD)) < 0)
|
||||
sysfatal("open %s: %r", file);
|
||||
}
|
||||
|
||||
if(Binit(&bout, 1, OWRITE) < 0)
|
||||
sysfatal("Binit: %r");
|
||||
memimageinit();
|
||||
|
||||
if((i = readmemimage(fd)) == nil)
|
||||
sysfatal("readimage %s: %r", file);
|
||||
close(fd);
|
||||
if((ni = memmultichan(i)) == nil)
|
||||
sysfatal("converting image to RGB24: %r");
|
||||
if(i != ni) {
|
||||
freememimage(i);
|
||||
i = ni;
|
||||
}
|
||||
err = memwritejpg(&bout, i, com, kflag, sflag);
|
||||
freememimage(i);
|
||||
|
||||
if(err != nil)
|
||||
fprint(2, "%s: %s\n", argv0, err);
|
||||
exits(err);
|
||||
}
|
70
sys/src/cmd/pict/topng.c
Normal file
70
sys/src/cmd/pict/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);
|
||||
}
|
91
sys/src/cmd/pict/toppm.c
Normal file
91
sys/src/cmd/pict/toppm.c
Normal file
@ -0,0 +1,91 @@
|
||||
#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'] [-r] [file]\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
Biobuf bout;
|
||||
Memimage *i, *ni;
|
||||
int fd, rflag;
|
||||
char buf[256];
|
||||
char *err, *comment;
|
||||
|
||||
rflag = 0;
|
||||
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;
|
||||
case 'r':
|
||||
rflag = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
if(argc > 1)
|
||||
usage();
|
||||
|
||||
if(Binit(&bout, 1, OWRITE) < 0)
|
||||
sysfatal("Binit failed: %r");
|
||||
|
||||
memimageinit();
|
||||
|
||||
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;
|
||||
}
|
||||
err = memwriteppm(&bout, i, comment, rflag);
|
||||
}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 RGB24: %r");
|
||||
if(i != ni){
|
||||
freememimage(i);
|
||||
i = ni;
|
||||
}
|
||||
if(comment)
|
||||
err = memwriteppm(&bout, i, comment, rflag);
|
||||
else{
|
||||
snprint(buf, sizeof buf, "Converted by Plan 9 from %s", argv[0]);
|
||||
err = memwriteppm(&bout, i, buf, rflag);
|
||||
}
|
||||
freememimage(i);
|
||||
}
|
||||
|
||||
if(err != nil)
|
||||
fprint(2, "toppm: %s\n", err);
|
||||
exits(err);
|
||||
}
|
339
sys/src/cmd/pict/torgbv.c
Normal file
339
sys/src/cmd/pict/torgbv.c
Normal file
@ -0,0 +1,339 @@
|
||||
#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[ERRMAX];
|
||||
|
||||
va_start(arg, fmt);
|
||||
vseprint(buf, buf+sizeof buf, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
errstr(buf, sizeof 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;
|
||||
int bpc;
|
||||
uint *map3;
|
||||
unsigned char *closest;
|
||||
Rawimage *im;
|
||||
int dx, dy;
|
||||
char err[ERRMAX];
|
||||
unsigned char *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:
|
||||
bpc = 1;
|
||||
rpic = i->chans[0];
|
||||
gpic = i->chans[1];
|
||||
bpic = i->chans[2];
|
||||
closest = closestycbcr;
|
||||
map3 = ycbcrmap;
|
||||
if(i->nchans != 3)
|
||||
return _remaperror("remap: RGB image has %d channels", i->nchans);
|
||||
goto Threecolor;
|
||||
|
||||
case CRGB:
|
||||
bpc = 1;
|
||||
rpic = i->chans[0];
|
||||
gpic = i->chans[1];
|
||||
bpic = i->chans[2];
|
||||
if(i->nchans != 3)
|
||||
return _remaperror("remap: RGB image has %d channels", i->nchans);
|
||||
goto rgbgen;
|
||||
|
||||
case CRGB24:
|
||||
bpc = 3;
|
||||
bpic = i->chans[0];
|
||||
gpic = i->chans[0] + 1;
|
||||
rpic = i->chans[0] + 2;
|
||||
goto rgbgen;
|
||||
|
||||
case CRGBA32:
|
||||
bpc = 4;
|
||||
/* i->chans[0]+0 is alpha */
|
||||
bpic = i->chans[0] + 1;
|
||||
gpic = i->chans[0] + 2;
|
||||
rpic = i->chans[0] + 3;
|
||||
|
||||
rgbgen:
|
||||
closest = closestrgb;
|
||||
map3 = rgbmap;
|
||||
|
||||
Threecolor:
|
||||
|
||||
if(errdiff == 0){
|
||||
outp = out;
|
||||
for(j=0; j<i->chanlen; j+=bpc){
|
||||
r = rpic[j]>>4;
|
||||
g = gpic[j]>>4;
|
||||
b = bpic[j]>>4;
|
||||
*outp++ = 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;
|
||||
rpic += bpc;
|
||||
gpic += bpc;
|
||||
bpic += bpc;
|
||||
/*
|
||||
* 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 CYA16:
|
||||
bpc = 2;
|
||||
/* i->chans[0] + 0 is alpha */
|
||||
rpic = i->chans[0] + 1;
|
||||
goto greygen;
|
||||
|
||||
case CY:
|
||||
bpc = 1;
|
||||
rpic = i->chans[0];
|
||||
if(i->nchans != 1)
|
||||
return _remaperror("remap: Y image has %d chans", i->nchans);
|
||||
|
||||
greygen:
|
||||
if(errdiff == 0){
|
||||
for(j=0; j<i->chanlen; j+=bpc){
|
||||
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 = *rpic + *rp;
|
||||
rpic += bpc;
|
||||
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;
|
||||
}
|
157
sys/src/cmd/pict/totif.c
Normal file
157
sys/src/cmd/pict/totif.c
Normal file
@ -0,0 +1,157 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
static Memimage *memtochan(Memimage *, uint32_t);
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [-c 'comment'] "
|
||||
"[-3bgGhklLptvyY] [file]\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
Biobuf bout;
|
||||
Memimage *i, *ni;
|
||||
int fd, chanflag, comp, opt;
|
||||
char *err, *file, *c;
|
||||
uint32_t chan;
|
||||
|
||||
chan = BGR24;
|
||||
chanflag = opt = 0;
|
||||
comp = 1;
|
||||
c = nil;
|
||||
ARGBEGIN {
|
||||
case '3': /* force RGB */
|
||||
chan = BGR24;
|
||||
chanflag = 1;
|
||||
break;
|
||||
case 'b':
|
||||
chan = GREY1;
|
||||
chanflag = 1;
|
||||
break;
|
||||
case 'c':
|
||||
c = EARGF(usage());
|
||||
break;
|
||||
case 'g': /* t4 */
|
||||
comp = 3;
|
||||
opt = 0;
|
||||
break;
|
||||
case 'G': /* t4 two-dimensional */
|
||||
comp = 3;
|
||||
opt = 1;
|
||||
break;
|
||||
case 'h': /* huffman */
|
||||
comp = 2;
|
||||
break;
|
||||
case 'k':
|
||||
chan = GREY8;
|
||||
chanflag = 1;
|
||||
break;
|
||||
case 'l': /* lzw */
|
||||
comp = 5;
|
||||
opt = 0;
|
||||
break;
|
||||
case 'L': /* lzw, horizontal differencing */
|
||||
comp = 5;
|
||||
opt = 1;
|
||||
break;
|
||||
case 'p': /* packbits */
|
||||
comp = 0x8005;
|
||||
break;
|
||||
case 't': /* t6 */
|
||||
comp = 4;
|
||||
break;
|
||||
case 'v': /* RGBV */
|
||||
chan = CMAP8;
|
||||
chanflag = 1;
|
||||
break;
|
||||
case 'y':
|
||||
chan = GREY2;
|
||||
chanflag = 1;
|
||||
break;
|
||||
case 'Y':
|
||||
chan = GREY4;
|
||||
chanflag = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
} ARGEND
|
||||
if(argc > 1)
|
||||
usage();
|
||||
if(argc == 0) {
|
||||
file = "<stdin>";
|
||||
fd = 0;
|
||||
} else {
|
||||
file = argv[0];
|
||||
if((fd = open(file, OREAD)) < 0)
|
||||
sysfatal("open %s: %r", file);
|
||||
}
|
||||
if(Binit(&bout, 1, OWRITE) < 0)
|
||||
sysfatal("Binit: %r");
|
||||
memimageinit();
|
||||
if((i = readmemimage(fd)) == nil)
|
||||
sysfatal("readmemimage %s: %r", file);
|
||||
close(fd);
|
||||
if(comp >= 2 && comp <= 4) {
|
||||
chan = GREY1;
|
||||
chanflag = 1;
|
||||
} else if(chan == GREY2) {
|
||||
if((ni = memtochan(i, chan)) == nil)
|
||||
sysfatal("memtochan: %r");
|
||||
if(i != ni) {
|
||||
freememimage(i);
|
||||
i = ni;
|
||||
}
|
||||
chan = GREY4;
|
||||
}
|
||||
if(!chanflag) {
|
||||
switch(i->chan) {
|
||||
case GREY1:
|
||||
case GREY4:
|
||||
case GREY8:
|
||||
case CMAP8:
|
||||
case BGR24:
|
||||
break;
|
||||
case GREY2:
|
||||
chan = GREY4;
|
||||
chanflag = 1;
|
||||
break;
|
||||
default:
|
||||
chanflag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(chanflag) {
|
||||
if((ni = memtochan(i, chan)) == nil)
|
||||
sysfatal("memtochan: %r");
|
||||
if(i != ni) {
|
||||
freememimage(i);
|
||||
i = ni;
|
||||
}
|
||||
}
|
||||
if((err = memwritetif(&bout, i, c, comp, opt)) != nil)
|
||||
fprint(2, "%s: %s\n", argv0, err);
|
||||
freememimage(i);
|
||||
exits(err);
|
||||
}
|
||||
|
||||
static Memimage *
|
||||
memtochan(Memimage *i, uint32_t chan)
|
||||
{
|
||||
Memimage *ni;
|
||||
|
||||
if(i->chan == chan)
|
||||
return i;
|
||||
if((ni = allocmemimage(i->r, chan)) == nil)
|
||||
return nil;
|
||||
memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
|
||||
return ni;
|
||||
}
|
162
sys/src/cmd/pict/totruecolor.c
Normal file
162
sys/src/cmd/pict/totruecolor.c
Normal file
@ -0,0 +1,162 @@
|
||||
#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];
|
||||
unsigned char *rp, *gp, *bp, *cmap, *inp, *outp, cmap1[4*256];
|
||||
int r, g, b, Y, Cr, Cb, psize;
|
||||
|
||||
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:
|
||||
case CRGBV:
|
||||
psize = (i->chandesc == CRGB1) ? 3 : 4;
|
||||
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);
|
||||
if(i->cmaplen > psize*256)
|
||||
return _remaperror("remap: can't do colormap size %d*%d", psize, i->cmaplen/psize);
|
||||
if(i->cmaplen != psize*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 = psize*(*inp++);
|
||||
r = cmap[k+2];
|
||||
g = cmap[k+1];
|
||||
b = cmap[k+0];
|
||||
r = (2125*r + 7154*g + 721*b)/10000; /* Poynton page 84 */
|
||||
*outp++ = r;
|
||||
}
|
||||
}else{
|
||||
for(j=0; j<i->chanlen; j++){
|
||||
k = psize*(*inp++);
|
||||
*outp++ = cmap[k+2];
|
||||
*outp++ = cmap[k+1];
|
||||
*outp++ = cmap[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;
|
||||
}
|
220
sys/src/cmd/pict/v210.c
Normal file
220
sys/src/cmd/pict/v210.c
Normal file
@ -0,0 +1,220 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <event.h>
|
||||
#include <keyboard.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
int cflag = 0;
|
||||
int dflag = 0;
|
||||
int eflag = 0;
|
||||
int nineflag = 0;
|
||||
int threeflag = 0;
|
||||
int output = 0;
|
||||
uint32_t outchan = CMAP8;
|
||||
int defaultcolor = 1;
|
||||
Image *image;
|
||||
|
||||
enum{
|
||||
Border = 2,
|
||||
Edge = 5
|
||||
};
|
||||
|
||||
char *show(int, char*);
|
||||
|
||||
Rawimage** readV210(int fd, int colorspace);
|
||||
|
||||
Rectangle
|
||||
imager(Image *i)
|
||||
{
|
||||
Point p1, p2;
|
||||
|
||||
p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min);
|
||||
p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
|
||||
return rectaddpt(i->r, subpt(p2, p1));
|
||||
}
|
||||
|
||||
void
|
||||
eresized(int new)
|
||||
{
|
||||
Rectangle r;
|
||||
|
||||
if(new && getwindow(display, Refnone) < 0){
|
||||
fprint(2, "readV210: can't reattach to window\n");
|
||||
exits("resize");
|
||||
}
|
||||
if(image == nil)
|
||||
return;
|
||||
r = imager(image);
|
||||
border(screen, r, -Border, nil, ZP);
|
||||
drawop(screen, r, image, nil, image->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: %s -39cdektv [file.yuv ...]\n", argv0);
|
||||
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, "readV210: 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, "readV210: 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, "readV210: 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 = readV210(fd, CYCbCr);
|
||||
if(array == nil || array[0]==nil){
|
||||
fprint(2, "readV210: 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, "readV210: 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, "readV210: allocimage %s failed: %r\n", name);
|
||||
return "allocimage";
|
||||
}
|
||||
if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
|
||||
fprint(2, "readV210: loadimage %s failed: %r\n", name);
|
||||
return "loadimage";
|
||||
}
|
||||
image = i;
|
||||
eresized(0);
|
||||
if((ch=ekbd())=='q' || ch==Kdel || ch==Keof)
|
||||
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, "readV210: %s: write error %r\n", name);
|
||||
return "write";
|
||||
}
|
||||
}else if(cflag){
|
||||
if(writerawimage(1, c) < 0){
|
||||
fprint(2, "readV210: %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;
|
||||
}
|
574
sys/src/cmd/pict/writegif.c
Normal file
574
sys/src/cmd/pict/writegif.c
Normal file
@ -0,0 +1,574 @@
|
||||
#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;
|
||||
unsigned char 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 unsigned char *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, uint32_t, 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(uint32_t);
|
||||
static void encode(Biobuf*, Rectangle, int, unsigned char*, uint);
|
||||
|
||||
static
|
||||
char*
|
||||
startgif0(Biobuf *fd, uint32_t 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, uint32_t 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;
|
||||
uint32_t rgb;
|
||||
unsigned char *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 */
|
||||
}
|
||||
}
|
||||
|
||||
/* imported from libdraw/arith.c to permit an extern log2 function */
|
||||
static int log2[] = {
|
||||
-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
|
||||
-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
|
||||
};
|
||||
|
||||
/*
|
||||
* Write header, logical screen descriptor, and color map
|
||||
*/
|
||||
static
|
||||
void
|
||||
writeheader(Biobuf *fd, Rectangle r, int depth, uint32_t 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 = log2[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;
|
||||
unsigned char *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-log2[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, unsigned char *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 = log2[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(uint32_t 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;
|
||||
}
|
915
sys/src/cmd/pict/writejpg.c
Normal file
915
sys/src/cmd/pict/writejpg.c
Normal file
@ -0,0 +1,915 @@
|
||||
/*
|
||||
* code/documentation from:
|
||||
* http://www.w3.org/Graphics/JPEG/jfif3.pdf
|
||||
* http://www.w3.org/Graphics/JPEG/itu-t81.pdf
|
||||
* http://en.wikipedia.org/wiki/JPEG
|
||||
* http://en.wikibooks.org/wiki/JPEG_-_Idea_and_Practice
|
||||
* http://code.google.com/p/go/source/browse/src/pkg/image/jpeg/writer.go
|
||||
* /sys/src/cmd/jpg
|
||||
*
|
||||
* fdct code from:
|
||||
* http://www.ijg.org/files/jpegsrc.v8c.tar.gz
|
||||
* http://code.google.com/p/go/source/browse/src/pkg/image/jpeg/fdct.go
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <bio.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
/*
|
||||
* imported from libdraw/arith.c to permit
|
||||
* extern log2 function
|
||||
*/
|
||||
static int log2[] = {
|
||||
-1, 0, 1, -1, 2, -1, -1, -1, 3,
|
||||
-1, -1, -1, -1, -1, -1, -1, 4,
|
||||
-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */,
|
||||
-1, -1, -1, -1, -1, -1, -1, 5
|
||||
};
|
||||
|
||||
/* fdct constants */
|
||||
enum {
|
||||
Fix02 = 2446, /* 0.298631336 */
|
||||
Fix03 = 3196, /* 0.390180644 */
|
||||
Fix05 = 4433, /* 0.541196100 */
|
||||
Fix07 = 6270, /* 0.765366865 */
|
||||
Fix08 = 7373, /* 0.899976223 */
|
||||
Fix11 = 9633, /* 1.175875602 */
|
||||
Fix15 = 12299, /* 1.501321110 */
|
||||
Fix18 = 15137, /* 1.847759065 */
|
||||
Fix19 = 16069, /* 1.961570560 */
|
||||
Fix20 = 16819, /* 2.053119869 */
|
||||
Fix25 = 20995, /* 2.562915447 */
|
||||
Fix30 = 25172 /* 3.072711026 */
|
||||
};
|
||||
|
||||
static int zigzag[64] = {
|
||||
0, 1, 5, 6, 14, 15, 27, 28,
|
||||
2, 4, 7, 13, 16, 26, 29, 42,
|
||||
3, 8, 12, 17, 25, 30, 41, 43,
|
||||
9, 11, 18, 24, 31, 40, 44, 53,
|
||||
10, 19, 23, 32, 39, 45, 52, 54,
|
||||
20, 22, 33, 38, 46, 51, 55, 60,
|
||||
21, 34, 37, 47, 50, 56, 59, 61,
|
||||
35, 36, 48, 49, 57, 58, 62, 63
|
||||
};
|
||||
|
||||
static int invzigzag[64] = {
|
||||
0, 1, 8, 16, 9, 2, 3, 10,
|
||||
17, 24, 32, 25, 18, 11, 4, 5,
|
||||
12, 19, 26, 33, 40, 48, 41, 34,
|
||||
27, 20, 13, 6, 7, 14, 21, 28,
|
||||
35, 42, 49, 56, 57, 50, 43, 36,
|
||||
29, 22, 15, 23, 30, 37, 44, 51,
|
||||
58, 59, 52, 45, 38, 31, 39, 46,
|
||||
53, 60, 61, 54, 47, 55, 62, 63
|
||||
};
|
||||
|
||||
/* section K.1 for quantization tables */
|
||||
static int qt[2][64] = {
|
||||
/* luminance */
|
||||
{16, 11, 10, 16, 24, 40, 51, 61,
|
||||
12, 12, 14, 19, 26, 58, 60, 55,
|
||||
14, 13, 16, 24, 40, 57, 69, 56,
|
||||
14, 17, 22, 29, 51, 87, 80, 62,
|
||||
18, 22, 37, 56, 68, 109, 103, 77,
|
||||
24, 35, 55, 64, 81, 104, 113, 92,
|
||||
49, 64, 78, 87, 103, 121, 120, 101,
|
||||
72, 92, 95, 98, 112, 100, 103, 99},
|
||||
|
||||
/* chrominance */
|
||||
{17, 18, 24, 47, 99, 99, 99, 99,
|
||||
18, 21, 26, 66, 99, 99, 99, 99,
|
||||
24, 26, 56, 99, 99, 99, 99, 99,
|
||||
47, 66, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99}
|
||||
};
|
||||
|
||||
/* section K.3.3 for huffman tables */
|
||||
static int dcbits[2][16] = {
|
||||
/* luminance */
|
||||
{0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
|
||||
/* chrominance */
|
||||
{0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
};
|
||||
|
||||
static int dchuffval[2][12] = {
|
||||
/* luminance */
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
|
||||
|
||||
/* chrominance */
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b}
|
||||
};
|
||||
|
||||
static int acbits[2][16] = {
|
||||
/* luminance */
|
||||
{0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
|
||||
0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d},
|
||||
|
||||
/* chrominance */
|
||||
{0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
|
||||
0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77}
|
||||
};
|
||||
|
||||
static int achuffval[2][162] = {
|
||||
/* luminance */
|
||||
{0x01, 0x02, 0x03, 0x00, 0x04, 0x11,
|
||||
0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
|
||||
0x13, 0x51, 0x61, 0x07, 0x22, 0x71,
|
||||
0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
|
||||
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
|
||||
0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,
|
||||
0x82, 0x09, 0x0a, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
|
||||
0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
|
||||
0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
|
||||
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,
|
||||
0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
|
||||
0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
|
||||
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
|
||||
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
|
||||
0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
|
||||
0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
|
||||
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
|
||||
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
|
||||
0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
|
||||
0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
|
||||
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
|
||||
0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
|
||||
0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa},
|
||||
|
||||
/* chrominance */
|
||||
{0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
|
||||
0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
|
||||
0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
|
||||
0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
|
||||
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33,
|
||||
0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
|
||||
0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
|
||||
0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
|
||||
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36,
|
||||
0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
|
||||
0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
|
||||
0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||||
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
|
||||
0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,
|
||||
0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
|
||||
0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
|
||||
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
|
||||
0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
|
||||
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
|
||||
0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
|
||||
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
|
||||
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
|
||||
0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa}
|
||||
};
|
||||
|
||||
static int ehufcod[2][12]; /* dc codes */
|
||||
static int ehufsid[2][12]; /* dc sizes */
|
||||
static int ehufcoa[2][251]; /* ac codes */
|
||||
static int ehufsia[2][251]; /* ac sizes */
|
||||
|
||||
static int byte;
|
||||
static int nbyte;
|
||||
|
||||
/* utilities */
|
||||
static int Bputs(Biobuf *, int);
|
||||
static int min(int, int);
|
||||
|
||||
/* encoding */
|
||||
static void grey2rgb(int *, int *, int *, int, int);
|
||||
static void rgb2ycc(int *, int *, int *, int, int, int);
|
||||
static void fdct(int *, int);
|
||||
static int csize(int, int);
|
||||
static void writebyte(Biobuf *);
|
||||
static void writebits(Biobuf *, int, int);
|
||||
static void writecode(Biobuf *, int, int);
|
||||
static int huf(Biobuf *, int *, int, int, int);
|
||||
static char *toycc1(int *, int *, int *, int, int, int, int, int,
|
||||
unsigned char *, int, int);
|
||||
static char *toycc2(int *, int *, int *, int, int, int, int, int,
|
||||
unsigned char *, int, int);
|
||||
static char *encode(Biobuf *, Rectangle, unsigned char *, uint32_t, int,
|
||||
int, int);
|
||||
|
||||
/* huffman tables */
|
||||
static void makehuf(int *, int *, int *, int *, int);
|
||||
|
||||
/* tables, markers, headers, trailers */
|
||||
static void writejfif(Biobuf *, int, int);
|
||||
static void writecomment(Biobuf *, char *);
|
||||
static void writequant(Biobuf *, int, int);
|
||||
static void writehuffman(Biobuf *, int, int);
|
||||
static void writeframe(Biobuf *, int, int, int);
|
||||
static void writescan(Biobuf *, int);
|
||||
static void writeheader(Biobuf *, int, int, char *, int, int);
|
||||
static void writetrailer(Biobuf *);
|
||||
static char *writedata(Biobuf *, Image *, Memimage *, int, int);
|
||||
static char *writejpg0(Biobuf *, Image *, Memimage *,
|
||||
Rectangle, uint32_t, char *, int, int);
|
||||
|
||||
static int
|
||||
Bputs(Biobuf *b, int s)
|
||||
{
|
||||
if(Bputc(b, s>>8) < 0)
|
||||
return -1;
|
||||
return Bputc(b, s);
|
||||
}
|
||||
|
||||
static int
|
||||
min(int a, int b)
|
||||
{
|
||||
return a < b? a: b;
|
||||
}
|
||||
|
||||
static void
|
||||
grey2rgb(int *r, int *g, int *b, int c, int depth)
|
||||
{
|
||||
if(depth == 1) {
|
||||
if(c != 0)
|
||||
c = 0xff;
|
||||
} else if(depth == 2)
|
||||
c = (c << 6) | (c << 4) | (c << 2) | c;
|
||||
else
|
||||
c = (c << 4) | c;
|
||||
c = cmap2rgb(c);
|
||||
*r = (c >> 16) & 0xff;
|
||||
*g = (c >> 8) & 0xff;
|
||||
*b = c & 0xff;
|
||||
}
|
||||
|
||||
static void
|
||||
rgb2ycc(int *y, int *cb, int *cr, int r, int g, int b)
|
||||
{
|
||||
*y = (int)(0.299*r + 0.587*g + 0.114*b);
|
||||
*cb = (int)(128.0 - 0.1687*r - 0.3313*g + 0.5*b);
|
||||
*cr = (int)(128.0 + 0.5*r - 0.4187*g - 0.0813*b);
|
||||
}
|
||||
|
||||
/* coefficients remain scaled up by 8 at the end */
|
||||
static void
|
||||
fdct(int *b, int sflag)
|
||||
{
|
||||
int x, y, z, tmp0, tmp1, tmp2, tmp3;
|
||||
int tmp10, tmp12, tmp11, tmp13;
|
||||
|
||||
/* rows */
|
||||
for(y = 0; y < 8; y++) {
|
||||
tmp0 = b[y*8+0] + b[y*8+7];
|
||||
tmp1 = b[y*8+1] + b[y*8+6];
|
||||
tmp2 = b[y*8+2] + b[y*8+5];
|
||||
tmp3 = b[y*8+3] + b[y*8+4];
|
||||
|
||||
tmp10 = tmp0 + tmp3;
|
||||
tmp12 = tmp0 - tmp3;
|
||||
tmp11 = tmp1 + tmp2;
|
||||
tmp13 = tmp1 - tmp2;
|
||||
|
||||
tmp0 = b[y*8+0] - b[y*8+7];
|
||||
tmp1 = b[y*8+1] - b[y*8+6];
|
||||
tmp2 = b[y*8+2] - b[y*8+5];
|
||||
tmp3 = b[y*8+3] - b[y*8+4];
|
||||
|
||||
b[y*8+0] = (tmp10 + tmp11 - 8*128) << 2;
|
||||
b[y*8+4] = (tmp10 - tmp11) << 2;
|
||||
|
||||
z = (tmp12 + tmp13) * Fix05;
|
||||
z += 1 << 10;
|
||||
b[y*8+2] = (z + tmp12*Fix07) >> 11;
|
||||
b[y*8+6] = (z - tmp13*Fix18) >> 11;
|
||||
|
||||
tmp10 = tmp0 + tmp3;
|
||||
tmp11 = tmp1 + tmp2;
|
||||
tmp12 = tmp0 + tmp2;
|
||||
tmp13 = tmp1 + tmp3;
|
||||
z = (tmp12 + tmp13) * Fix11;
|
||||
z += 1 << 10;
|
||||
|
||||
tmp0 *= Fix15;
|
||||
tmp1 *= Fix30;
|
||||
tmp2 *= Fix20;
|
||||
tmp3 *= Fix02;
|
||||
tmp10 *= -Fix08;
|
||||
tmp11 *= -Fix25;
|
||||
tmp12 *= -Fix03;
|
||||
tmp13 *= -Fix19;
|
||||
|
||||
tmp12 += z;
|
||||
tmp13 += z;
|
||||
|
||||
b[y*8+1] = (tmp0 + tmp10 + tmp12) >> 11;
|
||||
b[y*8+3] = (tmp1 + tmp11 + tmp13) >> 11;
|
||||
b[y*8+5] = (tmp2 + tmp11 + tmp12) >> 11;
|
||||
b[y*8+7] = (tmp3 + tmp10 + tmp13) >> 11;
|
||||
}
|
||||
/* columns */
|
||||
for(x = 0; x < 8; x++) {
|
||||
tmp0 = b[0*8+x] + b[7*8+x];
|
||||
tmp1 = b[1*8+x] + b[6*8+x];
|
||||
tmp2 = b[2*8+x] + b[5*8+x];
|
||||
tmp3 = b[3*8+x] + b[4*8+x];
|
||||
|
||||
if(sflag)
|
||||
tmp10 = (tmp0 + tmp3 + 1) << 1;
|
||||
else
|
||||
tmp10 = tmp0 + tmp3 + (1 << 1);
|
||||
tmp12 = tmp0 - tmp3;
|
||||
tmp11 = tmp1 + tmp2;
|
||||
tmp13 = tmp1 - tmp2;
|
||||
|
||||
tmp0 = b[0*8+x] - b[7*8+x];
|
||||
tmp1 = b[1*8+x] - b[6*8+x];
|
||||
tmp2 = b[2*8+x] - b[5*8+x];
|
||||
tmp3 = b[3*8+x] - b[4*8+x];
|
||||
|
||||
b[0*8+x] = (tmp10 + tmp11) >> 2;
|
||||
b[4*8+x] = (tmp10 - tmp11) >> 2;
|
||||
|
||||
z = (tmp12 + tmp13) * Fix05;
|
||||
z += 1 << 14;
|
||||
b[2*8+x] = (z + tmp12*Fix07) >> 15;
|
||||
b[6*8+x] = (z - tmp13*Fix18) >> 15;
|
||||
|
||||
tmp10 = tmp0 + tmp3;
|
||||
tmp11 = tmp1 + tmp2;
|
||||
tmp12 = tmp0 + tmp2;
|
||||
tmp13 = tmp1 + tmp3;
|
||||
z = (tmp12 + tmp13) * Fix11;
|
||||
z += 1 << 14;
|
||||
|
||||
tmp0 *= Fix15;
|
||||
tmp1 *= Fix30;
|
||||
tmp2 *= Fix20;
|
||||
tmp3 *= Fix02;
|
||||
tmp10 *= -Fix08;
|
||||
tmp11 *= -Fix25;
|
||||
tmp12 *= -Fix03;
|
||||
tmp13 *= -Fix19;
|
||||
|
||||
tmp12 += z;
|
||||
tmp13 += z;
|
||||
|
||||
b[1*8+x] = (tmp0 + tmp10 + tmp12) >> 15;
|
||||
b[3*8+x] = (tmp1 + tmp11 + tmp13) >> 15;
|
||||
b[5*8+x] = (tmp2 + tmp11 + tmp12) >> 15;
|
||||
b[7*8+x] = (tmp3 + tmp10 + tmp13) >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
csize(int coeff, int ac)
|
||||
{
|
||||
int i, max;
|
||||
|
||||
max = 1 << 10;
|
||||
if(!ac)
|
||||
max <<= 1;
|
||||
if(coeff < 0)
|
||||
coeff *= -1;
|
||||
if(coeff > max)
|
||||
sysfatal("csize: coeff too big: %d", coeff);
|
||||
i = ac? 1: 0;
|
||||
while(coeff >= (1<<i))
|
||||
i++;
|
||||
if(ac && (i < 1 || i > 10))
|
||||
sysfatal("csize: invalid ac ssss: %d", i);
|
||||
if(!ac && (i < 0 || i > 11))
|
||||
sysfatal("csize: invalid dc ssss: %d", i);
|
||||
return i;
|
||||
}
|
||||
|
||||
static void
|
||||
writebyte(Biobuf *fd)
|
||||
{
|
||||
Bputc(fd, byte);
|
||||
if(byte == 0xff) /* byte stuffing */
|
||||
Bputc(fd, 0x00);
|
||||
byte = 0;
|
||||
nbyte = 7;
|
||||
}
|
||||
|
||||
static void
|
||||
writebits(Biobuf *fd, int co, int si)
|
||||
{
|
||||
int i, bit;
|
||||
|
||||
for(i = si-1; i >= 0; i--) {
|
||||
bit = (co >> i) & 0x1;
|
||||
byte |= bit << nbyte;
|
||||
nbyte--;
|
||||
if(nbyte < 0)
|
||||
writebyte(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
writecode(Biobuf *fd, int co, int si)
|
||||
{
|
||||
if(si > 8) {
|
||||
writebits(fd, co>>8, si-8);
|
||||
si = 8;
|
||||
}
|
||||
writebits(fd, co, si);
|
||||
}
|
||||
|
||||
static int
|
||||
huf(Biobuf *fd, int *b, int pred, int chr, int sflag)
|
||||
{
|
||||
int k, r, s, rs, si, co, dc, diff, zz[64], p, q, z;
|
||||
|
||||
if(sflag) {
|
||||
for(k = 0; k < 64; k++) {
|
||||
p = b[zigzag[k]];
|
||||
q = qt[chr][zigzag[k]];
|
||||
zz[k] = p / q;
|
||||
}
|
||||
} else {
|
||||
for(k = 0; k < 64; k++) {
|
||||
p = b[k];
|
||||
q = (qt[chr][k] << 3);
|
||||
/* rounding */
|
||||
if(p >= 0)
|
||||
z = (p + (q >> 1)) / q;
|
||||
else
|
||||
z = -(-p + (q >> 1)) / q;
|
||||
zz[zigzag[k]] = z;
|
||||
}
|
||||
}
|
||||
|
||||
/* dc coefficient */
|
||||
dc = zz[0];
|
||||
zz[0] = diff = dc - pred;
|
||||
|
||||
s = csize(diff, 0);
|
||||
si = ehufsid[chr][s];
|
||||
co = ehufcod[chr][s];
|
||||
writecode(fd, co, si);
|
||||
if(diff < 0)
|
||||
diff -= 1;
|
||||
writecode(fd, diff, s);
|
||||
|
||||
/* figure F.2 */
|
||||
for(k = 1, r = 0; k < 64; k++) {
|
||||
if(zz[k] == 0) {
|
||||
if(k < 63)
|
||||
r++;
|
||||
else {
|
||||
si = ehufsia[chr][0x00];
|
||||
co = ehufcoa[chr][0x00];
|
||||
writecode(fd, co, si);
|
||||
}
|
||||
} else {
|
||||
while(r > 15) {
|
||||
si = ehufsia[chr][0xf0];
|
||||
co = ehufcoa[chr][0xf0];
|
||||
writecode(fd, co, si);
|
||||
r -= 16;
|
||||
}
|
||||
/* figure F.3 */
|
||||
s = csize(zz[k], 1);
|
||||
rs = (r << 4) | s;
|
||||
si = ehufsia[chr][rs];
|
||||
co = ehufcoa[chr][rs];
|
||||
writecode(fd, co, si);
|
||||
if(zz[k] < 0)
|
||||
zz[k] -= 1;
|
||||
writecode(fd, zz[k], s);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
return dc;
|
||||
}
|
||||
|
||||
static char *
|
||||
toycc1(int *y, int *cb, int *cr, int jx, int jy, int dx, int dy,
|
||||
int bpl, unsigned char *data, int ndata, int depth)
|
||||
{
|
||||
int i, j, k, l, m, n, u, v, pos, pmask, nmask, pix;
|
||||
int r, g, b;
|
||||
|
||||
m = 8 / depth;
|
||||
pmask = (1 << depth) - 1;
|
||||
nmask = 7 >> log2[depth];
|
||||
for(i = jy, k = 0; i < jy+8; i++) {
|
||||
v = min(i, dy-1);
|
||||
for(l = 0, j = jx/m; l < 8; l++, k++) {
|
||||
u = min(j, (dx-1)/m);
|
||||
n = l+jx >= dx? dx-jx-1: l;
|
||||
pos = v*bpl + u;
|
||||
if(pos >= ndata)
|
||||
return "WriteJPG: overflow";
|
||||
/* thanks writeppm */
|
||||
pix = (data[pos] >> depth*((nmask - n) &
|
||||
nmask)) & pmask;
|
||||
if(((n + 1) & nmask) == 0)
|
||||
j++;
|
||||
grey2rgb(&r, &g, &b, pix, depth);
|
||||
rgb2ycc(&y[k], &cb[k], &cr[k], r, g, b);
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static char *
|
||||
toycc2(int *y, int *cb, int *cr, int jx, int jy, int dx, int dy,
|
||||
int bpl, unsigned char *data, int ndata, int depth)
|
||||
{
|
||||
int i, j, k, m, u, v, pos;
|
||||
|
||||
m = depth / 8;
|
||||
for(i = jy, k = 0; i < jy+8; i++) {
|
||||
v = min(i, dy-1);
|
||||
for(j = jx*m; j < (jx+8)*m; j+=m, k++) {
|
||||
u = min(j, (dx-1)*m);
|
||||
pos = v*bpl + u;
|
||||
if(pos+m-1 >= ndata)
|
||||
return "WriteJPG: overflow";
|
||||
rgb2ycc(&y[k], &cb[k], &cr[k],
|
||||
data[pos+2*m/3],
|
||||
data[pos+m/3],
|
||||
data[pos]);
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static char *
|
||||
encode(Biobuf *fd, Rectangle r, unsigned char *data, uint32_t chan,
|
||||
int ndata, int kflag, int sflag)
|
||||
{
|
||||
int k, x, y, dx, dy, depth, bpl, ncomp;
|
||||
int b[3][64], pred[3];
|
||||
char *err;
|
||||
char *(*toycc)(int *, int *, int *, int, int, int, int,
|
||||
int, unsigned char *, int, int);
|
||||
|
||||
byte = 0;
|
||||
nbyte = 7;
|
||||
|
||||
switch(chan) {
|
||||
case GREY1:
|
||||
case GREY2:
|
||||
case GREY4:
|
||||
toycc = toycc1;
|
||||
break;
|
||||
case GREY8:
|
||||
case RGB24:
|
||||
toycc = toycc2;
|
||||
break;
|
||||
default:
|
||||
return "WriteJPG: can't handle channel type";
|
||||
}
|
||||
|
||||
/*
|
||||
* if dx or dy is not a multiple of 8,
|
||||
* the decoder should continue until reaching
|
||||
* the last mcu, even if the extra pixels go beyond
|
||||
* 0xffff. they are not shown anyway.
|
||||
*/
|
||||
dx = min(Dx(r), 0xffff);
|
||||
dy = min(Dy(r), 0xffff);
|
||||
depth = chantodepth(chan);
|
||||
bpl = bytesperline(r, depth);
|
||||
ncomp = kflag? 1: 3;
|
||||
memset(pred, 0, sizeof pred);
|
||||
for(x = 0, y = 0;;) {
|
||||
err = (*toycc)(b[0], b[1], b[2], x, y, dx, dy,
|
||||
bpl, data, ndata, depth);
|
||||
if(err != nil)
|
||||
return err;
|
||||
for(k = 0; k < ncomp; k++) {
|
||||
fdct(b[k], sflag);
|
||||
pred[k] = huf(fd, b[k], pred[k],
|
||||
k>0, sflag);
|
||||
}
|
||||
if((x += 8) >= dx) {
|
||||
if((y += 8) >= dy)
|
||||
break;
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
if(nbyte < 7) { /* bit padding */
|
||||
for(; nbyte >= 0; nbyte--)
|
||||
byte |= 0x1 << nbyte;
|
||||
writebyte(fd);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
makehuf(int *ehufco, int *ehufsi, int *bits, int *huffval, int n)
|
||||
{
|
||||
int i, j, k, code, si, lastk, *huffcode, *huffsize;
|
||||
|
||||
/* n+1 for lastk */
|
||||
if((huffcode = malloc((n+1)*sizeof *huffcode)) == nil)
|
||||
sysfatal("malloc: %r");
|
||||
if((huffsize = malloc((n+1)*sizeof *huffsize)) == nil)
|
||||
sysfatal("malloc: %r");
|
||||
/* figure C.1 */
|
||||
for(k = 0, i = 1, j = 1; i <= 16;) {
|
||||
if(j > bits[i-1]) { /* bits[i] in T.81: bug? */
|
||||
i++;
|
||||
j = 1;
|
||||
} else {
|
||||
huffsize[k++] = i;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
huffsize[k] = 0;
|
||||
lastk = k;
|
||||
/* figure C.2 */
|
||||
for(k = 0, code = 0, si = huffsize[0];;) {
|
||||
do {
|
||||
huffcode[k++] = code++;
|
||||
} while(huffsize[k] == si);
|
||||
if(huffsize[k] == 0)
|
||||
break;
|
||||
while(huffsize[k] != si) {
|
||||
code <<= 1;
|
||||
si++;
|
||||
}
|
||||
}
|
||||
/* figure C.3 */
|
||||
for(k = 0; k < lastk; k++) {
|
||||
i = huffval[k];
|
||||
ehufco[i] = huffcode[k];
|
||||
ehufsi[i] = huffsize[k];
|
||||
}
|
||||
free(huffcode);
|
||||
free(huffsize);
|
||||
}
|
||||
|
||||
static void
|
||||
writejfif(Biobuf *fd, int dx, int dy)
|
||||
{
|
||||
if(dx > 0xffff || dy > 0xffff)
|
||||
sysfatal("writejfif: dx or dy too big");
|
||||
Bputs(fd, 0xffe0);
|
||||
Bputs(fd, 0x0010);
|
||||
Bputc(fd, 0x4a);
|
||||
Bputc(fd, 0x46);
|
||||
Bputc(fd, 0x49);
|
||||
Bputc(fd, 0x46);
|
||||
Bputc(fd, 0x00);
|
||||
Bputs(fd, 0x0102);
|
||||
Bputc(fd, 0x01);
|
||||
Bputs(fd, dx);
|
||||
Bputs(fd, dy);
|
||||
Bputc(fd, 0x00);
|
||||
Bputc(fd, 0x00);
|
||||
}
|
||||
|
||||
static void
|
||||
writecomment(Biobuf *fd, char *com)
|
||||
{
|
||||
int n;
|
||||
|
||||
if(com != nil && com[0] != '\0') {
|
||||
n = min(strlen(com)+2, 0xffff);
|
||||
Bputs(fd, 0xfffe);
|
||||
Bputs(fd, n);
|
||||
Bwrite(fd, com, n-2);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
writequant(Biobuf *fd, int tq, int sflag)
|
||||
{
|
||||
int i, *p, *q;
|
||||
|
||||
if(tq != 0x0 && tq != 0x1)
|
||||
sysfatal("writequant: invalid Tq");
|
||||
q = qt[tq];
|
||||
Bputs(fd, 0xffdb);
|
||||
Bputs(fd, 0x0043);
|
||||
Bputc(fd, (0x0<<4)|tq);
|
||||
p = sflag? zigzag: invzigzag;
|
||||
for(i = 0; i < 64; i++)
|
||||
Bputc(fd, q[p[i]]);
|
||||
}
|
||||
|
||||
static void
|
||||
writehuffman(Biobuf *fd, int tc, int th)
|
||||
{
|
||||
int i, n, m, *b, *hv;
|
||||
|
||||
if((tc != 0x0 && tc != 0x1) || (th != 0x0 && th != 0x1))
|
||||
sysfatal("writehuffman: invalid Tc or Th");
|
||||
n = 0x0013;
|
||||
if(tc == 0x0) {
|
||||
b = dcbits[th];
|
||||
hv = dchuffval[th];
|
||||
m = nelem(dchuffval[th]);
|
||||
} else {
|
||||
b = acbits[th];
|
||||
hv = achuffval[th];
|
||||
m = nelem(achuffval[th]);
|
||||
}
|
||||
Bputs(fd, 0xffc4);
|
||||
Bputs(fd, n+m);
|
||||
Bputc(fd, (tc<<4)|th);
|
||||
for(i = 0; i < 16; i++)
|
||||
Bputc(fd, b[i]);
|
||||
for(i = 0; i < m; i++)
|
||||
Bputc(fd, hv[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
writeframe(Biobuf *fd, int y, int x, int kflag)
|
||||
{
|
||||
int n, nf;
|
||||
|
||||
nf = kflag? 0x01: 0x03;
|
||||
n = 0x0008 + 0x0003*nf;
|
||||
|
||||
Bputs(fd, 0xffc0);
|
||||
Bputs(fd, n);
|
||||
Bputc(fd, 0x08);
|
||||
Bputs(fd, y);
|
||||
Bputs(fd, x);
|
||||
Bputc(fd, nf);
|
||||
|
||||
/* Y component */
|
||||
Bputc(fd, 0x00);
|
||||
Bputc(fd, (0x1<<4)|0x1);
|
||||
Bputc(fd, 0x00);
|
||||
|
||||
if(!kflag) {
|
||||
/* Cb component */
|
||||
Bputc(fd, 0x01);
|
||||
Bputc(fd, (0x1<<4)|0x1);
|
||||
Bputc(fd, 0x01);
|
||||
|
||||
/* Cr component */
|
||||
Bputc(fd, 0x02);
|
||||
Bputc(fd, (0x1<<4)|0x1);
|
||||
Bputc(fd, 0x01);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
writescan(Biobuf *fd, int kflag)
|
||||
{
|
||||
int n, ns;
|
||||
|
||||
ns = kflag? 0x01: 0x03;
|
||||
n = 0x0006 + 0x0002*ns;
|
||||
|
||||
Bputs(fd, 0xffda);
|
||||
Bputs(fd, n);
|
||||
Bputc(fd, ns);
|
||||
|
||||
/* Y component */
|
||||
Bputc(fd, 0x00);
|
||||
Bputc(fd, (0x0<<4)|0x0);
|
||||
|
||||
if(!kflag) {
|
||||
/* Cb component */
|
||||
Bputc(fd, 0x01);
|
||||
Bputc(fd, (0x1<<4)|0x1);
|
||||
|
||||
/* Cr component */
|
||||
Bputc(fd, 0x02);
|
||||
Bputc(fd, (0x1<<4)|0x1);
|
||||
}
|
||||
|
||||
Bputc(fd, 0x00);
|
||||
Bputc(fd, 0x3f);
|
||||
Bputc(fd, (0x0<<4)|0x0);
|
||||
}
|
||||
|
||||
static void
|
||||
writeheader(Biobuf *fd, int dx, int dy, char *s, int kflag, int sflag)
|
||||
{
|
||||
int i;
|
||||
|
||||
dx = min(dx, 0xffff);
|
||||
dy = min(dy, 0xffff);
|
||||
|
||||
Bputs(fd, 0xffd8);
|
||||
writejfif(fd, dx, dy);
|
||||
writecomment(fd, s);
|
||||
writequant(fd, 0, sflag);
|
||||
if(!kflag)
|
||||
writequant(fd, 1, sflag);
|
||||
writeframe(fd, dy, dx, kflag);
|
||||
for(i = 0; i < 2; i++) {
|
||||
writehuffman(fd, i, 0);
|
||||
if(!kflag)
|
||||
writehuffman(fd, i, 1);
|
||||
}
|
||||
writescan(fd, kflag);
|
||||
}
|
||||
|
||||
static void
|
||||
writetrailer(Biobuf *fd)
|
||||
{
|
||||
Bputs(fd, 0xffd9);
|
||||
}
|
||||
|
||||
static char *
|
||||
writedata(Biobuf *fd, Image *i, Memimage *m, int kflag, int sflag)
|
||||
{
|
||||
char *err;
|
||||
unsigned char *data;
|
||||
int ndata, depth;
|
||||
uint32_t chan;
|
||||
Rectangle r;
|
||||
|
||||
if(m != nil) {
|
||||
r = m->r;
|
||||
depth = m->depth;
|
||||
chan = m->chan;
|
||||
} else {
|
||||
r = i->r;
|
||||
depth = i->depth;
|
||||
chan = i->chan;
|
||||
}
|
||||
|
||||
/*
|
||||
* potentially one extra byte on each
|
||||
* end of each scan line
|
||||
*/
|
||||
ndata = Dy(r) * (2 + Dx(r)*depth/8);
|
||||
if((data = malloc(ndata)) == nil)
|
||||
return "WriteJPG: malloc failed";
|
||||
if(m != nil)
|
||||
ndata = unloadmemimage(m, r, data, ndata);
|
||||
else
|
||||
ndata = unloadimage(i, r, data, ndata);
|
||||
if(ndata < 0) {
|
||||
if((err = malloc(ERRMAX)) == nil) {
|
||||
free(data);
|
||||
return "WriteJPG: malloc failed";
|
||||
}
|
||||
snprint(err, ERRMAX, "WriteJPG: %r");
|
||||
} else
|
||||
err = encode(fd, r, data, chan, ndata, kflag, sflag);
|
||||
free(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
static char *
|
||||
writejpg0(Biobuf *fd, Image *image, Memimage *memimage,
|
||||
Rectangle r, uint32_t chan, char *s, int kflag, int sflag)
|
||||
{
|
||||
int i;
|
||||
char *err;
|
||||
|
||||
switch(chan) {
|
||||
case GREY1:
|
||||
case GREY2:
|
||||
case GREY4:
|
||||
case GREY8:
|
||||
kflag = 1;
|
||||
break;
|
||||
case RGB24:
|
||||
break;
|
||||
default:
|
||||
return "WriteJPG: can't handle channel type";
|
||||
}
|
||||
for(i = 0; i < 2; i++) {
|
||||
memset(ehufcod[i], 0, sizeof ehufcod[i]);
|
||||
memset(ehufsid[i], 0, sizeof ehufsid[i]);
|
||||
memset(ehufcoa[i], 0, sizeof ehufcoa[i]);
|
||||
memset(ehufsia[i], 0, sizeof ehufsia[i]);
|
||||
makehuf(ehufcod[i], ehufsid[i], dcbits[i],
|
||||
dchuffval[i], nelem(dchuffval[i]));
|
||||
makehuf(ehufcoa[i], ehufsia[i], acbits[i],
|
||||
achuffval[i], nelem(achuffval[i]));
|
||||
}
|
||||
writeheader(fd, Dx(r), Dy(r), s, kflag, sflag);
|
||||
err = writedata(fd, image, memimage, kflag, sflag);
|
||||
writetrailer(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
char *
|
||||
writejpg(Biobuf *fd, Image *i, char *s, int kflag, int sflag)
|
||||
{
|
||||
return writejpg0(fd, i, nil, i->r, i->chan, s, kflag, sflag);
|
||||
}
|
||||
|
||||
char *
|
||||
memwritejpg(Biobuf *fd, Memimage *m, char *s, int kflag, int sflag)
|
||||
{
|
||||
return writejpg0(fd, nil, m, m->r, m->chan, s, kflag, sflag);
|
||||
}
|
267
sys/src/cmd/pict/writepng.c
Normal file
267
sys/src/cmd/pict/writepng.c
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* See PNG 1.2 spec, also RFC 2083.
|
||||
*/
|
||||
#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 ZlibR;
|
||||
typedef struct ZlibW ZlibW;
|
||||
|
||||
struct ZlibR
|
||||
{
|
||||
unsigned char *data;
|
||||
int width;
|
||||
int dx;
|
||||
int dy;
|
||||
int x;
|
||||
int y;
|
||||
int pixwid;
|
||||
};
|
||||
|
||||
struct ZlibW
|
||||
{
|
||||
Biobuf *io;
|
||||
unsigned char *buf;
|
||||
unsigned char *b;
|
||||
unsigned char *e;
|
||||
};
|
||||
|
||||
static uint32_t *crctab;
|
||||
static unsigned char PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
|
||||
|
||||
static void
|
||||
put4(unsigned char *a, uint32_t v)
|
||||
{
|
||||
a[0] = v>>24;
|
||||
a[1] = v>>16;
|
||||
a[2] = v>>8;
|
||||
a[3] = v;
|
||||
}
|
||||
|
||||
static void
|
||||
chunk(Biobuf *bo, char *type, unsigned char *d, int n)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
uint32_t 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)
|
||||
{
|
||||
int a, i, pixels, pixwid;
|
||||
unsigned char *b, *e, *img;
|
||||
ZlibR *z;
|
||||
|
||||
z = va;
|
||||
pixwid = z->pixwid;
|
||||
b = buf;
|
||||
e = b+n;
|
||||
while(b+pixwid < e){ /* one less for filter alg byte */
|
||||
if(z->y >= z->dy)
|
||||
break;
|
||||
if(z->x == 0)
|
||||
*b++ = FilterNone;
|
||||
pixels = (e-b)/pixwid;
|
||||
if(pixels > z->dx - z->x)
|
||||
pixels = z->dx - z->x;
|
||||
img = z->data + z->width*z->y + pixwid*z->x;
|
||||
memmove(b, img, pixwid*pixels);
|
||||
if(pixwid == 4){
|
||||
/*
|
||||
* Convert to non-premultiplied alpha.
|
||||
*/
|
||||
for(i=0; i<pixels; i++, b+=4){
|
||||
a = b[3];
|
||||
if(a == 0)
|
||||
b[0] = b[1] = b[2] = 0;
|
||||
else if(a != 255){
|
||||
if(b[0] >= a)
|
||||
b[0] = a;
|
||||
b[0] = (b[0]*255)/a;
|
||||
if(b[1] >= a)
|
||||
b[1] = a;
|
||||
b[1] = (b[1]*255)/a;
|
||||
if(b[2] >= a)
|
||||
b[2] = a;
|
||||
b[2] = (b[2]*255)/a;
|
||||
}
|
||||
}
|
||||
}else
|
||||
b += pixwid*pixels;
|
||||
|
||||
z->x += pixels;
|
||||
if(z->x >= z->dx){
|
||||
z->x = 0;
|
||||
z->y++;
|
||||
}
|
||||
}
|
||||
return b - (unsigned char*)buf;
|
||||
}
|
||||
|
||||
static void
|
||||
IDAT(ZlibW *z)
|
||||
{
|
||||
chunk(z->io, "IDAT", z->buf, z->b - z->buf);
|
||||
z->b = z->buf;
|
||||
}
|
||||
|
||||
static int
|
||||
zwrite(void *va, void *buf, int n)
|
||||
{
|
||||
int m;
|
||||
unsigned char *b, *e;
|
||||
ZlibW *z;
|
||||
|
||||
z = va;
|
||||
b = buf;
|
||||
e = b+n;
|
||||
|
||||
while(b < e){
|
||||
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*
|
||||
memRGBA(Memimage *i)
|
||||
{
|
||||
Memimage *ni;
|
||||
char buf[32];
|
||||
uint32_t dst;
|
||||
|
||||
/*
|
||||
* [A]BGR because we want R,G,B,[A] in big-endian order. Sigh.
|
||||
*/
|
||||
chantostr(buf, i->chan);
|
||||
if(strchr(buf, 'a'))
|
||||
dst = ABGR32;
|
||||
else
|
||||
dst = BGR24;
|
||||
|
||||
if(i->chan == dst)
|
||||
return i;
|
||||
|
||||
ni = allocmemimage(i->r, dst);
|
||||
if(ni == nil)
|
||||
return ni;
|
||||
memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
|
||||
return ni;
|
||||
}
|
||||
|
||||
char*
|
||||
memwritepng(Biobuf *io, Memimage *m, ImageInfo *II)
|
||||
{
|
||||
int err, n;
|
||||
unsigned char buf[200], *h;
|
||||
uint32_t vgamma;
|
||||
Tm *tm;
|
||||
Memimage *rgb;
|
||||
ZlibR zr;
|
||||
ZlibW zw;
|
||||
|
||||
crctab = mkcrctab(0xedb88320);
|
||||
if(crctab == nil)
|
||||
sysfatal("mkcrctab error");
|
||||
deflateinit();
|
||||
|
||||
rgb = memRGBA(m);
|
||||
if(rgb == nil)
|
||||
return "allocmemimage nil";
|
||||
|
||||
Bwrite(io, PNGmagic, sizeof PNGmagic);
|
||||
|
||||
/* IHDR chunk */
|
||||
h = buf;
|
||||
put4(h, Dx(m->r)); h += 4;
|
||||
put4(h, Dy(m->r)); h += 4;
|
||||
*h++ = 8; /* 8 bits per channel */
|
||||
if(rgb->chan == BGR24)
|
||||
*h++ = 2; /* RGB */
|
||||
else
|
||||
*h++ = 6; /* RGBA */
|
||||
*h++ = 0; /* compression - deflate */
|
||||
*h++ = 0; /* filter - none */
|
||||
*h++ = 0; /* interlace - none */
|
||||
chunk(io, "IHDR", buf, h-buf);
|
||||
|
||||
/* time - using now is suspect */
|
||||
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(io, "tIME", buf, h-buf);
|
||||
|
||||
/* gamma */
|
||||
if(II->fields_set & II_GAMMA){
|
||||
vgamma = II->gamma*100000;
|
||||
put4(buf, vgamma);
|
||||
chunk(io, "gAMA", buf, 4);
|
||||
}
|
||||
|
||||
/* comment */
|
||||
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(io, "tEXt", buf, n+strlen((char*)buf+n));
|
||||
}
|
||||
|
||||
/* image data */
|
||||
zr.dx = Dx(m->r);
|
||||
zr.dy = Dy(m->r);
|
||||
zr.width = rgb->width * sizeof(uint32_t);
|
||||
zr.data = rgb->data->bdata;
|
||||
zr.x = 0;
|
||||
zr.y = 0;
|
||||
zr.pixwid = chantodepth(rgb->chan)/8;
|
||||
zw.io = io;
|
||||
zw.buf = malloc(IDATSIZE);
|
||||
if(zw.buf == nil)
|
||||
sysfatal("malloc: %r");
|
||||
zw.b = zw.buf;
|
||||
zw.e = zw.b + IDATSIZE;
|
||||
if((err=deflatezlib(&zw, zwrite, &zr, zread, 6, 0)) < 0)
|
||||
sysfatal("deflatezlib %s", flateerr(err));
|
||||
if(zw.b > zw.buf)
|
||||
IDAT(&zw);
|
||||
free(zw.buf);
|
||||
chunk(io, "IEND", nil, 0);
|
||||
if(m != rgb)
|
||||
freememimage(rgb);
|
||||
return nil;
|
||||
}
|
214
sys/src/cmd/pict/writeppm.c
Normal file
214
sys/src/cmd/pict/writeppm.c
Normal file
@ -0,0 +1,214 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <bio.h>
|
||||
|
||||
#define MAXLINE 70
|
||||
|
||||
/* imported from libdraw/arith.c to permit an extern log2 function */
|
||||
static int log2[] = {
|
||||
-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
|
||||
-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
|
||||
};
|
||||
|
||||
static int bitc = 0;
|
||||
static int nbit = 0;
|
||||
|
||||
static
|
||||
void
|
||||
Bputbit(Biobufhdr *b, int c)
|
||||
{
|
||||
if(c >= 0x0){
|
||||
bitc = (bitc << 1) | (c & 0x1);
|
||||
nbit++;
|
||||
}else if(nbit > 0){
|
||||
for(; nbit < 8; nbit++)
|
||||
bitc <<= 1;
|
||||
}
|
||||
if(nbit == 8){
|
||||
Bputc(b, bitc);
|
||||
bitc = nbit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write data
|
||||
*/
|
||||
static
|
||||
char*
|
||||
writedata(Biobuf *fd, Image *image, Memimage *memimage, int rflag)
|
||||
{
|
||||
char *err;
|
||||
unsigned char *data;
|
||||
int i, x, y, ndata, depth, col, pix, xmask, pmask;
|
||||
uint32_t 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, "WritePPM: %r");
|
||||
free(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Encode and emit the data */
|
||||
col = 0;
|
||||
switch(chan){
|
||||
case GREY1:
|
||||
case GREY2:
|
||||
case GREY4:
|
||||
pmask = (1<<depth)-1;
|
||||
xmask = 7>>log2[depth];
|
||||
for(y=r.min.y; y<r.max.y; y++){
|
||||
i = (y-r.min.y)*bytesperline(r, depth);
|
||||
for(x=r.min.x; x<r.max.x; x++){
|
||||
pix = (data[i]>>depth*((xmask-x)&xmask))&pmask;
|
||||
if(((x+1)&xmask) == 0)
|
||||
i++;
|
||||
if(chan == GREY1){
|
||||
pix ^= 1;
|
||||
if(rflag){
|
||||
Bputbit(fd, pix);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if(rflag){
|
||||
Bputc(fd, pix);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
col += Bprint(fd, "%d", pix);
|
||||
if(col >= MAXLINE-(2+1)){
|
||||
Bprint(fd, "\n");
|
||||
col = 0;
|
||||
}else if(y < r.max.y-1 || x < r.max.x-1)
|
||||
col += Bprint(fd, " ");
|
||||
}
|
||||
if(rflag)
|
||||
Bputbit(fd, -1);
|
||||
}
|
||||
break;
|
||||
case GREY8:
|
||||
for(i=0; i<ndata; i++){
|
||||
if(rflag){
|
||||
Bputc(fd, data[i]);
|
||||
continue;
|
||||
}
|
||||
col += Bprint(fd, "%d", data[i]);
|
||||
if(col >= MAXLINE-(4+1)){
|
||||
Bprint(fd, "\n");
|
||||
col = 0;
|
||||
}else if(i < ndata-1)
|
||||
col += Bprint(fd, " ");
|
||||
}
|
||||
break;
|
||||
case RGB24:
|
||||
for(i=0; i<ndata; i+=3){
|
||||
if(rflag){
|
||||
Bputc(fd, data[i+2]);
|
||||
Bputc(fd, data[i+1]);
|
||||
Bputc(fd, data[i]);
|
||||
continue;
|
||||
}
|
||||
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 if(i < ndata-3)
|
||||
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, int rflag)
|
||||
{
|
||||
char *err;
|
||||
|
||||
switch(chan){
|
||||
case GREY1:
|
||||
Bprint(fd, "%s\n", rflag? "P4": "P1");
|
||||
break;
|
||||
case GREY2:
|
||||
case GREY4:
|
||||
case GREY8:
|
||||
Bprint(fd, "%s\n", rflag? "P5": "P2");
|
||||
break;
|
||||
case RGB24:
|
||||
Bprint(fd, "%s\n", rflag? "P6": "P3");
|
||||
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, rflag);
|
||||
|
||||
if(!rflag)
|
||||
Bprint(fd, "\n");
|
||||
Bflush(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
char*
|
||||
writeppm(Biobuf *fd, Image *image, char *comment, int rflag)
|
||||
{
|
||||
return writeppm0(fd, image, nil, image->r, image->chan, comment, rflag);
|
||||
}
|
||||
|
||||
char*
|
||||
memwriteppm(Biobuf *fd, Memimage *memimage, char *comment, int rflag)
|
||||
{
|
||||
return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment, rflag);
|
||||
}
|
206
sys/src/cmd/pict/writerawimage.c
Normal file
206
sys/src/cmd/pict/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{
|
||||
unsigned char *s;
|
||||
Hlist *next, *prev;
|
||||
};
|
||||
|
||||
int
|
||||
writerawimage(int fd, Rawimage *i)
|
||||
{
|
||||
unsigned char *outbuf, *outp, *eout; /* encoded data, pointer, end */
|
||||
unsigned char *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 */
|
||||
unsigned char *line, *eline; /* input line, end pointer */
|
||||
unsigned char *data, *edata; /* input buffer, end pointer */
|
||||
uint32_t n; /* length of input buffer */
|
||||
int bpl; /* input line length */
|
||||
int offs, runlen; /* offset, length of consumed data */
|
||||
unsigned char dumpbuf[NDUMP]; /* dump accumulator */
|
||||
int ndump; /* length of dump accumulator */
|
||||
int ncblock; /* size of buffer */
|
||||
Rectangle r;
|
||||
unsigned char *p, *q, *s, *es, *t;
|
||||
char hdr[11+5*12+1], buf[16];
|
||||
uint32_t 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;
|
||||
}
|
1333
sys/src/cmd/pict/writetif.c
Normal file
1333
sys/src/cmd/pict/writetif.c
Normal file
File diff suppressed because it is too large
Load Diff
294
sys/src/cmd/pict/ycbcr.h
Normal file
294
sys/src/cmd/pict/ycbcr.h
Normal file
@ -0,0 +1,294 @@
|
||||
unsigned int ycbcrmap[256] = {
|
||||
0x008080, 0x07A27A, 0x0FC474, 0x17E66F, 0x276963, 0x2F8B5E, 0x37AD58, 0x3FCF52,
|
||||
0x4F5247, 0x577441, 0x5F963C, 0x67B836, 0x773C2A, 0x7F5E25, 0x87801F, 0x8FA21A,
|
||||
0x9AA511, 0x118080, 0x09AA79, 0x11CC73, 0x19EE6E, 0x31635C, 0x3B8E55, 0x3EB353,
|
||||
0x44D64F, 0x594D3F, 0x627339, 0x6B9933, 0x6FBD30, 0x813623, 0x8A5B1D, 0x928017,
|
||||
0x9D800F, 0xA6A809, 0x228080, 0x0BB377, 0x13D572, 0x1BF76C, 0x3B5E55, 0x47914D,
|
||||
0x45B84E, 0x49DC4B, 0x634738, 0x6D7231, 0x779C2B, 0x77C22A, 0x8B311C, 0x945815,
|
||||
0x9F560E, 0xA98007, 0xB2AB00, 0x338080, 0x0DBB76, 0x15DD70, 0x1DFF6B, 0x45584E,
|
||||
0x539444, 0x4BBE49, 0x4EE347, 0x6D4231, 0x78702A, 0x839F22, 0x80C724, 0x952B15,
|
||||
0x1C969C, 0x23B896, 0x2BDA91, 0x3C5E85, 0x448080, 0x4BA27A, 0x53C474, 0x644769,
|
||||
0x6B6963, 0x738B5E, 0x7BAD58, 0x8C304C, 0x935247, 0x9B7441, 0xA3963C, 0x1474A2,
|
||||
0x1971AA, 0x239CA3, 0x28BF99, 0x2FE292, 0x4B5586, 0x558080, 0x54A679, 0x59CA73,
|
||||
0x704065, 0x79665F, 0x818C59, 0x85B154, 0x972A47, 0x9F4E42, 0xA8733C, 0xB09836,
|
||||
0xBE9A30, 0x1E6EB3, 0x2AA1AA, 0x2CC69C, 0x32E994, 0x5A4D88, 0x668080, 0x5EAA79,
|
||||
0x61CF73, 0x7D3963, 0x86635C, 0x908E55, 0x8FB551, 0xA32343, 0xAC4B3D, 0xB57237,
|
||||
0xC27231, 0xCC9C2B, 0x236BBB, 0x31A7B1, 0x31CD9F, 0x36F195, 0x694489, 0x778080,
|
||||
0x67AF78, 0x68D572, 0x893260, 0x946058, 0x9E8F51, 0x9AB84E, 0xAF1D3F, 0xB84738,
|
||||
0x38ADB8, 0x3FCFB3, 0x5052A7, 0x5874A2, 0x60969C, 0x67B896, 0x783C8B, 0x805E85,
|
||||
0x888080, 0x8FA27A, 0xA0256E, 0xA84769, 0xAF6963, 0xB78B5E, 0x2869C4, 0x308BBE,
|
||||
0x368CC6, 0x3FB2C0, 0x45D5B7, 0x5A4DAC, 0x6373A6, 0x6B99A0, 0x6FBD98, 0x87338C,
|
||||
0x905986, 0x998080, 0x9BA579, 0xAD1D6C, 0xB64267, 0xBE6761, 0xC68C5B, 0x2D66CC,
|
||||
0x3263D5, 0x3C8DCE, 0x46B8C7, 0x4ADCBB, 0x6447B1, 0x6E71AA, 0x789CA3, 0x78C29A,
|
||||
0x962B8D, 0xA05586, 0xAA8080, 0xA7A879, 0xBA166B, 0xC33D64, 0xCC655E, 0xD68D58,
|
||||
0xE58E55, 0x3760DD, 0x428ED5, 0x4DBDCE, 0x4FE2C0, 0x6E41B6, 0x7970AF, 0x839FA7,
|
||||
0x81C69C, 0xA5228F, 0xB05187, 0xBB8080, 0xB3AA79, 0xC80E6A, 0xD23963, 0xDB635C,
|
||||
0x54C3D5, 0x6447C9, 0x6C69C4, 0x748BBE, 0x7CADB8, 0x8C30AD, 0x9452A7, 0x9C74A2,
|
||||
0xA4969C, 0xB41A90, 0xBC3C8B, 0xC45E85, 0xCC8080, 0x3C5DE6, 0x447FE0, 0x4CA1DA,
|
||||
0x52A4E2, 0x5BC9DC, 0x6C42CF, 0x7567CA, 0x7D8CC3, 0x86B1BD, 0x982AB0, 0xA04EAB,
|
||||
0xA973A5, 0xB1989E, 0xC31191, 0xCC368C, 0xD45A86, 0xDD8080, 0x425AEE, 0x4A7FE8,
|
||||
0x507FF0, 0x59A6EA, 0x62CEE3, 0x753DD5, 0x7E65CF, 0x878CC9, 0x90B4C2, 0xA323B4,
|
||||
0xAC4BAE, 0xB572A8, 0xBF9AA1, 0xD20993, 0xDB308C, 0xE45886, 0xEE8080, 0x4757F7,
|
||||
0x4C54FF, 0x557FF8, 0x5FA9F1, 0x69D4EA, 0x7E38DB, 0x8763D5, 0x918DCE, 0x9BB8C7,
|
||||
0xB01CB8, 0xB947B1, 0xC371AA, 0xCD9CA3, 0xE10094, 0xEB2B8D, 0xF55586, 0xFF8080,
|
||||
};
|
||||
|
||||
unsigned char closestycbcr[16*16*16] = {
|
||||
8,55,55,38,21,21,4,4,4,0,79,79,80,114,142,159,
|
||||
8,55,38,38,21,4,4,4,4,0,79,79,80,114,142,159,
|
||||
55,55,38,21,21,4,4,4,0,0,79,79,80,114,142,159,
|
||||
55,38,38,21,4,4,4,4,0,0,79,79,80,114,142,159,
|
||||
55,38,21,21,4,4,4,0,0,0,79,79,80,114,142,159,
|
||||
38,38,21,4,4,4,4,0,0,0,79,79,80,114,142,159,
|
||||
38,21,21,4,4,4,0,0,0,0,79,79,80,114,142,159,
|
||||
38,21,4,4,4,4,0,0,0,0,79,79,80,114,142,159,
|
||||
21,21,4,4,4,4,0,0,0,0,79,79,80,114,142,159,
|
||||
21,4,4,4,4,0,0,0,0,17,79,79,80,114,142,159,
|
||||
5,5,5,5,5,1,1,1,1,1,64,64,64,143,143,144,
|
||||
22,5,5,5,18,18,18,18,18,18,64,64,81,98,143,144,
|
||||
6,6,6,52,52,52,52,52,52,52,65,65,98,115,115,128,
|
||||
6,6,6,2,2,2,2,2,2,2,65,65,82,115,128,145,
|
||||
23,23,36,36,36,36,36,36,36,36,82,99,99,116,145,162,
|
||||
7,7,3,3,3,3,3,3,3,3,66,66,116,116,129,129,
|
||||
25,8,8,55,38,38,21,4,4,67,67,80,97,142,159,160,
|
||||
25,8,55,55,38,21,21,4,4,67,79,80,97,142,159,160,
|
||||
8,8,55,38,38,21,4,4,4,67,79,80,97,142,159,160,
|
||||
8,55,55,38,21,21,4,4,4,79,79,80,97,142,159,160,
|
||||
8,55,38,38,21,4,4,4,4,79,79,80,97,142,159,160,
|
||||
55,55,38,21,21,4,4,4,0,79,79,80,97,142,159,160,
|
||||
55,38,38,21,4,4,4,4,0,79,79,80,97,142,159,160,
|
||||
55,38,21,21,4,4,4,0,0,79,79,80,97,142,159,160,
|
||||
38,38,21,4,4,4,4,17,17,17,79,80,97,142,159,160,
|
||||
5,5,5,5,5,5,1,1,17,34,64,64,143,143,143,144,
|
||||
22,22,5,5,5,5,1,1,1,64,64,81,81,143,144,161,
|
||||
39,22,22,22,5,35,35,35,35,35,81,81,98,115,144,178,
|
||||
6,6,6,6,6,2,2,2,2,65,65,65,115,128,128,145,
|
||||
23,23,23,23,19,19,19,19,19,65,82,82,99,128,145,162,
|
||||
57,7,7,7,53,53,53,53,53,66,66,116,116,129,129,179,
|
||||
24,7,7,7,20,20,20,20,20,66,66,83,116,129,146,146,
|
||||
42,25,25,8,55,38,38,21,4,67,67,67,114,142,160,177,
|
||||
42,25,8,8,55,38,21,21,4,67,67,97,114,142,160,177,
|
||||
25,25,8,55,55,38,21,4,4,67,67,97,114,142,160,177,
|
||||
25,8,8,55,38,38,21,4,4,67,67,97,114,142,160,177,
|
||||
25,8,55,55,38,21,21,4,4,67,80,97,114,142,160,177,
|
||||
8,8,55,38,38,21,4,4,4,67,80,97,114,142,160,177,
|
||||
8,55,55,38,21,21,4,4,4,79,80,97,114,142,160,177,
|
||||
8,55,38,38,21,4,4,4,17,79,80,97,114,142,160,177,
|
||||
55,55,38,21,21,4,4,34,34,34,80,97,114,142,160,177,
|
||||
9,9,22,5,5,5,5,5,34,64,64,81,143,143,144,206,
|
||||
39,39,22,22,22,5,5,18,18,64,81,98,98,144,161,178,
|
||||
56,39,39,6,6,6,6,52,52,65,65,98,115,128,178,178,
|
||||
23,23,23,6,6,6,19,19,19,65,82,82,128,145,145,207,
|
||||
40,40,40,40,23,36,36,36,36,82,99,116,116,145,162,179,
|
||||
57,7,7,7,7,3,3,3,3,66,66,116,129,129,179,192,
|
||||
41,41,24,24,24,37,37,37,37,83,100,100,146,146,163,192,
|
||||
59,42,25,25,8,55,55,38,67,67,84,130,130,159,177,205,
|
||||
42,42,25,8,8,55,38,38,67,67,84,130,130,159,177,205,
|
||||
42,25,25,8,55,55,38,21,67,67,67,130,130,159,177,205,
|
||||
42,25,8,8,55,38,38,21,67,67,67,130,142,159,177,205,
|
||||
25,25,8,55,55,38,21,21,67,67,67,114,142,159,177,205,
|
||||
25,25,8,55,38,38,21,4,67,67,67,114,142,159,177,205,
|
||||
25,8,8,55,38,21,21,4,67,67,80,114,142,159,177,205,
|
||||
25,8,55,55,38,21,4,4,34,67,80,114,142,159,177,205,
|
||||
9,9,9,9,5,5,5,51,51,51,64,143,143,144,206,206,
|
||||
9,9,9,22,22,22,5,5,51,64,81,143,143,144,161,206,
|
||||
56,56,39,39,39,22,22,6,69,81,98,98,115,161,178,178,
|
||||
10,56,56,6,6,6,6,6,65,65,65,115,128,145,207,207,
|
||||
10,40,40,40,23,23,23,19,82,82,99,99,145,145,162,208,
|
||||
57,57,57,57,7,7,7,53,66,66,116,116,129,162,179,192,
|
||||
11,24,24,24,24,7,7,20,66,83,83,129,146,146,192,192,
|
||||
58,58,41,41,41,41,37,37,100,100,117,117,163,163,180,209,
|
||||
12,59,42,42,25,8,8,71,71,84,101,130,147,193,193,222,
|
||||
59,59,42,25,25,8,55,71,84,84,101,130,147,193,205,222,
|
||||
59,42,42,25,8,8,55,71,84,84,84,130,130,193,205,222,
|
||||
59,42,25,25,8,55,55,38,84,84,130,130,130,160,205,222,
|
||||
42,42,25,8,8,55,38,67,67,84,130,130,130,160,205,222,
|
||||
42,25,25,8,55,55,38,67,67,84,130,130,159,160,205,222,
|
||||
42,25,8,8,55,38,38,67,67,67,130,130,159,160,205,222,
|
||||
25,9,9,9,55,38,21,51,51,68,131,131,159,160,206,222,
|
||||
26,9,9,9,9,22,5,68,68,68,131,143,144,161,206,223,
|
||||
26,26,9,39,39,22,22,68,68,68,98,143,144,161,178,223,
|
||||
10,56,56,56,39,39,6,69,69,69,115,115,128,178,207,207,
|
||||
10,10,10,40,23,23,23,69,69,82,128,128,145,162,207,208,
|
||||
11,11,57,57,40,40,40,70,70,99,116,129,162,162,179,225,
|
||||
11,11,57,57,7,7,7,70,70,66,116,129,146,179,192,209,
|
||||
28,41,41,41,41,41,24,87,100,100,100,146,163,163,209,209,
|
||||
58,58,58,58,58,58,58,54,117,117,117,163,180,180,180,226,
|
||||
29,12,59,59,42,25,71,71,71,101,118,147,164,193,193,210,
|
||||
12,12,59,42,42,25,71,71,71,101,101,147,164,193,193,210,
|
||||
12,59,59,42,25,25,71,71,101,101,130,147,164,193,193,239,
|
||||
12,59,42,42,25,8,71,71,101,101,130,147,147,193,193,239,
|
||||
59,59,42,25,25,8,71,71,84,101,130,147,147,193,222,239,
|
||||
59,42,42,25,8,8,55,71,84,101,130,130,147,193,222,239,
|
||||
59,42,25,25,8,55,55,84,84,84,130,130,147,177,222,239,
|
||||
13,26,9,9,9,9,72,68,68,131,131,131,148,206,206,223,
|
||||
43,26,26,9,9,9,22,68,85,85,131,131,161,178,223,224,
|
||||
43,43,56,56,56,39,39,69,85,85,132,132,178,178,207,224,
|
||||
27,10,10,10,56,56,69,69,69,132,132,132,145,207,207,208,
|
||||
27,27,27,10,40,40,40,86,86,103,132,145,162,179,208,225,
|
||||
11,11,11,57,57,57,70,70,70,133,133,129,179,179,192,242,
|
||||
28,28,11,11,41,24,24,87,87,87,129,146,163,192,209,209,
|
||||
45,45,58,58,58,58,41,104,104,117,163,163,180,180,226,226,
|
||||
62,58,58,58,58,58,58,121,117,117,117,180,180,180,243,243,
|
||||
46,29,12,12,59,42,88,88,88,118,134,164,181,193,210,227,
|
||||
29,29,12,59,59,42,88,88,88,118,118,164,181,193,210,227,
|
||||
29,12,12,59,42,42,71,71,118,118,118,164,181,193,210,227,
|
||||
29,12,59,59,42,25,71,71,101,118,147,164,181,193,210,227,
|
||||
12,12,59,42,42,25,71,71,101,118,147,164,193,193,210,240,
|
||||
12,59,59,42,25,25,71,71,101,101,147,164,193,193,210,240,
|
||||
13,13,42,26,9,9,72,72,101,101,131,148,194,194,194,240,
|
||||
13,43,43,26,26,9,72,72,85,131,131,148,194,194,223,241,
|
||||
60,60,43,26,26,56,72,85,102,102,148,165,194,194,224,241,
|
||||
14,27,10,10,10,56,73,102,102,132,132,132,195,207,208,225,
|
||||
44,27,27,27,10,10,73,86,103,132,132,149,195,208,225,225,
|
||||
44,44,44,11,11,57,103,103,120,133,133,166,179,179,225,242,
|
||||
28,28,11,11,11,57,70,87,87,133,133,150,192,192,209,226,
|
||||
45,45,28,28,58,41,104,104,104,150,150,163,180,209,226,226,
|
||||
62,62,45,58,58,58,121,121,121,121,180,180,180,180,243,243,
|
||||
62,62,58,58,58,58,121,121,121,121,180,180,180,180,243,243,
|
||||
63,46,29,29,12,75,105,105,105,134,151,197,181,227,244,244,
|
||||
46,46,29,12,12,75,105,105,134,134,134,181,181,227,244,244,
|
||||
46,29,29,12,59,75,88,88,134,134,134,181,181,210,227,244,
|
||||
46,29,12,12,59,88,88,88,118,134,134,181,181,210,227,244,
|
||||
29,29,12,59,59,88,88,88,118,134,164,181,181,210,227,244,
|
||||
29,12,12,59,42,88,88,88,118,118,164,181,193,210,227,244,
|
||||
13,13,13,13,26,72,72,72,135,135,148,165,194,211,228,228,
|
||||
30,60,60,43,43,72,72,72,102,135,165,165,194,211,228,241,
|
||||
14,60,60,60,43,73,73,102,119,119,165,182,195,195,228,241,
|
||||
14,14,27,27,27,73,73,73,119,132,149,195,195,212,225,242,
|
||||
61,44,44,44,27,90,90,120,120,149,166,166,212,212,242,242,
|
||||
61,61,61,11,11,74,74,120,120,133,133,196,196,196,242,242,
|
||||
45,45,28,28,28,74,74,104,104,150,150,167,196,209,226,243,
|
||||
62,62,45,45,45,91,121,121,121,167,167,184,180,226,243,243,
|
||||
62,62,62,62,58,121,121,121,121,184,184,184,180,243,243,243,
|
||||
62,62,62,62,58,121,121,121,121,184,184,180,180,243,243,243,
|
||||
63,63,46,29,75,75,122,122,151,151,151,197,197,244,244,244,
|
||||
63,63,46,29,75,75,122,122,151,151,151,197,197,244,244,244,
|
||||
63,46,46,29,75,75,122,122,151,151,151,197,197,244,244,244,
|
||||
63,46,29,29,75,75,105,105,134,151,151,197,197,227,244,244,
|
||||
46,46,29,12,75,75,105,105,134,151,197,197,210,227,244,244,
|
||||
30,30,13,13,76,76,89,135,135,135,198,198,211,228,245,245,
|
||||
30,30,13,13,76,89,89,89,135,135,165,182,211,228,245,245,
|
||||
47,60,60,60,60,106,106,119,119,119,182,182,228,228,245,245,
|
||||
14,14,14,14,77,73,73,119,136,136,182,195,195,212,229,246,
|
||||
31,14,14,44,44,90,90,90,136,136,166,166,212,229,246,246,
|
||||
15,61,61,61,44,74,74,137,137,166,183,183,196,246,246,242,
|
||||
15,15,15,28,91,91,74,137,137,150,183,196,213,213,230,243,
|
||||
62,62,62,45,45,91,91,121,167,167,184,184,213,230,243,243,
|
||||
62,62,62,62,62,108,121,121,184,184,184,184,230,247,243,243,
|
||||
62,62,62,62,62,125,121,121,184,184,184,184,247,243,243,243,
|
||||
62,62,62,62,62,121,121,121,184,184,184,184,247,243,243,243,
|
||||
63,63,63,46,92,92,122,138,138,168,168,214,214,231,244,244,
|
||||
63,63,63,46,92,92,122,138,138,168,168,214,214,231,244,244,
|
||||
63,63,46,46,92,92,122,138,151,168,197,197,214,244,244,244,
|
||||
63,63,46,29,75,75,122,138,151,168,197,197,214,244,244,244,
|
||||
63,46,46,29,75,75,122,122,151,151,197,197,214,244,244,244,
|
||||
47,47,30,30,76,76,106,139,152,152,198,198,215,245,245,245,
|
||||
48,47,30,30,76,123,123,123,152,152,198,198,228,245,245,245,
|
||||
48,31,14,14,77,123,123,136,136,136,199,199,245,245,245,245,
|
||||
32,31,31,14,77,90,90,136,136,153,199,199,229,229,246,246,
|
||||
32,32,61,61,107,107,107,153,153,153,183,183,229,246,246,246,
|
||||
16,15,15,61,78,91,91,137,137,137,183,183,213,246,246,246,
|
||||
16,16,16,45,108,108,108,154,154,154,184,213,230,230,247,247,
|
||||
33,62,62,62,125,125,125,154,171,184,184,230,230,247,247,243,
|
||||
62,62,62,62,125,125,125,125,184,184,184,184,247,247,247,243,
|
||||
62,62,62,62,125,125,125,121,184,184,184,184,247,247,243,243,
|
||||
62,62,62,62,125,125,125,121,184,184,184,184,247,247,243,243,
|
||||
63,63,63,126,109,109,138,155,155,185,185,231,231,248,248,244,
|
||||
63,63,63,109,109,109,138,138,138,185,185,231,231,248,248,244,
|
||||
63,63,63,109,109,109,138,138,168,185,185,231,231,248,244,244,
|
||||
63,63,63,109,109,92,138,138,168,185,214,214,231,248,244,244,
|
||||
48,48,47,93,93,93,139,139,139,169,198,215,215,232,245,245,
|
||||
48,48,47,93,93,93,139,139,169,169,215,215,232,245,245,245,
|
||||
48,48,48,93,93,123,123,140,169,169,215,215,232,245,245,245,
|
||||
32,32,31,77,77,77,140,140,153,199,199,216,216,246,246,246,
|
||||
49,32,32,94,94,107,107,153,153,170,216,216,246,246,246,246,
|
||||
49,49,15,78,78,124,124,137,170,200,200,200,246,246,246,246,
|
||||
16,16,16,78,78,124,124,154,154,200,200,217,230,230,247,247,
|
||||
33,33,16,95,125,125,125,171,171,171,217,230,247,247,247,247,
|
||||
50,33,62,125,125,125,125,171,188,184,184,247,247,247,247,247,
|
||||
50,62,62,125,125,125,125,188,188,184,184,247,247,247,247,247,
|
||||
50,62,62,125,125,125,125,188,184,184,184,247,247,247,247,247,
|
||||
50,62,62,125,125,125,125,188,184,184,184,247,247,247,247,243,
|
||||
63,63,63,126,126,126,155,172,172,201,201,248,248,248,248,248,
|
||||
63,63,63,126,126,126,155,155,172,201,201,248,248,248,248,248,
|
||||
63,63,63,126,126,126,155,155,185,201,201,248,248,248,248,248,
|
||||
63,63,63,126,126,126,155,155,185,202,202,248,248,248,248,244,
|
||||
48,48,48,110,110,110,139,156,202,202,232,232,249,249,249,245,
|
||||
48,48,48,110,110,110,156,156,186,186,232,232,249,249,245,245,
|
||||
48,48,48,94,94,140,140,140,186,186,216,216,249,249,245,245,
|
||||
49,49,111,111,94,140,140,140,170,216,216,233,233,246,246,246,
|
||||
49,49,111,111,111,124,141,170,170,187,233,233,250,246,246,246,
|
||||
49,16,95,95,95,141,141,141,187,200,217,217,217,246,246,246,
|
||||
33,33,95,95,95,141,141,171,171,217,217,234,247,247,247,247,
|
||||
50,50,96,96,125,125,188,188,188,188,234,234,247,247,247,247,
|
||||
50,50,50,125,125,125,188,188,188,188,234,247,247,247,247,247,
|
||||
50,50,50,125,125,125,188,188,188,188,247,247,247,247,247,247,
|
||||
50,50,62,125,125,125,188,188,188,188,247,247,247,247,247,247,
|
||||
50,50,62,125,125,125,188,188,188,184,247,247,247,247,247,247,
|
||||
63,63,126,126,126,126,189,189,189,218,218,248,248,248,248,248,
|
||||
63,63,126,126,126,126,172,172,201,218,218,248,248,248,248,248,
|
||||
63,63,126,126,126,172,172,172,201,218,218,248,248,248,248,248,
|
||||
48,48,127,127,127,156,173,173,202,202,219,249,249,249,249,249,
|
||||
48,48,127,127,127,173,173,173,202,202,249,249,249,249,249,249,
|
||||
48,48,127,127,127,173,173,173,186,203,249,249,249,249,249,249,
|
||||
49,49,111,111,111,157,157,157,203,203,233,233,250,250,250,246,
|
||||
49,49,112,112,112,157,157,157,187,203,233,250,250,250,250,246,
|
||||
49,49,112,112,112,141,141,187,187,204,250,250,250,250,246,246,
|
||||
50,33,96,96,96,158,158,158,204,217,234,234,234,251,247,247,
|
||||
50,50,96,96,96,158,158,188,188,234,234,251,251,247,247,247,
|
||||
50,50,113,113,113,175,188,188,188,234,251,251,251,247,247,247,
|
||||
50,50,113,113,113,125,188,188,188,251,251,251,247,247,247,247,
|
||||
50,50,113,113,125,125,188,188,188,251,251,251,247,247,247,247,
|
||||
50,50,113,113,125,125,188,188,188,251,251,247,247,247,247,247,
|
||||
50,50,113,125,125,125,188,188,188,251,251,247,247,247,247,247,
|
||||
63,126,126,126,126,189,189,189,235,235,235,252,248,248,248,248,
|
||||
63,126,126,126,126,189,189,189,218,235,235,235,248,248,248,248,
|
||||
63,126,126,126,126,189,189,189,219,219,235,248,248,248,248,248,
|
||||
48,127,127,127,127,190,190,190,219,219,236,249,249,249,249,249,
|
||||
48,127,127,127,127,190,190,190,219,219,236,249,249,249,249,249,
|
||||
48,127,127,127,127,174,174,203,203,220,220,249,249,249,249,249,
|
||||
49,112,112,112,112,174,174,174,220,220,250,250,250,250,250,250,
|
||||
49,112,112,112,112,174,191,191,204,204,250,250,250,250,250,250,
|
||||
49,112,112,112,158,158,158,204,204,204,250,250,250,250,250,250,
|
||||
50,113,113,113,113,175,175,175,221,234,251,251,251,251,251,247,
|
||||
50,113,113,113,113,175,175,188,188,251,251,251,251,251,251,247,
|
||||
50,113,113,113,113,176,176,188,188,251,251,251,251,251,247,247,
|
||||
50,113,113,113,113,176,188,188,188,251,251,251,251,251,247,247,
|
||||
50,113,113,113,113,176,188,188,188,251,251,251,251,247,247,247,
|
||||
50,113,113,113,113,188,188,188,188,251,251,251,251,247,247,247,
|
||||
50,113,113,113,113,188,188,188,188,251,251,251,247,247,247,247,
|
||||
126,126,126,126,189,189,189,189,235,252,252,252,252,248,248,248,
|
||||
126,126,126,126,189,189,189,189,235,252,252,252,252,248,248,248,
|
||||
127,127,127,127,190,190,190,190,236,236,253,253,249,249,249,249,
|
||||
127,127,127,127,190,190,190,190,236,236,253,253,249,249,249,249,
|
||||
127,127,127,127,190,190,190,190,236,236,253,249,249,249,249,249,
|
||||
112,112,112,112,191,191,191,220,220,237,237,250,250,250,250,250,
|
||||
112,112,112,112,191,191,191,191,237,237,237,250,250,250,250,250,
|
||||
112,112,112,112,191,191,191,221,221,221,250,250,250,250,250,250,
|
||||
113,113,113,113,175,175,175,221,221,221,251,251,251,251,251,251,
|
||||
113,113,113,113,176,176,176,221,238,238,251,251,251,251,251,251,
|
||||
113,113,113,113,176,176,176,176,238,251,251,251,251,251,251,251,
|
||||
113,113,113,113,176,176,176,176,251,251,251,251,251,251,251,247,
|
||||
113,113,113,113,176,176,176,176,251,251,251,251,251,251,251,247,
|
||||
113,113,113,113,176,176,176,188,251,251,251,251,251,251,251,247,
|
||||
113,113,113,113,176,176,176,188,251,251,251,251,251,251,247,247,
|
||||
113,113,113,113,176,176,188,188,251,251,251,251,251,251,247,247,
|
||||
254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,
|
||||
254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,
|
||||
254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,
|
||||
254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,
|
||||
254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,
|
||||
254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,
|
||||
254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,
|
||||
254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
};
|
||||
|
220
sys/src/cmd/pict/yuv.c
Normal file
220
sys/src/cmd/pict/yuv.c
Normal file
@ -0,0 +1,220 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <draw.h>
|
||||
#include <event.h>
|
||||
#include <keyboard.h>
|
||||
#include "imagefile.h"
|
||||
|
||||
int cflag = 0;
|
||||
int dflag = 0;
|
||||
int eflag = 0;
|
||||
int nineflag = 0;
|
||||
int threeflag = 0;
|
||||
int output = 0;
|
||||
uint32_t outchan = CMAP8;
|
||||
int defaultcolor = 1;
|
||||
Image *image;
|
||||
|
||||
enum{
|
||||
Border = 2,
|
||||
Edge = 5
|
||||
};
|
||||
|
||||
char *show(int, char*);
|
||||
|
||||
Rawimage** readyuv(int fd, int colorspace);
|
||||
|
||||
Rectangle
|
||||
imager(Image *i)
|
||||
{
|
||||
Point p1, p2;
|
||||
|
||||
p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min);
|
||||
p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
|
||||
return rectaddpt(i->r, subpt(p2, p1));
|
||||
}
|
||||
|
||||
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 = imager(image);
|
||||
border(screen, r, -Border, nil, ZP);
|
||||
drawop(screen, r, image, nil, image->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: 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==Kdel || ch==Keof)
|
||||
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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user