1 /*
2 * Copyright (c) 2002-2003 Michael David Adams.
3 * All rights reserved.
4 */
5
6 /* __START_OF_JASPER_LICENSE__
7 *
8 * JasPer License Version 2.0
9 *
10 * Copyright (c) 2001-2006 Michael David Adams
11 * Copyright (c) 1999-2000 Image Power, Inc.
12 * Copyright (c) 1999-2000 The University of British Columbia
13 *
14 * All rights reserved.
15 *
16 * Permission is hereby granted, free of charge, to any person (the
17 * "User") obtaining a copy of this software and associated documentation
18 * files (the "Software"), to deal in the Software without restriction,
19 * including without limitation the rights to use, copy, modify, merge,
20 * publish, distribute, and/or sell copies of the Software, and to permit
21 * persons to whom the Software is furnished to do so, subject to the
22 * following conditions:
23 *
24 * 1. The above copyright notices and this permission notice (which
25 * includes the disclaimer below) shall be included in all copies or
26 * substantial portions of the Software.
27 *
28 * 2. The name of a copyright holder shall not be used to endorse or
29 * promote products derived from the Software without specific prior
30 * written permission.
31 *
32 * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
33 * LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
34 * THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
35 * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
36 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
37 * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO
38 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
39 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
40 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
41 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
42 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE
43 * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
44 * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
45 * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
46 * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
47 * PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS
48 * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
49 * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE
50 * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
51 * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
52 * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
53 * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
54 * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
55 * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
56 * RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
57 * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
58 *
59 * __END_OF_JASPER_LICENSE__
60 */
61
62 /******************************************************************************\
63 * Includes
64 \******************************************************************************/
65
66 #include <jasper/jasper.h>
67 #include <stdlib.h>
68 #include <math.h>
69 #include <inttypes.h>
70 #if defined(JAS_HAVE_GL_GLUT_H)
71 #include <GL/glut.h>
72 #else
73 #include <glut.h>
74 #endif
75
76 /******************************************************************************\
77 *
78 \******************************************************************************/
79
80 #define MAXCMPTS 256
81 #define BIGPANAMOUNT 0.90
82 #define SMALLPANAMOUNT 0.05
83 #define BIGZOOMAMOUNT 2.0
84 #define SMALLZOOMAMOUNT 1.41421356237310
85
86 #define min(x, y) (((x) < (y)) ? (x) : (y))
87 #define max(x, y) (((x) > (y)) ? (x) : (y))
88
89 typedef struct {
90
91 /* The number of image files to view. */
92 int numfiles;
93
94 /* The names of the image files. */
95 char **filenames;
96
97 /* The title for the window. */
98 const char *title;
99
100 /* The time to wait before advancing to the next image (in ms). */
101 int tmout;
102
103 /* Loop indefinitely over all images. */
104 int loop;
105
106 int verbose;
107
108 #if defined(JAS_DEFAULT_MAX_MEM_USAGE)
109 size_t max_mem;
110 #endif
111
112 } cmdopts_t;
113
114 typedef struct {
115
116 int width;
117
118 int height;
119
120 GLshort *data;
121
122 } pixmap_t;
123
124 typedef struct {
125
126 /* The index of the current image file. */
127 int filenum;
128
129 /* The image. */
130 jas_image_t *image;
131 jas_image_t *altimage;
132
133 float botleftx;
134 float botlefty;
135 float toprightx;
136 float toprighty;
137
138 int viewportwidth;
139 int viewportheight;
140
141 /* The image for display. */
142 pixmap_t vp;
143
144 /* The active timer ID. */
145 int activetmid;
146
147 /* The next available timer ID. */
148 int nexttmid;
149
150 int monomode;
151
152 unsigned cmptno;
153
154 } gs_t;
155
156 /******************************************************************************\
157 *
158 \******************************************************************************/
159
160 static void displayfunc(void);
161 static void reshapefunc(int w, int h);
162 static void keyboardfunc(unsigned char key, int x, int y);
163 static void specialfunc(int key, int x, int y);
164 static void timerfunc(int value);
165
166 static void usage(void);
167 static void nextimage(void);
168 static void previmage(void);
169 static void nextcmpt(void);
170 static void prevcmpt(void);
171 static int loadimage(void);
172 static void unloadimage(void);
173 static int jas_image_render2(jas_image_t *image, unsigned cmptno, float vtlx, float vtly,
174 float vsx, float vsy, int vw, int vh, GLshort *vdata);
175 static int jas_image_render(jas_image_t *image, float vtlx, float vtly,
176 float vsx, float vsy, int vw, int vh, GLshort *vdata);
177
178 static void dumpstate(void);
179 static int pixmap_resize(pixmap_t *p, int w, int h);
180 static void cmdinfo(void);
181
182 static void cleanupandexit(int);
183 static void init(void);
184
185 static void zoom(float sx, float sy);
186 static void pan(float dx, float dy);
187 static void panzoom(float dx, float dy, float sx, float sy);
188 static void render(void);
189
190 /******************************************************************************\
191 *
192 \******************************************************************************/
193
194 static const jas_opt_t opts[] = {
195 {'V', "version", 0},
196 {'v', "v", 0},
197 {'h', "help", 0},
198 {'w', "wait", JAS_OPT_HASARG},
199 {'l', "loop", 0},
200 {'t', "title", JAS_OPT_HASARG},
201 #if defined(JAS_DEFAULT_MAX_MEM_USAGE)
202 {'m', "memory-limit", JAS_OPT_HASARG},
203 #endif
204 {-1, 0, 0}
205 };
206
207 char *cmdname = 0;
208 cmdopts_t cmdopts;
209 gs_t gs;
210 jas_stream_t *streamin = 0;
211
212 /******************************************************************************\
213 *
214 \******************************************************************************/
215
main(int argc,char ** argv)216 int main(int argc, char **argv)
217 {
218 int c;
219
220 init();
221
222 /* Determine the base name of this command. */
223 if ((cmdname = strrchr(argv[0], '/'))) {
224 ++cmdname;
225 } else {
226 cmdname = argv[0];
227 }
228
229 /* Initialize the JasPer library. */
230 if (jas_init()) {
231 abort();
232 }
233
234 glutInit(&argc, argv);
235 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
236 glutCreateWindow(cmdname);
237 glutReshapeFunc(reshapefunc);
238 glutDisplayFunc(displayfunc);
239 glutSpecialFunc(specialfunc);
240 glutKeyboardFunc(keyboardfunc);
241
242 cmdopts.numfiles = 0;
243 cmdopts.filenames = 0;
244 cmdopts.title = 0;
245 cmdopts.tmout = 0;
246 cmdopts.loop = 0;
247 cmdopts.verbose = 0;
248 #if defined(JAS_DEFAULT_MAX_MEM_USAGE)
249 cmdopts.max_mem = JAS_DEFAULT_MAX_MEM_USAGE;
250 #endif
251
252 while ((c = jas_getopt(argc, argv, opts)) != EOF) {
253 switch (c) {
254 case 'w':
255 cmdopts.tmout = atof(jas_optarg) * 1000;
256 break;
257 case 'l':
258 cmdopts.loop = 1;
259 break;
260 case 't':
261 cmdopts.title = jas_optarg;
262 break;
263 case 'v':
264 cmdopts.verbose = 1;
265 break;
266 case 'm':
267 #if defined(JAS_DEFAULT_MAX_MEM_USAGE)
268 cmdopts.max_mem = strtoull(jas_optarg, 0, 10);
269 #endif
270 break;
271 case 'V':
272 printf("%s\n", JAS_VERSION);
273 fprintf(stderr, "libjasper %s\n", jas_getversion());
274 cleanupandexit(EXIT_SUCCESS);
275 break;
276 default:
277 case 'h':
278 usage();
279 break;
280 }
281 }
282
283 if (jas_optind < argc) {
284 /* The images are to be read from one or more explicitly named
285 files. */
286 cmdopts.numfiles = argc - jas_optind;
287 cmdopts.filenames = &argv[jas_optind];
288 } else {
289 /* The images are to be read from standard input. */
290 static char *null = 0;
291 cmdopts.filenames = &null;
292 cmdopts.numfiles = 1;
293 }
294
295 #if defined(JAS_DEFAULT_MAX_MEM_USAGE)
296 jas_set_max_mem_usage(cmdopts.max_mem);
297 #endif
298
299 streamin = jas_stream_fdopen(0, "rb");
300
301 /* Load the next image. */
302 nextimage();
303
304 /* Start the GLUT main event handler loop. */
305 glutMainLoop();
306
307 return EXIT_SUCCESS;
308 }
309
310 /******************************************************************************\
311 *
312 \******************************************************************************/
313
cmdinfo()314 static void cmdinfo()
315 {
316 fprintf(stderr, "JasPer Image Viewer (Version %s).\n",
317 JAS_VERSION);
318 fprintf(stderr, "Copyright (c) 2002-2003 Michael David Adams.\n"
319 "All rights reserved.\n");
320 fprintf(stderr, "%s\n", JAS_NOTES);
321 }
322
323 static const char *const helpinfo[] = {
324 "The following options are supported:\n",
325 " --help Print this help information and exit.\n",
326 " --version Print version information and exit.\n",
327 " --loop Loop indefinitely through images.\n",
328 " --wait N Advance to next image after N seconds.\n",
329 0
330 };
331
usage()332 static void usage()
333 {
334 const char *s;
335 int i;
336 cmdinfo();
337 fprintf(stderr, "usage: %s [options] [file1 file2 ...]\n", cmdname);
338 for (i = 0, s = helpinfo[i]; s; ++i, s = helpinfo[i]) {
339 fprintf(stderr, "%s", s);
340 }
341 cleanupandexit(EXIT_FAILURE);
342 }
343
344 /******************************************************************************\
345 * GLUT Callback Functions
346 \******************************************************************************/
347
348 /* Display callback function. */
349
displayfunc()350 static void displayfunc()
351 {
352
353 float w;
354 float h;
355 int regbotleftx;
356 int regbotlefty;
357 int regtoprightx;
358 int regtoprighty;
359 int regwidth;
360 int regheight;
361 float x;
362 float y;
363 float xx;
364 float yy;
365
366 if (cmdopts.verbose) {
367 fprintf(stderr, "displayfunc()\n");
368 }
369
370 regbotleftx = max(ceil(gs.botleftx), 0);
371 regbotlefty = max(ceil(gs.botlefty), 0);
372 regtoprightx = min(gs.vp.width, floor(gs.toprightx));
373 regtoprighty = min(gs.vp.height, floor(gs.toprighty));
374 regwidth = regtoprightx - regbotleftx;
375 regheight = regtoprighty - regbotlefty;
376 w = gs.toprightx - gs.botleftx;
377 h = gs.toprighty - gs.botlefty;
378 x = (regbotleftx - gs.botleftx) / w;
379 y = (regbotlefty - gs.botlefty) / h;
380 xx = (regtoprightx - gs.botleftx) / w;
381 yy = (regtoprighty - gs.botlefty) / h;
382
383 assert(regwidth > 0);
384 assert(regheight > 0);
385
386 glClear(GL_COLOR_BUFFER_BIT);
387 glPixelStorei(GL_UNPACK_ALIGNMENT, sizeof(GLshort));
388 glPixelStorei(GL_UNPACK_ROW_LENGTH, gs.vp.width);
389 glPixelStorei(GL_UNPACK_SKIP_PIXELS, regbotleftx);
390 glPixelStorei(GL_UNPACK_SKIP_ROWS, regbotlefty);
391 glRasterPos2f(x * gs.viewportwidth, y * gs.viewportheight);
392 glPixelZoom((xx - x) * ((double) gs.viewportwidth) / regwidth, (yy - y) * ((double) gs.viewportheight) / regheight);
393 glDrawPixels(regwidth, regheight, GL_RGBA, GL_UNSIGNED_SHORT,
394 gs.vp.data);
395 glFlush();
396 glutSwapBuffers();
397
398 }
399
400 /* Reshape callback function. */
401
reshapefunc(int w,int h)402 static void reshapefunc(int w, int h)
403 {
404 if (cmdopts.verbose) {
405 fprintf(stderr, "reshapefunc(%d, %d)\n", w, h);
406 dumpstate();
407 }
408
409 glViewport(0, 0, w, h);
410 glMatrixMode(GL_PROJECTION);
411 glLoadIdentity();
412 gluOrtho2D(0, w, 0, h);
413 glMatrixMode(GL_MODELVIEW);
414 glLoadIdentity();
415 glTranslatef(0, 0, 0);
416 glRasterPos2i(0, 0);
417
418 zoom((double) gs.viewportwidth / w, (double) gs.viewportheight / h);
419 gs.viewportwidth = w;
420 gs.viewportheight = h;
421
422 }
423
424 /* Keyboard callback function. */
425
keyboardfunc(unsigned char key,int x,int y)426 static void keyboardfunc(unsigned char key, int x, int y)
427 {
428 if (cmdopts.verbose) {
429 fprintf(stderr, "keyboardfunc(%d, %d, %d)\n", key, x, y);
430 }
431
432 switch (key) {
433 case ' ':
434 nextimage();
435 break;
436 case '\b':
437 previmage();
438 break;
439 case '>':
440 zoom(BIGZOOMAMOUNT, BIGZOOMAMOUNT);
441 glutPostRedisplay();
442 break;
443 case '.':
444 zoom(SMALLZOOMAMOUNT, SMALLZOOMAMOUNT);
445 glutPostRedisplay();
446 break;
447 case '<':
448 zoom(1.0 / BIGZOOMAMOUNT, 1.0 / BIGZOOMAMOUNT);
449 glutPostRedisplay();
450 break;
451 case ',':
452 zoom(1.0 / SMALLZOOMAMOUNT, 1.0 / SMALLZOOMAMOUNT);
453 glutPostRedisplay();
454 break;
455 case 'c':
456 nextcmpt();
457 break;
458 case 'C':
459 prevcmpt();
460 break;
461 case 'h':
462 fprintf(stderr, "h help\n");
463 fprintf(stderr, "> zoom in (large)\n");
464 fprintf(stderr, ", zoom in (small)\n");
465 fprintf(stderr, "< zoom out (large)\n");
466 fprintf(stderr, ". zoom out (small)\n");
467 fprintf(stderr, "down arrow pan down\n");
468 fprintf(stderr, "up arrow pan up\n");
469 fprintf(stderr, "left arrow pan left\n");
470 fprintf(stderr, "right arrow pan right\n");
471 fprintf(stderr, "space next image\n");
472 fprintf(stderr, "backspace previous image\n");
473 fprintf(stderr, "q quit\n");
474 break;
475 case 'q':
476 cleanupandexit(EXIT_SUCCESS);
477 break;
478 }
479 }
480
481 /* Special keyboard callback function. */
482
specialfunc(int key,int x,int y)483 static void specialfunc(int key, int x, int y)
484 {
485 if (cmdopts.verbose) {
486 fprintf(stderr, "specialfunc(%d, %d, %d)\n", key, x, y);
487 }
488
489 switch (key) {
490 case GLUT_KEY_UP:
491 {
492 float panamount;
493 panamount = (glutGetModifiers() & GLUT_ACTIVE_SHIFT) ?
494 BIGPANAMOUNT : SMALLPANAMOUNT;
495 pan(0.0, panamount * (gs.toprighty - gs.botlefty));
496 glutPostRedisplay();
497 }
498 break;
499 case GLUT_KEY_DOWN:
500 {
501 float panamount;
502 panamount = (glutGetModifiers() & GLUT_ACTIVE_SHIFT) ?
503 BIGPANAMOUNT : SMALLPANAMOUNT;
504 pan(0.0, -panamount * (gs.toprighty - gs.botlefty));
505 glutPostRedisplay();
506 }
507 break;
508 case GLUT_KEY_LEFT:
509 {
510 float panamount;
511 panamount = (glutGetModifiers() & GLUT_ACTIVE_SHIFT) ?
512 BIGPANAMOUNT : SMALLPANAMOUNT;
513 pan(-panamount * (gs.toprightx - gs.botleftx), 0.0);
514 glutPostRedisplay();
515 }
516 break;
517 case GLUT_KEY_RIGHT:
518 {
519 float panamount;
520 panamount = (glutGetModifiers() & GLUT_ACTIVE_SHIFT) ?
521 BIGPANAMOUNT : SMALLPANAMOUNT;
522 pan(panamount * (gs.toprightx - gs.botleftx), 0.0);
523 glutPostRedisplay();
524 }
525 break;
526 default:
527 break;
528 }
529 }
530
531 /* Timer callback function. */
532
timerfunc(int value)533 static void timerfunc(int value)
534 {
535 if (cmdopts.verbose) {
536 fprintf(stderr, "timerfunc(%d)\n", value);
537 }
538 if (value == gs.activetmid) {
539 nextimage();
540 }
541 }
542
543 /******************************************************************************\
544 *
545 \******************************************************************************/
546
zoom(float sx,float sy)547 static void zoom(float sx, float sy)
548 {
549 panzoom(0, 0, sx, sy);
550 }
551
pan(float dx,float dy)552 static void pan(float dx, float dy)
553 {
554 panzoom(dx, dy, 1.0, 1.0);
555 }
556
panzoom(float dx,float dy,float sx,float sy)557 static void panzoom(float dx, float dy, float sx, float sy)
558 {
559 float cx;
560 float cy;
561 int reginh;
562 int reginv;
563
564 reginh = (gs.botleftx >= 0 && gs.toprightx <= gs.vp.width);
565 reginv = (gs.botlefty >= 0 && gs.toprighty <= gs.vp.height);
566
567 if (cmdopts.verbose) {
568 fprintf(stderr, "start of panzoom\n");
569 dumpstate();
570 fprintf(stderr, "reginh=%d reginv=%d\n", reginh, reginv);
571 }
572
573 if (dx || dy) {
574 gs.botleftx += dx;
575 gs.botlefty += dy;
576 gs.toprightx += dx;
577 gs.toprighty += dy;
578 }
579
580 if (sx != 1.0 || sy != 1.0) {
581 cx = (gs.botleftx + gs.toprightx) / 2.0;
582 cy = (gs.botlefty + gs.toprighty) / 2.0;
583 float w = gs.toprightx - gs.botleftx;
584 float h = gs.toprighty - gs.botlefty;
585 gs.botleftx = cx - 0.5 * w / sx;
586 gs.botlefty = cy - 0.5 * h / sy;
587 gs.toprightx = cx + 0.5 * w / sx;
588 gs.toprighty = cy + 0.5 * h / sy;
589 }
590
591 if (reginh) {
592 if (gs.botleftx < 0) {
593 dx = -gs.botleftx;
594 gs.botleftx += dx;
595 gs.toprightx += dx;
596 } else if (gs.toprightx > gs.vp.width) {
597 dx = gs.vp.width - gs.toprightx;
598 gs.botleftx += dx;
599 gs.toprightx += dx;
600 }
601 }
602 if (gs.botleftx < 0 || gs.toprightx > gs.vp.width) {
603 float w = gs.toprightx - gs.botleftx;
604 gs.botleftx = 0.5 * gs.vp.width - 0.5 * w;
605 gs.toprightx = 0.5 * gs.vp.width + 0.5 * w;
606 }
607
608 if (reginv) {
609 if (gs.botlefty < 0) {
610 dy = -gs.botlefty;
611 gs.botlefty += dy;
612 gs.toprighty += dy;
613 } else if (gs.toprighty > gs.vp.height) {
614 dy = gs.vp.height - gs.toprighty;
615 gs.botlefty += dy;
616 gs.toprighty += dy;
617 }
618 }
619 if (gs.botlefty < 0 || gs.toprighty > gs.vp.height) {
620 float h = gs.toprighty - gs.botlefty;
621 gs.botlefty = 0.5 * gs.vp.height - 0.5 * h;
622 gs.toprighty = 0.5 * gs.vp.height + 0.5 * h;
623 }
624
625 if (cmdopts.verbose) {
626 fprintf(stderr, "end of panzoom\n");
627 dumpstate();
628 }
629 }
630
nextcmpt()631 static void nextcmpt()
632 {
633 if (gs.monomode) {
634 if (gs.cmptno == jas_image_numcmpts(gs.image) - 1) {
635 if (gs.altimage) {
636 gs.monomode = 0;
637 } else {
638 gs.cmptno = 0;
639 }
640 } else {
641 ++gs.cmptno;
642 }
643 } else {
644 gs.monomode = 1;
645 gs.cmptno = 0;
646 }
647 render();
648 glutPostRedisplay();
649 }
650
prevcmpt()651 static void prevcmpt()
652 {
653 if (gs.monomode) {
654 if (!gs.cmptno) {
655 gs.monomode = 0;
656 } else {
657 --gs.cmptno;
658 }
659 } else {
660 gs.monomode = 1;
661 gs.cmptno = jas_image_numcmpts(gs.image) - 1;
662 }
663 render();
664 glutPostRedisplay();
665 }
666
nextimage()667 static void nextimage()
668 {
669 int n;
670 unloadimage();
671 for (n = cmdopts.numfiles; n > 0; --n) {
672 ++gs.filenum;
673 if (gs.filenum >= cmdopts.numfiles) {
674 if (cmdopts.loop) {
675 gs.filenum = 0;
676 } else {
677 cleanupandexit(EXIT_SUCCESS);
678 }
679 }
680 if (!loadimage()) {
681 return;
682 }
683 fprintf(stderr, "cannot load image\n");
684 }
685 cleanupandexit(EXIT_SUCCESS);
686 }
687
previmage()688 static void previmage()
689 {
690 int n;
691 unloadimage();
692 for (n = cmdopts.numfiles; n > 0; --n) {
693 --gs.filenum;
694 if (gs.filenum < 0) {
695 if (cmdopts.loop) {
696 gs.filenum = cmdopts.numfiles - 1;
697 } else {
698 cleanupandexit(EXIT_SUCCESS);
699 }
700 }
701 if (!loadimage()) {
702 return;
703 }
704 }
705 cleanupandexit(EXIT_SUCCESS);
706 }
707
loadimage()708 static int loadimage()
709 {
710 jas_stream_t *in;
711 int vh;
712 int vw;
713 char *pathname;
714 jas_cmprof_t *outprof = NULL;
715
716 assert(!gs.image);
717 assert(!gs.altimage);
718
719 gs.image = 0;
720 gs.altimage = 0;
721
722 pathname = cmdopts.filenames[gs.filenum];
723
724 if (pathname && pathname[0] != '\0') {
725 if (cmdopts.verbose) {
726 fprintf(stderr, "opening file %s\n", pathname);
727 }
728 /* The input image is to be read from a file. */
729 if (!(in = jas_stream_fopen(pathname, "rb"))) {
730 fprintf(stderr, "error: cannot open file %s\n", pathname);
731 goto error;
732 }
733 } else {
734 /* The input image is to be read from standard input. */
735 in = streamin;
736 }
737
738 if (cmdopts.verbose) {
739 fprintf(stderr, "decoding image\n");
740 }
741
742 /* Get the input image data. */
743 if (!(gs.image = jas_image_decode(in, -1, 0))) {
744 fprintf(stderr, "error: cannot load image data\n");
745 goto error;
746 }
747
748 /* Close the input stream. */
749 if (in != streamin) {
750 jas_stream_close(in);
751 }
752
753 if (cmdopts.verbose) {
754 fprintf(stderr, "creating color profile\n");
755 }
756
757 if (!(outprof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB)))
758 goto error;
759 if (!(gs.altimage = jas_image_chclrspc(gs.image, outprof, JAS_CMXFORM_INTENT_PER)))
760 goto error;
761
762 jas_cmprof_destroy(outprof);
763 outprof = NULL;
764
765 vw = jas_image_width(gs.image);
766 vh = jas_image_height(gs.image);
767
768 gs.botleftx = jas_image_tlx(gs.image);
769 gs.botlefty = jas_image_tly(gs.image);
770 gs.toprightx = jas_image_brx(gs.image);
771 gs.toprighty = jas_image_bry(gs.image);
772 if (gs.altimage) {
773 gs.monomode = 0;
774 } else {
775 gs.monomode = 1;
776 gs.cmptno = 0;
777 }
778
779
780 if (cmdopts.verbose) {
781 fprintf(stderr, "num of components %d\n", jas_image_numcmpts(gs.image));
782 fprintf(stderr, "dimensions %"PRIiFAST32" %"PRIiFAST32"\n",
783 jas_image_width(gs.image), jas_image_height(gs.image));
784 }
785
786 gs.viewportwidth = vw;
787 gs.viewportheight = vh;
788 pixmap_resize(&gs.vp, vw, vh);
789 if (cmdopts.verbose) {
790 fprintf(stderr, "preparing image for viewing\n");
791 }
792 render();
793 if (cmdopts.verbose) {
794 fprintf(stderr, "done preparing image for viewing\n");
795 }
796
797 if (vw != glutGet(GLUT_WINDOW_WIDTH) ||
798 vh != glutGet(GLUT_WINDOW_HEIGHT)) {
799 glutReshapeWindow(vw, vh);
800 }
801 if (cmdopts.title) {
802 glutSetWindowTitle(cmdopts.title);
803 } else {
804 glutSetWindowTitle((pathname && pathname[0] != '\0') ? pathname :
805 "stdin");
806 }
807 /* If we reshaped the window, GLUT will automatically invoke both
808 the reshape and display callback (in this order). Therefore, we
809 only need to explicitly force the display callback to be invoked
810 if the window was not reshaped. */
811 glutPostRedisplay();
812
813 if (cmdopts.tmout != 0) {
814 glutTimerFunc(cmdopts.tmout, timerfunc, gs.nexttmid);
815 gs.activetmid = gs.nexttmid;
816 ++gs.nexttmid;
817 }
818
819 return 0;
820
821 error:
822 if (outprof != NULL)
823 jas_cmprof_destroy(outprof);
824 unloadimage();
825 return -1;
826 }
827
unloadimage()828 static void unloadimage()
829 {
830 if (gs.image) {
831 jas_image_destroy(gs.image);
832 gs.image = 0;
833 }
834 if (gs.altimage) {
835 jas_image_destroy(gs.altimage);
836 gs.altimage = 0;
837 }
838 }
839
840 /******************************************************************************\
841 *
842 \******************************************************************************/
843
pixmap_resize(pixmap_t * p,int w,int h)844 static int pixmap_resize(pixmap_t *p, int w, int h)
845 {
846 GLshort* buf;
847 if (!(buf = realloc(p->data, w * h * 4 * sizeof(GLshort)))) {
848 return -1;
849 }
850 p->width = w;
851 p->height = h;
852 p->data = buf;
853 return 0;
854 }
855
dumpstate()856 static void dumpstate()
857 {
858 printf("blx=%f bly=%f trx=%f try=%f\n", gs.botleftx, gs.botlefty, gs.toprightx, gs.toprighty);
859 }
860
861 #define vctocc(i, co, cs, vo, vs) \
862 (((vo) + (i) * (vs) - (co)) / (cs))
863
jas_image_render(jas_image_t * image,float vtlx,float vtly,float vsx,float vsy,int vw,int vh,GLshort * vdata)864 static int jas_image_render(jas_image_t *image, float vtlx, float vtly,
865 float vsx, float vsy, int vw, int vh, GLshort *vdata)
866 {
867 int i;
868 int j;
869 int k;
870 int x;
871 int y;
872 int v[3];
873 GLshort *vdatap;
874 int cmptlut[3];
875 int width;
876 int height;
877 int hs;
878 int vs;
879 int tlx;
880 int tly;
881
882 if ((cmptlut[0] = jas_image_getcmptbytype(image,
883 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
884 (cmptlut[1] = jas_image_getcmptbytype(image,
885 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
886 (cmptlut[2] = jas_image_getcmptbytype(image,
887 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0)
888 goto error;
889 width = jas_image_cmptwidth(image, cmptlut[0]);
890 height = jas_image_cmptheight(image, cmptlut[0]);
891 tlx = jas_image_cmpttlx(image, cmptlut[0]);
892 tly = jas_image_cmpttly(image, cmptlut[0]);
893 vs = jas_image_cmptvstep(image, cmptlut[0]);
894 hs = jas_image_cmpthstep(image, cmptlut[0]);
895 for (i = 1; i < 3; ++i) {
896 if (jas_image_cmptwidth(image, cmptlut[i]) != width ||
897 jas_image_cmptheight(image, cmptlut[i]) != height)
898 goto error;
899 }
900 for (i = 0; i < vh; ++i) {
901 vdatap = &vdata[(vh - 1 - i) * (4 * vw)];
902 for (j = 0; j < vw; ++j) {
903 x = vctocc(j, tlx, hs, vtlx, vsx);
904 y = vctocc(i, tly, vs, vtly, vsy);
905 if (x >= 0 && x < width && y >= 0 && y < height) {
906 for (k = 0; k < 3; ++k) {
907 v[k] = jas_image_readcmptsample(image, cmptlut[k], x, y);
908 v[k] <<= 16 - jas_image_cmptprec(image, cmptlut[k]);
909 if (v[k] < 0) {
910 v[k] = 0;
911 } else if (v[k] > 65535) {
912 v[k] = 65535;
913 }
914 }
915 } else {
916 v[0] = 0;
917 v[1] = 0;
918 v[2] = 0;
919 }
920 *vdatap++ = v[0];
921 *vdatap++ = v[1];
922 *vdatap++ = v[2];
923 *vdatap++ = 0;
924 }
925 }
926 return 0;
927 error:
928 return -1;
929 }
930
jas_image_render2(jas_image_t * image,unsigned cmptno,float vtlx,float vtly,float vsx,float vsy,int vw,int vh,GLshort * vdata)931 static int jas_image_render2(jas_image_t *image, unsigned cmptno, float vtlx,
932 float vtly, float vsx, float vsy, int vw, int vh, GLshort *vdata)
933 {
934 int i;
935 int j;
936 int x;
937 int y;
938 int v;
939 GLshort *vdatap;
940
941 if (cmptno >= image->numcmpts_) {
942 fprintf(stderr, "bad parameter\n");
943 goto error;
944 }
945 for (i = 0; i < vh; ++i) {
946 vdatap = &vdata[(vh - 1 - i) * (4 * vw)];
947 for (j = 0; j < vw; ++j) {
948 x = vctocc(j, jas_image_cmpttlx(image, cmptno), jas_image_cmpthstep(image, cmptno), vtlx, vsx);
949 y = vctocc(i, jas_image_cmpttly(image, cmptno), jas_image_cmptvstep(image, cmptno), vtly, vsy);
950 v = (x >= 0 && x < jas_image_cmptwidth(image, cmptno) && y >=0 && y < jas_image_cmptheight(image, cmptno)) ? jas_image_readcmptsample(image, cmptno, x, y) : 0;
951 v <<= 16 - jas_image_cmptprec(image, cmptno);
952 if (v < 0) {
953 v = 0;
954 } else if (v > 65535) {
955 v = 65535;
956 }
957 *vdatap++ = v;
958 *vdatap++ = v;
959 *vdatap++ = v;
960 *vdatap++ = 0;
961 }
962 }
963 return 0;
964 error:
965 return -1;
966 }
967
968
render()969 static void render()
970 {
971 float vtlx;
972 float vtly;
973
974 vtlx = gs.botleftx;
975 vtly = gs.toprighty;
976 if (cmdopts.verbose) {
977 // fprintf(stderr, "vtlx=%f, vtly=%f, vsx=%f, vsy=%f\n",
978 // vtlx, vtly, gs.sx, gs.sy);
979 /* suppress -Wunused-but-set-variable */
980 (void)vtlx; (void)vtly;
981 }
982
983 if (gs.monomode) {
984 if (cmdopts.verbose) {
985 fprintf(stderr, "component %d\n", gs.cmptno);
986 }
987 jas_image_render2(gs.image, gs.cmptno, 0.0, 0.0,
988 1.0, 1.0, gs.vp.width, gs.vp.height, gs.vp.data);
989 } else {
990 if (cmdopts.verbose) {
991 fprintf(stderr, "color\n");
992 }
993 jas_image_render(gs.altimage, 0.0, 0.0, 1.0, 1.0,
994 gs.vp.width, gs.vp.height, gs.vp.data);
995 }
996
997 }
998
999 #if 0
1000
1001 #define vctocc(i, co, cs, vo, vs) \
1002 (((vo) + (i) * (vs) - (co)) / (cs))
1003
1004 static void drawview(jas_image_t *image, float vtlx, float vtly,
1005 float sx, float sy, pixmap_t *p)
1006 {
1007 int i;
1008 int j;
1009 int k;
1010 int red;
1011 int grn;
1012 int blu;
1013 int lum;
1014 GLshort *datap;
1015 int x;
1016 int y;
1017 int *cmptlut;
1018 int numcmpts;
1019 int v[4];
1020 int u[4];
1021 int color;
1022
1023 cmptlut = gs.cmptlut;
1024 switch (jas_image_colorspace(gs.image)) {
1025 case JAS_IMAGE_CS_RGB:
1026 case JAS_IMAGE_CS_YCBCR:
1027 color = 1;
1028 numcmpts = 3;
1029 break;
1030 case JAS_IMAGE_CS_GRAY:
1031 default:
1032 numcmpts = 1;
1033 color = 0;
1034 break;
1035 }
1036
1037 for (i = 0; i < p->height; ++i) {
1038 datap = &p->data[(p->height - 1 - i) * (4 * p->width)];
1039 for (j = 0; j < p->width; ++j) {
1040 if (!gs.monomode && color) {
1041 for (k = 0; k < numcmpts; ++k) {
1042 x = vctocc(j, jas_image_cmpttlx(gs.image, cmptlut[k]), jas_image_cmpthstep(gs.image, cmptlut[k]), vtlx, sx);
1043 y = vctocc(i, jas_image_cmpttly(gs.image, cmptlut[k]), jas_image_cmptvstep(gs.image, cmptlut[k]), vtly, sy);
1044 v[k] = (x >= 0 && x < jas_image_cmptwidth(gs.image, cmptlut[k]) && y >=0 && y < jas_image_cmptheight(gs.image, cmptlut[k])) ? jas_matrix_get(gs.cmpts[cmptlut[k]], y, x) : 0;
1045 v[k] <<= 16 - jas_image_cmptprec(gs.image, cmptlut[k]);
1046 }
1047 switch (jas_image_colorspace(gs.image)) {
1048 case JAS_IMAGE_CS_RGB:
1049 break;
1050 case JAS_IMAGE_CS_YCBCR:
1051 u[0] = (1/1.772) * (v[0] + 1.402 * v[2]);
1052 u[1] = (1/1.772) * (v[0] - 0.34413 * v[1] - 0.71414 * v[2]);
1053 u[2] = (1/1.772) * (v[0] + 1.772 * v[1]);
1054 v[0] = u[0];
1055 v[1] = u[1];
1056 v[2] = u[2];
1057 break;
1058 }
1059 } else {
1060 x = vctocc(j, jas_image_cmpttlx(gs.image, gs.cmptno), jas_image_cmpthstep(gs.image, gs.cmptno), vtlx, sx);
1061 y = vctocc(i, jas_image_cmpttly(gs.image, gs.cmptno), jas_image_cmptvstep(gs.image, gs.cmptno), vtly, sy);
1062 v[0] = (x >= 0 && x < jas_image_cmptwidth(gs.image, gs.cmptno) && y >=0 && y < jas_image_cmptheight(gs.image, gs.cmptno)) ? jas_matrix_get(gs.cmpts[gs.cmptno], y, x) : 0;
1063 v[0] <<= 16 - jas_image_cmptprec(gs.image, gs.cmptno);
1064 v[1] = v[0];
1065 v[2] = v[0];
1066 v[3] = 0;
1067 }
1068
1069 for (k = 0; k < 3; ++k) {
1070 if (v[k] < 0) {
1071 v[k] = 0;
1072 } else if (v[k] > 65535) {
1073 v[k] = 65535;
1074 }
1075 }
1076
1077 *datap++ = v[0];
1078 *datap++ = v[1];
1079 *datap++ = v[2];
1080 *datap++ = 0;
1081 }
1082 }
1083 }
1084
1085 #endif
1086
cleanupandexit(int status)1087 static void cleanupandexit(int status)
1088 {
1089 unloadimage();
1090 exit(status);
1091 }
1092
init()1093 static void init()
1094 {
1095 gs.filenum = -1;
1096 gs.image = 0;
1097 gs.altimage = 0;
1098 gs.nexttmid = 0;
1099 gs.vp.width = 0;
1100 gs.vp.height = 0;
1101 gs.vp.data = 0;
1102 gs.viewportwidth = -1;
1103 gs.viewportheight = -1;
1104 }
1105