aboutsummaryrefslogtreecommitdiff
path: root/lib/fax-encoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fax-encoder.cc')
-rw-r--r--lib/fax-encoder.cc411
1 files changed, 411 insertions, 0 deletions
diff --git a/lib/fax-encoder.cc b/lib/fax-encoder.cc
new file mode 100644
index 0000000..90abe8c
--- /dev/null
+++ b/lib/fax-encoder.cc
@@ -0,0 +1,411 @@
+// fax-encoder.cc -- convert scanlines to fascimile format
+// Copyright (C) 2008 SEIKO EPSON CORPORATION
+//
+// This file is part of the 'iscan' program.
+//
+// The 'iscan' program is free-ish software.
+// You can redistribute it and/or modify it under the terms of the GNU
+// General Public License as published by the Free Software Foundation;
+// either version 2 of the License or at your option any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS
+// FOR A PARTICULAR PURPOSE or MERCHANTABILITY.
+// See the GNU General Public License for more details.
+//
+// You should have received a verbatim copy of the GNU General Public
+// License along with this program; if not, write to:
+//
+// Free Software Foundation, Inc.
+// 59 Temple Place, Suite 330
+// Boston, MA 02111-1307 USA
+//
+// As a special exception, the copyright holders give permission
+// to link the code of this program with the esmod library and
+// distribute linked combinations including the two. You must obey
+// the GNU General Public License in all respects for all of the
+// code used other then esmod.
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "fax-encoder.hh"
+
+#include <vector>
+#include <stdint.h>
+
+#define WHITE false
+#define BLACK true
+
+namespace iscan
+{
+ using namespace std;
+
+ struct code {
+ unsigned int bits;
+ unsigned int code;
+ };
+
+ static const size_t g3_make_up_min = 64;
+ static const size_t g3_make_up_inc = 64;
+ static const size_t g3_extra_make_up_min = 1792;
+ static const size_t g3_extra_make_up_max = 2560;
+
+ //! Terminating codes for white runs of less than 64 pixels.
+ static const struct code g3_white_terminal[] =
+ {
+ { 8, 0x35 },
+ { 6, 0x07 },
+ { 4, 0x07 },
+ { 4, 0x08 },
+ { 4, 0x0b },
+ { 4, 0x0c },
+ { 4, 0x0e },
+ { 4, 0x0f },
+ { 5, 0x13 },
+ { 5, 0x14 },
+ { 5, 0x07 },
+ { 5, 0x08 },
+ { 6, 0x08 },
+ { 6, 0x03 },
+ { 6, 0x34 },
+ { 6, 0x35 },
+ { 6, 0x2a },
+ { 6, 0x2b },
+ { 7, 0x27 },
+ { 7, 0x0c },
+ { 7, 0x08 },
+ { 7, 0x17 },
+ { 7, 0x03 },
+ { 7, 0x04 },
+ { 7, 0x28 },
+ { 7, 0x2b },
+ { 7, 0x13 },
+ { 7, 0x24 },
+ { 7, 0x18 },
+ { 8, 0x02 },
+ { 8, 0x03 },
+ { 8, 0x1a },
+ { 8, 0x1b },
+ { 8, 0x12 },
+ { 8, 0x13 },
+ { 8, 0x14 },
+ { 8, 0x15 },
+ { 8, 0x16 },
+ { 8, 0x17 },
+ { 8, 0x28 },
+ { 8, 0x29 },
+ { 8, 0x2a },
+ { 8, 0x2b },
+ { 8, 0x2c },
+ { 8, 0x2d },
+ { 8, 0x04 },
+ { 8, 0x05 },
+ { 8, 0x0a },
+ { 8, 0x0b },
+ { 8, 0x52 },
+ { 8, 0x53 },
+ { 8, 0x54 },
+ { 8, 0x55 },
+ { 8, 0x24 },
+ { 8, 0x25 },
+ { 8, 0x58 },
+ { 8, 0x59 },
+ { 8, 0x5a },
+ { 8, 0x5b },
+ { 8, 0x4a },
+ { 8, 0x4b },
+ { 8, 0x32 },
+ { 8, 0x33 },
+ { 8, 0x34 },
+ };
+
+ //! Terminating codes for black runs of less than 64 pixels.
+ static const struct code g3_black_terminal[] =
+ {
+ { 10, 0x37 },
+ { 3, 0x02 },
+ { 2, 0x03 },
+ { 2, 0x02 },
+ { 3, 0x03 },
+ { 4, 0x03 },
+ { 4, 0x02 },
+ { 5, 0x03 },
+ { 6, 0x05 },
+ { 6, 0x04 },
+ { 7, 0x04 },
+ { 7, 0x05 },
+ { 7, 0x07 },
+ { 8, 0x04 },
+ { 8, 0x07 },
+ { 9, 0x18 },
+ { 10, 0x17 },
+ { 10, 0x18 },
+ { 10, 0x08 },
+ { 11, 0x67 },
+ { 11, 0x68 },
+ { 11, 0x6c },
+ { 11, 0x37 },
+ { 11, 0x28 },
+ { 11, 0x17 },
+ { 11, 0x18 },
+ { 12, 0xca },
+ { 12, 0xcb },
+ { 12, 0xcc },
+ { 12, 0xcd },
+ { 12, 0x68 },
+ { 12, 0x69 },
+ { 12, 0x6a },
+ { 12, 0x6b },
+ { 12, 0xd2 },
+ { 12, 0xd3 },
+ { 12, 0xd4 },
+ { 12, 0xd5 },
+ { 12, 0xd6 },
+ { 12, 0xd7 },
+ { 12, 0x6c },
+ { 12, 0x6d },
+ { 12, 0xda },
+ { 12, 0xdb },
+ { 12, 0x54 },
+ { 12, 0x55 },
+ { 12, 0x56 },
+ { 12, 0x57 },
+ { 12, 0x64 },
+ { 12, 0x65 },
+ { 12, 0x52 },
+ { 12, 0x53 },
+ { 12, 0x24 },
+ { 12, 0x37 },
+ { 12, 0x38 },
+ { 12, 0x27 },
+ { 12, 0x28 },
+ { 12, 0x58 },
+ { 12, 0x59 },
+ { 12, 0x2b },
+ { 12, 0x2c },
+ { 12, 0x5a },
+ { 12, 0x66 },
+ { 12, 0x67 },
+ };
+
+ //! Make up codes for white runs of 64 to 1728 + 63 pixels.
+ static const struct code g3_white_make_up[] =
+ { // runlength 64 + index * 64
+ { 5, 0x1b },
+ { 5, 0x12 },
+ { 6, 0x17 },
+ { 7, 0x37 },
+ { 8, 0x36 },
+ { 8, 0x37 },
+ { 8, 0x64 },
+ { 8, 0x65 },
+ { 8, 0x68 },
+ { 8, 0x67 },
+ { 9, 0xcc },
+ { 9, 0xcd },
+ { 9, 0xd2 },
+ { 9, 0xd3 },
+ { 9, 0xd4 },
+ { 9, 0xd5 },
+ { 9, 0xd6 },
+ { 9, 0xd7 },
+ { 9, 0xd8 },
+ { 9, 0xd9 },
+ { 9, 0xda },
+ { 9, 0xdb },
+ { 9, 0x98 },
+ { 9, 0x99 },
+ { 9, 0x9a },
+ { 6, 0x18 },
+ { 9, 0x9b },
+ };
+
+ //! Make up codes for black runs of 64 to 1728 + 63 pixels.
+ static const struct code g3_black_make_up[] =
+ { // runlength 64 + index * 64
+ { 10, 0x0f },
+ { 12, 0xc8 },
+ { 12, 0xc9 },
+ { 12, 0x5b },
+ { 12, 0x33 },
+ { 12, 0x34 },
+ { 12, 0x35 },
+ { 13, 0x6c },
+ { 13, 0x6d },
+ { 13, 0x4a },
+ { 13, 0x4b },
+ { 13, 0x4c },
+ { 13, 0x4d },
+ { 13, 0x72 },
+ { 13, 0x73 },
+ { 13, 0x74 },
+ { 13, 0x75 },
+ { 13, 0x76 },
+ { 13, 0x77 },
+ { 13, 0x52 },
+ { 13, 0x53 },
+ { 13, 0x54 },
+ { 13, 0x55 },
+ { 13, 0x5a },
+ { 13, 0x5b },
+ { 13, 0x64 },
+ { 13, 0x65 },
+ };
+
+ //! Additional make up codes for run of more than 1792 pixels.
+ static const struct code g3_extra_make_up[] =
+ { // runlength 1792 + index * 64
+ { 11, 0x08 },
+ { 11, 0x0c },
+ { 11, 0x0d },
+ { 12, 0x12 },
+ { 12, 0x13 },
+ { 12, 0x14 },
+ { 12, 0x15 },
+ { 12, 0x16 },
+ { 12, 0x17 },
+ { 12, 0x1c },
+ { 12, 0x1d },
+ { 12, 0x1e },
+ { 12, 0x1f },
+ };
+
+ static string transform (vector<size_t>& runs);
+
+ //! Converts a packed \a line of pixels into FAX G3 encoded scanline.
+ /*! This functions merely collects the run lengths into a vector and
+ passes that vector off to transform().
+ */
+ string
+ fax_encoder::operator() (const byte_type* line, size_type n)
+ {
+ bool colour = WHITE;
+ size_t length = 0;
+ vector<size_t> runs;
+
+ uint8_t bit = 0x80;
+
+ n *= 8;
+
+ while (0 < n--)
+ {
+ if (colour == bool ((*line | ~bit) & bit))
+ {
+ ++length;
+ }
+ else
+ {
+ runs.push_back (length);
+ colour = (WHITE == colour ? BLACK : WHITE);
+ length = 1;
+ }
+
+ bit >>= 1;
+ if (0 == bit)
+ {
+ bit = 0x80;
+ ++line;
+ }
+ }
+ runs.push_back (length);
+
+ return transform (runs);
+ }
+
+ //! Converts a vector of run lengths into a FAX G3 encoded string.
+ /*! The string always starts with an end-of-line marker and will be
+ filled if necessary.
+ */
+ static string
+ transform (vector<size_t>& runs)
+ {
+ vector<size_t>::iterator it = runs.begin ();
+ bool colour = WHITE;
+
+ string result;
+ unsigned char ch = 0x00;
+ size_t i = 0;
+
+ unsigned int mask = 1 << 11;
+ unsigned int code = 1;
+
+ while (mask)
+ {
+ if (code & mask) ch |= (1 << (7 - i % 8));
+ ++i;
+ mask >>= 1;
+ if (0 == i % 8)
+ {
+ result.push_back (ch);
+ ch = 0x00;
+ }
+ }
+
+ while (runs.end () != it)
+ {
+ bool terminal = false;
+ do
+ {
+ const struct code *c = NULL;
+
+ if (g3_extra_make_up_max <= *it)
+ {
+ size_t index = ((g3_extra_make_up_max - g3_extra_make_up_min)
+ / g3_make_up_inc);
+
+ c = g3_extra_make_up + index;
+ *it -= g3_extra_make_up_max;
+ }
+ else if (g3_extra_make_up_min <= *it)
+ {
+ size_t index = (*it - g3_extra_make_up_min) / g3_make_up_inc;
+
+ c = g3_extra_make_up + index;
+ *it -= g3_extra_make_up_min + index * g3_make_up_inc;
+ }
+ else if (g3_make_up_min <= *it)
+ {
+ size_t index = (*it - g3_make_up_min) / g3_make_up_inc;
+
+ c = ((WHITE == colour ? g3_white_make_up : g3_black_make_up)
+ + index);
+ *it -= g3_make_up_min + index * g3_make_up_inc;
+ }
+ else
+ {
+ c = ((WHITE == colour ? g3_white_terminal : g3_black_terminal)
+ + *it);
+ *it = 0;
+ terminal = true;
+ }
+
+ unsigned int mask = 1 << (c->bits - 1);
+ unsigned int code = c->code;
+
+ while (mask)
+ {
+ if (code & mask) ch |= (1 << (7 - i % 8));
+ ++i;
+ mask >>= 1;
+ if (0 == i % 8)
+ {
+ result.push_back (ch);
+ ch = 0x00;
+ }
+ }
+ }
+ while (!terminal);
+
+ ++it;
+ colour = (WHITE == colour ? BLACK : WHITE);
+ }
+ if (0 != i % 8)
+ result.push_back (ch);
+
+ return result;
+ }
+
+} // namespace iscan