diff mupdf-source/source/fitz/encode-fax.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/source/fitz/encode-fax.c	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,318 @@
+// Copyright (C) 2004-2021 Artifex Software, Inc.
+//
+// This file is part of MuPDF.
+//
+// MuPDF is free software: you can redistribute it and/or modify it under the
+// terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+//
+// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
+//
+// Alternative licensing terms are available from the licensor.
+// For commercial licensing, see <https://www.artifex.com/> or contact
+// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
+// CA 94129, USA, for further information.
+
+#include "mupdf/fitz.h"
+
+/* Fax G3/G4 tables */
+
+typedef struct
+{
+	unsigned short code;
+	unsigned short nbits;
+} cfe_code;
+
+typedef struct {
+	cfe_code termination[64];
+	cfe_code makeup[41];
+} cf_runs;
+
+/* Define the end-of-line code. */
+static const cfe_code cf_run_eol = {1, 12};
+
+/* Define the 2-D run codes. */
+static const cfe_code cf2_run_pass = {0x1, 4};
+static const cfe_code cf2_run_vertical[7] =
+{
+	{0x3, 7},
+	{0x3, 6},
+	{0x3, 3},
+	{0x1, 1},
+	{0x2, 3},
+	{0x2, 6},
+	{0x2, 7}
+};
+static const cfe_code cf2_run_horizontal = {1, 3};
+
+/* White run codes. */
+static const cf_runs cf_white_runs =
+{
+	/* Termination codes */
+	{
+		{0x35, 8}, {0x7, 6}, {0x7, 4}, {0x8, 4},
+		{0xb, 4}, {0xc, 4}, {0xe, 4}, {0xf, 4},
+		{0x13, 5}, {0x14, 5}, {0x7, 5}, {0x8, 5},
+		{0x8, 6}, {0x3, 6}, {0x34, 6}, {0x35, 6},
+		{0x2a, 6}, {0x2b, 6}, {0x27, 7}, {0xc, 7},
+		{0x8, 7}, {0x17, 7}, {0x3, 7}, {0x4, 7},
+		{0x28, 7}, {0x2b, 7}, {0x13, 7}, {0x24, 7},
+		{0x18, 7}, {0x2, 8}, {0x3, 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}, {0x4, 8}, {0x5, 8}, {0xa, 8},
+		{0xb, 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, 8}
+	},
+
+	/* Make-up codes */
+	{
+		{0, 0} /* dummy */ , {0x1b, 5}, {0x12, 5}, {0x17, 6},
+		{0x37, 7}, {0x36, 8}, {0x37, 8}, {0x64, 8},
+		{0x65, 8}, {0x68, 8}, {0x67, 8}, {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, 9}, {0x18, 6}, {0x9b, 9},
+		{0x8, 11}, {0xc, 11}, {0xd, 11}, {0x12, 12},
+		{0x13, 12}, {0x14, 12}, {0x15, 12}, {0x16, 12},
+		{0x17, 12}, {0x1c, 12}, {0x1d, 12}, {0x1e, 12},
+		{0x1f, 12}
+	}
+};
+
+/* Black run codes. */
+static const cf_runs cf_black_runs =
+{
+	/* Termination codes */
+	{
+		{0x37, 10}, {0x2, 3}, {0x3, 2}, {0x2, 2},
+		{0x3, 3}, {0x3, 4}, {0x2, 4}, {0x3, 5},
+		{0x5, 6}, {0x4, 6}, {0x4, 7}, {0x5, 7},
+		{0x7, 7}, {0x4, 8}, {0x7, 8}, {0x18, 9},
+		{0x17, 10}, {0x18, 10}, {0x8, 10}, {0x67, 11},
+		{0x68, 11}, {0x6c, 11}, {0x37, 11}, {0x28, 11},
+		{0x17, 11}, {0x18, 11}, {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, 12}
+	},
+
+	/* Make-up codes. */
+	{
+		{0, 0} /* dummy */ , {0xf, 10}, {0xc8, 12}, {0xc9, 12},
+		{0x5b, 12}, {0x33, 12}, {0x34, 12}, {0x35, 12},
+		{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, 13},
+		{0x8, 11}, {0xc, 11}, {0xd, 11}, {0x12, 12},
+		{0x13, 12}, {0x14, 12}, {0x15, 12}, {0x16, 12},
+		{0x17, 12}, {0x1c, 12}, {0x1d, 12}, {0x1e, 12},
+		{0x1f, 12}
+	}
+};
+
+static inline int
+getbit(const unsigned char *buf, int x)
+{
+	/* Invert bit to handle BlackIs1=false */
+	return ( ( buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 ) ^ 1;
+}
+
+static inline int
+find_changing(const unsigned char *line, int x, int w)
+{
+	int a, b;
+
+	if (!line || x >= w)
+		return w;
+
+	if (x == -1)
+	{
+		a = 0;
+		x = 0;
+	}
+	else
+	{
+		a = getbit(line, x);
+		x++;
+	}
+	while (x < w)
+	{
+		b = getbit(line, x);
+		if (a != b)
+			break;
+		x++;
+	}
+
+	return x;
+}
+
+static inline int
+find_changing_color(const unsigned char *line, int x, int w, int color)
+{
+	if (!line || x >= w)
+		return w;
+	x = find_changing(line, x, w);
+	if (x < w && getbit(line, x) != color)
+		x = find_changing(line, x, w);
+	return x;
+}
+
+static inline int
+getrun(const unsigned char *line, int x, int w, int c)
+{
+	int z = x;
+	while (z < w)
+	{
+		int b = getbit(line, z);
+		if (c != b)
+			break;
+		++z;
+	}
+	return z - x;
+}
+
+static inline void
+putcode(fz_context *ctx, fz_buffer *out, const cfe_code *run)
+{
+	fz_append_bits(ctx, out, run->code, run->nbits);
+}
+
+static void
+putrun(fz_context *ctx, fz_buffer *out, int run, int c)
+{
+	const cf_runs *codetable = c ? &cf_black_runs : &cf_white_runs;
+	if (run > 63)
+	{
+		int m = run >> 6;
+		while (m > 40)
+		{
+			putcode(ctx, out, &codetable->makeup[40]);
+			m -= 40;
+		}
+		if (m > 0)
+			putcode(ctx, out, &codetable->makeup[m]);
+		putcode(ctx, out, &codetable->termination[run & 63]);
+	}
+	else
+	{
+		putcode(ctx, out, &codetable->termination[run]);
+	}
+}
+
+fz_buffer *
+fz_compress_ccitt_fax_g4(fz_context *ctx, const unsigned char *src, int columns, int rows, ptrdiff_t stride)
+{
+	fz_buffer *out = fz_new_buffer(ctx, (stride * rows) >> 3);
+	const unsigned char *ref = NULL;
+
+	fz_try(ctx)
+	{
+		while (rows-- > 0)
+		{
+			int a0 = -1;
+			int c = 0;
+
+			while (a0 < columns)
+			{
+				int a1 = find_changing(src, a0, columns);
+				int b1 = find_changing_color(ref, a0, columns, c^1);
+				int b2 = find_changing(ref, b1, columns);
+				int diff = b1 - a1;
+				if (a0 < 0)
+					a0 = 0;
+
+				/* pass mode */
+				if (b2 < a1)
+				{
+					putcode(ctx, out, &cf2_run_pass);
+					a0 = b2;
+				}
+
+				/* vertical mode */
+				else if (diff >= -3 && diff <= 3)
+				{
+					putcode(ctx, out, &cf2_run_vertical[diff + 3]);
+					a0 = a1;
+					c = c^1;
+				}
+
+				/* horizontal mode */
+				else
+				{
+					int a2 = find_changing(src, a1, columns);
+					putcode(ctx, out, &cf2_run_horizontal);
+					putrun(ctx, out, a1 - a0, c);
+					putrun(ctx, out, a2 - a1, c^1);
+					a0 = a2;
+				}
+			}
+
+			ref = src;
+			src += stride;
+		}
+
+		putcode(ctx, out, &cf_run_eol);
+		putcode(ctx, out, &cf_run_eol);
+	}
+	fz_catch(ctx)
+	{
+		fz_drop_buffer(ctx, out);
+		fz_rethrow(ctx);
+	}
+
+	return out;
+}
+
+fz_buffer *
+fz_compress_ccitt_fax_g3(fz_context *ctx, const unsigned char *src, int columns, int rows, ptrdiff_t stride)
+{
+	fz_buffer *out = fz_new_buffer(ctx, (stride * rows) >> 3);
+	int i;
+
+	fz_try(ctx)
+	{
+		while (rows-- > 0)
+		{
+			int a0 = 0;
+			int c = 0;
+			while (a0 < columns)
+			{
+				int run = getrun(src, a0, columns, c);
+				putrun(ctx, out, run, c);
+				a0 += run;
+				c = c^1;
+			}
+			src += stride;
+		}
+
+		for (i = 0; i < 6; ++i)
+			putcode(ctx, out, &cf_run_eol);
+	}
+	fz_catch(ctx)
+	{
+		fz_drop_buffer(ctx, out);
+		fz_rethrow(ctx);
+	}
+
+	return out;
+}