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