xref: /plan9-contrib/sys/src/cmd/jpg/ppm.c (revision 9863c128e160e47d0bf3a33658496e0e3d0bd48e)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <draw.h>
5 #include <event.h>
6 #include "imagefile.h"
7 
8 int		cflag = 0;
9 int		dflag = 0;
10 int		eflag = 0;
11 int		nineflag = 0;
12 int		threeflag = 0;
13 int		output = 0;
14 ulong	outchan = CMAP8;
15 int		defaultcolor = 1;
16 Image	*image;
17 
18 enum{
19 	Border	= 2,
20 	Edge		= 5
21 };
22 
23 char	*show(int, char*);
24 
25 void
eresized(int new)26 eresized(int new)
27 {
28 	Rectangle r;
29 
30 	if(new && getwindow(display, Refnone) < 0){
31 		fprint(2, "ppm: can't reattach to window\n");
32 		exits("resize");
33 	}
34 	if(image == nil)
35 		return;
36 	r = insetrect(screen->clipr, Edge+Border);
37 	r.max.x = r.min.x+Dx(image->r);
38 	r.max.y = r.min.y+Dy(image->r);
39 	border(screen, r, -Border, nil, ZP);
40 	drawop(screen, r, image, nil, image->r.min, S);
41 	flushimage(display, 1);
42 }
43 
44 void
main(int argc,char * argv[])45 main(int argc, char *argv[])
46 {
47 	int fd, i;
48 	char *err;
49 
50 	ARGBEGIN{
51 	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */
52 		threeflag++;
53 		/* fall through */
54 	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */
55 		cflag++;
56 		dflag++;
57 		output++;
58 		defaultcolor = 0;
59 		outchan = RGB24;
60 		break;
61 	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */
62 		cflag++;
63 		dflag++;
64 		output++;
65 		if(defaultcolor)
66 			outchan = CMAP8;
67 		break;
68 	case 'd':		/* suppress display of image */
69 		dflag++;
70 		break;
71 	case 'e':		/* disable floyd-steinberg error diffusion */
72 		eflag++;
73 		break;
74 	case 'k':		/* force black and white */
75 		defaultcolor = 0;
76 		outchan = GREY8;
77 		break;
78 	case 'v':		/* force RGBV */
79 		defaultcolor = 0;
80 		outchan = CMAP8;
81 		break;
82 	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */
83 		nineflag++;
84 		dflag++;
85 		output++;
86 		if(defaultcolor)
87 			outchan = CMAP8;
88 		break;
89 	default:
90 		fprint(2, "usage: ppm -39cdektv  [file.ppm ...]\n");
91 		exits("usage");
92 	}ARGEND;
93 
94 	err = nil;
95 	if(argc == 0)
96 		err = show(0, "<stdin>");
97 	else{
98 		for(i=0; i<argc; i++){
99 			fd = open(argv[i], OREAD);
100 			if(fd < 0){
101 				fprint(2, "ppm: can't open %s: %r\n", argv[i]);
102 				err = "open";
103 			}else{
104 				err = show(fd, argv[i]);
105 				close(fd);
106 			}
107 			if((nineflag || cflag) && argc>1 && err==nil){
108 				fprint(2, "ppm: exiting after one file\n");
109 				break;
110 			}
111 		}
112 	}
113 	exits(err);
114 }
115 
116 int
init(void)117 init(void)
118 {
119 	static int inited;
120 
121 	if(inited == 0){
122 		if(initdraw(0, 0, 0) < 0){
123 			fprint(2, "ppm: initdraw failed: %r");
124 			return -1;
125 		}
126 		einit(Ekeyboard|Emouse);
127 		inited++;
128 	}
129 	return 1;
130 }
131 
132 char*
show(int fd,char * name)133 show(int fd, char *name)
134 {
135 	Rawimage **array, *r, *c;
136 	Image *i;
137 	int j, ch;
138 	char buf[32];
139 
140 	array = readpixmap(fd, CRGB);
141 	if(array == nil || array[0]==nil){
142 		fprint(2, "ppm: decode %s failed: %r\n", name);
143 		return "decode";
144 	}
145 	if(!dflag){
146 		if(init() < 0)
147 			return "initdraw";
148 		if(defaultcolor && screen->depth>8)
149 			outchan = RGB24;
150 	}
151 	r = array[0];
152 	if(outchan == CMAP8)
153 		c = torgbv(r, !eflag);
154 	else{
155 		if(outchan==GREY8 || (r->chandesc==CY && threeflag==0))
156 			c = totruecolor(r, CY);
157 		else
158 			c = totruecolor(r, CRGB24);
159 	}
160 	if(c == nil){
161 		fprint(2, "ppm: converting %s to local format failed: %r\n", name);
162 		return "torgbv";
163 	}
164 	if(!dflag){
165 		if(r->chandesc == CY)
166 			outchan = GREY8;
167 		i = allocimage(display, c->r, outchan, 0, 0);
168 		if(i == nil){
169 			fprint(2, "ppm: allocimage %s failed: %r\n", name);
170 			return "allocimage";
171 		}
172 		if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
173 			fprint(2, "ppm: loadimage %s failed: %r\n", name);
174 			return "loadimage";
175 		}
176 		image = i;
177 		eresized(0);
178 		if((ch=ekbd())=='q' || ch==0x7F || ch==0x04)
179 			exits(nil);
180 		draw(screen, screen->clipr, display->white, nil, ZP);
181 		image = nil;
182 		freeimage(i);
183 	}
184 	if(nineflag){
185 		if(r->chandesc == CY)
186 			outchan = GREY8;
187 		chantostr(buf, outchan);
188 		print("%11s %11d %11d %11d %11d ", buf,
189 			c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y);
190 		if(write(1, c->chans[0], c->chanlen) != c->chanlen){
191 			fprint(2, "ppm: %s: write error %r\n", name);
192 			return "write";
193 		}
194 	}else if(cflag){
195 		if(writerawimage(1, c) < 0){
196 			fprint(2, "ppm: %s: write error: %r\n", name);
197 			return "write";
198 		}
199 	}
200 	for(j=0; j<r->nchans; j++)
201 		free(r->chans[j]);
202 	free(r->cmap);
203 	free(r);
204 	free(array);
205 	if(c){
206 		free(c->chans[0]);
207 		free(c);
208 	}
209 	return nil;
210 }
211