File indexing completed on 2024-04-21 14:45:54

0001 /*
0002     SPDX-FileCopyrightText: William D. Pence <https://heasarc.gsfc.nasa.gov/fitsio/>
0003     SPDX-FileCopyrightText: R. Seaman
0004 
0005     SPDX-License-Identifier: LicenseRef-NASA-FV-License-Agreement
0006 
0007     Calls fits_img_compress in the CFITSIO library by W. Pence, HEASARC
0008 */
0009 
0010 #include <ctype.h>
0011 /* #include <signal.h> */
0012 #include "fitsio.h"
0013 #include "fpack.h"
0014 
0015 /* ==================================================================
0016 int main(int argc, char *argv[])
0017 {
0018     fpstate fpvar;
0019 
0020     if (argc <= 1) { fp_usage (); fp_hint (); exit (-1); }
0021 
0022     fp_init (&fpvar);
0023     fp_get_param (argc, argv, &fpvar);
0024 
0025     if (fpvar.listonly) {
0026         fp_list (argc, argv, fpvar);
0027 
0028     } else {
0029         fp_preflight (argc, argv, FPACK, &fpvar);
0030         fp_loop (argc, argv, FPACK, fpvar);
0031     }
0032 
0033     exit (0);
0034 }
0035 ================================================================== */
0036 int _fp_msg (const char *msg)
0037 {
0038         printf ("%s", msg);
0039         return(0);
0040 }
0041 
0042 int fp_get_param (int argc, char *argv[], fpstate *fpptr)
0043 {
0044     int gottype=0, gottile=0, wholetile=0, iarg, len, ndim, ii, doffset;
0045     char    tmp[SZ_STR], tile[SZ_STR];
0046 
0047         if (fpptr->initialized != FP_INIT_MAGIC) {
0048             fp_msg ("Error: internal initialization error\n"); exit (-1);
0049         }
0050 
0051     tile[0] = 0;
0052 
0053     /* flags must come first and be separately specified
0054      */
0055     for (iarg = 1; iarg < argc; iarg++) {
0056         if ((argv[iarg][0] == '-' && strlen (argv[iarg]) == 2) ||
0057             !strncmp(argv[iarg], "-q", 2) || !strncmp(argv[iarg], "-qz", 3) ||
0058             !strncmp(argv[iarg], "-g1", 3) || !strncmp(argv[iarg], "-g2", 3) ||
0059             !strncmp(argv[iarg], "-i2f", 4) ||
0060             !strncmp(argv[iarg], "-n3ratio", 8) || !strncmp(argv[iarg], "-n3min", 6) ||
0061             !strncmp(argv[iarg], "-tableonly", 10) || !strncmp(argv[iarg], "-table", 6) )  
0062         {
0063 
0064         /* Rice is the default, so -r is superfluous  */
0065         if (       argv[iarg][1] == 'r') {
0066             fpptr->comptype = RICE_1;
0067             if (gottype) {
0068             fp_msg ("Error: multiple compression flags\n");
0069             fp_usage (); exit (-1);
0070             } else
0071             gottype++;
0072 
0073         } else if (argv[iarg][1] == 'p') {
0074             fpptr->comptype = PLIO_1;
0075             if (gottype) {
0076             fp_msg ("Error: multiple compression flags\n");
0077             fp_usage (); exit (-1);
0078             } else
0079             gottype++;
0080 
0081         } else if (argv[iarg][1] == 'g') {
0082             /* test for modifiers following the 'g' */
0083                     if (argv[iarg][2] == '2')
0084                 fpptr->comptype = GZIP_2;
0085             else
0086                 fpptr->comptype = GZIP_1;
0087 
0088             if (gottype) {
0089             fp_msg ("Error: multiple compression flags\n");
0090             fp_usage (); exit (-1);
0091             } else
0092             gottype++;
0093 /*
0094         } else if (argv[iarg][1] == 'b') {
0095             fpptr->comptype = BZIP2_1;
0096             if (gottype) {
0097             fp_msg ("Error: multiple compression flags\n");
0098             fp_usage (); exit (-1);
0099             } else
0100             gottype++;
0101 */
0102         } else if (argv[iarg][1] == 'h') {
0103             fpptr->comptype = HCOMPRESS_1;
0104             if (gottype) {
0105             fp_msg ("Error: multiple compression flags\n");
0106             fp_usage (); exit (-1);
0107             } else
0108             gottype++;
0109 
0110         } else if (argv[iarg][1] == 'd') {
0111             fpptr->comptype = NOCOMPRESS;
0112             if (gottype) {
0113             fp_msg ("Error: multiple compression flags\n");
0114             fp_usage (); exit (-1);
0115             } else
0116             gottype++;
0117 
0118         } else if (!strcmp(argv[iarg], "-i2f")) {
0119             /* this means convert integer images to float, and then */
0120             /* quantize and compress the float image.  This lossy */
0121             /* compression method may give higher compression than the */
0122             /* lossless compression method that is usually applied to */
0123             /* integer images. */
0124             
0125             fpptr->int_to_float = 1;
0126 
0127         } else if (!strcmp(argv[iarg], "-n3ratio")) {
0128             /* this is the minimum ratio between the MAD noise sigma */
0129             /* and the q parameter value in the case where the integer */
0130             /* image is quantized and compressed like a float image. */
0131             if (++iarg >= argc) {
0132             fp_usage (); exit (-1);
0133             } else {
0134             fpptr->n3ratio = (float) atof (argv[iarg]);
0135             }
0136         } else if (!strcmp(argv[iarg], "-n3min")) {
0137             /* this is the minimum  MAD noise sigma in the case where the */
0138             /* integer image is quantized and compressed like a float image. */
0139             if (++iarg >= argc) {
0140             fp_usage (); exit (-1);
0141             } else {
0142             fpptr->n3min = (float) atof (argv[iarg]);
0143             }
0144         } else if (argv[iarg][1] == 'q') {
0145             /* test for modifiers following the 'q' */
0146 
0147                     if (argv[iarg][2] == 'z') {
0148                 fpptr->dither_method = 2;  /* preserve zero pixels */
0149 
0150                         if (argv[iarg][3] == 't') {
0151                     fpptr->dither_offset = -1;  /* dither based on tile checksum */
0152 
0153                         } else if (isdigit(argv[iarg][3])) { /* is a number appended to q? */
0154                    doffset = atoi(argv[iarg]+3);
0155 
0156                            if (doffset == 0) {
0157                       fpptr->no_dither = 1;  /* don't dither the quantized values */
0158                    } else if (doffset > 0 && doffset <= 10000) {
0159                       fpptr->dither_offset = doffset;
0160                    } else {
0161                   fp_msg ("Error: invalid q suffix\n");
0162                   fp_usage (); exit (-1);
0163                    }
0164             }
0165             } else {
0166                         if (argv[iarg][2] == 't') {
0167                     fpptr->dither_offset = -1;  /* dither based on tile checksum */
0168 
0169                         } else if (isdigit(argv[iarg][2])) { /* is a number appended to q? */
0170                    doffset = atoi(argv[iarg]+2);
0171 
0172                            if (doffset == 0) {
0173                       fpptr->no_dither = 1;  /* don't dither the quantized values */
0174                    } else if (doffset > 0 && doffset <= 10000) {
0175                       fpptr->dither_offset = doffset;
0176                    } else {
0177                   fp_msg ("Error: invalid q suffix\n");
0178                   fp_usage (); exit (-1);
0179                    }
0180             }
0181             }
0182 
0183             if (++iarg >= argc) {
0184             fp_usage (); exit (-1);
0185             } else {
0186             fpptr->quantize_level = (float) atof (argv[iarg]);
0187             }
0188         } else if (argv[iarg][1] == 'n') {
0189             if (++iarg >= argc) {
0190             fp_usage (); exit (-1);
0191             } else {
0192             fpptr->rescale_noise = (float) atof (argv[iarg]);
0193             }
0194         } else if (argv[iarg][1] == 's') {
0195             if (++iarg >= argc) {
0196             fp_usage (); exit (-1);
0197             } else {
0198             fpptr->scale = (float) atof (argv[iarg]);
0199             }
0200         } else if (!strcmp(argv[iarg], "-tableonly")) {
0201             fpptr->do_tables = 1;
0202             fpptr->do_images = 0;
0203             fp_msg ("Note: -tableonly is intended for feasibility studies, not general use.\n");
0204 
0205         } else if (!strcmp(argv[iarg], "-table")) {
0206             fpptr->do_tables = 1;
0207             fp_msg ("Note: -table is intended for feasibility studies, not general use.\n");
0208 
0209         } else if (argv[iarg][1] == 't') {
0210             if (gottile) {
0211             fp_msg ("Error: multiple tile specifications\n");
0212             fp_usage (); exit (-1);
0213             } else
0214             gottile++;
0215 
0216             if (++iarg >= argc) {
0217             fp_usage (); exit (-1);
0218             } else
0219             strncpy (tile, argv[iarg], SZ_STR-1); /* checked below */
0220 
0221         } else if (argv[iarg][1] == 'v') {
0222             fpptr->verbose = 1;
0223 
0224         } else if (argv[iarg][1] == 'w') {
0225             wholetile++;
0226             if (gottile) {
0227             fp_msg ("Error: multiple tile specifications\n");
0228             fp_usage (); exit (-1);
0229             } else
0230             gottile++;
0231 
0232         } else if (argv[iarg][1] == 'F') {
0233             fpptr->clobber++;       /* overwrite existing file */
0234 
0235         } else if (argv[iarg][1] == 'D') {
0236             fpptr->delete_input++;
0237 
0238         } else if (argv[iarg][1] == 'Y') {
0239             fpptr->do_not_prompt++;
0240 
0241         } else if (argv[iarg][1] == 'S') {
0242             fpptr->to_stdout++;
0243 
0244         } else if (argv[iarg][1] == 'L') {
0245             fpptr->listonly++;
0246 
0247         } else if (argv[iarg][1] == 'C') {
0248             fpptr->do_checksums = 0;
0249 
0250         } else if (argv[iarg][1] == 'T') {
0251             fpptr->test_all = 1;
0252 
0253         } else if (argv[iarg][1] == 'R') {
0254             if (++iarg >= argc) {
0255             fp_usage (); fp_hint (); exit (-1);
0256             } else
0257             strncpy (fpptr->outfile, argv[iarg], SZ_STR);
0258 
0259         } else if (argv[iarg][1] == 'H') {
0260             fp_help (); exit (0);
0261 
0262         } else if (argv[iarg][1] == 'V') {
0263             fp_version (); exit (0);
0264 
0265         } else {
0266             fp_msg ("Error: unknown command line flag `");
0267             fp_msg (argv[iarg]); fp_msg ("'\n");
0268             fp_usage (); fp_hint (); exit (-1);
0269         }
0270 
0271         } else
0272         break;
0273     }
0274 
0275     if (fpptr->scale != 0. && 
0276              fpptr->comptype != HCOMPRESS_1 && fpptr->test_all != 1) {
0277 
0278         fp_msg ("Error: `-s' requires `-h or -T'\n"); exit (-1);
0279     }
0280 
0281     if (fpptr->quantize_level == 0) {
0282     
0283         if ((fpptr->comptype != GZIP_1) && (fpptr->comptype != GZIP_2)) {
0284             fp_msg ("Error: `-q 0' only allowed with GZIP\n"); exit (-1);
0285         }
0286 
0287             if (fpptr->int_to_float == 1) {
0288             fp_msg ("Error: `-q 0' not allowed with -i2f\n"); exit (-1);
0289         }
0290     }
0291 
0292     if (wholetile) {
0293         for (ndim=0; ndim < MAX_COMPRESS_DIM; ndim++)
0294         fpptr->ntile[ndim] = (long) -1;
0295 
0296     } else if (gottile) {
0297         len = strlen (tile);
0298         for (ii=0, ndim=0; ii < len; ) {
0299         if (! (isdigit (tile[ii]) || tile[ii] == ',')) {
0300             fp_msg ("Error: `-t' requires comma separated tile dims, ");
0301             fp_msg ("e.g., `-t 100,100'\n"); exit (-1);
0302         }
0303 
0304         if (tile[ii] == ',') { ii++; continue; }
0305 
0306         fpptr->ntile[ndim] = atol (&tile[ii]);
0307         for ( ; isdigit(tile[ii]); ii++);
0308 
0309         if (++ndim > MAX_COMPRESS_DIM) {
0310             fp_msg ("Error: too many dimensions for `-t', max=");
0311             snprintf (tmp, SZ_STR,"%d\n", MAX_COMPRESS_DIM); fp_msg (tmp);
0312             exit (-1);
0313         }
0314         }
0315     }
0316 
0317     if (iarg >= argc) {
0318         fp_msg ("Error: no FITS files to compress\n");
0319         fp_usage (); exit (-1);
0320     } else
0321         fpptr->firstfile = iarg;
0322 
0323     return(0);
0324 }
0325 
0326 /* ================================================================== */
0327 int fp_usage (void)
0328 {
0329 fp_msg ("usage: fpack ");
0330 fp_msg (
0331 "[-r|-h|-g|-p] [-w|-t <axes>] [-q <level>] [-s <scale>] [-n <noise>] -v <FITS>\n");
0332 fp_msg ("more:   [-T] [-R] [-F] [-D] [-Y] [-S] [-L] [-C] [-H] [-V] [-i2f]\n");
0333 return(0);
0334 }
0335 
0336 /* ================================================================== */
0337 int fp_hint (void) 
0338 { fp_msg ("      `fpack -H' for help\n"); 
0339 return(0);
0340 }
0341 
0342 /* ================================================================== */
0343 int fp_help (void)
0344 {
0345 fp_msg ("fpack, a FITS image compression program.  Version ");
0346 fp_version ();
0347 fp_usage ();
0348 fp_msg ("\n");
0349 fp_msg ("NOTE: the compression parameters specified on the fpack command line may\n");
0350 fp_msg ("be over-ridden by compression directive keywords in the header of each HDU\n");
0351 fp_msg ("of the input file(s). See the fpack User's Guide for more details\n");
0352 fp_msg ("\n");
0353 
0354 fp_msg ("Flags must be separate and appear before filenames:\n");
0355 fp_msg (" -r          Rice compression [default], or\n");
0356 fp_msg (" -h          Hcompress compression, or\n");
0357 fp_msg (" -g  or -g1  GZIP_1 (per-tile) compression, or\n");
0358 fp_msg (" -g2         GZIP_2 (per-tile) compression (with byte shuffling), or\n");
0359 /*
0360 fp_msg (" -b          BZIP2 (per-tile) compression, or\n");
0361 */
0362 fp_msg (" -p          PLIO compression (only for positive 8 or 16-bit integer images).\n");
0363 fp_msg (" -d          Tile the image without compression (debugging mode).\n");
0364 
0365 fp_msg (" -w          Compress the whole image as a single large tile.\n");
0366 fp_msg (" -t <axes>   Comma separated list of tile dimensions [default is row by row].\n");
0367 
0368 fp_msg (" -q <level>  Quantized level spacing when converting floating point images to\n");
0369 fp_msg ("             scaled integers. (+value relative to sigma of background noise;\n");
0370 fp_msg ("             -value is absolute). Default q value of 4 gives a compression ratio\n");
0371 fp_msg ("             of about 6 with very high fidelity (only 0.26% increase in noise).\n");
0372 fp_msg ("             Using q values of  2, or 1 will give compression ratios of\n");
0373 fp_msg ("             about 8, or 10, respectively (with 1.0% or 4.1% noise increase).\n");
0374 fp_msg ("             The scaled quantized values are randomly dithered using a seed \n");
0375 fp_msg ("             value determined from the system clock at run time.\n");
0376 fp_msg ("             Use -q0 instead of -q to suppress random dithering.\n");
0377 fp_msg ("             Use -qz instead of -q to not dither zero-valued pixels.\n");
0378 fp_msg ("             Use -qt or -qzt to compute random dithering seed from first tile checksum.\n");
0379 fp_msg ("             Use -qN or -qzN, (N in range 1 to 10000) to use a specific dithering seed.\n");
0380 fp_msg ("             Floating-point images can be losslessly compressed by selecting\n");
0381 fp_msg ("             the GZIP algorithm and specifying -q 0, but this is slower and often\n");
0382 fp_msg ("             produces much less compression than the default quantization method.\n");
0383 fp_msg (" -i2f        Convert integer images to floating point, then quantize and compress\n");
0384 fp_msg ("             using the specified q level.  When used appropriately, this lossy\n");
0385 fp_msg ("             compression method can give much better compression than the normal\n");
0386 fp_msg ("             lossless compression methods without significant loss of information.\n");
0387 fp_msg ("             The -n3ratio and -n3min flags control the minimum noise thresholds;\n");
0388 fp_msg ("             Images below these thresholds will be losslessly compressed.\n");
0389 fp_msg (" -n3ratio    Minimum ratio of background noise sigma divided by q.  Default = 2.0.\n");
0390 fp_msg (" -n3min      Minimum background noise sigma. Default = 6. The -i2f flag will be ignored\n");
0391 fp_msg ("             if the noise level in the image does not exceed both thresholds.\n");
0392 fp_msg (" -s <scale>  Scale factor for lossy Hcompress [default = 0 = lossless]\n");
0393 fp_msg ("             (+values relative to RMS noise; -value is absolute)\n");
0394 fp_msg (" -n <noise>  Rescale scaled-integer images to reduce noise and improve compression.\n");
0395 fp_msg (" -v          Verbose mode; list each file as it is processed.\n");
0396 fp_msg (" -T          Show compression algorithm comparison test statistics; files unchanged.\n");
0397 fp_msg (" -R <file>   Write the comparison test report (above) to a text file.\n");
0398 fp_msg (" -table      Compress FITS binary tables as well as compress any image HDUs.\n");
0399 fp_msg (" -tableonly  Compress only FITS binary tables; do not compress any image HDUs.\n");
0400 fp_msg ("             \n");
0401 
0402 fp_msg ("\nkeywords shared with funpack:\n");
0403 
0404 fp_msg (" -F          Overwrite input file by output file with same name.\n");
0405 fp_msg (" -D          Delete input file after writing output.\n");
0406 fp_msg (" -Y          Suppress prompts to confirm -F or -D options.\n");
0407 
0408 fp_msg (" -S          Output compressed FITS files to STDOUT.\n");
0409 fp_msg (" -L          List contents; files unchanged.\n");
0410 
0411 fp_msg (" -C          Don't update FITS checksum keywords.\n");
0412 
0413 fp_msg (" -H          Show this message.\n");
0414 fp_msg (" -V          Show version number.\n");
0415 
0416 fp_msg ("\n <FITS>      FITS files to pack; enter '-' (a hyphen) to read input from stdin stream.\n");
0417 fp_msg (" Refer to the fpack User's Guide for more extensive help.\n");
0418 return(0);
0419 }