Initial revision v0.00
authoryves
Wed Jul 21 15:27:55 1999 +0000
changeset 0ffe49af855fa
child 1 ed545413d8c9
Initial revision
cals2tiff.c
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/cals2tiff.c	Wed Jul 21 15:27:55 1999 +0000
     1.3 @@ -0,0 +1,414 @@
     1.4 +#include <stdio.h>
     1.5 +#include <stdlib.h>
     1.6 +#include <string.h>
     1.7 +
     1.8 +
     1.9 +/***************************************
    1.10 + *
    1.11 + * Copyright Yves Dorfsman 1999.
    1.12 + *
    1.13 + * --------------------------------------------------------------------------
    1.14 + * cals2tiff is free software; you can redistribute it and/or modify it
    1.15 + * under the terms of the GNU General Public License as published by
    1.16 + * the Free Software Foundation; either version 2 of the License, or
    1.17 + * (at your option) any later version.
    1.18 + *
    1.19 + * cals2tiff is distributed in the hope that it will be useful, but WITHOUT
    1.20 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    1.21 + * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
    1.22 + * License for more details.
    1.23 + *
    1.24 + * You should have received a copy of the GNU General Public License
    1.25 + * along with Orca in the COPYING-GPL file; if not, write to the Free
    1.26 + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    1.27 + * 02111-1307 USA
    1.28 + * --------------------------------------------------------------------------
    1.29 + *
    1.30 + * cals2tiff
    1.31 + *
    1.32 + * This program is used to convert .cal files (US NAVY CALS raster file
    1.33 + * Type 1) into .tiff files (baseline TIFF bilevel images).
    1.34 + *
    1.35 + * All it really does is change the header. CALS only support compressed
    1.36 + * data, and only through CCITT group 4 algorithm (T6). Tiff revision 6.0
    1.37 + * can support this same compression schem (among others), and therefore
    1.38 + * there is no need to change the data to convert from one format to the
    1.39 + * other.
    1.40 + *
    1.41 + * Error code returned:
    1.42 + *     1:  Wrong number of arguments
    1.43 + *     2:  Couldn't open arg1 for reading
    1.44 + *     3:  Couldn't open arg2 for writting
    1.45 + *     4:  Pb encountered while reading the header of arg1
    1.46 + *     5:  Something's wrong in the header, propably not a CALS files
    1.47 + *
    1.48 + * Potential bugs:
    1.49 + * The spec do not give example of orientation (x, 90), so I guessed them !
    1.50 + * If I'm wrong, or if you do have example of these orientations, please do
    1.51 + * email me to let me know.
    1.52 + *
    1.53 + *
    1.54 + *
    1.55 + ***************************************/
    1.56 +
    1.57 +
    1.58 +void usage(char*);
    1.59 +void make_lit_end(long*, char*, int);
    1.60 +
    1.61 +
    1.62 +
    1.63 +
    1.64 +main (int argc, char** argv)
    1.65 +{
    1.66 +char buffer[4096],
    1.67 +     *token,
    1.68 +     *pt,
    1.69 +     b[4],
    1.70 +     IFDentry[12],
    1.71 +     *tag, *field_type, *n_values, *values;
    1.72 +
    1.73 +               
    1.74 +size_t rsize;
    1.75 +
    1.76 +int  i,
    1.77 +     rorient = 0,
    1.78 +     rorient1 = 0,
    1.79 +     rorient2 = 0,
    1.80 +     IFDoffset = 24,
    1.81 +     nbr_dir_entry = 11;
    1.82 +
    1.83 +long data_length,
    1.84 +     rpelcnt1 = 0,
    1.85 +     rpelcnt2 =0,
    1.86 +     rdensity = 0,
    1.87 +     full;
    1.88 +     
    1.89 +FILE *cals_file, *tiff_file;
    1.90 +
    1.91 +
    1.92 +
    1.93 +/* Need two arguments */
    1.94 +if (argc != 3)
    1.95 +  {
    1.96 +  usage(argv[0]);
    1.97 +  return 1;
    1.98 +  }
    1.99 +
   1.100 +
   1.101 +/* Check that we can open the files */
   1.102 +
   1.103 +cals_file = fopen(argv[1], "rb");
   1.104 +if (cals_file == 0)
   1.105 +  {
   1.106 +  strcpy(buffer, "\nTrying to open ");
   1.107 +  strcat(buffer, argv[1]);
   1.108 +  strcat(buffer, " for reading");
   1.109 +  perror(buffer);
   1.110 +  usage(argv[0]);
   1.111 +  return 2;
   1.112 +  }
   1.113 +
   1.114 +tiff_file = fopen(argv[2], "wb");
   1.115 +if (cals_file == 0)
   1.116 +  {
   1.117 +  strcpy(buffer, "\nTrying to open ");
   1.118 +  strcat(buffer, argv[2]);
   1.119 +  strcat(buffer, " for writting");
   1.120 +  perror(buffer);
   1.121 +  usage(argv[0]);
   1.122 +  return 3;
   1.123 +  }
   1.124 +
   1.125 +
   1.126 +
   1.127 +
   1.128 +/**********************
   1.129 + * Ok, now we've got both files open
   1.130 + **********************/
   1.131 +
   1.132 +/* Look for rpelcnt and rdensity in the CALS file */
   1.133 +/*
   1.134 + * In a CALS file, the header si 2048 bytes, records are fixed length of 128
   1.135 + * bytes, names (tags ?) are followed by a colon, followed by a space. If 
   1.136 + * more than one value, then the first value is followed by a comma, followed
   1.137 + * by a space, followed by the next value.
   1.138 + */
   1.139 +
   1.140 +
   1.141 +for (i = 0 ; i < 16 ; i++)
   1.142 +  {
   1.143 +  buffer[128] = 0;
   1.144 +  if ( fread(buffer, 128, 1, cals_file) != 1)
   1.145 +    {
   1.146 +    perror("\nWhile reading the file\n");
   1.147 +    fprintf(stderr, "\nYour file is probably not a CALS file....\n");
   1.148 +    usage(argv[0]);
   1.149 +    return  4;
   1.150 +    }
   1.151 +
   1.152 +  token = strtok(buffer, ":, ");
   1.153 +
   1.154 +  if ( strcmp(token, "rpelcnt") == 0)
   1.155 +    {
   1.156 +    /*** rpelcnt ****/
   1.157 +    token = strtok((char *)0, ":, ");
   1.158 +    rpelcnt1 = strtol(token, (char **)NULL, 10);
   1.159 +
   1.160 +    token = strtok((char *)0, ":, ");
   1.161 +    rpelcnt2 = strtol(token, (char **)NULL, 10);
   1.162 +    }
   1.163 +
   1.164 +       /*
   1.165 +        * Autocad seems to produce a bogus header with "rdensty" instead
   1.166 +        * of "rdensity"......
   1.167 +        */
   1.168 +  else if ( (strcmp(token, "rdensity") == 0) || (strcmp(token, "rdensty") == 0) )
   1.169 +         {
   1.170 +         /*** rdensity ****/
   1.171 +         token = strtok((char *)0, ":, ");
   1.172 +         rdensity = strtol(token, (char **)NULL, 10);
   1.173 +         }
   1.174 +
   1.175 +        else if (strcmp(token, "rorient") == 0)
   1.176 +                {
   1.177 +                /*** rorient ****/
   1.178 +                token = strtok((char *)0, ":, ");
   1.179 +                rorient1 = (long) strtol(token, (char **)NULL, 10);
   1.180 +
   1.181 +                token = strtok((char *)0, ":, ");
   1.182 +                rorient2 = (long) strtol(token, (char **)NULL, 10);
   1.183 +
   1.184 +                if (rorient2 == 90)
   1.185 +                  {
   1.186 +                  switch (rorient1)
   1.187 +                    {
   1.188 +                    case   0: rorient = 2; break;
   1.189 +                    case  90: rorient = 5; break;
   1.190 +                    case 180: rorient = 4; break;
   1.191 +                    case 270: rorient = 7; break;
   1.192 +                    }
   1.193 +                  }
   1.194 +
   1.195 +                else if (rorient2 == 270)
   1.196 +                       {
   1.197 +                       switch (rorient1)
   1.198 +                         {
   1.199 +                         case   0: rorient = 1; break;
   1.200 +                         case  90: rorient = 8; break;
   1.201 +                         case 180: rorient = 3; break;
   1.202 +                         case 270: rorient = 6; break;
   1.203 +                         }
   1.204 +                       }
   1.205 +                }
   1.206 +
   1.207 +  /** rpelcnt, rdensity and rorient cannot be null, so if they are equal to zero
   1.208 +    * that means that we haven't found them yet
   1.209 +    **/
   1.210 +
   1.211 +  if ( (rpelcnt1 != 0) && (rpelcnt2 != 0) && (rdensity != 0) && (rorient != 0L) )
   1.212 +    break;
   1.213 +
   1.214 +  
   1.215 +  }
   1.216 +
   1.217 +  if ( (rpelcnt1 == 0) || (rpelcnt2 == 0) || (rdensity == 0) || (rorient == 0) )
   1.218 +    {
   1.219 +    fprintf(stderr, "\nThe file %s is in the wrong format.\n", argv[0]);
   1.220 +    fprintf(stderr, "Here are the values I have found:\n");
   1.221 +    fprintf(stderr, "rpelcnt: %li, %li\n", rpelcnt1, rpelcnt2);
   1.222 +    fprintf(stderr, "rdensity: %li\n", rdensity);
   1.223 +    fprintf(stderr, "rorient: %i, %i\n", rorient1, rorient2);
   1.224 +    usage(argv[0]);
   1.225 +    return  5;
   1.226 +    }
   1.227 +  
   1.228 +
   1.229 +
   1.230 +/************************
   1.231 + * Find out the length (in bytes) of the data segment
   1.232 + ************************/
   1.233 +
   1.234 +fseek(cals_file, 0L, SEEK_END);
   1.235 +data_length = ftell(cals_file) - (long) 2048;
   1.236 +
   1.237 +/*********************
   1.238 + * Write header
   1.239 + *********************/
   1.240 +
   1.241 +/* Byte Order: little endian */
   1.242 +buffer[0] = 0x49 ; buffer[1] = 0x49 ;
   1.243 +
   1.244 +/* type of file: TIFF */
   1.245 +buffer[2] = 42 ; buffer[3] = 00 ;
   1.246 +
   1.247 +/* The IFD starts at 24 because the first part of the header end at 8,
   1.248 + * and I need 16 bytes to write the x and y density
   1.249 + */
   1.250 +full = (long) IFDoffset; make_lit_end(&full, buffer+4, 4);
   1.251 +
   1.252 +fwrite(buffer, 1, 8, tiff_file);
   1.253 +
   1.254 +/*********
   1.255 + * Now write xdensity and ydensity
   1.256 + *********/
   1.257 +
   1.258 +full = rdensity ; make_lit_end(&full, b, 4);
   1.259 +fwrite(b, 1, 4, tiff_file);
   1.260 +full = (long) 1 ; make_lit_end(&full, b, 4);
   1.261 +fwrite(b, 1, 4, tiff_file);
   1.262 +
   1.263 +full = rdensity ; make_lit_end(&full, b, 4);
   1.264 +fwrite(b, 1, 4, tiff_file);
   1.265 +full = (long) 1 ; make_lit_end(&full, b, 4);
   1.266 +fwrite(b, 1, 4, tiff_file);
   1.267 +
   1.268 +/** Number of entries in the directoy **/
   1.269 +full = (long) nbr_dir_entry ; make_lit_end(&full, b, 2);
   1.270 +fwrite(b, 1, 2, tiff_file);
   1.271 +
   1.272 +/** Now the directory itself **/
   1.273 +/* Directory entries are saved in an array of char, each part of it being
   1.274 + * pointed to by pointers.
   1.275 + * I chose this method to avoid the problem of intemember padding in a 
   1.276 + * structure (so that this program is more portable).
   1.277 + */
   1.278 +
   1.279 +tag        = IFDentry ;
   1.280 +field_type = tag + 2;
   1.281 +n_values   = field_type + 2;
   1.282 +values     = n_values +4;
   1.283 +
   1.284 +/* Image Width */
   1.285 +full = 0x100L            ; make_lit_end(&full, tag, 2);
   1.286 +full = 4L                ; make_lit_end(&full, field_type, 2);
   1.287 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.288 +full = rpelcnt1   ; make_lit_end(&full, values, 4);
   1.289 +fwrite(IFDentry, 1, 12, tiff_file);
   1.290 +
   1.291 +/* Image Length */
   1.292 +full = 0x101L            ; make_lit_end(&full, tag, 2);
   1.293 +full = 4L                ; make_lit_end(&full, field_type, 2);
   1.294 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.295 +full = rpelcnt2   ; make_lit_end(&full, values, 4);
   1.296 +fwrite(IFDentry, 1, 12, tiff_file);
   1.297 +
   1.298 +/* Compression */
   1.299 +full = 0x103L            ; make_lit_end(&full, tag, 2);
   1.300 +full = 3L                ; make_lit_end(&full, field_type, 2);
   1.301 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.302 +full = 4L                ; make_lit_end(&full, values, 4);
   1.303 +fwrite(IFDentry, 1, 12, tiff_file);
   1.304 +
   1.305 +/* Photometric Interpretation */
   1.306 +full = 0x106L            ; make_lit_end(&full, tag, 2);
   1.307 +full = 3L                ; make_lit_end(&full, field_type, 2);
   1.308 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.309 +full = 0L                ; make_lit_end(&full, values, 4);
   1.310 +fwrite(IFDentry, 1, 12, tiff_file);
   1.311 +
   1.312 +/* Strip Offsets */
   1.313 +full = 0x111L            ; make_lit_end(&full, tag, 2);
   1.314 +full = 4L                ; make_lit_end(&full, field_type, 2);
   1.315 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.316 +full = (long) (nbr_dir_entry * 12 + 2 + IFDoffset);
   1.317 +                           make_lit_end(&full, values, 4);
   1.318 +fwrite(IFDentry, 1, 12, tiff_file);
   1.319 +
   1.320 +/* Orientation */
   1.321 +full = 0x112L            ; make_lit_end(&full, tag, 2);
   1.322 +full = 3L                ; make_lit_end(&full, field_type, 2);
   1.323 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.324 +full = (long) rorient    ; make_lit_end(&full, values, 4);
   1.325 +fwrite(IFDentry, 1, 12, tiff_file);
   1.326 +
   1.327 +/* Samples Per Pixel */
   1.328 +full = 0x115L            ; make_lit_end(&full, tag, 2);
   1.329 +full = 3L                ; make_lit_end(&full, field_type, 2);
   1.330 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.331 +full = 1L                ; make_lit_end(&full, values, 4);
   1.332 +fwrite(IFDentry, 1, 12, tiff_file);
   1.333 +
   1.334 +/* Rows per Strip (the whole image is in 1 strip) */
   1.335 +/*
   1.336 +full = 0x116L            ; make_lit_end(&full, tag, 2);
   1.337 +full = 4L                ; make_lit_end(&full, field_type, 2);
   1.338 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.339 +full = rpelcnt2          ; make_lit_end(&full, values, 4);
   1.340 +fwrite(IFDentry, 1, 12, tiff_file);
   1.341 + */
   1.342 +
   1.343 +/* Strip Byte Counts (total nbr of byte for data) */
   1.344 +full = 0x117L            ; make_lit_end(&full, tag, 2);
   1.345 +full = 4L                ; make_lit_end(&full, field_type, 2);
   1.346 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.347 +full = (long) data_length; make_lit_end(&full, values, 4);
   1.348 +fwrite(IFDentry, 1, 12, tiff_file);
   1.349 +
   1.350 +/* Xresolution */
   1.351 +full = 0x11AL            ; make_lit_end(&full, tag, 2);
   1.352 +full = 5L                ; make_lit_end(&full, field_type, 2);
   1.353 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.354 +full = 8L                ; make_lit_end(&full, values, 4);
   1.355 +fwrite(IFDentry, 1, 12, tiff_file);
   1.356 +
   1.357 +/* Yresolution */
   1.358 +full = 0x11BL            ; make_lit_end(&full, tag, 2);
   1.359 +full = 5L                ; make_lit_end(&full, field_type, 2);
   1.360 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.361 +full = 16L               ; make_lit_end(&full, values, 4);
   1.362 +fwrite(IFDentry, 1, 12, tiff_file);
   1.363 +
   1.364 +/* Resolution Unit */
   1.365 +full = 0x128L            ; make_lit_end(&full, tag, 2);
   1.366 +full = 3L                ; make_lit_end(&full, field_type, 2);
   1.367 +full = 1L                ; make_lit_end(&full, n_values, 4);
   1.368 +full = 2L                ; make_lit_end(&full, values, 4);
   1.369 +fwrite(IFDentry, 1, 12, tiff_file);
   1.370 +
   1.371 +
   1.372 +/**************************************************
   1.373 + * Now, just copy the whole data piece into the new file
   1.374 + **************************************************/
   1.375 +fseek(cals_file, 2048L, SEEK_SET);
   1.376 +
   1.377 +do
   1.378 +  {
   1.379 +  rsize = fread(buffer, 1, 4096, cals_file);
   1.380 +  fwrite(buffer, 1, rsize, tiff_file);
   1.381 +  } while (rsize == 4096);
   1.382 +
   1.383 +
   1.384 +
   1.385 +}
   1.386 +
   1.387 +
   1.388 +
   1.389 +
   1.390 +void usage(char *progname)
   1.391 +  {
   1.392 +  fprintf(stderr, "\a\nUsage: %s file.cal file.tiff\n\n", progname);
   1.393 +  fprintf(stderr, "file.cal should be an existing file using the US Navy\n");
   1.394 +  fprintf(stderr, "CALS raster type 1 format (see MIL-PRF-28002).\n\n");
   1.395 +  fprintf(stderr, "Yves Dorfsman - SollerS inc.\n\n\n");
   1.396 +  }
   1.397 +
   1.398 +
   1.399 +/**************************************
   1.400 + * This little sub-routine transform a short or a long
   1.401 + * into a series of char, from lsb (b[0]) to msb (b[3]), so it is easier
   1.402 + * to always write in little endian.
   1.403 + **************************************/
   1.404 +void make_lit_end(long *full, char *b, int count)
   1.405 +  {
   1.406 +  long   other;
   1.407 +  int    i;
   1.408 +
   1.409 +  for ( i = 0 ; i < count ; i++)
   1.410 +    {
   1.411 +    other = *full;
   1.412 +    other = other >> (i * 8);
   1.413 +    other &= 0x000FF;
   1.414 +    b[i] = other;
   1.415 +    }
   1.416 +
   1.417 +  }