]> Creatis software - gdcm.git/blob - src/gdcmjpegls/Encoder/encoder.c
use GDCM_NAME_SPACE:: instead of gdcm::, even in Examples ...
[gdcm.git] / src / gdcmjpegls / Encoder / encoder.c
1 /* SPMG/JPEG-LS IMPLEMENTATION V.2.1
2    =====================================
3    These programs are Copyright (c) University of British Columbia. All rights reserved.
4    They may be freely redistributed in their entirety provided that this copyright
5    notice is not removed. THEY MAY NOT BE SOLD FOR PROFIT OR INCORPORATED IN
6    COMMERCIAL PROGRAMS WITHOUT THE WRITTEN PERMISSION OF THE COPYRIGHT HOLDER.
7    Each program is provided as is, without any express or implied warranty,
8    without even the warranty of fitness for a particular purpose.
9
10    =========================================================
11    THIS SOFTWARE IS BASED ON HP's implementation of jpeg-ls:
12    =========================================================
13
14    LOCO-I/JPEG-LS IMPLEMENTATION V.0.90
15    -------------------------------------------------------------------------------
16    (c) COPYRIGHT HEWLETT-PACKARD COMPANY, 1995-1999.
17         HEWLETT-PACKARD COMPANY ("HP") DOES NOT WARRANT THE ACCURACY OR
18    COMPLETENESS OF THE INFORMATION GIVEN HERE.  ANY USE MADE OF, OR
19    RELIANCE ON, SUCH INFORMATION IS ENTIRELY AT USER'S OWN RISK.
20         BY DOWNLOADING THE LOCO-I/JPEG-LS COMPRESSORS/DECOMPRESSORS
21    ("THE SOFTWARE") YOU AGREE TO BE BOUND BY THE TERMS AND CONDITIONS
22    OF THIS LICENSING AGREEMENT.
23         YOU MAY DOWNLOAD AND USE THE SOFTWARE FOR NON-COMMERCIAL PURPOSES
24    FREE OF CHARGE OR FURTHER OBLIGATION.  YOU MAY NOT, DIRECTLY OR
25    INDIRECTLY, DISTRIBUTE THE SOFTWARE FOR A FEE, INCORPORATE THIS
26    SOFTWARE INTO ANY PRODUCT OFFERED FOR SALE, OR USE THE SOFTWARE
27    TO PROVIDE A SERVICE FOR WHICH A FEE IS CHARGED.
28         YOU MAY MAKE COPIES OF THE SOFTWARE AND DISTRIBUTE SUCH COPIES TO
29    OTHER PERSONS PROVIDED THAT SUCH COPIES ARE ACCOMPANIED BY
30    HEWLETT-PACKARD'S COPYRIGHT NOTICE AND THIS AGREEMENT AND THAT
31    SUCH OTHER PERSONS AGREE TO BE BOUND BY THE TERMS OF THIS AGREEMENT.
32         THE SOFTWARE IS NOT OF PRODUCT QUALITY AND MAY HAVE ERRORS OR DEFECTS.
33    THE JPEG-LS STANDARD IS STILL UNDER DEVELOPMENT. THE SOFTWARE IS NOT A
34    FINAL OR FULL IMPLEMENTATION OF THE STANDARD.  HP GIVES NO EXPRESS OR
35    IMPLIED WARRANTY OF ANY KIND AND ANY IMPLIED WARRANTIES OF
36    MERCHANTABILITY AND FITNESS FOR PURPOSE ARE DISCLAIMED.
37         HP SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
38    OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE.
39    -------------------------------------------------------------------------------
40 */
41
42 /* encoder.c --- the main module, argument parsing, file I/O
43  *
44  * 
45  * Initial code by Alex Jakulin,  Aug. 1995
46  *
47  * Modified and optimized: Gadiel Seroussi, October 1995
48  *
49  * Color Enhancement: Guillermo Sapiro, August 1996
50  *
51  * Modified and added Restart marker and input tables by:
52  * David Cheng-Hsiu Chu, and Ismail R. Ismail march 1999
53  */
54
55 #include "global.h"
56 #include "math.h"
57 #include "string.h"
58 #include "jpegmark.h"
59
60 static char *banner="\n\
61 =============================================\n\
62 SPMG/JPEG-LS COMPRESSOR " JPEGLSVERSION "\n\
63 =============================================\n\
64 These programs are Copyright (c) University of British Columbia.\n\
65 All rights reserved. They may be freely redistributed in their\n\
66 entirety provided that this copyright  notice is not removed.\n\
67 They may not be sold for profit or incorporated in commercial\n\
68 programs without the written permission of the copyright holder.\n\
69 Each program is provided as is, without any express or implied\n\
70 warranty, without even the warranty of fitness for a particular\n\
71 purpose.\n\
72 \n\
73 =========================================================\n\
74 THIS SOFTWARE IS BASED ON HP's implementation of jpeg-ls:\n\
75 =========================================================\n\
76 (c) COPYRIGHT HEWLETT-PACKARD COMPANY, 1995-1999.\n";
77
78 pixel *pscanline, *cscanline, *scanl0, *scanl1;
79 pixel *c_pscanline[MAX_COMPONENTS], *c_cscanline[MAX_COMPONENTS], 
80       *c_scanl0[MAX_COMPONENTS],    *c_scanl1[MAX_COMPONENTS];
81
82 jpeg_ls_header *head_frame,*head_scan[MAX_SCANS];
83
84 int columns, rows, components, 
85     samplingx[MAX_COMPONENTS], samplingy[MAX_COMPONENTS];
86 int c_columns[MAX_COMPONENTS];
87 int c_rows[MAX_COMPONENTS];
88 int whose_max_size_rows, whose_max_size_columns;
89 int  color_mode;  
90 int  need_lse;         /* if we need an LSE marker (non-default params) */
91 int need_table;          /* if we need an LSE marker (mapping table) */
92 int need_restart;        /* if we need to add restart markers */
93 int restart_interval;          /* indicates the restart interval */
94 int  multi;          /* if the files are separate */
95 int  application_header;      /* application bytes written in the header */
96 int  all_header;        /* all bytes of the header, including application
97                bytes and JPEG-LS bytes */
98 int  shift=0;        /* Shift value for sparse images */
99 int  palete=0;        /* for paletized images */
100 int lossy;          /* Indicates if in lossy mode or not */
101 int lutmax;          /* lutmax is either 256 or 4501 */
102 int bpp16;                     /* Indicates if 16 bits per pixel mode or not */
103 char *mappingtablefilename=NULL;     /* Mapping table filename */
104
105 /* reset */
106 #ifndef FIXRESET
107 int  RESET;
108 #endif
109
110
111 /* alphabet size */
112 #ifndef FIXALPHA
113 int     alpha,        /* alphabet size */
114   ceil_half_alpha; /* ceil(alpha/2) */
115 #endif
116
117 #ifdef POW2
118 int  highmask;
119 #endif
120
121
122
123
124 /* Read one row of pixel values */
125
126 inline void read_one_line(pixel* line, int cols, FILE* infile)
127 {
128   unsigned char* line8;
129   int i;
130   
131   if (bpp16==FALSE)
132   {
133     line8 = (unsigned char *)safealloc(cols);
134
135     if (fread(line8, 1, cols, infile) != cols)
136       fprintf(stderr,"Input file is truncated");
137
138     for(i=0; i<cols; i++)
139                         line[i] = line8[i];
140     free(line8);
141
142   }
143   else
144   {
145     if (fread(line, 2, cols, infile) != cols)
146       fprintf(stderr,"Input file is truncated");
147
148   }
149 }
150
151
152
153
154
155 /* Initialize the buffers for each line */
156 void initbuffers(int multi, int comp) {
157
158     int  i;
159
160     if (multi)     /* The files are received independent */
161
162     for (i=0;i<comp;i++) {
163       c_scanl0[i] = (pixel *)safecalloc((c_columns[i]+LEFTMARGIN+RIGHTMARGIN), sizeof(pixel) );
164       c_scanl1[i] = (pixel *)safecalloc((c_columns[i]+LEFTMARGIN+RIGHTMARGIN), sizeof(pixel) );
165
166         c_pscanline[i] = c_scanl0[i] + (LEFTMARGIN-1);
167         c_cscanline[i] = c_scanl1[i] + (LEFTMARGIN-1);
168     }
169
170     else {       /* Only 1 file received */
171   
172       scanl0 = (pixel *)safecalloc(components*(columns+LEFTMARGIN+RIGHTMARGIN), sizeof(pixel) );
173       scanl1 = (pixel *)safecalloc(components*(columns+LEFTMARGIN+RIGHTMARGIN), sizeof(pixel) );
174
175   /* Adjust scan line pointers taking into account the margins,
176      and also the fact that indexing for scan lines starts from 1
177    */
178        pscanline = scanl0 + components*(LEFTMARGIN-1);
179       cscanline = scanl1 + components*(LEFTMARGIN-1);
180     }
181
182     bitoinit();
183 }
184
185
186
187
188 /* Swap the pointers to the current and previous scanlines */
189
190 void swaplines()
191 {
192   pixel *temp;
193   temp = pscanline;
194   pscanline = cscanline;
195   cscanline = temp;
196 }
197
198
199
200
201 /* Swap the pointers to the current and previous scanlines */
202
203 void c_swaplines(int i)
204 {
205   pixel *temp;
206   temp = c_pscanline[i];
207   c_pscanline[i] = c_cscanline[i];
208   c_cscanline[i] = temp;
209 }
210
211
212
213 /* close the line buffers */
214 int closebuffers(int multi) {
215   int pos,i;
216
217         bitoflush();
218
219   if (multi==0)
220      fclose(in);
221     else
222        for (i=0;i<components;i++)
223       fclose(c_in[i]);
224
225   pos = ftell(out);
226
227         fclose(out);
228
229         free(scanl0);
230         free(scanl1);
231
232   return pos;
233 }
234
235
236
237
238 /* Initialization Function - Reads in parameters from image and command line */
239
240 void initialize(int argc, char *argv[]) 
241 {
242   char *infilename=NULL,
243        *c_infilename[MAX_COMPONENTS],
244      *outfilename = OUTFILE COMPSUFFIX,
245      *color_mode_string;
246   int  i, n_c, common_rows, common_alpha,
247      min_size_rows, min_size_columns,
248      temp_reset,
249      alpha0,
250      gotinf = 0,
251      gotoutf = 0;
252
253
254   n_c=0;
255   multi=0;
256   color_mode=DEFAULT_COLOR_MODE;
257   need_lse=0;
258   need_table=0;
259   need_restart=0;
260   restart_interval=0;
261   components=0;
262   T1=T2=T3=0;
263 #ifndef FIXRESET
264   RESET=DEFAULT_RESET;
265 #endif
266   
267   /* Initialize NEAR to zero and loss-less mode */
268   NEAR = DEF_NEAR;
269   lossy = FALSE;
270
271   /* Go through the arguments in command line */
272   for ( i=1; i<argc; i++ )
273       if ( argv[i][0] == '-' )  {
274       switch ( argv[i][1] ) {
275
276       /* Enable use of Restart Markers */
277       case 't':
278         need_restart = 1;
279         if ( sscanf(argv[i]+2,"%d",&restart_interval) != 1 ) {
280           bad_flag(argv[i]);
281         }
282         break;
283
284       /* Enable use of Mapping Tables */
285       case 'm':
286         need_table = 2;
287         mappingtablefilename = argv[i]+2;
288         break;
289
290       /* Reset value */
291       case 'r': 
292         if ( sscanf(argv[i]+2,"%d",&temp_reset) != 1 ) {
293           bad_flag(argv[i]);
294         }
295         if ( temp_reset != DEFAULT_RESET ) {
296           need_lse = 1;
297 #ifdef FIXRESET
298           fprintf(stderr,"ERROR: This version compiled with fixed RESET = %d, got %d\n",DEFAULT_RESET,temp_reset);
299           exit(10);
300 #else
301         RESET = temp_reset;
302 #endif
303         }
304           break;
305
306       /* Colour mode */
307       case 'c':
308         if ( sscanf(argv[i]+2,"%d",&color_mode) != 1 ) {
309           bad_flag(argv[i]);
310         }
311         break;
312
313       /* Sparse(?) mode */
314       case 'p':
315         if ( sscanf(argv[i]+2,"%d",&shift) != 1 ) {
316           bad_flag(argv[i]);
317         }
318         if (shift!=0) {
319           fprintf(stderr,"Sorry, sparse mode not implemented (shift=%d).\n",shift);
320           exit(10);
321         }
322         break;
323
324       /* Infile names */
325       case 'i':
326         infilename = c_infilename[components++] = argv[i]+2;
327         gotinf = 1;
328         break;
329
330       /* Outfile names */
331       case 'o':
332         outfilename = argv[i]+2;
333         gotoutf = 1;
334         break;
335
336       /* Verbose level */
337       case 'v':
338         if ( sscanf(argv[i],"-v%d",&verbose) != 1 ) {
339           verbose=2;
340         }
341         break;
342
343       /* Error level - if 0 then means loss-less mode */
344       case 'e':
345       case 'n':
346         if ( sscanf(argv[i]+2,"%d",&NEAR) != 1 ) {
347           bad_flag(argv[i]);
348         }
349         if ( NEAR == 0 )
350           lossy = FALSE;
351         else
352           lossy = TRUE;
353         break;
354
355       /* Threshold Levels */
356       case 's':
357       case 'S':
358       case 'T':
359         need_lse = 1;
360         switch(argv[i][2]) {
361
362         case 'a':
363           if ( sscanf(argv[i]+3,"%d",&T1) != 1 ) {
364             bad_flag(argv[i]);
365           }
366           break;
367
368         case 'b':
369           if ( sscanf(argv[i]+3,"%d",&T2) != 1 ) {
370             bad_flag(argv[i]);
371           }
372           break;
373
374         case 'c':
375           if ( sscanf(argv[i]+3,"%d",&T3) != 1 ) {
376             bad_flag(argv[i]);
377           }
378           break;
379
380         default:
381           bad_flag(argv[i]);
382           break;
383         }
384         break;
385
386       default:
387         usage();
388         exit(0);
389       }
390       }
391       else {
392       infilename = c_infilename[components++] = argv[i];
393       gotinf = 1;
394       }
395
396       
397   
398   if ( verbose < 1 )
399       verbose = 1;  /* at least the banner will show */
400
401   /* check that color mode is valid and pick color mode string */
402   switch ( color_mode ) {
403       case PLANE_INT:
404       color_mode_string = plane_int_string;
405       multi=1;
406       break;
407       case LINE_INT:
408       color_mode_string = line_int_string;
409       if (components>1) multi=1;
410         break;
411       case PIXEL_INT:
412       color_mode_string = pixel_int_string;
413       if (components>1){
414         fprintf(stderr,"ERROR: specified more than 1 input file in pixel interleaved mode\n");
415         exit(10);
416       }
417       break;
418       default:
419       fprintf(stderr,"ERROR: Invalid color mode %d\n",color_mode);
420       usage();
421       exit(10);
422   }
423
424
425   /* Assign file pointers to in files */
426   if ( (infilename == NULL) && (multi==0 || components<1) ) {
427     usage();
428     exit(0);
429   }
430   else {
431     if ( strcmp(infilename,"-") == 0 )
432       in = stdin;
433     else {
434       if (multi==0) {
435       if ( (in=fopen(infilename,"rb")) == NULL ) {
436         perror(infilename);
437         exit(10);
438       }
439       }
440       else {
441         for (i=0;i<components;i++)
442         if ( (c_in[i]=fopen(c_infilename[i],"rb")) == NULL ) {
443           perror(c_infilename[i]);
444           exit(10);
445         }
446       }
447     }
448   }
449
450
451   /* Assigns pointers to out files */
452   if ( outfilename == NULL ) {
453     usage();
454     exit(0);
455   }
456   else {
457     if ( strcmp(outfilename,"-") == 0 ) {
458       out = stdout;
459       msgfile = stderr;
460     }
461     else if ( (out=fopen(outfilename,"wb")) == NULL ) {
462       perror(outfilename);
463       exit(10);
464     }
465   }
466
467   /* Print messages */
468   if ( verbose )
469       fprintf(msgfile,"%s\n",banner);
470
471
472 #define LESS_CONTEXTS 1
473
474   if ( verbose>1 )
475       fprintf(msgfile,"Number of contexts (non-run): %d regular + %d EOR = %d\n",CONTEXTS-LESS_CONTEXTS,EOR_CONTEXTS,TOT_CONTEXTS-LESS_CONTEXTS);
476   
477   /* Read image headers*/
478   if (multi==0) {
479     if ( read_header_6(in, &columns, &rows, &alpha0, &components) != 0 )
480       error("Could not read image header. Must be PPM or PGM file.\n");
481     /* Single component => PLANE_INT */
482     if ( (color_mode==LINE_INT || color_mode==PIXEL_INT) && components==1) {  
483       /*
484                         fprintf(msgfile,"Single component received: Color mode changed to PLANE INTERLEAVED\n");
485       */
486       color_mode=PLANE_INT;
487       color_mode_string = plane_int_string;
488       multi=1;
489       c_columns[0]=columns;
490       c_rows[0] = rows;
491       c_in[0]=in;
492     }
493   }
494   else {
495     for (i=0;i<components;i++) {
496       if (read_header_5(c_in[i], &(c_columns[i]), &(c_rows[i]), &alpha0) != 0 )
497         error("ERROR: Could not read image header. Must be PGM file.\n");
498       if (i==0) {
499         common_rows=c_rows[0];
500         common_alpha=alpha0;
501       }
502       else if ((alpha0!=common_alpha)) {
503         fprintf(stderr,"\nERROR: All components must have same maximal value\n");
504         exit(10);
505       }
506     }
507   }
508
509 #ifdef FIXALPHA
510         alpha0++;
511   if ( alpha0 != alpha ) {
512       fprintf(stderr, "Sorry, this version has been optimized for alphabet size = %d, got %d\n",alpha,alpha0);
513       exit(10);
514   }
515 #else
516   alpha = alpha0+1;  /* number read from file header is alpha-1 */
517   ceil_half_alpha = (alpha+1)/2;
518 #endif
519
520 #ifdef POW2
521   highmask = -alpha;
522 /* check that alpha is a power of 2 */
523   for ( alpha0=alpha, i=-1; alpha0; alpha0>>=1, i++);
524   if ( alpha != (1<<i) ) {
525       fprintf(stderr, "Sorry, this version has been optimized for alphabet size = power of 2, got %d\n",alpha);
526       exit(10);
527   }
528 #endif  
529
530   /* Check for 16 or 8 bit mode */
531   if (alpha <= MAXA16 && alpha > MAXA8)
532   {
533     bpp16 = TRUE;
534     lutmax = LUTMAX16;
535   }
536   else if (alpha <= MAXA8 && alpha >= 1)
537   {
538     bpp16 = FALSE;
539     lutmax = LUTMAX8;
540   }
541   else { 
542     fprintf(stderr,"Got alpha = %d\n",alpha);
543     error("Bad value for alpha. Sorry...\n");
544   }
545
546
547   /* print out parameters */
548   if ( verbose ) {
549       if (!multi)
550       fprintf(msgfile,"Input  file: %s\nOutput file: %s\n",infilename,outfilename);
551       else {
552       fprintf(msgfile,"Input  files: ");
553       for (i=0;i<components;i++)
554         fprintf(msgfile," %s ",c_infilename[i]);
555       fprintf(msgfile,"\nOutput file: %s\n",outfilename);
556       }
557
558       if (!multi)
559       fprintf(msgfile,"Image: cols=%d rows=%d alpha=%d comp=%d mode=%d (%s)",
560         columns, rows, alpha, components, 
561         color_mode, color_mode_string);
562       else {
563       fprintf(msgfile,"Image: cols=");
564       for (i=0;i<components;i++)
565         fprintf(msgfile," %d",c_columns[i]);
566       fprintf(msgfile," rows=");
567       for (i=0;i<components;i++)
568         fprintf(msgfile," %d",c_rows[i]);
569       fprintf(msgfile," alpha=%d comp=%d mode=%d (%s)",
570         alpha, components, color_mode,
571         color_mode_string);
572       }
573
574       fprintf(msgfile,"\n");
575    }
576
577
578   /* compute auxiliary parameters for near-lossless (globals) */
579   if (lossy==TRUE) {
580     quant = 2*NEAR+1;
581     qbeta = (alpha + 2*NEAR + quant-1 )/quant;
582     beta = quant*qbeta;
583     ceil_half_qbeta = (qbeta+1)/2;
584     negNEAR = -NEAR;
585     if ( verbose )
586       fprintf(msgfile,"Near-lossless mode: NEAR = %d  beta = %d  qbeta = %d\n",NEAR,beta,qbeta);
587   }
588
589
590   /* compute bits per sample for input symbols */
591   for ( bpp=1; (1L<<bpp)<alpha; bpp++ );
592
593   /* check if alpha is a power of 2: */
594   if ( alpha != (1<<bpp) )
595       need_lse = 1; /* if not, MAXVAL will be non-default, and 
596              we'll need to specify it in an LSE marker */
597
598
599   /* compute bits per sample for unencoded prediction errors */
600   if (lossy==TRUE)
601     for ( qbpp=1; (1L<<qbpp)<qbeta; qbpp++ );
602   else
603     qbpp = bpp;
604
605
606   if ( bpp < 2 ) bpp = 2;
607   
608   /* limit for unary part of Golomb code */
609   if ( bpp < 8 )
610       limit = 2*(bpp + 8) - qbpp -1;
611   else
612       limit = 4*bpp - qbpp - 1;   
613
614
615   /* check for smallest subsampled file and compute the sampling */
616   if ((components>1) && (multi)) {
617     min_size_columns=c_columns[components-1];
618     min_size_rows=c_rows[components-1];
619     for (i=0;i<components-1;i++) {
620       if (c_columns[i]<min_size_columns) 
621         min_size_columns=c_columns[i];
622       if (c_rows[i]<min_size_rows) 
623         min_size_rows=c_rows[i];
624     }
625
626     for (i=0;i<components;i++) {
627       samplingx[i]=c_columns[i]/min_size_columns;
628       samplingy[i]=c_rows[i]/min_size_rows;
629       if ((samplingx[i]>4) || ((c_columns[i]%min_size_columns)!=0)) {
630         fprintf(stderr,"\nImage sizes not compatible\n");
631         exit(10);
632       }
633       if ((samplingy[i]>4) || ((c_rows[i]%min_size_rows)!=0)) {
634         fprintf(stderr,"\nImage sizes not compatible\n");
635         exit(10);
636       }
637     }
638
639     min_size_columns=c_columns[0];
640     whose_max_size_columns=0;
641     min_size_rows=c_rows[0];
642     whose_max_size_rows=0;
643
644     for (i=1;i<components;i++) { 
645       if (c_columns[i]>min_size_columns) {
646         whose_max_size_columns=i;
647         min_size_columns=c_columns[i];
648       }
649       if (c_rows[i]>min_size_rows) {
650         whose_max_size_rows=i;
651         min_size_rows=c_rows[i];
652       }
653     }
654   }
655   else {
656     for (i=0;i<components;i++) samplingx[i] = samplingy[i] = 1;
657   }
658
659   /* Allocate memory pools. */
660   initbuffers(multi, components);  
661 }
662
663
664
665
666
667 int main (int argc, char *argv[]) {
668
669     int n,n_c,n_r,my_i, number_of_scans, n_s, i;
670   double t0, t1, get_utime();
671   long tot_in = 0,
672        tot_out = 0,
673        pos0, pos1;
674   int temp_columns;
675   int MCUs_counted;
676
677
678   pixel *local_scanl0,*local_scanl1,*local_pscanline,*local_cscanline;
679
680   application_header = all_header = 0;
681
682   /* Parse the parameters, initialize */
683   initialize(argc, argv); 
684
685   /* Start timer (must be AFTER initialize()) */
686   t0 = get_utime();   
687
688   /* Compute the number of scans */
689   /* Multiple scans only for PLANE_INT in this implementation */
690
691   if (color_mode==PLANE_INT)
692     number_of_scans=components;
693   else
694     number_of_scans = 1;
695
696
697   /* Write the frame header - allocate memory for jpegls header */
698   head_frame = (jpeg_ls_header *) safecalloc(1,sizeof(jpeg_ls_header));
699   for (n_s=0;n_s<number_of_scans;n_s++)
700     head_scan[n_s] = (jpeg_ls_header *) safecalloc(1,sizeof(jpeg_ls_header));
701
702   /* Assigns columns/rows to head_frame */
703   if (!multi) {
704     head_frame->columns=columns;
705     head_frame->rows=rows;
706   }
707   else {
708     head_frame->columns=c_columns[whose_max_size_columns];
709     head_frame->rows=c_rows[whose_max_size_rows];
710   }
711
712   head_frame->alp=alpha;
713   head_frame->comp=components;
714
715   /* Assign component id and samplingx/samplingy */
716   for (i=0;i<components;i++) {
717     head_frame->comp_ids[i]=i+1;
718     head_frame->samplingx[i]=samplingx[i];
719     head_frame->samplingy[i]=samplingy[i];
720   }
721
722   head_frame->NEAR=NEAR; /* Not needed, scan information */
723   head_frame->need_lse=need_lse; /* Not needed, for commpletness  */
724   head_frame->color_mode=color_mode; /* Not needed, scan information */
725   head_frame->shift=shift; /* Not needed, scan information */
726
727   for (n_s=0;n_s<number_of_scans;n_s++) {
728     head_scan[n_s]->alp = alpha;
729     head_scan[n_s]->NEAR = NEAR;
730     head_scan[n_s]->T1 = T1;
731     head_scan[n_s]->T2 = T2;
732     head_scan[n_s]->T3 = T3;
733     head_scan[n_s]->RES = RESET;
734     head_scan[n_s]->shift = shift;
735     head_scan[n_s]->color_mode = color_mode;
736   }
737
738
739   if (color_mode==PLANE_INT) { /* One plane per scan */
740     for (n_s=0;n_s<number_of_scans;n_s++) {
741       head_scan[n_s]->comp=1;
742       head_scan[n_s]->comp_ids[0]=n_s+1;
743     }
744   }
745   else {
746     for (n_s=0;n_s<number_of_scans;n_s++) {
747       head_scan[n_s]->comp=head_frame->comp;
748       for (n_c=0;n_c<head_frame->comp;n_c++)
749         head_scan[n_s]->comp_ids[n_c]=n_c+1;
750     }
751   }
752   
753   /* Write SOI */
754   all_header = write_marker(out, SOI);
755
756   /* Write the frame */
757   all_header += write_jpegls_frame(out, head_frame);
758
759   /* End of frame header writing */
760
761
762   if ((components>1) && (multi==0)) {
763
764   /* Received PPM file, allocate auxiliary buffers */
765
766     local_scanl0 = (pixel *)safecalloc(columns+LEFTMARGIN+RIGHTMARGIN,sizeof(pixel) );
767     local_scanl1 = (pixel *)safecalloc(columns+LEFTMARGIN+RIGHTMARGIN,sizeof(pixel) );
768
769     local_pscanline = local_scanl0 + LEFTMARGIN-1;
770     local_cscanline = local_scanl1 + LEFTMARGIN-1;
771
772   }
773
774
775   /* Go through each scan and process line by line */
776   for (n_s=0;n_s<number_of_scans;n_s++) {
777
778     /* process scans one by one */
779
780     if (n_s==0) {
781       /* The thresholds for the scan. Must re-do per scan is change. */
782       set_thresholds(alpha, NEAR, &T1, &T2, &T3);
783       for (i=0;i<number_of_scans;i++) {
784         head_scan[n_s]->T1=T1;
785         head_scan[n_s]->T2=T2;
786         head_scan[n_s]->T3=T3;
787       }
788
789       /* After the thresholds are set, write LSE marker if we have */
790       /* non-default parameters or if we need a mapping table */
791       if ( need_lse != 0 )
792         all_header += write_jpegls_extmarker(out, head_scan[n_s], LSE_PARAMS, mappingtablefilename);
793       if ( need_table != 0 )
794         all_header += write_jpegls_extmarker(out, head_scan[n_s], LSE_MAPTABLE, mappingtablefilename);
795
796
797       /* If using restart markers, write the DRI header */
798       if ( need_restart != 0 )
799       {  
800         head_scan[n_s]->restart_interval = restart_interval;
801         all_header += write_jpegls_restartmarker(out, head_scan[n_s]);
802       }
803       
804       
805       /* Print out parameters */
806       if (verbose)
807         fprintf(msgfile,"Parameters: T1=%d T2=%d T3=%d RESET=%d limit=%d\n",T1, T2, T3,RESET,limit);
808
809       /* Prepare LUTs for context quantization */
810       /* Must re-do when Thresholds change */
811       prepareLUTs();
812
813       if (lossy==TRUE)
814         /* prepare div/mul tables for near-lossless quantization */
815         prepare_qtables(alpha, NEAR);
816
817       /* Check for errors */
818       check_compatibility(head_frame, head_scan[0],0);
819
820     }
821
822     /* Restart Marker is reset after every scan */
823     MCUs_counted = 0;
824
825     /* Write the scan header */
826     all_header += write_jpegls_scan(out, head_scan[n_s]);
827     pos0 = ftell(out);  /* position in output file, after header */
828
829     /* Initializations for each scan */
830     /* Start from 1st image row */
831     n=0;
832
833     /* initialize stats arrays */
834     if (lossy==TRUE)
835       init_stats(qbeta);
836     else
837       init_stats(alpha);
838
839     /* initialize run processing */
840     init_process_run(MAXRUN);
841
842
843     if (color_mode==LINE_INT) {  /* line interleaved */
844       if (!multi) {       /* Single file received */
845 /***********************************************************************/
846 /*           Line interleaved mode with single file received           */
847 /***********************************************************************/
848
849         if (lossy==FALSE)
850
851           /* LOSSLESS mode */
852           while (++n <= rows) {
853
854             read_one_line(cscanline + components, components*columns, in);
855
856             tot_in += components*columns;
857
858             /* 'extend' the edges */
859             for (n_c=0;n_c<components;n_c++)
860               cscanline[-components+n_c] = cscanline[n_c]=pscanline[components+n_c];
861
862             for (n_c=0;n_c<components;n_c++) {
863               if (components > 1) {
864                 for (my_i=0;my_i<columns+LEFTMARGIN+RIGHTMARGIN;my_i++){
865                   local_cscanline[-1+my_i]=cscanline[-components+my_i*components+n_c];
866                   local_pscanline[-1+my_i]=pscanline[-components+my_i*components+n_c];
867                 }
868               }
869               else {
870                 local_cscanline=cscanline;
871                 local_pscanline=pscanline;
872               }
873
874               /* process the lines */
875               lossless_doscanline(local_pscanline, local_cscanline, columns,n_c);
876             }
877
878             /* 'extend' the edges */
879             for (n_c=0;n_c<components;n_c++)
880               cscanline[components*(columns+1)+n_c]=cscanline[components*columns+n_c];
881
882             /* make the current scanline the previous one */
883             swaplines();
884
885             /* Insert restart markers if enabled */
886             if (need_restart)
887             {
888               /* Insert restart markers only after a restart interval */
889               if ((MCUs_counted % restart_interval) == 0)
890               {
891                 bitoflush();
892                 write_marker(out, (RSTm + ((MCUs_counted / restart_interval)%8)));
893               }
894               MCUs_counted++;
895             }
896           }
897
898         else
899
900           /* LOSSY mode */
901           while (++n <= rows) {
902
903             read_one_line(cscanline + components, components*columns, in);
904
905             tot_in += components*columns;
906
907             /* 'extend' the edges */
908             for (n_c=0;n_c<components;n_c++)
909               cscanline[-components+n_c] = cscanline[n_c]=pscanline[components+n_c];
910
911             for (n_c=0;n_c<components;n_c++) {
912               if (components > 1) {
913                 for (my_i=0;my_i<columns+LEFTMARGIN+RIGHTMARGIN;my_i++){
914                   local_cscanline[-1+my_i]=cscanline[-components+my_i*components+n_c];
915                   local_pscanline[-1+my_i]=pscanline[-components+my_i*components+n_c];
916                 }
917               }
918               else {
919                 local_cscanline=cscanline;
920                 local_pscanline=pscanline;
921               }
922
923               /* process the lines */
924               lossy_doscanline(local_pscanline, local_cscanline, columns,n_c);
925
926               if (components>1)
927                 for (my_i=0;my_i<columns+LEFTMARGIN+RIGHTMARGIN;my_i++)
928                   cscanline[-components+my_i*components+n_c]=local_cscanline[-1+my_i];
929             }
930
931             /* 'extend' the edges */
932             for (n_c=0;n_c<components;n_c++)
933               cscanline[components*(columns+1)+n_c]=cscanline[components*columns+n_c];
934
935             /* make the current scanline the previous one */
936             swaplines();
937
938             /* Insert restart markers if enabled */
939             if (need_restart)
940             {
941               /* Insert restart markers only after a restart interval */
942               if ((MCUs_counted % restart_interval) == 0)
943               {
944                 bitoflush();
945                 write_marker(out, (RSTm + ((MCUs_counted / restart_interval)%8)));
946               }
947               MCUs_counted++;
948             }
949           }
950
951       }
952       else {  /* Multiple files */
953         /* color_mode==LINE_INT and multi==1  */
954
955 /***********************************************************************/
956 /*           Line interleaved mode with multiple files received        */
957 /***********************************************************************/
958         n++;
959
960         if (lossy==FALSE)
961
962           /* LOSSLESS mode */
963           while (n <= c_rows[whose_max_size_rows]) {
964
965             for (n_c=0;n_c<components;n_c++) {
966               for (n_r=0;n_r<samplingy[n_c];n_r++) {
967
968                 read_one_line(c_cscanline[n_c] + 1, c_columns[n_c], c_in[n_c]);
969
970                 tot_in += c_columns[n_c];
971
972                 /* 'extend' the edges */
973                 c_cscanline[n_c][-1]=c_cscanline[n_c][0]=c_pscanline[n_c][1];
974
975                 /* process the lines */
976                 lossless_doscanline(c_pscanline[n_c], c_cscanline[n_c], c_columns[n_c],n_c);
977
978                 /* 'extend' the edges */
979                 c_cscanline[n_c][c_columns[n_c]+1]=c_cscanline[n_c][c_columns[n_c]];
980
981                 /* make the current scanline the previous one */
982                 c_swaplines(n_c);
983               }
984             }  /* End of loop for each file */
985
986             n+=samplingy[whose_max_size_rows];
987
988             /* Insert restart markers if enabled */
989             if (need_restart)
990             {
991               /* Insert restart markers only after a restart interval */
992               if ((MCUs_counted % restart_interval) == 0)
993               {
994                 bitoflush();
995                 write_marker(out, (RSTm + ((MCUs_counted / restart_interval)%8)));
996               }
997               MCUs_counted++;
998             }
999
1000           }  /* End while of LINE_INT with multiple input files */
1001
1002         else
1003
1004           /* LOSSY mode */
1005           while (n <= c_rows[whose_max_size_rows]) {
1006
1007             for (n_c=0;n_c<components;n_c++) {
1008               for (n_r=0;n_r<samplingy[n_c];n_r++) {
1009
1010                 read_one_line(c_cscanline[n_c] + 1, c_columns[n_c], c_in[n_c]);
1011
1012                 tot_in += c_columns[n_c];
1013
1014                 /* 'extend' the edges */
1015                 c_cscanline[n_c][-1]=c_cscanline[n_c][0]=c_pscanline[n_c][1];
1016
1017                 /* process the lines */
1018                 lossy_doscanline(c_pscanline[n_c], c_cscanline[n_c], c_columns[n_c],n_c);
1019
1020                 /* 'extend' the edges */
1021                 c_cscanline[n_c][c_columns[n_c]+1]=c_cscanline[n_c][c_columns[n_c]];
1022
1023                 /* make the current scanline the previous one */
1024                 c_swaplines(n_c);
1025               }
1026             }  /* End of loop for each file */
1027
1028             n+=samplingy[whose_max_size_rows];
1029
1030             /* Insert restart markers if enabled */
1031             if (need_restart)
1032             {
1033               /* Insert restart markers only after a restart interval */
1034               if ((MCUs_counted % restart_interval) == 0)
1035               {
1036                 bitoflush();
1037                 write_marker(out, (RSTm + ((MCUs_counted / restart_interval)%8)));
1038               }
1039               MCUs_counted++;
1040             }
1041
1042           }  /* End while of LINE_INT with multiple input files */
1043
1044       }  /* Closes the else, LINE_INT and multi=1 */
1045
1046     }  /* Closes part for color_mode=LINE_INT */
1047     else {
1048       if (color_mode==PIXEL_INT) {
1049 /***********************************************************************/
1050 /*           Pixel interleaved mode with single file received          */
1051 /***********************************************************************/
1052
1053         if (lossy==FALSE)
1054
1055           /* LOSSLESS mode */
1056           while (++n <= rows) {
1057
1058             read_one_line(cscanline+components, components*columns, in);
1059
1060             tot_in += components*columns;
1061
1062             /* 'extend' the edges */
1063             for (n_c=0;n_c<components;n_c++)
1064               cscanline[-components+n_c]=cscanline[n_c]=pscanline[components+n_c];
1065
1066             /* process the lines */
1067             lossless_doscanline_pixel(pscanline, cscanline, components*columns);
1068
1069             /* 'extend' the edges */
1070             for (n_c=0;n_c<components;n_c++)
1071               cscanline[components*(columns+1)+n_c] = cscanline[components*columns+n_c];
1072
1073             /* make the current scanline the previous one */
1074             swaplines();
1075
1076             /* Insert restart markers if enabled */
1077             if (need_restart)
1078             {
1079               /* Insert restart markers only after a restart interval */
1080               if ((MCUs_counted % restart_interval) == 0)
1081               {
1082                 bitoflush();
1083                 write_marker(out, (RSTm + ((MCUs_counted / restart_interval)%8)));
1084               }
1085               MCUs_counted++;
1086             }
1087           }
1088
1089         else
1090
1091           /* LOSSY mode */
1092           while (++n <= rows) {
1093
1094             read_one_line(cscanline+components, components*columns, in);
1095
1096             tot_in += components*columns;
1097
1098             /* 'extend' the edges */
1099             for (n_c=0;n_c<components;n_c++)
1100               cscanline[-components+n_c]=cscanline[n_c]=pscanline[components+n_c];
1101
1102             /* process the lines */
1103             lossy_doscanline_pixel(pscanline, cscanline, components*columns);
1104
1105             /* 'extend' the edges */
1106             for (n_c=0;n_c<components;n_c++)
1107               cscanline[components*(columns+1)+n_c] = cscanline[components*columns+n_c];
1108
1109             /* make the current scanline the previous one */
1110             swaplines();
1111
1112             /* Insert restart markers if enabled */
1113             if (need_restart)
1114             {
1115               /* Insert restart markers only after a restart interval */
1116               if ((MCUs_counted % restart_interval) == 0)
1117               {
1118                 bitoflush();
1119                 write_marker(out, (RSTm + ((MCUs_counted / restart_interval)%8)));
1120               }
1121               MCUs_counted++;
1122             }
1123           }
1124
1125       }  /* Closes if PIXEL_INT */
1126       else {  /* NON PIXEL_INT */
1127 /***********************************************************************/
1128 /*           Plane interleaved mode                    */
1129 /***********************************************************************/
1130
1131         if (lossy==FALSE)
1132         
1133           /* LOSSLESS mode */
1134           while (++n <= c_rows[n_s]) {
1135             
1136             temp_columns = c_columns[n_s];
1137
1138             read_one_line(c_cscanline[n_s]+1, temp_columns, c_in[n_s]);
1139
1140             tot_in += temp_columns;
1141
1142             /* 'extend' the edges */
1143             c_cscanline[n_s][-1]=c_cscanline[n_s][0]=c_pscanline[n_s][1];
1144
1145             /* process the lines */
1146             lossless_doscanline(c_pscanline[n_s], c_cscanline[n_s], temp_columns, n_s);
1147
1148             /* 'extend' the edges */
1149             c_cscanline[n_s][temp_columns+1] = c_cscanline[n_s][temp_columns];
1150
1151             /* make the current scanline the previous one */
1152             c_swaplines(n_s);
1153
1154             /* Insert restart markers if enabled */
1155             if (need_restart)
1156             {
1157               /* Insert restart markers only after a restart interval */
1158               if ((MCUs_counted % restart_interval) == 0)
1159               {
1160                 bitoflush();
1161                 write_marker(out, (RSTm + ((MCUs_counted / restart_interval)%8)));
1162               }
1163               MCUs_counted++;
1164             }
1165
1166           }
1167
1168         else
1169
1170           /* LOSSY mode */
1171           while (++n <= c_rows[n_s]) {
1172
1173             temp_columns = c_columns[n_s];
1174
1175             read_one_line(c_cscanline[n_s]+1, temp_columns, c_in[n_s]);
1176
1177             tot_in += temp_columns;
1178
1179             /* 'extend' the edges */
1180             c_cscanline[n_s][-1]=c_cscanline[n_s][0]=c_pscanline[n_s][1];
1181
1182             /* process the lines */
1183             lossy_doscanline(c_pscanline[n_s], c_cscanline[n_s], temp_columns,n_s);
1184
1185             /* 'extend' the edges */
1186             c_cscanline[n_s][temp_columns+1] = c_cscanline[n_s][temp_columns];
1187
1188             /* make the current scanline the previous one */
1189             c_swaplines(n_s);
1190
1191             /* Insert restart markers if enabled */
1192             if (need_restart)
1193             {
1194               /* Insert restart markers only after a restart interval */
1195               if ((MCUs_counted % restart_interval) == 0)
1196               {
1197                 bitoflush();
1198                 write_marker(out, (RSTm + ((MCUs_counted / restart_interval)%8)));
1199               }
1200               MCUs_counted++;
1201             }
1202
1203           }
1204
1205       }  /* End for each component in PLANE_INT */
1206
1207     }  /* End for non LINE_INT */
1208     bitoflush();
1209
1210   }  /* End of loop on scans */
1211
1212   all_header += write_marker(out, EOI);
1213
1214   /* Close down */
1215   close_process_run();
1216     pos1= closebuffers(multi);
1217
1218   /* total bytes out, including JPEG-LS header, but not
1219      application-specific header bytes */
1220   /* tot_out = (pos1-all_header)*8; */
1221   tot_out = pos1*8;
1222
1223   t1 = get_utime();
1224
1225   if (need_table)
1226     fprintf(msgfile, "Used the mapping table from file : %s\n",mappingtablefilename);
1227
1228   if (need_restart)
1229     fprintf(msgfile, "Used restart markers with restart interval : %i\n", restart_interval);
1230
1231   if ( verbose )
1232       fprintf(msgfile,"Marker segment bytes: %ld\n",all_header);
1233
1234   fprintf(msgfile,"Total bits out: %ld  Symbols in: %ld  %5.3lf bps  (%5.3lf : 1)\n",
1235            tot_out,
1236            tot_in,tot_out/(double)tot_in, 
1237            (log((double)alpha)/log(2.0))*tot_in/tot_out);
1238   fprintf(msgfile,"Time = %1.3lf secs : %1.0lf KSymbols/sec\n",t1-t0,
1239           (tot_in)/(1024*(t1-t0)));
1240
1241     return 0;                                       /* OK! */
1242 }
1243
1244
1245
1246
1247 /* Message to show how to use program */
1248 usage()
1249 {
1250   fprintf(stderr,"%s\n",banner);
1251   fprintf(stderr,"Usage: %s [flags] infile1 [infile2,infile3,...] [-ooutfile]\n\
1252 infile1    : Input file: must be in PGM or PPM format\n\
1253 infile2,...: Additional input files for \"plane interleaved\"\n\
1254        or \"line interleaved\" modes. Must be in PGM (P5) format.\n\
1255 FLAGS  :\n\
1256 -i<infile> : Alternate input specification, use -i- for stdin.\n\
1257 -o<outfile>: Output specification, use -o- for stdout (default=%s).\n\
1258 -Ta<num>, -Tb<num>, -Tc<num>: thresholds for context quantization (a.k.a.\n\
1259        T1,T2,T3; must have Ta<=Tb<=Tc<=maxs; defaults depend on alphabet\n\
1260        size and lossless/near-lossless mode; see standard specification).\n\
1261 -r<num>    : Reset interval for statistics (standard default=%d).\n\
1262 ", "locoe", OUTFILE COMPSUFFIX,DEFAULT_RESET);
1263   fprintf(stderr,"\
1264 -c<num>    : Mode for multi-component images (program default=%d):\n\
1265        %d:%s  %d:%s  %d:%s.\n",
1266          DEFAULT_COLOR_MODE,
1267          PLANE_INT, "plane-interleaved",
1268          LINE_INT,  "line-interleaved",
1269          PIXEL_INT, "sample-interleaved"
1270          );
1271 fprintf(stderr,"\
1272 -n<error> or\n\
1273 -e<error>  : Max allowed loss per symbol (default = %d).\n",
1274 DEF_NEAR);
1275
1276 fprintf(stderr,"\
1277 -m<table>  : Use mapping table where <table> is a file in the format:\n\
1278          1st byte of <table> is the Table ID,\n\
1279          2nd byte of <table> is the Width of each table entry (in bytes),\n\
1280          3rd - 6th byte of <table> is the Max Table Index Value specified\n\
1281                    as an integer (4 bytes),\n\
1282          7th byte and on are the table entries.\n");
1283 fprintf(stderr,"\
1284 -t<num>    : Use Restart Markers where <num> is the restart interval \n\
1285              (ie. number of MCU's between restart markers).\n");
1286
1287 fprintf(stderr,"\
1288 -h         : Print this help.\n");
1289     fprintf(stderr,"\
1290 *** No spaces allowed between a flag and its argument.\n\
1291 *** Use -Ta,-Tb,-Tc,-r only if you know what you are doing!\n\
1292 ");
1293 }
1294
1295
1296
1297 /* Print out message for a bad flag */
1298 bad_flag(char *s)
1299 {
1300     fprintf(stderr,"Bad flag %s\n",s);
1301     usage();
1302     exit(10);
1303 }
1304
1305
1306
1307 /* Functions that read the PGM header */
1308
1309 #define HEADER_MAXLINE 256
1310
1311 int read_header_6(FILE *fin, int *widthp, int *heightp, int *maxvalp, int *comp)
1312 {
1313   char line[HEADER_MAXLINE];
1314   int  cols,rows,maxval;
1315
1316   if ( nextline(line, fin) != 0 )
1317     return -10;
1318
1319   if (strncmp(line,"P5",2)==0) *comp=1;
1320   else if (strncmp(line,"P6",2)==0) *comp=3;
1321        else if (strncmp(line,"P7",2)==0) *comp=4;
1322           else return -1;
1323   
1324   if ( nextline(line, fin) != 0 )
1325     return -10;
1326   
1327   if ( sscanf(line,"%d %d",&cols,&rows) != 2 )
1328     return -1;
1329   
1330   if ( nextline(line, fin) != 0 )
1331     return -10;
1332
1333   if ( sscanf(line,"%d",&maxval) != 1 )
1334     return -1;
1335   
1336   *widthp = cols;
1337   *heightp = rows;
1338   *maxvalp = maxval;
1339
1340   return 0;
1341 }
1342
1343
1344
1345 int read_header_5(FILE *fin, int *widthp, int *heightp, int *maxvalp)
1346 {
1347   char line[HEADER_MAXLINE];
1348   int  cols,rows,maxval;
1349
1350   if ( nextline(line, fin) != 0 )
1351     return -10;
1352
1353   if (strncmp(line,"P5",2)!=0)
1354     return -1;
1355   
1356   if ( nextline(line, fin) != 0 )
1357     return -10;
1358   
1359   if ( sscanf(line,"%d %d",&cols,&rows) != 2 )
1360     return -1;
1361   
1362   if ( nextline(line, fin) != 0 )
1363     return -10;
1364
1365   if ( sscanf(line,"%d",&maxval) != 1 )
1366     return -1;
1367   
1368   *widthp = cols;
1369   *heightp = rows;
1370   *maxvalp = maxval;
1371
1372   return 0;
1373 }
1374
1375
1376
1377 /* Used to read in header lines of PGM/PPM files */
1378 int nextline(char *line, FILE *fp)
1379 {
1380   char *p;
1381
1382   do {
1383     p = fgets(line, HEADER_MAXLINE, fp);
1384     /*
1385     if ( p != NULL )
1386         fprintf(stderr,"%s",line);
1387     */
1388
1389   } while ( p != NULL && *p == '#' );
1390
1391   if ( p==NULL )
1392     return -1;
1393   
1394   return 0;
1395 }
1396