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 + }