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