summaryrefslogtreecommitdiff
path: root/toolbin/halftone/gen_ordered/gen_ordered_main.c
blob: e792ebdcd8075fd37d989a0934d97100b38851af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
/* Copyright (C) 2001-2020 Artifex Software, Inc.
   All Rights Reserved.

   This software is provided AS-IS with no warranty, either express or
   implied.

   This software is distributed under license and may not be copied,
   modified or distributed except as expressly authorized under the terms
   of the license contained in the file LICENSE in this distribution.

   Refer to licensing information at http://www.artifex.com or contact
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
   CA 94945, U.S.A., +1(415)492-9861, for further information.
*/
/* Ordered Dither Screen Creation Tool. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <sys/stat.h>
#include <math.h>

typedef unsigned char byte;
#define false 0
#define true 1
#ifndef __cplusplus
    typedef int bool;
#endif	/* __cpluplus */

/* included from base/gen_ordered.h */
#include "gen_ordered.h"

static int htsc_save_tos(htsc_dig_grid_t *final_mask);
static int htsc_save_screen(htsc_dig_grid_t *final_mask, bool use_holladay_grid, int S,
                      htsc_param_t params);

/* -------------------------  _snprintf -----------------------------*/

#if defined(_MSC_VER)
#  if _MSC_VER>=1900 /* VS 2014 and later have (finally) snprintf */
#     define STDC99
#  else /* _MSC_VER >= 1900 */
      /* Microsoft Visual C++ 2005  doesn't properly define snprintf,
         which is defined in the C standard ISO/IEC 9899:1999 (E) */

      #include <stdarg.h>

      int snprintf(char *buffer, size_t count, const char *format, ...)
      {
          if (count > 0) {
              va_list args;
              int n;

              va_start(args, format);
              n = _vsnprintf(buffer, count, format, args);
              buffer[count - 1] = 0;
              va_end(args);
              return n;
          } else
              return 0;
      }
#  endif /* _MSC_VER >= 1900 */
#endif /* defined _MSC_VER */

static int
usage (void)
{
    printf ("Usage: gen_ordered [-a target_angle] [-l target_lpi] [-q target_quantization_levels] \n");
    printf ("                 [-r WxH] [-s size_of_supercell] [-d dot_shape_code] -v verbosity\n");
    printf ("                 [ -f [ps | ppm | raw | raw16 | tos] ]\n");
    printf ("a is the desired angle in degrees for the screen\n");
    printf ("b is the desired bit depth of the output threshold\n");
    printf ("  valid only with -ps or the default raw output\n");
    printf ("dot shape codes are as follows: \n");
    printf ("0  CIRCLE \n");
    printf ("1  REDBOOK CIRCLE \n");
    printf ("2  INVERTED \n");
    printf ("3  RHOMBOID \n");
    printf ("4  LINE_X \n");
    printf ("5  LINE_Y \n");
    printf ("6  DIAMOND1 \n");
    printf ("7  DIAMOND2 \n");
    printf ("8  ROUNDSPOT \n");
    printf ("f [tos | ppm | ps | raw] is the output format\n");
    printf ("     If no output format is indicate a turn on sequence output will be created\n");
    printf ("   ppm is an Portable Pixmap image file\n");
    printf ("   ps indicates postscript style output file\n");
    printf ("   raw is a raw 8-bit binary, row major file\n");
    printf ("   tos indicates to output a turn on sequence which can\n");
    printf ("     be fed into thresh_remap to apply a linearization curve.\n");
    printf ("l is the desired lines per inch (lpi)\n");
    printf ("q is the desired number of quantization (gray) levels\n");
    printf ("r is the device resolution in dots per inch (dpi)\n");
    printf ("  use a single number for r if the resolution is symmetric\n");
    printf ("s is the desired size of the super cell\n");
    printf ("v is the verbosity level. Default is 0 which is error messages only.\n");
    return 1;
}

/* Return the pointer to the value for an argument, either at 'arg' or the next argv */
/* Allows for either -ovalue or -o value option syntax */
/* Returns NULL if there is no value (at end of argc arguments) */
static const char *
get_arg (int argc, char **argv, int *pi, const char *arg)
{
    if (arg[0] != 0) {
        return arg;
    } else {
      (*pi)++;
      if (*pi == argc) {
        return NULL;
      } else {
        return argv[*pi];
      }
    }
}

