SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sdds2tiff.c
Go to the documentation of this file.
1/**
2 * @file sdds2tiff.c
3 * @brief Converts SDDS files to TIFF images.
4 *
5 * @details
6 * This program reads data from an SDDS (Self Describing Data Set) file and generates TIFF images.
7 * Each page in the input file is converted to a separate TIFF image.
8 * It supports options for processing pages, specifying data columns, and adjusting the output format.
9 *
10 * @section Usage
11 * ```
12 * sdds2tiff <input> <output>
13 * [-pipe[=input]]
14 * [-fromPage=<pageNumber>]
15 * [-toPage=<pageNumber>]
16 * [-columnPrefix=<Line>]
17 * [-maxContrast]
18 * [-16bit]
19 * ```
20 *
21 * @section Options
22 * | Option | Description |
23 * |--------------------------|-----------------------------------------------------------------|
24 * | `-pipe` | Specifies that input should be read from a pipe. |
25 * | `-fromPage` | Starts conversion from the specified page number. |
26 * | `-toPage` | Stops conversion at the specified page number. |
27 * | `-columnPrefix` | Prefix for column names containing line data. |
28 * | `-maxContrast` | Adjusts the image for maximum contrast. |
29 * | `-16bit` | Outputs images in 16-bit depth. |
30 *
31 * @subsection Incompatibilities
32 * - `-columnPrefix` requires a valid column prefix; otherwise, a default prefix `Line` is used.
33 * - `-16bit` changes the output depth to 16 bits and requires the maximum value in the data to not exceed 65535.
34 *
35 * @copyright
36 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
37 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
38 *
39 * @license
40 * This file is distributed under the terms of the Software License Agreement
41 * found in the file LICENSE included with this distribution.
42 *
43 * @authors
44 * R. Soliday, M. Borland
45 */
46
47#include "tiffio.h"
48#include "SDDS.h"
49#include "mdb.h"
50#include "scan.h"
51
52/* Enumeration for option types */
53typedef enum {
54 OPT_MAXCONTRAST,
55 OPT_FROMPAGE,
56 OPT_TOPAGE,
57 OPT_COLUMNPREFIX,
58 OPT_PIPE,
59 OPT_16BIT,
60 N_OPTIONS
61} option_type;
62
63/* Option names */
64static char *option[N_OPTIONS] = {
65 "maxcontrast", "frompage", "topage", "columnPrefix", "pipe", "16bit"};
66
67/* Usage message */
68static char *USAGE =
69 "sdds2tiff [<input>] [<output>] \n"
70 " [-pipe[=input]]\n"
71 " [-fromPage=<pageNumber>] \n"
72 " [-toPage=<pageNumber>]\n"
73 " [-columnPrefix=<Line>]\n"
74 " [-maxContrast]\n"
75 " [-16bit]\n"
76 " Two styles of input files are accepted:\n"
77 " 1. A single column SDDS file with Variable1Name and Variable2Name parameters,\n"
78 " as well as <Variable1Name>Dimension and <Variable2Name>Dimension parameters.\n"
79 " 2. A file containing multiple columns called Line*.\n"
80 "\n"
81 " Each page in the input file will be converted to a separate TIFF image.\n"
82 " The output files will be named <output>.%04ld\n\n"
83 " Program by Robert Soliday. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
84
85/* Main function */
86int main(int argc, char *argv[]) {
87 SDDS_DATASET SDDS_dataset;
88 SCANNED_ARG *s_arg;
89 TIFF *tif;
90 char **columnNames = NULL;
91 char *input = NULL, *output = NULL;
92 char *columnPrefix = NULL;
93 char *buffer = NULL, *outputName = NULL;
94 uint16_t *buffer16 = NULL;
95 int32_t **data = NULL;
96 long j;
97 long bit16 = 0;
98 long linesFound = 0;
99 int64_t i, k;
100 int64_t rows = 0;
101 int32_t nColumns = 0;
102 long maxvalue = 0;
103 long page = 1;
104 long index = 1;
105 long fromPage = 0;
106 long toPage = 0;
107 int maxContrast = 0;
108 double div = 1;
109 char *xVar = NULL, *yVar = NULL;
110 char zColumnName[40];
111 char xDimName[40], yDimName[40];
112 int64_t xDim;
113 int32_t yDim;
114 long style = 1;
115 unsigned long pipeFlags = 0;
116 long maxPossibleLong = 255;
117 double maxPossible = maxPossibleLong;
118
119 /* Register program name */
121
122 /* Process arguments */
123 argc = scanargs(&s_arg, argc, argv);
124 if (argc < 3) {
125 fprintf(stderr, "%s", USAGE);
126 return 1;
127 }
128
129 /* Parse options */
130 for (i = 1; i < argc; i++) {
131 if (s_arg[i].arg_type == OPTION) {
132 switch (match_string(s_arg[i].list[0], option, N_OPTIONS, 0)) {
133 case OPT_MAXCONTRAST:
134 maxContrast = 1;
135 break;
136 case OPT_FROMPAGE:
137 if (s_arg[i].n_items < 2) {
138 SDDS_Bomb("invalid -fromPage syntax");
139 }
140 if (sscanf(s_arg[i].list[1], "%ld", &fromPage) != 1 || fromPage <= 0) {
141 SDDS_Bomb("invalid -fromPage syntax or value");
142 }
143 break;
144 case OPT_TOPAGE:
145 if (s_arg[i].n_items < 2) {
146 SDDS_Bomb("invalid -toPage syntax");
147 }
148 if (sscanf(s_arg[i].list[1], "%ld", &toPage) != 1 || toPage <= 0) {
149 SDDS_Bomb("invalid -toPage syntax or value");
150 }
151 break;
152 case OPT_COLUMNPREFIX:
153 if (s_arg[i].n_items < 2) {
154 SDDS_Bomb("invalid -columnPrefix syntax");
155 }
156 SDDS_CopyString(&columnPrefix, s_arg[i].list[1]);
157 break;
158 case OPT_PIPE:
159 if (!processPipeOption(s_arg[i].list + 1, s_arg[i].n_items - 1, &pipeFlags)) {
160 fprintf(stderr, "invalid -pipe syntax\n");
161 return 1;
162 }
163 break;
164 case OPT_16BIT:
165 bit16 = 1;
166 maxPossible = maxPossibleLong = 65535;
167 break;
168 default:
169 fprintf(stderr, "sdds2tiff: invalid option seen\n%s", USAGE);
170 return 1;
171 }
172 } else {
173 if (!input) {
174 SDDS_CopyString(&input, s_arg[i].list[0]);
175 } else if (!output) {
176 SDDS_CopyString(&output, s_arg[i].list[0]);
177 } else {
178 fprintf(stderr, "sdds2tiff: too many filenames\n%s", USAGE);
179 return 1;
180 }
181 }
182 }
183
184 if (fromPage && toPage && fromPage > toPage) {
185 SDDS_Bomb("invalid -fromPage and -toPage");
186 }
187
188 if (!columnPrefix) {
189 columnPrefix = malloc(5 * sizeof(char));
190 sprintf(columnPrefix, "Line");
191 }
192
193 if (pipeFlags & USE_STDIN) {
194 processFilenames("sdds2tiff", &input, &output, USE_STDIN, 1, NULL);
195 }
196 if (!SDDS_InitializeInput(&SDDS_dataset, input)) {
197 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
198 }
199
200 outputName = malloc((strlen(output) + 10) * sizeof(char));
201
202 /* Check required parameters */
203 if (SDDS_CheckParameter(&SDDS_dataset, "Variable1Name", NULL, SDDS_STRING, NULL) != SDDS_CHECK_OKAY) {
204 style = 2;
205 }
206 if (SDDS_CheckParameter(&SDDS_dataset, "Variable2Name", NULL, SDDS_STRING, NULL) != SDDS_CHECK_OKAY) {
207 style = 2;
208 }
209
210 columnNames = SDDS_GetColumnNames(&SDDS_dataset, &nColumns);
211 if (!columnNames) {
212 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
213 }
214
215 /* Handle different styles */
216 if (style == 1) {
217 if (nColumns != 1) {
218 fprintf(stderr, "sdds2tiff: Expected one column but found more than one\n");
219 return 1;
220 }
221 sprintf(zColumnName, "%s", columnNames[0]);
222 } else if (style == 2) {
223 for (i = 0; i < nColumns; i++) {
224 if (strncmp(columnPrefix, columnNames[i], strlen(columnPrefix)) == 0) {
225 linesFound++;
226 }
227 }
228 if (linesFound == 0) {
229 fprintf(stderr, "sdds2tiff: No columns found named %s*\n", columnPrefix);
230 return 1;
231 }
232 data = malloc(linesFound * sizeof(*data));
233 }
234
235 /* Process each page */
236 while (SDDS_ReadTable(&SDDS_dataset) > 0) {
237 if ((fromPage > 0 && fromPage > page) || (toPage > 0 && toPage < page)) {
238 continue;
239 }
240
241 rows = SDDS_RowCount(&SDDS_dataset);
242
243 if (style == 1) {
244 if (!SDDS_GetParameter(&SDDS_dataset, "Variable1Name", &xVar)) {
245 fprintf(stderr, "sdds2tiff: problem getting parameter Variable1Name\n");
246 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
247 }
248 if (!SDDS_GetParameter(&SDDS_dataset, "Variable2Name", &yVar)) {
249 fprintf(stderr, "sdds2tiff: problem getting parameter Variable2Name\n");
250 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
251 }
252
253 sprintf(xDimName, "%sDimension", xVar);
254 sprintf(yDimName, "%sDimension", yVar);
255 if (!SDDS_GetParameterAsLong64(&SDDS_dataset, xDimName, &xDim)) {
256 fprintf(stderr, "sdds2tiff: problem getting parameter %s\n", xDimName);
257 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
258 }
259 if (!SDDS_GetParameterAsLong(&SDDS_dataset, yDimName, &yDim)) {
260 fprintf(stderr, "sdds2tiff: problem getting parameter %s\n", yDimName);
261 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
262 }
263
264 fprintf(stderr, "%s %s\n", xVar, yVar);
265 fprintf(stderr, "%" PRId64 " %" PRId32 "\n", xDim, yDim);
266 free(xVar);
267 free(yVar);
268
269 if (xDim * yDim != rows) {
270 fprintf(stderr, "sdds2tiff: %s * %s does not equal the number of rows in the page\n", xDimName, yDimName);
271 return 1;
272 }
273
274 data = malloc(sizeof(*data));
275 data[0] = SDDS_GetColumnInLong(&SDDS_dataset, zColumnName);
276 for (i = 0; i < rows; i++) {
277 if (data[0][i] > maxvalue) {
278 maxvalue = data[0][i];
279 }
280 }
281
282 if (!bit16) {
283 buffer = malloc(rows * sizeof(char));
284 } else {
285 buffer16 = malloc(rows * sizeof(int16_t));
286 }
287 } else if (style == 2) {
288 j = 0;
289 for (i = 0; i < nColumns; i++) {
290 if (strncmp(columnPrefix, columnNames[i], strlen(columnPrefix)) == 0) {
291 data[j] = SDDS_GetColumnInLong(&SDDS_dataset, columnNames[i]);
292 for (k = 0; k < rows; k++) {
293 if (data[j][k] > maxvalue) {
294 maxvalue = data[j][k];
295 }
296 }
297 j++;
298 }
299 }
300
301 if (!bit16) {
302 buffer = malloc(rows * linesFound * sizeof(char));
303 } else {
304 buffer16 = malloc(rows * linesFound * sizeof(uint16_t));
305 }
306
307 xDim = rows;
308 yDim = linesFound;
309 }
310
311 if (maxContrast) {
312 div = maxvalue / maxPossible;
313 } else if (maxvalue <= maxPossibleLong) {
314 div = 1;
315 } else if (maxvalue <= 3 * maxPossibleLong) {
316 div = 3;
317 } else {
318 div = maxvalue / maxPossible;
319 }
320
321 sprintf(outputName, "%s.%04ld", output, index);
322 tif = TIFFOpen(outputName, "w");
323 if (tif) {
324 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, xDim);
325 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, yDim);
326 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bit16 ? 16 : 8);
327 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
328 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, yDim);
329 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
330 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
331 TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
332 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
333 TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
334
335 if (style == 1) {
336 k = 0;
337 for (i = 0; i < xDim; i++) {
338 for (j = 0; j < yDim; j++) {
339 if (!bit16) {
340 buffer[xDim * (yDim - (j + 1)) + i] = (unsigned int)(round(data[0][k] / div));
341 } else {
342 buffer16[xDim * (yDim - (j + 1)) + i] = (uint16_t)(round(data[0][k] / div));
343 }
344 k++;
345 }
346 }
347 TIFFWriteEncodedStrip(tif, 0, bit16 ? (char *)buffer16 : buffer, rows * (bit16 ? 2 : 1));
348 } else if (style == 2) {
349 for (j = 0; j < yDim; j++) {
350 for (i = 0; i < xDim; i++) {
351 if (!bit16) {
352 buffer[j * xDim + i] = (unsigned int)(round(data[(yDim - j) - 1][i] / div));
353 } else {
354 buffer16[j * xDim + i] = (uint16_t)(round(data[(yDim - j) - 1][i] / div));
355 }
356 }
357 }
358 TIFFWriteEncodedStrip(tif, 0, bit16 ? (char *)buffer16 : buffer, xDim * yDim * (bit16 ? 2 : 1));
359 }
360 TIFFClose(tif);
361 }
362
363 if (buffer) {
364 free(buffer);
365 }
366 if (buffer16) {
367 free(buffer16);
368 }
369 if (style == 1) {
370 free(data[0]);
371 free(data);
372 } else if (style == 2) {
373 for (j = 0; j < yDim; j++) {
374 free(data[j]);
375 }
376 }
377
378 index++;
379 }
380
381 if (!SDDS_Terminate(&SDDS_dataset)) {
382 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
383 }
384
385 if (input) {
386 free(input);
387 }
388 if (output) {
389 free(output);
390 }
391 if (outputName) {
392 free(outputName);
393 }
394
395 for (i = 0; i < nColumns; i++) {
396 if (columnNames[i]) {
397 free(columnNames[i]);
398 }
399 }
400
401 if (columnNames) {
402 free(columnNames);
403 }
404
405 if (style == 2 && data) {
406 free(data);
407 }
408
409 free_scanargs(&s_arg, argc);
410 return 0;
411}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t * SDDS_GetParameterAsLong(SDDS_DATASET *SDDS_dataset, char *parameter_name, int32_t *memory)
Retrieves the value of a specified parameter as a 32-bit integer from the current data table of a dat...
int32_t * SDDS_GetColumnInLong(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of 32-bit integers,...
void * SDDS_GetParameter(SDDS_DATASET *SDDS_dataset, char *parameter_name, void *memory)
Retrieves the value of a specified parameter from the current data table of a data set.
int64_t * SDDS_GetParameterAsLong64(SDDS_DATASET *SDDS_dataset, char *parameter_name, int64_t *memory)
Retrieves the value of a specified parameter as a 64-bit integer from the current data table of an SD...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
char ** SDDS_GetColumnNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all columns in the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
int32_t SDDS_CheckParameter(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a parameter exists in the SDDS dataset with the specified name, units, and type.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:856
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:584