1 /* This is a plugin for GIMP.
2 *
3 * Copyright (C) 1997 Jochen Friedrich
4 * Parts Copyright (C) 1995 Gert Doering
5 * Parts Copyright (C) 1995 Spencer Kimball and Peter Mattis
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <errno.h>
24 #include <string.h>
25
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29
30 #include <sys/types.h>
31 #include <fcntl.h>
32
33 #include <glib.h> /* For G_OS_WIN32 */
34 #include <glib/gstdio.h>
35
36 #ifdef G_OS_WIN32
37 #include <io.h>
38 #endif
39
40 #ifndef _O_BINARY
41 #define _O_BINARY 0
42 #endif
43
44 #include <libgimp/gimp.h>
45
46 #include "g3.h"
47
48 #include "libgimp/stdplugins-intl.h"
49
50
51 #define LOAD_PROC "file-faxg3-load"
52 #define VERSION "0.6"
53
54 /* Declare local functions.
55 */
56
57 static void query (void);
58 static void run (const gchar *name,
59 gint nparams,
60 const GimpParam *param,
61 gint *nreturn_vals,
62 GimpParam **return_vals);
63
64 static gint32 load_image (const gchar *filename,
65 GError **error);
66
67 static gint32 emitgimp (gint hcol,
68 gint row,
69 const gchar *bitmap,
70 gint bperrow,
71 const gchar *filename,
72 GError **error);
73
74
75 const GimpPlugInInfo PLUG_IN_INFO =
76 {
77 NULL, /* init_proc */
78 NULL, /* quit_proc */
79 query, /* query_proc */
80 run, /* run_proc */
81 };
82
MAIN()83 MAIN ()
84
85 void
86 query (void)
87 {
88 static const GimpParamDef load_args[] =
89 {
90 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
91 { GIMP_PDB_STRING, "filename", "The name of the file to load" },
92 { GIMP_PDB_STRING, "raw-filename", "The name of the file to load" },
93 };
94 static const GimpParamDef load_return_vals[] =
95 {
96 { GIMP_PDB_IMAGE, "image", "Output image" },
97 };
98
99 gimp_install_procedure (LOAD_PROC,
100 "loads g3 fax files",
101 "This plug-in loads Fax G3 Image files.",
102 "Jochen Friedrich",
103 "Jochen Friedrich, Gert Doering, Spencer Kimball & Peter Mattis",
104 VERSION,
105 N_("G3 fax image"),
106 NULL,
107 GIMP_PLUGIN,
108 G_N_ELEMENTS (load_args),
109 G_N_ELEMENTS (load_return_vals),
110 load_args, load_return_vals);
111
112 gimp_register_file_handler_mime (LOAD_PROC, "image/g3-fax");
113 gimp_register_magic_load_handler (LOAD_PROC,
114 "g3",
115 "",
116 "4,string,Research");
117 }
118
119 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)120 run (const gchar *name,
121 gint nparams,
122 const GimpParam *param,
123 gint *nreturn_vals,
124 GimpParam **return_vals)
125 {
126 static GimpParam values[2];
127 gint32 image_ID;
128 GError *error = NULL;
129
130 INIT_I18N ();
131 gegl_init (NULL, NULL);
132
133 *nreturn_vals = 1;
134 *return_vals = values;
135
136 values[0].type = GIMP_PDB_STATUS;
137 values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
138
139 if (strcmp (name, LOAD_PROC) == 0)
140 {
141 image_ID = load_image (param[1].data.d_string, &error);
142
143 if (image_ID != -1)
144 {
145 *nreturn_vals = 2;
146
147 values[0].data.d_status = GIMP_PDB_SUCCESS;
148 values[1].type = GIMP_PDB_IMAGE;
149 values[1].data.d_image = image_ID;
150 }
151 else
152 {
153 values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
154
155 if (error)
156 {
157 *nreturn_vals = 2;
158
159 values[1].type = GIMP_PDB_STRING;
160 values[1].data.d_string = error->message;
161 }
162 }
163 }
164 }
165
166 #ifdef DEBUG
167 void
putbin(unsigned long d)168 putbin (unsigned long d)
169 {
170 unsigned long i = 0x80000000;
171
172 while (i != 0)
173 {
174 putc((d & i) ? '1' : '0', stderr);
175 i >>= 1;
176 }
177 putc('\n', stderr);
178 }
179 #endif
180
181 static int byte_tab[256];
182 /* static int o_stretch; */ /* -stretch: double each line */
183 /* static int o_stretch_force=-1; */ /* -1: guess from filename */
184 /* static int o_lj; */ /* -l: LJ output */
185 /* static int o_turn; */ /* -t: turn 90 degrees right */
186
187 struct g3_tree * black, * white;
188
189 #define CHUNK 2048;
190 static char rbuf[2048]; /* read buffer */
191 static int rp; /* read pointer */
192 static int rs; /* read buffer size */
193
194 #define MAX_ROWS 4300
195 #define MAX_COLS 1728 /* !! FIXME - command line parameter */
196
197
198 static gint32
load_image(const gchar * filename,GError ** error)199 load_image (const gchar *filename,
200 GError **error)
201 {
202 int data;
203 int hibit;
204 struct g3_tree *p;
205 int nr_pels;
206 int fd;
207 int color;
208 int i, rr, rsize;
209 int cons_eol;
210 int last_eol_row;
211
212 gint32 image_id;
213 gint bperrow = MAX_COLS/8; /* bytes per bit row */
214 gchar *bitmap; /* MAX_ROWS by (bperrow) bytes */
215 gchar *bp; /* bitmap pointer */
216 gint row;
217 gint max_rows; /* max. rows allocated */
218 gint col, hcol; /* column, highest column ever used */
219
220 gimp_progress_init_printf (_("Opening '%s'"),
221 gimp_filename_to_utf8 (filename));
222
223 /* initialize lookup trees */
224 build_tree (&white, t_white);
225 build_tree (&white, m_white);
226 build_tree (&black, t_black);
227 build_tree (&black, m_black);
228
229 init_byte_tab (0, byte_tab);
230
231 fd = g_open (filename, O_RDONLY | _O_BINARY, 0);
232
233 if (fd < 0)
234 {
235 g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
236 _("Could not open '%s' for reading: %s"),
237 gimp_filename_to_utf8 (filename), g_strerror (errno));
238 return -1;
239 }
240
241 hibit = 0;
242 data = 0;
243
244 cons_eol = 0; /* consecutive EOLs read - zero yet */
245 last_eol_row = 0;
246
247 color = 0; /* start with white */
248 rr = 0;
249
250 rsize = lseek (fd, 0L, SEEK_END);
251 lseek (fd, 0L, 0);
252
253 rs = read (fd, rbuf, sizeof (rbuf));
254 if (rs < 0)
255 {
256 perror ("read");
257 close (fd);
258 gimp_quit ();
259 }
260
261 rr += rs;
262 gimp_progress_update ((float) rr / rsize / 2.0);
263
264 /* skip GhostScript header */
265 rp = (rs >= 64 && strcmp (rbuf + 1, "PC Research, Inc") == 0) ? 64 : 0;
266
267 /* initialize bitmap */
268
269 row = col = hcol = 0;
270
271 bitmap = g_new0 (gchar, (max_rows = MAX_ROWS) * MAX_COLS / 8);
272 if (! bitmap)
273 {
274 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
275 _("Could not create buffer to process image data."));
276 return -1;
277 }
278
279 bp = &bitmap[row * MAX_COLS / 8];
280
281 while (rs > 0 && cons_eol < 10) /* i.e., while (!EOF) */
282 {
283 #ifdef DEBUG
284 g_printerr ("hibit=%2d, data=", hibit);
285 putbin (data);
286 #endif
287
288 while (hibit < 20)
289 {
290 data |= (byte_tab[(int) (unsigned char) rbuf[rp++]] << hibit);
291 hibit += 8;
292
293 if (rp >= rs)
294 {
295 rs = read (fd, rbuf, sizeof (rbuf));
296 if (rs < 0)
297 { perror ("read2");
298 break;
299 }
300 rr += rs;
301 gimp_progress_update ((float) rr / rsize / 2.0);
302 rp = 0;
303 if (rs == 0)
304 goto do_write;
305 }
306
307 #ifdef DEBUG
308 g_printerr ("hibit=%2d, data=", hibit);
309 putbin (data);
310 #endif
311 }
312
313 if (color == 0) /* white */
314 p = white->nextb[data & BITM];
315 else /* black */
316 p = black->nextb[data & BITM];
317
318 while (p != NULL && ! (p->nr_bits))
319 {
320 data >>= FBITS;
321 hibit -= FBITS;
322 p = p->nextb[data & BITM];
323 }
324
325 if (p == NULL) /* invalid code */
326 {
327 g_printerr ("invalid code, row=%d, col=%d, file offset=%lx, skip to eol\n",
328 row, col, (unsigned long) lseek (fd, 0, 1) - rs + rp);
329
330 while ((data & 0x03f) != 0)
331 {
332 data >>= 1; hibit--;
333
334 if ( hibit < 20 )
335 {
336 data |= (byte_tab[(int) (unsigned char) rbuf[rp++]] << hibit);
337 hibit += 8;
338
339 if (rp >= rs) /* buffer underrun */
340 {
341 rs = read (fd, rbuf, sizeof (rbuf));
342
343 if (rs < 0)
344 { perror ("read4");
345 break;
346 }
347
348 rr += rs;
349 gimp_progress_update ((float) rr / rsize / 2.0);
350 rp = 0;
351 if (rs == 0)
352 goto do_write;
353 }
354 }
355 }
356 nr_pels = -1; /* handle as if eol */
357 }
358 else /* p != NULL <-> valid code */
359 {
360 data >>= p->nr_bits;
361 hibit -= p->nr_bits;
362
363 nr_pels = ((struct g3_leaf *) p)->nr_pels;
364 #ifdef DEBUG
365 g_printerr ("PELs: %d (%c)\n", nr_pels, '0' + color);
366 #endif
367 }
368
369 /* handle EOL (including fill bits) */
370 if (nr_pels == -1)
371 {
372 #ifdef DEBUG
373 g_printerr ("hibit=%2d, data=", hibit);
374 putbin (data);
375 #endif
376 /* skip filler 0bits -> seek for "1"-bit */
377 while ((data & 0x01) != 1)
378 {
379 if ((data & 0xf) == 0) /* nibble optimization */
380 {
381 hibit-= 4;
382 data >>= 4;
383 }
384 else
385 {
386 hibit--;
387 data >>= 1;
388 }
389
390 /* fill higher bits */
391 if (hibit < 20)
392 {
393 data |= ( byte_tab[(int) (unsigned char) rbuf[ rp++]] << hibit);
394 hibit += 8;
395
396 if (rp >= rs) /* buffer underrun */
397 {
398 rs = read (fd, rbuf, sizeof (rbuf));
399 if ( rs < 0 )
400 {
401 perror ("read3");
402 break;
403 }
404 rr += rs;
405 gimp_progress_update ((float) rr / rsize / 2.0);
406 rp = 0;
407 if (rs == 0)
408 goto do_write;
409 }
410 }
411 #ifdef DEBUG
412 g_printerr ("hibit=%2d, data=", hibit );
413 putbin(data);
414 #endif
415 } /* end skip 0bits */
416 hibit--;
417 data >>=1;
418
419 color = 0;
420
421 if (col == 0)
422 {
423 if (last_eol_row != row)
424 {
425 cons_eol++; /* consecutive EOLs */
426 last_eol_row = row;
427 }
428 }
429 else
430 {
431 if (col > hcol && col <= MAX_COLS)
432 hcol = col;
433 row++;
434
435 /* bitmap memory full? make it larger! */
436 if (row >= max_rows)
437 {
438 gchar *p = g_try_realloc (bitmap,
439 (max_rows += 500) * MAX_COLS / 8);
440 if (p == NULL)
441 {
442 perror ("realloc() failed, page truncated");
443 rs = 0;
444 }
445 else
446 {
447 bitmap = p;
448 memset (&bitmap[ row * MAX_COLS / 8 ], 0,
449 (max_rows - row) * MAX_COLS / 8);
450 }
451 }
452
453 col=0; bp = &bitmap[row * MAX_COLS / 8];
454 cons_eol = 0;
455 }
456 }
457 else /* not eol */
458 {
459 if (col + nr_pels > MAX_COLS)
460 nr_pels = MAX_COLS - col;
461
462 if (color == 0) /* white */
463 {
464 col += nr_pels;
465 }
466 else /* black */
467 {
468 register int bit = (0x80 >> (col & 07));
469 register char *w = & bp[col >> 3];
470
471 for (i = nr_pels; i > 0; i--)
472 {
473 *w |= bit;
474 bit >>=1;
475 if (bit == 0)
476 {
477 bit = 0x80;
478 w++;
479 }
480 col++;
481 }
482 }
483
484 if (nr_pels < 64)
485 color = !color; /* terminating code */
486 }
487 } /* end main loop */
488
489 do_write: /* write pbm (or whatever) file */
490
491 if (fd != 0)
492 close (fd); /* close input file */
493
494 #ifdef DEBUG
495 g_printerr ("consecutive EOLs: %d, max columns: %d\n", cons_eol, hcol);
496 #endif
497
498 image_id = emitgimp (hcol, row, bitmap, bperrow, filename, error);
499
500 g_free (bitmap);
501
502 return image_id;
503 }
504
505 /* hcol is the number of columns, row the number of rows
506 * bperrow is the number of bytes actually used by hcol, which may
507 * be greater than (hcol+7)/8 [in case of an unscaled g3 image less
508 * than 1728 pixels wide]
509 */
510
511 static gint32
emitgimp(gint hcol,gint row,const gchar * bitmap,gint bperrow,const gchar * filename,GError ** error)512 emitgimp (gint hcol,
513 gint row,
514 const gchar *bitmap,
515 gint bperrow,
516 const gchar *filename,
517 GError **error)
518 {
519 GeglBuffer *buffer;
520 gint32 image_ID;
521 gint32 layer_ID;
522 guchar *buf;
523 guchar tmp;
524 gint x, y;
525 gint xx, yy;
526 gint tile_height;
527
528 /* initialize */
529
530 tmp = 0;
531
532 #ifdef DEBUG
533 g_printerr ("emit gimp: %d x %d\n", hcol, row);
534 #endif
535
536 if (hcol > GIMP_MAX_IMAGE_SIZE || hcol <= 0 ||
537 row > GIMP_MAX_IMAGE_SIZE || row <= 0)
538 {
539 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
540 _("Invalid image dimensions (%d x %d). "
541 "Image may be corrupt."),
542 hcol, row);
543 return -1;
544 }
545
546 image_ID = gimp_image_new (hcol, row, GIMP_GRAY);
547 if (image_ID == -1)
548 {
549 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
550 _("Could not create image."));
551 return -1;
552 }
553 gimp_image_set_filename (image_ID, filename);
554
555 layer_ID = gimp_layer_new (image_ID, _("Background"),
556 hcol,
557 row,
558 GIMP_GRAY_IMAGE,
559 100,
560 gimp_image_get_default_new_layer_mode (image_ID));
561 gimp_image_insert_layer (image_ID, layer_ID, -1, 0);
562
563 buffer = gimp_drawable_get_buffer (layer_ID);
564
565 tile_height = gimp_tile_height ();
566 #ifdef DEBUG
567 g_printerr ("tile height: %d\n", tile_height);
568 #endif
569
570 buf = g_new (guchar, hcol * tile_height);
571 if (! buf)
572 {
573 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
574 _("Could not create buffer to process image data."));
575 g_object_unref (buffer);
576 gimp_image_delete(image_ID);
577 return -1;
578 }
579
580 xx = 0;
581 yy = 0;
582
583 for (y = 0; y < row; y++)
584 {
585 for (x = 0; x < hcol; x++)
586 {
587 if ((x & 7) == 0)
588 tmp = bitmap[y * bperrow + (x >> 3)];
589
590 buf[xx++] = tmp&(128 >> (x & 7)) ? 0 : 255;
591 }
592
593 if ((y - yy) == tile_height - 1)
594 {
595 #ifdef DEBUG
596 g_printerr ("update tile height: %d\n", tile_height);
597 #endif
598
599 gegl_buffer_set (buffer, GEGL_RECTANGLE (0, yy, hcol, tile_height), 0,
600 NULL, buf, GEGL_AUTO_ROWSTRIDE);
601
602 gimp_progress_update (0.5 + (float) y / row / 2.0);
603
604 xx = 0;
605 yy += tile_height;
606 }
607 }
608
609 if (row - yy)
610 {
611 #ifdef DEBUG
612 g_printerr ("update rest: %d\n", row-yy);
613 #endif
614
615 gegl_buffer_set (buffer, GEGL_RECTANGLE (0, yy, hcol, row - yy), 0,
616 NULL, buf, GEGL_AUTO_ROWSTRIDE);
617 }
618
619 gimp_progress_update (1.0);
620
621 g_free (buf);
622
623 g_object_unref (buffer);
624
625 return image_ID;
626 }
627