int
main (int argc, char **argv)
{
    int code, i, j, k, m, S;
    htsc_param_t params;
    htsc_dig_grid_t final_mask;

    htsc_set_default_params(&params);

    for (i = 1; i < argc; i++) {
      const char *arg = argv[i];
      const char *arg_value;

      if (arg[0] == '-') {
          switch (arg[1]) {
            case 'a':
              if ((arg_value = get_arg(argc, argv, &i, arg + 2)) == NULL)
                  goto usage_exit;
              params.targ_scr_ang = atoi(arg_value);
              break;
            case 'f':
              if ((arg_value = get_arg(argc, argv, &i, arg + 2)) == NULL)
                  goto usage_exit;
              switch (arg_value[0]) {
                  case 'p':
                    params.output_format = (arg_value[1] == 's') ?
                                            OUTPUT_PS : OUTPUT_PPM;
                    break;
                  case 'r':
                    j = sscanf(arg_value, "raw%d", &k);
                    if (j == 0 || k == 8)
                        params.output_format = OUTPUT_RAW;
                    else
                        params.output_format = OUTPUT_RAW16;
                    break;
                  case 't':
                    params.output_format = OUTPUT_TOS;
                    break;
                  default:
                    goto usage_exit;
              }
              break;
            case 'd':
              if ((arg_value = get_arg(argc, argv, &i, arg + 2)) == NULL)
                  goto usage_exit;
              j = atoi(arg_value);
              if (j < 0 || j > CUSTOM)
                  params.spot_type = CIRCLE;
              else
                  params.spot_type = j;
              break;
            case 'l':
              if ((arg_value = get_arg(argc, argv, &i, arg + 2)) == NULL)
                  goto usage_exit;
              params.targ_lpi = atoi(arg_value);
              break;
            case 'q':
              if ((arg_value = get_arg(argc, argv, &i, arg + 2)) == NULL)
                  goto usage_exit;
              params.targ_quant = atoi(arg_value);
              params.targ_quant_spec = true;
              break;
            case 'r':
              if ((arg_value = get_arg(argc, argv, &i, arg + 2)) == NULL)
                  goto usage_exit;
              j = sscanf(arg_value, "%dx%d", &k, &m);
              if (j < 1)
                  goto usage_exit;
              params.horiz_dpi = k;
              if (j > 1) {
                  params.vert_dpi = m;
              } else {
                  params.vert_dpi = k;
              }
              break;
            case 's':
              if ((arg_value = get_arg(argc, argv, &i, arg + 2)) == NULL)
                  goto usage_exit;
              params.targ_size = atoi(arg_value);
              params.targ_size_spec = true;
              break;
            case 'v':
              if ((arg_value = get_arg(argc, argv, &i, arg + 2)) == NULL)
                  goto usage_exit;
              params.verbose = atoi(arg_value);
              break;
            default:
usage_exit:   return usage();
            }
        }
    }
    final_mask.memory = NULL;				/* quiet compiler */
    code = htsc_gen_ordered(params, &S, &final_mask);

    if (code >= 0)
        code = htsc_save_screen(&final_mask, params.holladay, S, params);

    if (final_mask.data != NULL)
        free(final_mask.data);

    return code;
}

/* Save turn on order list, Assume that htsc_gen_ordered has already converted to TOS */
static int
htsc_save_tos(htsc_dig_grid_t *final_mask)
{
    int width = final_mask->width;
    int height = final_mask->height;
    int *buff_ptr;
    FILE *fid;
    int k = 0;
    int count= height * width;

    fid = fopen("turn_on_seq.out","w");
    fprintf(fid,"# W=%d H=%d\n",width, height);

    /* Write out */
    buff_ptr = final_mask->data;
    for (k = 0; k < count; k++) {
        fprintf(fid,"%d\t%d\n", *buff_ptr++, *buff_ptr++);
    }
    fclose(fid);
    return 0;
}

static int
htsc_save_screen(htsc_dig_grid_t *final_mask, bool use_holladay_grid, int S,
                htsc_param_t params)
{
    char full_file_name[FULL_FILE_NAME_LENGTH];
    FILE *fid;
    int x,y, code = 0;
    int *buff_ptr = final_mask->data;
    int width = final_mask->width;
    int height = final_mask->height;
    byte data;
    unsigned short data_short;
    output_format_type output_format = params.output_format;
    char *output_extension = (output_format == OUTPUT_PS) ? "ps" :
                        ((output_format == OUTPUT_PPM) ? "ppm" :
                        ((output_format == OUTPUT_RAW16 ? "16.raw" : "raw")));

    if (output_format == OUTPUT_TOS) {
        /* We need to figure out the turn-on sequence from the threshold
           array */
        code = htsc_save_tos(final_mask);
    } else {
        if (use_holladay_grid) {
            snprintf(full_file_name, FULL_FILE_NAME_LENGTH, "Screen_Holladay_Shift%d_%dx%d.%s", S, width,
                    height, output_extension);
        } else {
            snprintf(full_file_name, FULL_FILE_NAME_LENGTH, "Screen_Dithered_%dx%d.%s",width,height,
                    output_extension);
        }
        fid = fopen(full_file_name,"wb");

        if (output_format == OUTPUT_PPM)
            fprintf(fid, "P5\n"
                    "# Halftone threshold array, %s, [%d, %d], S=%d\n"
                    "%d %d\n"
                    "255\n",
                    use_holladay_grid ? "Holladay_Shift" : "Dithered", width, height,
                    S, width, height);
        if (output_format != OUTPUT_PS) {
            /* Both BIN and PPM format write the same binary data */
            if (output_format == OUTPUT_RAW || output_format == OUTPUT_PPM) {
                for (y = 0; y < height; y++) {
                    for ( x = 0; x < width; x++ ) {
                        data_short = (unsigned short) (*buff_ptr & 0xffff);
                        data_short = ROUND((double) data_short * 255.0 / MAXVAL);
                        if (data_short > 255) data_short = 255;
                        data = (byte) (data_short & 0xff);
                        fwrite(&data, sizeof(byte), 1, fid);
                        buff_ptr++;
                    }
                }
            } else {	/* raw16 data */
                for (y = 0; y < height; y++) {
                    for ( x = 0; x < width; x++ ) {
                        data_short = (unsigned short) (*buff_ptr & 0xffff);
                        fwrite(&data_short, sizeof(short), 1, fid);
                        buff_ptr++;
                    }
                }
            }
        } else {	/* ps output format */
            if (params.targ_quant <= 256) {
                /* Output PS HalftoneType 3 dictionary */
                fprintf(fid, "%%!PS\n"
                        "<< /HalftoneType 3\n"
                        "   /Width  %d\n"
                        "   /Height %d\n"
                        "   /Thresholds <\n",
                        width, height);

                for (y = 0; y < height; y++) {
                    for ( x = 0; x < width; x++ ) {
                        data_short = (unsigned short) (*buff_ptr & 0xffff);
                        data_short = ROUND((double) data_short * 255.0 / MAXVAL);
                        if (data_short > 255) data_short = 255;
                        data = (byte) (data_short & 0xff);
                        fprintf(fid, "%02x", data);
                        buff_ptr++;
                        if ((x & 0x1f) == 0x1f && (x != (width - 1)))
                            fprintf(fid, "\n");
                    }
                    fprintf(fid, "\n");
                }
                fprintf(fid, "   >\n"
                        ">>\n"
                        );
            } else {
                /* Output PS HalftoneType 16 dictionary. Single array. */
                fprintf(fid, "%%!PS\n"
                        "%% Create a 'filter' from local hex data\n"
                        "{ currentfile /ASCIIHexDecode filter /ReusableStreamDecode filter } exec\n");
                /* hex data follows, 'file' object will be left on stack */
                for (y = 0; y < height; y++) {
                    for ( x = 0; x < width; x++ ) {
                        data_short = (unsigned short) (*buff_ptr & 0xffff);
                        fprintf(fid, "%04x", data_short);
                        buff_ptr++;
                        if ((x & 0x1f) == 0x1f && (x != (width - 1)))
                            fprintf(fid, "\n");
                    }
                    fprintf(fid, "\n");	/* end of one row */
                }
                fprintf(fid, ">\n");	/* ASCIIHexDecode EOF */
                fprintf(fid,
                        "<< /Thresholds 2 index    %% file object for the 16-bit data\n"
                        "   /HalftoneType 16\n"
                        "   /Width  %d\n"
                        "   /Height %d\n"
                        ">>\n"
                        "exch pop     %% discard ResuableStreamDecode file leaving the Halftone dict.\n",
                        width, height);
            }
        }
        fclose(fid);
    }
    return code;
}