summaryrefslogtreecommitdiff
path: root/ip
diff options
context:
space:
mode:
authorJinkun Jang <jinkun.jang@samsung.com>2013-03-13 01:42:35 +0900
committerJinkun Jang <jinkun.jang@samsung.com>2013-03-13 01:42:35 +0900
commit72835b3d805ac6c7cdaac7d3aff107567e938314 (patch)
tree0f2a04dc3d0672c0960a62804c6e7758673e393c /ip
parenteb5e5ee9adb02776056d1b4494f66150a2fc45f1 (diff)
downloadhplip-72835b3d805ac6c7cdaac7d3aff107567e938314.tar.gz
hplip-72835b3d805ac6c7cdaac7d3aff107567e938314.tar.bz2
hplip-72835b3d805ac6c7cdaac7d3aff107567e938314.zip
Tizen 2.1 base
Diffstat (limited to 'ip')
-rw-r--r--ip/hpip.h918
-rw-r--r--ip/ipdefs.h116
-rw-r--r--ip/ipmain.c1342
-rw-r--r--ip/xbi2gray.c453
-rw-r--r--ip/xchgbpp.c627
-rw-r--r--ip/xcolrspc.c1191
-rw-r--r--ip/xconvolve.c658
-rw-r--r--ip/xcrop.c470
-rw-r--r--ip/xfakemono.c465
-rw-r--r--ip/xfax.c3566
-rw-r--r--ip/xform.h340
-rw-r--r--ip/xgamma.c760
-rw-r--r--ip/xgray2bi.c614
-rw-r--r--ip/xgrayout.c495
-rw-r--r--ip/xinvert.c459
-rw-r--r--ip/xjpg_dct.c393
-rw-r--r--ip/xjpg_dct.h50
-rw-r--r--ip/xjpg_dec.c2838
-rw-r--r--ip/xjpg_enc.c2184
-rw-r--r--ip/xjpg_fix.c839
-rw-r--r--ip/xjpg_huf.c558
-rw-r--r--ip/xjpg_huf.h83
-rw-r--r--ip/xjpg_mrk.h91
-rw-r--r--ip/xmatrix.c547
-rw-r--r--ip/xpad.c523
-rw-r--r--ip/xpcx.c1318
-rw-r--r--ip/xpnm.c591
-rw-r--r--ip/xrotate.c819
-rw-r--r--ip/xsaturation.c463
-rw-r--r--ip/xscale.c1277
-rw-r--r--ip/xskel.c456
-rw-r--r--ip/xtable.c742
-rw-r--r--ip/xthumb.c558
-rw-r--r--ip/xtiff.c1338
-rw-r--r--ip/xtonemap.c496
-rw-r--r--ip/xyxtract.c451
36 files changed, 29089 insertions, 0 deletions
diff --git a/ip/hpip.h b/ip/hpip.h
new file mode 100644
index 0000000..10ca913
--- /dev/null
+++ b/ip/hpip.h
@@ -0,0 +1,918 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*****************************************************************************\
+ *
+ * hpojip.h - Interface into the Image Processing module
+ *
+ *****************************************************************************
+ *
+ * Mark Overton, Dec 1997
+ *
+\*****************************************************************************/
+
+
+#if !defined HPIP_INC
+#define HPIP_INC
+
+#if defined(__cplusplus)
+ extern "C" {
+#endif
+
+#include <stdlib.h>
+
+/* TODO: Fix this! */
+// #include <endian.h>
+#undef LITTLE_ENDIAN
+
+#define FAR
+#define WINAPI
+#define EXPORT(x) x
+
+typedef unsigned char BYTE, *PBYTE, FAR *LPBYTE;
+typedef unsigned short WORD, *PWORD, FAR *LPWORD;
+typedef unsigned short USHORT, *PUSHORT, FAR *LPUSHORT;
+typedef unsigned int DWORD, *PDWORD, FAR *LPDWORD;
+typedef unsigned int UINT, *PUINT, FAR *LPUINT;
+typedef unsigned long ULONG, *PULONG, FAR *LPULONG;
+typedef enum { FALSE=0, TRUE=1 } BOOL;
+typedef void VOID, *PVOID, FAR *LPVOID;
+typedef long long int __int64;
+
+typedef struct {
+ BYTE rgbRed:8;
+ BYTE rgbGreen:8;
+ BYTE rgbBlue:8;
+} __attribute__((packed)) RGBQUAD;
+
+/****************************************************************************\
+ ****************************************************************************
+ *
+ * COMMON DEFINITIONS for both xform drivers and ip functions
+ *
+ ****************************************************************************
+\****************************************************************************/
+
+#define IP_MAX_XFORMS 20 /* Max number of xforms we can handle. */
+
+/* These bit-values are returned by all transform driver and ip functions.
+ * Zero or more of these bits is set, telling you if anything interesting
+ * happened.
+ */
+#define IP_READY_FOR_DATA 0X0001u
+#define IP_PARSED_HEADER 0x0002u
+#define IP_CONSUMED_ROW 0x0004u
+#define IP_PRODUCED_ROW 0x0008u
+#define IP_INPUT_ERROR 0x0010u
+#define IP_FATAL_ERROR 0x0020u
+#define IP_NEW_INPUT_PAGE 0x0040u
+#define IP_NEW_OUTPUT_PAGE 0x0080u
+#define IP_WRITE_INSERT_OK 0x0100u
+#define IP_DONE 0x0200u
+
+
+/* IP_IMAGE_TRAITS describes everything about an image. If an item is not
+ * known, a negative number is used, meaning "I don't know." So all items
+ * are signed.
+ */
+typedef struct {
+ int iPixelsPerRow;
+ int iBitsPerPixel;
+ int iComponentsPerPixel;
+ long lHorizDPI; /* 32.0 or 16.16 fixed-point */
+ long lVertDPI; /* 32.0 or 16.16 fixed-point */
+ long lNumRows;
+ int iNumPages;
+ int iPageNum;
+} IP_IMAGE_TRAITS, *PIP_IMAGE_TRAITS, FAR*LPIP_IMAGE_TRAITS;
+
+typedef union {
+ DWORD dword;
+ PVOID pvoid;
+ __int64 i64;
+ RGBQUAD rgbquad;
+ float fl;
+} DWORD_OR_PVOID;
+
+//#ifdef HPIP_INTERNAL
+#include "xform.h" // this file uses the above definitions
+//#else
+//typedef struct IP_XFORM_TBL_s FAR *LPIP_XFORM_TBL;
+//#endif
+
+
+/****************************************************************************\
+ ****************************************************************************
+ *
+ * Definitions for Exported IP Routines
+ *
+ ****************************************************************************
+\****************************************************************************/
+
+
+/* Synopsis of the interface:
+ *
+ * Main routines:
+ *
+ * ipOpen - opens a new conversion-job
+ * ipConvert - converts some data
+ * ipClose - closes the conversion-job
+ *
+ * Ancillary routines:
+ *
+ * ipGetFuncPtrs - loads table with ptrs to these global routines
+ * ipGetClientDataPtr - returns ptr to client data-area in instance
+ * ipInsertedData - client inserted some data in output data stream
+ * ipGetImageTraits - returns traits of input and output images
+ */
+
+/* handle for a conversion job */
+typedef void FAR*IP_HANDLE, *FAR*PIP_HANDLE, FAR*FAR*LPIP_HANDLE;
+
+typedef void (WINAPI *LPIP_PEEK_FUNC)(
+ IP_HANDLE hJob, /* handle for job making the callback */
+ LPIP_IMAGE_TRAITS pTraits, /* traits of the data being peeked at */
+ int nBytes, /* # bytes in buffer below */
+ LPBYTE pBuf, /* data being peeked at */
+ long nFilePos, /* file-position where data belongs */
+ PVOID pUserdata); /* Data passed to the user in peek calls. */
+
+
+/* IP_XFORM - The list of the standard xforms supplied in image processor
+ *
+ * Warning: If the list below changes, you must also change an array in
+ * ipmain.c that is indexed by this enum.
+ */
+typedef enum {
+ X_FAX_ENCODE, X_FAX_DECODE, /* MH, MR and MMR formats */
+ X_PCX_ENCODE, X_PCX_DECODE,
+ /* X_BMP_ENCODE, X_BMP_DECODE, */
+ X_JPG_ENCODE, X_JPG_DECODE, X_JPG_FIX,
+ X_TIF_ENCODE, X_TIF_DECODE,
+ X_PNM_ENCODE, X_PNM_DECODE,
+ X_SCALE,
+ X_GRAY_2_BI, X_BI_2_GRAY,
+ X_CNV_COLOR_SPACE,
+ X_Y_EXTRACT,
+ /* X_HEADER, */
+ X_THUMB,
+ X_TABLE, /* tables are: user1,user3,mirror,gamma,threshold,pass-thru */
+ X_CROP,
+ X_TONEMAP,
+ X_SATURATION,
+ X_ROTATE,
+ X_PAD,
+ X_FAKE_MONO,
+ X_GRAYOUT,
+ X_CHANGE_BPP,
+ X_MATRIX,
+ X_CONVOLVE,
+ X_INVERT,
+ X_SKEL,
+} IP_XFORM, *PIP_XFORM, FAR*LPIP_XFORM;
+
+
+#define IP_MAX_XFORM_INFO 8
+
+/* IP_XFORM_SPEC - Fully specifies an xform
+ * Each transform driver documents what goes into aXformInfo.
+ */
+typedef struct {
+ LPIP_XFORM_TBL pXform; /* ptr to jmp-table for xform to do */
+ IP_XFORM eXform; /* which xform (used if pXform is NULL) */
+ LPIP_PEEK_FUNC pfReadPeek; /* callback when xform dvr reads data */
+ LPIP_PEEK_FUNC pfWritePeek; /* callback when xform dvr writes data */
+ PVOID pUserData; /* Data passed to user in peek functions. */
+ DWORD_OR_PVOID aXformInfo[IP_MAX_XFORM_INFO]; /* xform-specific info */
+} IP_XFORM_SPEC, *PIP_XFORM_SPEC, FAR*LPIP_XFORM_SPEC;
+
+
+
+/*****************************************************************************\
+ *
+ * ipOpen - Opens a new conversion job
+ *
+ *****************************************************************************
+ *
+ * This routine allocates some instance data, including space for nClientData.
+ * More memory is allocated once row-lengths are such are known.
+ * To deallocate all memory, ipClose must be called.
+ *
+ * The nXforms and pXforms parameters specify the sequence of transforms
+ * to go from input to output. The handle for the new job is returned
+ * in *pXform.
+ *
+ * A restriction on the list of xforms: the data-flows between xforms must be
+ * fixed-length buffers. This restricts you to raw raster rows between xforms.
+ * The data-flows into and out of ipConvert can be variable-length in nature.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipOpen (
+ int nXforms, /* in: number of xforms in lpXforms below */
+ LPIP_XFORM_SPEC lpXforms, /* in: list of xforms we should perform */
+ int nClientData, /* in: # bytes of additional client data */
+ LPIP_HANDLE phJob); /* out: handle for conversion job */
+
+
+
+/*****************************************************************************\
+ *
+ * ipMirrorBytes - Swaps bits in each byte of buffer
+ * (bits 0<->7, 1<->6, etc.)
+ *
+\*****************************************************************************/
+
+VOID ipMirrorBytes(PBYTE pbInputBuf,DWORD dwInputAvail);
+
+
+
+/*****************************************************************************\
+ *
+ * ipConvert - Converts some input data (work-horse function)
+ *
+ *****************************************************************************
+ *
+ * This function consumes input data and produces output data via the
+ * input- and output-buffer parameters. And it tells you what's happening
+ * via its function return value.
+ *
+ * On entry, pbInputBuf and wInputAvail specify the location and number of
+ * data-bytes in the input buffer. On return, pwInputUsed tells you how
+ * many of those input bytes were consumed. pdwInputNextPos tells you
+ * where in the input file you should read next for the following call;
+ * 0 is the beginning of the file. This is almost always the current file
+ * position plus pwInputUsed; if not, a file-seek is being requested.
+ *
+ * The output buffer parameters are analogous to the input parameters,
+ * except that pdwOutputThisPos tells you where the bytes just output
+ * should be written in the output file. That is, it applies to *this*
+ * write, not the *next* write, unlike the input arrangement.
+ * The output buffer pointers are allowed to be NULL, in which case
+ * the output is discarded.
+ *
+ * The function return value is a bit-mask that tells you if anything
+ * interesting happened. Multiple bits can be set. This information
+ * should be treated as independent of the data-transfers occuring via
+ * the parameters. The IP_CONSUMED_ROW and IP_PRODUCED_ROW bits can
+ * be used to count how many rows have been input and output.
+ *
+ * The IP_NEW_OUTPUT_PAGE bit is set when or after the last row of the
+ * page has been sent, and before the first row of the following page (if
+ * any) is sent.
+ *
+ * You may wish to insert secret data, such as thumbnails, into the
+ * output stream. When ipConvert returns the IP_WRITE_INSERT_OK bit,
+ * it is giving you permission to write stuff AFTER you write the output
+ * buffer it gave you. After adding your secret data, you must call
+ * ipInsertedData to tell us how many bytes were added.
+ *
+ * When there is no more input data, ipConvert must be called repeatedly
+ * with a NULL pbInputBuf parameter, which tells the processor to flush out
+ * any buffered rows. Keep calling it until it returns the IP_DONE bit.
+ *
+ * Do not call ipConvert again after it has returned either error bit or
+ * IP_DONE.
+ *
+ * At any time after ipConvert returns the IP_PARSED_HEADER bit,
+ * ipGetImageTraits may be called to obtain the input and output traits.
+ * IP_PARSED_HEADER is returned in *every* call after the header was parsed.
+ *
+ * Return value: Zero or more of these bits may be set:
+ *
+ * IP_PARSED_HEADER = input header has been parsed; traits are known
+ * IP_CONSUMED_ROW = an input row was parsed
+ * IP_PRODUCED_ROW = an output row was produced
+ * IP_INPUT_ERROR = syntax error in input data
+ * IP_FATAL_ERROR = misc error (internal error or bad param)
+ * IP_NEW_INPUT_PAGE = just encountered end of page on input
+ * IP_NEW_OUTPUT_PAGE = just finished outputting a page
+ * IP_WRITE_INSERT_OK = okay to insert data in output file
+ * IP_DONE = conversion is completed.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipConvert (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ LPBYTE pbInputBuf, /* in: ptr to input buffer */
+ LPDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ LPDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in output buf */
+ LPBYTE pbOutputBuf, /* in: ptr to output buffer */
+ LPDWORD pdwOutputUsed, /* out: # bytes written in out buf */
+ LPDWORD pdwOutputThisPos); /* out: file-pos to write this data */
+
+
+
+/*****************************************************************************\
+ *
+ * ipClose - Destroys the given conversion job
+ *
+ *****************************************************************************
+ *
+ * This routine deallocates all memory associated with the given conversion
+ * job. It may be called at any time, which is how you do an abort.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipClose (
+ IP_HANDLE hJob); /* in: handle to conversion job */
+
+
+/****************************************************************************\
+ *
+ * ipResultMask - Selects bit-results to be returned by ipConvert
+ *
+ ****************************************************************************
+ *
+ * The mask parameter is the OR of the IP_... bits you want returned by
+ * calls to ipConvert. A 1 means you want that bit; 0 means you don't.
+ * By disabling frequently-returned bits, efficiency will improve because
+ * fewer ipConvert calls will be made because each call can do more work.
+ *
+ * The mask is all zeroes by default. The IP_DONE, IP_FATAL_ERROR, and
+ * IP_INPUT_ERROR bits are always enabled, regardless of their bit-values
+ * in the mask.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipResultMask (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ WORD wMask); /* in: result bits you are interested in */
+
+
+/*****************************************************************************\
+ *
+ * ipGetClientDataPtr - Returns ptr to client's data in conversion instance
+ *
+ *****************************************************************************
+ *
+ * ipOpen accepts an nClientData parameter which is the number of extra bytes
+ * we allocate for the client for his own use. This function returns the
+ * pointer to that memory in the given conversion instance.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipGetClientDataPtr (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ LPVOID FAR*ppvClientData); /* out: ptr to client's memory area */
+
+
+
+/*****************************************************************************\
+ *
+ * ipSetDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the first transform might not
+ * include *all* the image traits we'd like to know. Those not specified
+ * in the file-header are filled in from info provided by this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipSetDefaultInputTraits (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ LPIP_IMAGE_TRAITS pTraits); /* in: default image traits */
+
+
+
+/*****************************************************************************\
+ *
+ * ipGetOutputTraits - Returns the output traits before ipConvert is called
+ *
+ *****************************************************************************
+ *
+ * If the first xform does not have a header, then you can call this function
+ * *after* calling ipSetDefaultInputTraits to get the output image traits.
+ * Ordinarily, you'd have to call ipConvert a few times and wait until it tells
+ * you that the (non-existent) header has been parsed. But if you need the
+ * output traits before calling ipConvert, this function will return them.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipGetOutputTraits (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ LPIP_IMAGE_TRAITS pTraits); /* out: output image traits */
+
+
+
+/*****************************************************************************\
+ *
+ * ipGetImageTraits - Returns traits of input and output images
+ *
+ *****************************************************************************
+ *
+ * At any time after ipConvert has returned the IP_PARSED_HEADER bit, this
+ * function may be called to obtain the traits of the input and output images.
+ * If a pointer parameter is NULL, that traits record is not returned.
+ *
+ * After the conversion job is done, these traits will contain the actual
+ * number of rows input and output.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipGetImageTraits (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ LPIP_IMAGE_TRAITS pInputTraits, /* out: traits of input image */
+ LPIP_IMAGE_TRAITS pOutputTraits); /* out: traits of output image */
+
+
+
+/*****************************************************************************\
+ *
+ * ipInsertedData - Client inserted some bytes into our output stream
+ *
+ *****************************************************************************
+ *
+ * After ipConvert returns the IP_WRITE_INSERT_OK bit, and after the client
+ * writes out the output buffer, he is permitted to write out some additional
+ * data for his own use, such as a thumbnail image. After writing the added
+ * data, the client calls this function to tell us how much data he wrote.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipInsertedData (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ DWORD dwNumBytes); /* in: # of bytes of additional data written */
+
+
+
+/*****************************************************************************\
+ *
+ * ipOverrideDPI - Force a different DPI to be reported in the output
+ *
+ *****************************************************************************
+ *
+ * The values supplied only change the DPI that's *reported* in the output
+ * traits and in the header (if any) of the output file. These DPI values
+ * do *not* affect the transforms, and do *not* affect or change any scaling.
+ *
+ * The image processor code supplies these values in the input traits of
+ * the last transform in the list of transforms so that they'll make it
+ * in the output file header.
+ *
+ * The DPI values are in fixed-point with 16 bits of fraction. A value of
+ * 0 means "no override; use the normal value".
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipOverrideDPI (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ DWORD dwHorizDPI, /* in: horiz DPI as 16.16; 0 means no override */
+ DWORD dwVertDPI); /* in: vert DPI as 16.16; 0 means no override */
+
+
+
+/*****************************************************************************\
+ *
+ * ipGetFuncPtrs - Loads jump-table with pointers to the ip entry points
+ *
+ *****************************************************************************
+ *
+ * This function loads a jump-table (typedef'ed below) for your convenience
+ * so you won't have to call GetProcAddress on every function.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+/*****************************************************************************\
+ *
+ * ipGetXformTable - Returns ptr to IP_XFORM_TBL for transform.
+ *
+ *****************************************************************************
+ *
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL phXform);
+
+
+
+/*** Prototype for ipGetFuncPtrs function ***/
+typedef WORD (WINAPI *IPOPEN) (int, LPIP_XFORM_SPEC,
+ int, LPIP_HANDLE);
+typedef WORD (WINAPI *IPCONVERT) (IP_HANDLE, DWORD, LPBYTE,
+ LPDWORD, LPDWORD, DWORD,
+ LPBYTE, LPDWORD, LPDWORD);
+typedef WORD (WINAPI *IPCLOSE) (IP_HANDLE);
+typedef WORD (WINAPI *IPGETCLIENTDATAPTR) (IP_HANDLE, LPVOID FAR *);
+typedef WORD (WINAPI *IPRESULTMASK) (IP_HANDLE, WORD);
+typedef WORD (WINAPI *IPSETDEFAULTINPUTTRAITS) (IP_HANDLE,
+ LPIP_IMAGE_TRAITS);
+typedef WORD (WINAPI *IPGETIMAGETRAITS) (IP_HANDLE,
+ LPIP_IMAGE_TRAITS,
+ LPIP_IMAGE_TRAITS);
+typedef WORD (WINAPI *IPINSERTEDDATA) (IP_HANDLE, DWORD);
+typedef WORD (WINAPI *IPOVERRIDEDPI) (IP_HANDLE, DWORD, DWORD);
+
+typedef WORD (WINAPI *IPGETXFORMTABLE) (LPIP_XFORM_TBL);
+
+typedef WORD (WINAPI *IPGETOUTPUTTRAITS) (IP_HANDLE,
+ LPIP_IMAGE_TRAITS);
+
+typedef struct {
+ WORD wStructSize; /* # of bytes in this struct */
+ IPOPEN ipOpen;
+ IPCONVERT ipConvert;
+ IPCLOSE ipClose;
+ IPGETCLIENTDATAPTR ipGetClientDataPtr;
+ IPRESULTMASK ipResultMask;
+ IPSETDEFAULTINPUTTRAITS ipSetDefaultInputTraits;
+ IPGETIMAGETRAITS ipGetImageTraits;
+ IPINSERTEDDATA ipInsertedData;
+ IPOVERRIDEDPI ipOverrideDPI;
+ IPGETOUTPUTTRAITS ipGetOutputTraits;
+} IP_JUMP_TBL, * PIP_JUMP_TBL, FAR * LPIP_JUMP_TBL;
+
+/*** Prototype for ipGetFuncPtrs function ***/
+typedef WORD (WINAPI *LPFNIPGETFUNCPTRS) (LPIP_JUMP_TBL);
+
+EXPORT(WORD) ipGetFuncPtrs (LPIP_JUMP_TBL lpJumpTbl);
+
+/****************************************************************************\
+ ****************************************************************************
+ *
+ * OPTION DEFINITIONS for xform drivers
+ *
+ ****************************************************************************
+\****************************************************************************/
+
+/* xbi2gray.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_BI_2_GRAY_OUTPUT_BPP 0
+#define IP_BI_2_GRAY_WHITE_PIXEL 1
+#define IP_BI_2_GRAY_BLACK_PIXEL 2
+
+
+#if 0
+
+/* xbmp.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_BMP_NEGATIVE_HEIGHT 0
+
+#endif
+
+
+/* xchgbpp.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_CHANGE_BPP_OUTPUT_BPP 0
+
+
+/* xcolrspc.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_CNV_COLOR_SPACE_WHICH_CNV 0
+#define IP_CNV_COLOR_SPACE_GAMMA 1
+
+/* The following conversions are possible: */
+
+typedef enum {
+ IP_CNV_YCC_TO_CIELAB = 0,
+ IP_CNV_CIELAB_TO_YCC = 1,
+ IP_CNV_YCC_TO_SRGB = 2,
+ IP_CNV_SRGB_TO_YCC = 3,
+ IP_CNV_LHS_TO_SRGB = 4,
+ IP_CNV_SRGB_TO_LHS = 5,
+ IP_CNV_BGR_SWAP = 100
+} IP_WHICH_CNV;
+
+
+/* xconvolve.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_CONVOLVE_NROWS 0
+#define IP_CONVOLVE_NCOLS 1
+#define IP_CONVOLVE_MATRIX 2
+#define IP_CONVOLVE_DIVISOR 3
+
+#define IP_CONVOLVE_MAXSIZE 9 /* up to 9x9 matrix */
+
+
+/* xcrop.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_CROP_LEFT 0
+#define IP_CROP_RIGHT 1
+#define IP_CROP_TOP 2
+#define IP_CROP_MAXOUTROWS 3
+
+
+/* xfakemono.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_FAKE_MONO_BPP 0
+
+
+/* xfax.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_FAX_FORMAT 0
+#define IP_FAX_NO_EOLS 1
+#define IP_FAX_MIN_ROW_LEN 2
+
+enum {IP_FAX_MH, IP_FAX_MR, IP_FAX_MMR};
+
+
+/* xgray2bi.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_GRAY_2_BI_THRESHOLD 0
+
+
+/* xgrayout.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_GRAYOUT_LEFT 0
+#define IP_GRAYOUT_RIGHT 1
+#define IP_GRAYOUT_TOP 2
+#define IP_GRAYOUT_BOTTOM 3
+
+
+#if 0
+
+/* xheader.h */
+
+/* xheader.h - aXformInfo[0] struct given to xheader.c, the header generator
+ *
+ * Mark Overton, March 1998
+ */
+
+#define IP_HEADER_SPEC 0
+
+/* aXformInfo[IP_HEADER_SPEC] shall be a pointer pointing to this: */
+
+typedef struct {
+ PSTR pszLeftStr; // ptr to left-justified string; 0 -> none
+ PSTR pszCenterStr; // ptr to centered string; 0 -> none
+ PSTR pszRightStr; // ptr to right-justified string; 0 -> none
+ WORD wCharSet; // character set (may be a two-byte set)
+ PSTR pszTypeFace; // ptr to name of typeface (required)
+ float fHeightPoints; // point-size of font
+ float fMarginPoints; // left and right margin, in points
+ BOOL bOverlay; // 0=append header, 1=overlay it on top of page
+ RGBQUAD rgbWhite; // a white pixel
+ RGBQUAD rgbBlack; // a black pixel
+} __attribute__((packed)) XHEADER_SPEC, *PXHEADER_SPEC, FAR*LPXHEADER_SPEC;
+
+/* A header is one line of text appearing at the top of faxes. This is known
+ * as a "TTI" in faxland. We implement this as a left-justified portion, a
+ * centered portion, and a right-justified portion. All three portions are
+ * optional.
+ *
+ * Note that xheader.c copies over the string fields in the struct. Therefore,
+ * those strings may go away after the call to cvtOpen.
+ *
+ * The bOverlay field controls whether the header is concatenated
+ * to the top of the page (0), or overlays the top of the page (1).
+ *
+ * xheader.c needs to know what values to use for white and black pixels,
+ * so rgbWhite and rgbBlack are a white pixel and black pixel repectively.
+ * If the page data is gray (8 bits/pixel), only the rgbRed field is used.
+ * If the page data is bilevel, then only the least significant bit of rgbRed
+ * is used.
+ */
+#endif
+
+
+/* xjpg.h */
+
+/* This .h file contains symbols xjpg_dec.c and xjpg_enc.c
+ * See those .c files for instructions on using these transforms.
+ */
+
+/* Specifications for decoder: */
+
+#define IP_JPG_DECODE_OUTPUT_SUBSAMPLED 0
+#define IP_JPG_DECODE_FROM_DENALI 1
+
+/* Specifications for encoder: */
+
+#define IP_JPG_ENCODE_QUALITY_FACTORS 0
+#define IP_JPG_ENCODE_SAMPLE_FACTORS 1
+#define IP_JPG_ENCODE_ALREADY_SUBSAMPLED 2
+#define IP_JPG_ENCODE_FOR_DENALI 3
+#define IP_JPG_ENCODE_OUTPUT_DNL 4
+#define IP_JPG_ENCODE_FOR_COLOR_FAX 5
+#define IP_JPG_ENCODE_DUMMY_HEADER_LEN 6
+
+
+/* xpad.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_PAD_LEFT 0
+#define IP_PAD_RIGHT 1
+#define IP_PAD_TOP 2
+#define IP_PAD_BOTTOM 3
+#define IP_PAD_VALUE 4
+#define IP_PAD_MIN_HEIGHT 5
+
+
+/* xrotate.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_ROTATE_UPPER_LEFT 0
+#define IP_ROTATE_UPPER_RIGHT 1
+#define IP_ROTATE_LOWER_LEFT 2
+#define IP_ROTATE_OUTPUT_SIZE 3
+#define IP_ROTATE_FAST 4
+
+
+/* xsaturation.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_SATURATION_FACTOR 0
+
+
+/* xscale.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_SCALE_HORIZ_FACTOR 0
+#define IP_SCALE_VERT_FACTOR 1
+#define IP_SCALE_FAST 2
+
+
+/* xskel.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_SKEL_SPEC_1 0
+#define IP_SKEL_SPEC_2 1
+
+
+/* xtable.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_TABLE_WHICH 0
+#define IP_TABLE_OPTION 1
+
+#define IP_TABLE_COLOR_1 1
+#define IP_TABLE_COLOR_2 2
+#define IP_TABLE_COLOR_3 3
+
+typedef enum {
+ IP_TABLE_USER,
+ IP_TABLE_PASS_THRU,
+ IP_TABLE_GAMMA,
+ IP_TABLE_THRESHOLD,
+ IP_TABLE_MIRROR,
+ IP_TABLE_USER_THREE,
+ IP_TABLE_BW_CLIP,
+ IP_TABLE_USER_WORD,
+ IP_TABLE_USER_THREE_WORD
+} IP_TABLE_TYPE;
+
+
+/* xthumb.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_THUMB_SCALE_SPEC 0
+
+
+/* xtiff.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_TIFF_FILE_PATH 0
+
+
+/* xtonemap.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_TONEMAP_POINTER 0
+#define IP_TONEMAP_LUM_SPACE 1
+
+
+/* xyxtract.h */
+
+/* This .h file contains symbols for the transform in the corresponding .c file.
+ * See that .c file for instructions on using this transform.
+ */
+
+#define IP_Y_EXTRACT_COLOR_SPACE 0
+
+typedef enum {
+ IP_Y_EXTRACT_LUM_CHROME,
+ IP_Y_EXTRACT_RGB,
+ IP_Y_EXTRACT_BGR
+} IP_Y_EXTRACT_WHICH_SPACE;
+
+#if defined(__cplusplus)
+ }
+#endif
+
+#endif
+
+
+/* End of File */
diff --git a/ip/ipdefs.h b/ip/ipdefs.h
new file mode 100644
index 0000000..6611c6a
--- /dev/null
+++ b/ip/ipdefs.h
@@ -0,0 +1,116 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*****************************************************************************\
+ *
+ * ipdefs.h - Definitions common among image processor files
+ *
+ * Mark Overton, Jan 1998
+ *
+\*****************************************************************************/
+
+#if ! defined IPDEFS_INC
+#define IPDEFS_INC
+
+#ifdef EXPORT_TRANSFORM
+#define fatalBreakPoint() assert(0);
+#else
+extern void fatalBreakPoint(void);
+#endif
+
+#define INSURE(must_be_true) \
+do { \
+ if (! (must_be_true)) { \
+ fatalBreakPoint(); \
+ goto fatal_error; \
+ } \
+} while (0)
+
+
+#define HANDLE_TO_PTR(hJob_macpar, inst_macpar) \
+do { \
+ inst_macpar = (void*)hJob_macpar; \
+ INSURE (inst_macpar->dwValidChk == CHECK_VALUE); \
+} while (0)
+
+
+#define IP_MEM_ALLOC(nBytes_macpar, ptr_macpar) \
+do { \
+ /* the weirdness below is equivalent to a type cast */ \
+ /* the 12 below is buffer-overrun allowance */ \
+/* *(void**)&(ptr_macpar) = (void*) malloc(nBytes_macpar+12); */ \
+ (ptr_macpar) = malloc(nBytes_macpar+12); \
+ INSURE (ptr_macpar != NULL); \
+} while (0)
+
+
+#define IP_MEM_FREE(ptr_macpar) \
+do { \
+ if (ptr_macpar != NULL) \
+ free (ptr_macpar); \
+} while (0)
+
+
+#define IP_MAX(valOne,valTwo) \
+ ((valOne)>(valTwo) ? (valOne) : (valTwo))
+
+#define IP_MIN(valOne,valTwo) \
+ ((valOne)<(valTwo) ? (valOne) : (valTwo))
+
+
+/* We use approx NTSC weights of 5/16, 9/16, 2/16 for R, G and B respectively. */
+#define NTSC_LUMINANCE(Rval,Gval,Bval) \
+ ((((Rval)<<2) + (Rval) + ((Gval)<<3) + (Gval) + ((Bval)<<1)) >> 4)
+
+
+/* The MUL32HIHALF macro does a signed 32x32->64 multiply, and then
+ * discards the low 32 bits, giving you the high 32 bits. The way
+ * this is done is compiler-dependent.
+ */
+#if 0
+#define MUL32HIHALF(firstpar, secondpar, hihalfresult) { \
+ __int64 prod64; \
+ prod64 = (__int64)(firstpar) * (secondpar); \
+ hihalfresult = ((int*)&prod64)[1]; \
+ /* above, use a [0] for big endian */
+#endif
+#define MUL32HIHALF(firstpar, secondpar, hihalfresult) { \
+ hihalfresult = ((__int64)(firstpar) * (secondpar)) >> 32; \
+}
+
+#endif
+
+/* End of File */
diff --git a/ip/ipmain.c b/ip/ipmain.c
new file mode 100644
index 0000000..598ead3
--- /dev/null
+++ b/ip/ipmain.c
@@ -0,0 +1,1342 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*****************************************************************************\
+ *
+ * ipmain.c - main control code and entry points for image processor
+ *
+ *****************************************************************************
+ *
+ * Mark Overton, Dec 1997
+ *
+\*****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h> /* for memcpy, memset, etc. */
+#include <unistd.h>
+#include "hpip.h"
+#include "ipdefs.h"
+
+//#define HPIP_DEBUG
+
+#ifdef HPIP_DEBUG
+ #include <stdio.h>
+ #include <assert.h>
+
+ #define _T(msg) msg
+
+ #define PRINT0(args...) fprintf(stderr, args)
+
+ #if 0
+ #define PRINT1(args...) fprintf(stderr, args)
+ #else
+ #define PRINT1(args...)
+ #endif
+
+ #undef INSURE
+ #define INSURE(boolexp) \
+ do { if (0) goto fatal_error; assert(boolexp); } while(0)
+
+ int infd;
+ int outfd;
+
+#else
+ #define PRINT0(args...)
+ #define PRINT1(args...)
+#endif
+
+
+
+/*****************************************************************************\
+ *
+ * Constants
+ *
+\*****************************************************************************/
+
+
+#define CHECK_VALUE 0xACEC0DE4U /* for checking validity of instance struc */
+#define MIN_GENBUF_LEN 4000 /* arbitrary, but higher boosts speed some */
+#define PERMANENT_RESULTS \
+ (IP_INPUT_ERROR | IP_FATAL_ERROR | IP_DONE)
+
+
+
+/*****************************************************************************\
+ *
+ * Types
+ *
+\*****************************************************************************/
+
+
+/* XFORM_STATE enum - all possible states of an xform */
+
+typedef enum {
+ XS_NONEXISTENT=0, /* xform is not yet instantiated */
+ XS_PARSING_HEADER, /* parsing header (always goes thru this state) */
+ XS_CONVERTING, /* inputting and outputting */
+ XS_CONV_NOT_RFD, /* only outputting; not ready for input */
+ XS_FLUSHING, /* outputting buffered stuff; no more input */
+ XS_DONE /* done and de-instantiated */
+} XFORM_STATE;
+
+
+/* XFORM_INFO type - everything we know about an xform */
+
+typedef struct {
+ XFORM_STATE eState; /* state of this xform */
+ PIP_XFORM_TBL pXform; /* ptr to jmp-table for xform */
+ LPIP_PEEK_FUNC pfReadPeek; /* callback when xform dvr reads data */
+ LPIP_PEEK_FUNC pfWritePeek; /* callback when xform dvr writes data */
+ PVOID pUserData; /* Data passed to user in peek functions. */
+ DWORD_OR_PVOID aXformInfo[8]; /* xform-specific information */
+ IP_XFORM_HANDLE hXform; /* handle for the xform */
+ IP_IMAGE_TRAITS inTraits; /* traits of input data into xform */
+ IP_IMAGE_TRAITS outTraits; /* traits of output data from xform */
+ DWORD dwMinInBufLen; /* min # bytes in input buf */
+ DWORD dwMinOutBufLen; /* min # bytes in output buf */
+} XFORM_INFO, *PXFORM_INFO;
+
+
+/* GENBUF type - a general-purpose buffer which allows one to write or read
+ * varying amounts of data.
+ */
+typedef struct {
+ PBYTE pbBuf; /* ptr to beginning of buffer */
+ DWORD dwBufLen; /* size of entire buffer (# of bytes) */
+ DWORD dwValidStart; /* index of first valid data byte in buffer */
+ DWORD dwValidLen; /* number of valid data bytes in buffer */
+ DWORD dwFilePos; /* file-pos of start of valid data (starts at 0) */
+} GENBUF, *PGENBUF;
+
+
+/* INST type - all variables in an instance of the image processor */
+
+typedef struct {
+
+ /* genbufs are used for input into the first xform, and to store output
+ * from the last xform. The client's input data is first put into gbIn,
+ * which is then fed into the first xform. The last xform's output is put
+ * into gbOut, which is then copied out to the client's output buffer.
+ */
+ GENBUF gbIn;
+ GENBUF gbOut;
+
+ /* mid-buffers are simple buffers that handle fixed-length raster-rows
+ * passed between xforms in the xform-list. For an xform, there's an input
+ * and an output buffer. For the next xform, they swap roles, so the old
+ * output buffer becomes the new input buffer, and vice versa. When the
+ * roles are swapped, the two pointers below are swapped.
+ */
+ PBYTE pbMidInBuf; /* ptr to beginning of input mid-buf */
+ PBYTE pbMidOutBuf; /* ptr to beginning of output mid-buf */
+ DWORD dwMidLen; /* size of either buffer (# of bytes) */
+ DWORD dwMidValidLen; /* # of bytes of good data in input mid-buf */
+ int iOwner; /* index into xfArray of xform owning (using)
+ * the input mid-buf. negative means no owner
+ * and that pbMidInBuf is empty */
+
+ /* variables pertaining to the array of xforms */
+
+ XFORM_INFO xfArray[IP_MAX_XFORMS]; /* the array of xforms */
+ WORD xfCount; /* number of xforms */
+
+ /* misc variables */
+
+ DWORD dwValidChk; /* struct validity check value */
+ DWORD dwForcedHorizDPI; /* horiz DPI override as 16.16; 0=none */
+ DWORD dwForcedVertDPI; /* vert DPI override as 16.16; 0=none */
+ WORD wResultMask; /* desired ipConvert result bits */
+ long lInRows; /* number of rows we've input */
+ long lOutRows; /* number of rows we've output */
+ int iInPages; /* number of pages we've received */
+ int iOutPages; /* number of pages we've output */
+ BOOL pendingInsert; /* ret IP_WRITE_INSERT_OK after outbuf empty? */
+
+} INST, *PINST;
+
+
+
+/*****************************************************************************\
+ *
+ * xformJumpTables - Array of ptrs to all driver jump tables
+ *
+ * Warning: This array is indexed by the enum IP_XFORM. If one changes,
+ * the other must change too.
+ *
+\*****************************************************************************/
+
+extern IP_XFORM_TBL faxEncodeTbl, faxDecodeTbl;
+extern IP_XFORM_TBL pcxEncodeTbl, pcxDecodeTbl;
+/* extern IP_XFORM_TBL bmpEncodeTbl, bmpDecodeTbl; */
+extern IP_XFORM_TBL jpgEncodeTbl, jpgDecodeTbl, jpgFixTbl;
+extern IP_XFORM_TBL tifEncodeTbl, tifDecodeTbl;
+extern IP_XFORM_TBL pnmEncodeTbl, pnmDecodeTbl;
+extern IP_XFORM_TBL scaleTbl;
+extern IP_XFORM_TBL gray2biTbl, bi2grayTbl;
+extern IP_XFORM_TBL colorTbl;
+extern IP_XFORM_TBL yXtractTbl;
+/* extern IP_XFORM_TBL headerTbl; */
+extern IP_XFORM_TBL thumbTbl;
+extern IP_XFORM_TBL tableTbl;
+extern IP_XFORM_TBL cropTbl;
+extern IP_XFORM_TBL tonemapTbl;
+extern IP_XFORM_TBL saturationTbl;
+extern IP_XFORM_TBL rotateTbl;
+extern IP_XFORM_TBL padTbl;
+extern IP_XFORM_TBL fakeMonoTbl;
+extern IP_XFORM_TBL grayOutTbl;
+extern IP_XFORM_TBL changeBPPTbl;
+extern IP_XFORM_TBL matrixTbl;
+extern IP_XFORM_TBL convolveTbl;
+extern IP_XFORM_TBL invertTbl;
+extern IP_XFORM_TBL skelTbl;
+
+static IP_XFORM_TBL * const xformJumpTables[] = {
+ &faxEncodeTbl, &faxDecodeTbl, /* MH, MR and MMR formats */
+ &pcxEncodeTbl, &pcxDecodeTbl,
+ /* &bmpEncodeTbl, &bmpDecodeTbl, */
+ &jpgEncodeTbl, &jpgDecodeTbl, &jpgFixTbl,
+ &tifEncodeTbl, &tifDecodeTbl,
+ &pnmEncodeTbl, &pnmDecodeTbl,
+ &scaleTbl,
+ &gray2biTbl, &bi2grayTbl,
+ &colorTbl,
+ &yXtractTbl,
+ /* &headerTbl, */
+ &thumbTbl,
+ &tableTbl,
+ &cropTbl,
+ &tonemapTbl,
+ &saturationTbl,
+ &rotateTbl,
+ &padTbl,
+ &fakeMonoTbl,
+ &grayOutTbl,
+ &changeBPPTbl,
+ &matrixTbl,
+ &convolveTbl,
+ &invertTbl,
+ &skelTbl,
+};
+
+
+
+/*****************************************************************************\
+ *
+ * fatalBreakPoint - Called when INSURE fails, used for debugger breakpoint
+ *
+\*****************************************************************************/
+
+void fatalBreakPoint (void)
+{
+ /* do nothing */
+#if defined _DEBUG
+ __asm int 3;
+#endif
+ PRINT0 (_T("\nhit fatalBreakPoint!\n"));
+}
+
+
+
+/*****************************************************************************\
+ *
+ * deleteMidBufs - Frees the two mid-buffers, if they've been allocated
+ *
+\*****************************************************************************/
+
+static void deleteMidBufs (PINST g)
+{
+ PRINT0 (_T("deleteMidBufs\n"));
+
+ if (g->pbMidInBuf != NULL)
+ IP_MEM_FREE (g->pbMidInBuf);
+
+ if (g->pbMidOutBuf != NULL)
+ IP_MEM_FREE (g->pbMidOutBuf);
+
+ g->pbMidInBuf = NULL;
+ g->pbMidOutBuf = NULL;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipOpen - Opens a new conversion job
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipOpen (
+ int nXforms, /* in: number of xforms in lpXforms below */
+ LPIP_XFORM_SPEC lpXforms, /* in: the xforms we should perform */
+ int nClientData, /* in: # bytes of additional client data */
+ PIP_HANDLE phJob) /* out: handle for conversion job */
+{
+ PINST g;
+ int i;
+ PIP_XFORM_SPEC src;
+ PXFORM_INFO dest;
+
+#ifdef HPIP_DEBUG
+ char *ipIn = "/tmp/ipIn.dib";
+#endif
+
+ PRINT0 (_T("ipOpen: nXforms=%d\n"), nXforms);
+ INSURE (nXforms>0 && lpXforms!=NULL && nClientData>=0 && phJob!=NULL);
+
+#ifdef HPIP_DEBUG
+ for (i=0; i<nXforms; i++)
+ {
+ switch (lpXforms[i].eXform)
+ {
+ case X_FAX_DECODE:
+ PRINT0("Fax_format=%d\n", lpXforms[i].aXformInfo[IP_FAX_FORMAT].dword);
+ ipIn = "/tmp/ipIn.pbm";
+ break;
+ case X_JPG_DECODE:
+ PRINT0("JPG_decode=%d\n", lpXforms[i].aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword);
+ ipIn = "/tmp/ipIn.jpg";
+ break;
+ case X_CNV_COLOR_SPACE:
+ PRINT0("Color_space conversion=%d\n", lpXforms[i].aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword);
+ PRINT0("Color_space gamma=%d\n", lpXforms[i].aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword);
+ break;
+ case X_CROP:
+ PRINT0("Crop_left=%d\n", lpXforms[i].aXformInfo[IP_CROP_LEFT].dword);
+ PRINT0("Crop_right=%d\n", lpXforms[i].aXformInfo[IP_CROP_RIGHT].dword);
+ PRINT0("Crop_top=%d\n", lpXforms[i].aXformInfo[IP_CROP_TOP].dword);
+ PRINT0("Crop_maxoutrows=%d\n", lpXforms[i].aXformInfo[IP_CROP_MAXOUTROWS].dword);
+ break;
+ case X_PAD:
+ PRINT0("Pad_left=%d\n", lpXforms[i].aXformInfo[IP_PAD_LEFT].dword);
+ PRINT0("Pad_right=%d\n", lpXforms[i].aXformInfo[IP_PAD_RIGHT].dword);
+ PRINT0("Pad_top=%d\n", lpXforms[i].aXformInfo[IP_PAD_TOP].dword);
+ PRINT0("Pad_bottom=%d\n", lpXforms[i].aXformInfo[IP_PAD_BOTTOM].dword);
+ PRINT0("Pad_value=%d\n", lpXforms[i].aXformInfo[IP_PAD_VALUE].dword);
+ PRINT0("Pad_minheight=%d\n", lpXforms[i].aXformInfo[IP_PAD_MIN_HEIGHT].dword);
+ break;
+ default:
+ PRINT0("Unknown xform\n");
+ break;
+ }
+ }
+
+ infd = creat(ipIn, 0600);
+ outfd = creat("/tmp/ipOut.ppm", 0600);
+#endif
+
+ /**** Create Instance and Init Misc Variables ****/
+
+ IP_MEM_ALLOC (sizeof(INST) + nClientData, g);
+ *phJob = g;
+
+ memset (g, 0, sizeof(INST));
+ g->dwValidChk = CHECK_VALUE;
+ g->iOwner = -1;
+ g->wResultMask = PERMANENT_RESULTS;
+
+ /**** Transfer the Xforms to xfArray ****/
+
+ g->xfCount = (WORD)nXforms;
+
+ for (i=0; i<nXforms; i++) {
+ src = &(lpXforms[i]);
+ dest = &(g->xfArray[i]);
+
+ dest->eState = XS_NONEXISTENT;
+ dest->pXform = (src->pXform != NULL)
+ ? src->pXform
+ : xformJumpTables[src->eXform];
+ INSURE (dest->pXform != NULL);
+ dest->pfReadPeek = src->pfReadPeek;
+ dest->pfWritePeek = src->pfWritePeek;
+ dest->pUserData = src->pUserData;
+ memcpy (dest->aXformInfo, src->aXformInfo, sizeof(dest->aXformInfo));
+ }
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipClose - Destroys the given conversion job, deallocating all its memory
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipClose (IP_HANDLE hJob)
+{
+ PINST g;
+ PXFORM_INFO pXform;
+ WORD n;
+
+ PRINT0 (_T("ipClose: hJob=%p\n"), (void*)hJob);
+ HANDLE_TO_PTR (hJob, g);
+
+ /**** Delete All Buffers ****/
+
+ deleteMidBufs (g);
+ g->dwMidLen = 0;
+ g->dwMidValidLen = 0;
+
+ if (g->gbIn.pbBuf != NULL) IP_MEM_FREE (g->gbIn.pbBuf);
+ if (g->gbOut.pbBuf != NULL) IP_MEM_FREE (g->gbOut.pbBuf);
+
+ /**** Delete All Xform Instances ****/
+
+ for (n=0; n<g->xfCount; n++) {
+ pXform = &(g->xfArray[n]);
+ if (pXform->hXform != NULL)
+ pXform->pXform->closeXform (pXform->hXform);
+ }
+
+ IP_MEM_FREE (g); /* Delete our instance, and we're done */
+
+#ifdef HPIP_DEBUG
+ close(infd);
+ close(outfd);
+#endif
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipGetClientDataPtr - Returns ptr to client's data in conversion instance
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipGetClientDataPtr (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ PVOID *ppvClientData) /* out: ptr to client's memory area */
+{
+ PINST g;
+
+ PRINT0 (_T("ipGetClientDataPtr\n"));
+ HANDLE_TO_PTR (hJob, g);
+ *ppvClientData = (PVOID)((PBYTE)g + sizeof(INST));
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * ipResultMask - Selects bit-results to be returned by ipConvert
+ *
+\****************************************************************************/
+
+EXPORT(WORD) ipResultMask (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ WORD wMask) /* in: result bits you are interested in */
+{
+ PINST g;
+
+ PRINT0 (_T("ipResultMask: hJob=%p, wMask=%04x\n"), (void*)hJob, wMask);
+ HANDLE_TO_PTR (hJob, g);
+ g->wResultMask = wMask | PERMANENT_RESULTS;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipSetDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the first transform might not
+ * include *all* the image traits we'd like to know. Those not specified
+ * in the file-header are filled in from info provided by this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipSetDefaultInputTraits (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ LPIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PINST g;
+ PIP_IMAGE_TRAITS p;
+
+ PRINT0 (_T("ipSetDefaultInputTraits: hJob=%p PixelsPerRow=%d BitsPerPixel=%d ComponentsPerPixel=%d HorzDPI=%ld VertDPI=%ld Rows=%ld Pages=%d PageNum=%d\n"),
+ (void*)hJob, pTraits->iPixelsPerRow, pTraits->iBitsPerPixel, pTraits->iComponentsPerPixel, pTraits->lHorizDPI,
+ pTraits->lVertDPI, pTraits->lNumRows, pTraits->iNumPages, pTraits->iPageNum);
+ HANDLE_TO_PTR (hJob, g);
+ INSURE (g->xfArray[0].eState == XS_NONEXISTENT);
+ g->xfArray[0].inTraits = *pTraits; /* a structure copy */
+
+ /* Convert DPI from integer to 16.16 fixed-pt if necessary */
+ p = &(g->xfArray[0].inTraits);
+ if (p->lHorizDPI < 0x10000) p->lHorizDPI <<= 16;
+ if (p->lVertDPI < 0x10000) p->lVertDPI <<= 16;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipGetImageTraits - Returns traits of input and output images
+ *
+ *****************************************************************************
+ *
+ * After the conversion job is done, these traits will contain the actual
+ * number of rows input and output (ipConvert patches traits upon completion).
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipGetImageTraits (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ LPIP_IMAGE_TRAITS pInputTraits, /* out: traits of input image */
+ LPIP_IMAGE_TRAITS pOutputTraits) /* out: traits of output image */
+{
+ PINST g;
+ PXFORM_INFO pTail;
+
+ PRINT0 (_T("ipGetImageTraits: hJob=%p\n"), (void*)hJob);
+ HANDLE_TO_PTR (hJob, g);
+ INSURE (g->xfCount > 0);
+ pTail = &(g->xfArray[g->xfCount-1]);
+
+ if (pInputTraits != NULL) {
+ INSURE (g->xfArray[0].eState > XS_PARSING_HEADER);
+ *pInputTraits = g->xfArray[0].inTraits;
+ PRINT0 (_T("InputTraits: hJob=%p PixelsPerRow=%d BitsPerPixel=%d ComponentsPerPixel=%d HorzDPI=%ld VertDPI=%ld Rows=%ld Pages=%d PageNum=%d\n"),
+ (void*)hJob, pInputTraits->iPixelsPerRow, pInputTraits->iBitsPerPixel, pInputTraits->iComponentsPerPixel, pInputTraits->lHorizDPI,
+ pInputTraits->lVertDPI, pInputTraits->lNumRows, pInputTraits->iNumPages, pInputTraits->iPageNum);
+ }
+
+ if (pOutputTraits != NULL) {
+ INSURE (pTail->eState > XS_PARSING_HEADER);
+ *pOutputTraits = pTail->outTraits;
+ PRINT0 (_T("OutputTraits: hJob=%p PixelsPerRow=%d BitsPerPixel=%d ComponentsPerPixel=%d HorzDPI=%ld VertDPI=%ld Rows=%ld Pages=%d PageNum=%d\n"),
+ (void*)hJob, pOutputTraits->iPixelsPerRow, pOutputTraits->iBitsPerPixel, pOutputTraits->iComponentsPerPixel, pOutputTraits->lHorizDPI,
+ pOutputTraits->lVertDPI, pOutputTraits->lNumRows, pOutputTraits->iNumPages, pOutputTraits->iPageNum);
+ }
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipInsertedData - Client inserted some bytes into our output stream
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipInsertedData (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ DWORD dwNumBytes) /* in: # of bytes of additional data written */
+{
+ PINST g;
+ PXFORM_INFO pTail;
+
+ PRINT0 (_T("ipInsertedData: hJob=%p, dwNumBytes=%d\n"), (void*)hJob, dwNumBytes);
+ HANDLE_TO_PTR (hJob, g);
+ INSURE (g->xfCount > 0);
+ pTail = &(g->xfArray[g->xfCount-1]);
+ INSURE (pTail->eState > XS_PARSING_HEADER);
+ INSURE (g->gbOut.dwValidLen == 0); /* output genbuf must be empty */
+
+ pTail->pXform->insertedData (pTail->hXform, dwNumBytes);
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipOverrideDPI - Force a different DPI to be reported in the output
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipOverrideDPI (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ DWORD dwHorizDPI, /* in: horiz DPI as 16.16; 0 means no override */
+ DWORD dwVertDPI) /* in: vert DPI as 16.16; 0 means no override */
+{
+ PINST g;
+
+ PRINT0 (_T("ipOverrideDPI: dwHorizDPI=%x, dwVertDPI=%x\n"),
+ dwHorizDPI, dwVertDPI);
+ HANDLE_TO_PTR (hJob, g);
+
+ /* Convert from integer to fixed-pt if necessary */
+ if (dwHorizDPI < 0x10000) dwHorizDPI <<= 16;
+ if (dwVertDPI < 0x10000) dwVertDPI <<= 16;
+
+ g->dwForcedHorizDPI = dwHorizDPI;
+ g->dwForcedVertDPI = dwVertDPI;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipGetFuncPtrs - Loads jump-table with pointers to the ip entry points
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipGetFuncPtrs (LPIP_JUMP_TBL lpJumpTbl)
+{
+ PRINT0 (_T("ipGetFuncPtrs\n"));
+ INSURE (lpJumpTbl!=NULL && lpJumpTbl->wStructSize==sizeof(IP_JUMP_TBL));
+
+ lpJumpTbl->ipOpen = (LPVOID) ipOpen;
+ lpJumpTbl->ipConvert = (LPVOID) ipConvert;
+ lpJumpTbl->ipClose = (LPVOID) ipClose;
+ lpJumpTbl->ipGetClientDataPtr = (LPVOID) ipGetClientDataPtr;
+ lpJumpTbl->ipResultMask = (LPVOID) ipResultMask;
+ lpJumpTbl->ipSetDefaultInputTraits = (LPVOID) ipSetDefaultInputTraits;
+ lpJumpTbl->ipGetImageTraits = (LPVOID) ipGetImageTraits;
+ lpJumpTbl->ipInsertedData = (LPVOID) ipInsertedData;
+ lpJumpTbl->ipOverrideDPI = (LPVOID) ipOverrideDPI;
+ lpJumpTbl->ipGetOutputTraits = (LPVOID) ipGetOutputTraits;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipGetOutputTraits - Returns the output traits before ipConvert is called
+ *
+ *****************************************************************************
+ *
+ * If the first xform does not have a header, then you can call this function
+ * *after* calling ipSetDefaultInputTraits to get the output image traits.
+ * Ordinarily, you'd have to call ipConvert a few times and wait until it tells
+ * you that the (non-existent) header has been parsed. But if you need the
+ * output traits before calling ipConvert, this function will return them.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipGetOutputTraits (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ LPIP_IMAGE_TRAITS pTraits) /* out: output image traits */
+{
+ PINST g;
+ IP_IMAGE_TRAITS inTraits, outTraits;
+ int iXform;
+ PXFORM_INFO pXform;
+ WORD result;
+ DWORD dwHeaderLen;
+ DWORD dwInUsed, dwInNextPos;
+
+ HANDLE_TO_PTR (hJob, g);
+ INSURE (g->xfCount>=1);
+ inTraits = g->xfArray[0].inTraits; /* set by SetDefaultInputTraits */
+
+ for (iXform=0; iXform<g->xfCount; iXform++) {
+ pXform = &(g->xfArray[iXform]);
+ INSURE (pXform->eState == XS_NONEXISTENT);
+
+ /* Open the xform, set it up, get the traits, and close it */
+
+ result = pXform->pXform->openXform (&pXform->hXform);
+ INSURE (result == IP_DONE);
+
+ result = pXform->pXform->setDefaultInputTraits (
+ pXform->hXform, &inTraits);
+ INSURE (result == IP_DONE);
+
+ result = pXform->pXform->setXformSpec (
+ pXform->hXform, pXform->aXformInfo);
+ INSURE (result == IP_DONE);
+
+ result = pXform->pXform->getHeaderBufSize (
+ pXform->hXform, &dwHeaderLen);
+ INSURE (result == IP_DONE);
+ INSURE (dwHeaderLen == 0);
+
+ result = pXform->pXform->getActualTraits (
+ pXform->hXform,
+ 0, NULL, &dwInUsed, &dwInNextPos,
+ &inTraits, &outTraits);
+ INSURE (result & IP_DONE);
+
+ result = pXform->pXform->closeXform (pXform->hXform);
+ INSURE (result == IP_DONE);
+
+ inTraits = outTraits;
+ pXform->hXform = NULL;
+ }
+
+ *pTraits = outTraits;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipConvert - Converts some input data (work-horse function)
+ *
+\*****************************************************************************/
+
+EXPORT(WORD) ipConvert (
+ IP_HANDLE hJob, /* in: handle to conversion job */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in output buf */
+ PBYTE pbOutputBuf, /* in: ptr to output buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write this data */
+{
+ PINST g;
+ WORD ipResult;
+ int iXform;
+ WORD result;
+ PGENBUF pgbIn, pgbOut;
+ BOOL atTheHead, atTheTail;
+ PXFORM_INFO pXform, pPriorXform, pNextXform;
+ BOOL needInput, selectCnvState;
+ DWORD dwBytes;
+ int i;
+ DWORD n;
+ DWORD dwInUsed, dwOutUsed;
+ DWORD dwInNextPos, dwOutThisPos;
+ DWORD dwTheInLen, dwTheOutLen;
+ PBYTE pbTemp;
+ PBYTE pbTheInBuf, pbTheOutBuf;
+ DWORD dwJunk;
+
+ if (pbOutputBuf == NULL) {
+ /* client wants us to discard all data */
+ pdwOutputUsed = &dwJunk;
+ pdwOutputThisPos = &dwJunk;
+ dwOutputAvail = 0xfffffffu;
+ }
+
+ PRINT0 (_T("ipConvert: hJob=%p, pbInputBuf=%p InputBufSize=%d pbOutputBuf=%p OutputBufSize=%d\n"),
+ (void*)hJob, pbInputBuf, dwInputAvail, pbOutputBuf, dwOutputAvail);
+ INSURE (pdwInputUsed !=NULL && pdwInputNextPos !=NULL &&
+ pdwOutputUsed!=NULL && pdwOutputThisPos!=NULL);
+ HANDLE_TO_PTR (hJob, g);
+ INSURE (g->xfCount>=1);
+
+ pgbIn = &g->gbIn;
+ pgbOut = &g->gbOut;
+
+ *pdwInputUsed = 0;
+ *pdwOutputUsed = 0;
+ ipResult = 0;
+
+ /**************************/
+ /* Beginning of Main Loop */
+ /**************************/
+
+ while (TRUE) {
+
+ /**** Output any data in the output genbuf ****/
+
+ if (*pdwOutputUsed == 0)
+ *pdwOutputThisPos = pgbOut->dwFilePos;
+
+ if (pgbOut->dwValidLen != 0) { /* output genbuf is not empty */
+ /* Logic below:
+ *
+ * 1. If next output file-pos doesn't match output genbuf, exit loop.
+ *
+ * 2. Copy as much as possible from output genbuf to clients output buf.
+ * 2.1 decide number of bytes to copy
+ * 2.2 copy them
+ * 2.3 update misc variables
+ *
+ * 3. If output genbuf is not empty, exit loop (client's buf is full),
+ * else set wValidStart to 0 because output genbuf is empty.
+ */
+
+ if ((*pdwOutputThisPos+*pdwOutputUsed) != pgbOut->dwFilePos) {
+ PRINT0 (_T("ipConvert: output seek to %d\n"), pgbOut->dwFilePos);
+ goto exitLoop;
+ }
+
+ dwBytes = pgbOut->dwValidLen;
+ if (dwOutputAvail < dwBytes)
+ dwBytes = dwOutputAvail;
+
+ if (pbOutputBuf != NULL) {
+ memcpy (pbOutputBuf + *pdwOutputUsed,
+ pgbOut->pbBuf + pgbOut->dwValidStart,
+ dwBytes);
+ }
+
+ *pdwOutputUsed += dwBytes;
+ dwOutputAvail -= dwBytes;
+ pgbOut->dwValidStart += dwBytes;
+ pgbOut->dwFilePos += dwBytes;
+ pgbOut->dwValidLen -= dwBytes;
+
+ if (pgbOut->dwValidLen != 0)
+ goto exitLoop;
+
+ pgbOut->dwValidStart = 0; /* output genbuf is now empty */
+ }
+
+ if (g->pendingInsert) {
+ g->pendingInsert = FALSE;
+ ipResult |= IP_WRITE_INSERT_OK;
+ }
+
+ /**** If ipResult has any returnable bits set, exit loop now ****/
+
+ if (ipResult & g->wResultMask)
+ goto exitLoop;
+
+ /**** Select an xform to run ****/
+
+ /* select the owner of input midbuf, or negative means 'none selected' */
+ iXform = g->iOwner;
+
+ if (iXform < 0) {
+ for (i=g->xfCount-1; i>=0; i--) {
+ if (g->xfArray[i].eState == XS_CONV_NOT_RFD) {
+ /* select last xform that's convnotrfd; this xform
+ * is outputting (or thinking) but not inputting */
+ iXform = i;
+ break;
+ }
+ }
+ }
+
+ if (iXform < 0) {
+ for (i=0; i<g->xfCount; i++) {
+ if (g->xfArray[i].eState != XS_DONE) {
+ /* select first xform that's not done */
+ iXform = i;
+ break;
+ }
+ }
+ }
+
+ if (iXform < 0) {
+ /* all xforms are done: discard all input, and report that we're done */
+ *pdwInputUsed = dwInputAvail;
+ ipResult |= IP_DONE;
+ /* patch the last outtraits with actual # of rows output, so that
+ * ipGetImageTraits will return actual row-count after we're done */
+ g->xfArray[g->xfCount-1].outTraits.lNumRows = g->lOutRows;
+ /* patch first intraits for the same reason */
+ g->xfArray[0].inTraits.lNumRows = g->lInRows;
+ goto exitLoop;
+ }
+
+ /**** Miscellaneous preparation ****/
+
+ pXform = &(g->xfArray[iXform]);
+ atTheHead = (iXform == 0);
+ atTheTail = (iXform == g->xfCount-1);
+ pPriorXform = atTheHead ? NULL : &(g->xfArray[iXform-1]);
+ pNextXform = atTheTail ? NULL : &(g->xfArray[iXform+1]);
+
+ /**** Create the Xform if necessary ****/
+
+ if (pXform->eState == XS_NONEXISTENT) {
+ PRINT0 (_T("ipConvert: creating xform %d\n"), iXform);
+ INSURE (atTheHead || pPriorXform->eState>=XS_CONVERTING);
+
+ if (atTheHead) {
+ /* this xform's input traits were set by ipSetDefaultInputTraits */
+ } else {
+ /* this xform's input traits are prior xform's output traits */
+ memcpy (&pXform->inTraits, &pPriorXform->outTraits,
+ sizeof(IP_IMAGE_TRAITS));
+
+ if (atTheTail) {
+ /* apply any DPI overrides */
+ if (g->dwForcedHorizDPI != 0)
+ pXform->inTraits.lHorizDPI = (long)g->dwForcedHorizDPI;
+ if (g->dwForcedVertDPI != 0)
+ pXform->inTraits.lVertDPI = (long)g->dwForcedVertDPI;
+ }
+ }
+
+ result = pXform->pXform->openXform (&pXform->hXform);
+ INSURE (result == IP_DONE);
+ result = pXform->pXform->setDefaultInputTraits (
+ pXform->hXform, &pXform->inTraits);
+ INSURE (result == IP_DONE);
+ result = pXform->pXform->setXformSpec (
+ pXform->hXform, pXform->aXformInfo);
+ INSURE (result == IP_DONE);
+ result = pXform->pXform->getHeaderBufSize (
+ pXform->hXform, &pXform->dwMinInBufLen);
+ INSURE (result == IP_DONE);
+
+ if (! atTheHead) {
+ /* a header is only allowed on first xform */
+ INSURE (pXform->dwMinInBufLen == 0);
+ } else {
+ /* allocate the input genbuf */
+ if (pXform->dwMinInBufLen == 0)
+ pXform->dwMinInBufLen = 1;
+ PRINT0 (_T("ipConvert: alloc input genbuf, len=%d\n"),
+ pXform->dwMinInBufLen);
+ IP_MEM_ALLOC (pXform->dwMinInBufLen, pgbIn->pbBuf);
+ pgbIn->dwBufLen = pXform->dwMinInBufLen;
+ pgbIn->dwValidStart = 0;
+ pgbIn->dwValidLen = 0;
+ pgbIn->dwFilePos = 0;
+ }
+
+ pXform->eState = XS_PARSING_HEADER;
+ }
+
+ /**** Enter flushing state if appropriate ****/
+
+ if (pXform->eState == XS_CONVERTING &&
+ (( atTheHead && pbInputBuf==NULL && pgbIn->dwValidLen==0) ||
+ (!atTheHead && pPriorXform->eState==XS_DONE && g->iOwner<0))) {
+ /* there will never be any more input to this xform: start flushing */
+ PRINT0 (_T("ipConvert: xform %d is now flushing\n"), iXform);
+ pXform->eState = XS_FLUSHING;
+ }
+
+ /**** Check that input data and output space are available ****/
+
+ needInput = (pXform->eState==XS_PARSING_HEADER ||
+ pXform->eState==XS_CONVERTING);
+
+ if (needInput) {
+ if (! atTheHead) {
+ /* the input midbuf must contain data */
+ INSURE (g->iOwner>=0 && g->dwMidValidLen>0);
+ PRINT1 (_T("not at head, pixels = %08x\n"), *(DWORD*)(g->pbMidInBuf));
+ } else if (pbInputBuf != NULL) {
+ DWORD dwUnusedStart;
+
+ /* left-justify data in input genbuf if necessary */
+
+ if (pgbIn->dwBufLen-pgbIn->dwValidStart < pXform->dwMinInBufLen) {
+ /* too much wasted space on left end, so left justify */
+ memmove (pgbIn->pbBuf, pgbIn->pbBuf + pgbIn->dwValidStart,
+ pgbIn->dwValidLen);
+ pgbIn->dwValidStart = 0;
+ PRINT1 (_T("left just, pixels = %08x\n"), *(DWORD*)(pgbIn->pbBuf));
+ }
+
+ /* put as much client input as possible into the input genbuf */
+
+ dwUnusedStart = pgbIn->dwValidStart + pgbIn->dwValidLen;
+ dwBytes = pgbIn->dwBufLen - dwUnusedStart;
+ if (dwBytes > dwInputAvail)
+ dwBytes = dwInputAvail;
+
+ memcpy (pgbIn->pbBuf + dwUnusedStart,
+ pbInputBuf + *pdwInputUsed,
+ dwBytes);
+
+ pgbIn->dwValidLen += dwBytes;
+ *pdwInputUsed += dwBytes;
+ dwInputAvail -= dwBytes;
+ *pdwInputNextPos += dwBytes;
+
+ /* if input genbuf has insufficient data, exit loop */
+ if (pgbIn->dwValidLen < pXform->dwMinInBufLen)
+ goto exitLoop;
+ PRINT1 (_T("at head, pixels = %08x\n"), *(DWORD*)(pgbIn->pbBuf));
+ }
+ }
+
+ if (atTheTail && pXform->eState!=XS_PARSING_HEADER) {
+ /* output might be produced; output genbuf must be empty */
+ INSURE (pgbOut->dwValidLen == 0);
+ }
+
+ /**** Call the Conversion Routine ****/
+
+ pbTheInBuf = atTheHead ? pgbIn->pbBuf + pgbIn->dwValidStart : g->pbMidInBuf;
+ dwTheInLen = atTheHead ? pgbIn->dwValidLen : g->dwMidValidLen;
+ pbTheOutBuf = atTheTail ? pgbOut->pbBuf : g->pbMidOutBuf;
+ dwTheOutLen = atTheTail ? pgbOut->dwBufLen : g->dwMidLen;
+
+ if (pXform->eState == XS_PARSING_HEADER) {
+ result = pXform->pXform->getActualTraits (
+ pXform->hXform,
+ dwTheInLen, pbTheInBuf, &dwInUsed, &dwInNextPos,
+ &pXform->inTraits,
+ &pXform->outTraits);
+ dwOutUsed = 0;
+ dwOutThisPos = 0;
+ } else {
+ if (pXform->eState == XS_FLUSHING)
+ pbTheInBuf = NULL;
+ result = pXform->pXform->convert (
+ pXform->hXform,
+ dwTheInLen, pbTheInBuf, &dwInUsed, &dwInNextPos,
+ dwTheOutLen, pbTheOutBuf, &dwOutUsed, &dwOutThisPos);
+ }
+
+ PRINT1 (_T("ipConvert: xform %d returned %04x\n"), iXform, result);
+ PRINT1 (_T("ipConvert: consumed %d and produced %d bytes\n"),
+ dwInUsed, dwOutUsed);
+
+ if (pbTheOutBuf != NULL)
+ PRINT1 (_T("ipConvert: out data = %08x\n"), *(DWORD*)pbTheOutBuf);
+
+ INSURE ((result & IP_FATAL_ERROR) == 0);
+
+ /**** Update Input and Output Buffers ****/
+
+ if (dwInUsed > 0) {
+ if (pXform->pfReadPeek != NULL) {
+ #if defined _WIN32
+ __try {
+ #endif
+ pXform->pfReadPeek (hJob, &(pXform->inTraits),
+ dwInUsed, pbTheInBuf, pgbIn->dwFilePos,
+ pXform->pUserData);
+ #if defined _WIN32
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ goto fatal_error;
+ }
+ #endif
+ }
+
+ if (! atTheHead) {
+ /* We _assume_ that the xform consumed all the data in the midbuf */
+ g->iOwner = -1; /* input midbuf is consumed and un-owned now */
+ g->dwMidValidLen = 0;
+ }
+ }
+
+ if (needInput && atTheHead) {
+ if (dwInUsed >= pgbIn->dwValidLen) {
+ /* consumed all input; mark input genbuf as empty */
+ pgbIn->dwValidLen = 0;
+ pgbIn->dwValidStart = 0;
+ pgbIn->dwFilePos = dwInNextPos;
+ } else {
+ /* advance counters in genbuf */
+ pgbIn->dwValidLen -= dwInUsed;
+ pgbIn->dwValidStart += dwInUsed;
+ pgbIn->dwFilePos += dwInUsed;
+ }
+
+ /* if new genbuf file-pos doesn't match what xform wants,
+ * discard remainder of buffer */
+ if (pgbIn->dwFilePos != dwInNextPos) {
+ PRINT0 (_T("ipConvert: input seek to %d\n"), dwInNextPos);
+ pgbIn->dwValidLen = 0;
+ pgbIn->dwValidStart = 0;
+ pgbIn->dwFilePos = dwInNextPos;
+ }
+ }
+
+ if (dwOutUsed > 0) {
+ if (pXform->pfWritePeek != NULL) {
+ #if defined _WIN32
+ __try {
+ #endif
+ pXform->pfWritePeek (hJob, &(pXform->outTraits),
+ dwOutUsed, pbTheOutBuf, dwOutThisPos,
+ pXform->pUserData);
+ #if defined _WIN32
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ goto fatal_error;
+ }
+ #endif
+ }
+
+ if (atTheTail) {
+ pgbOut->dwFilePos = dwOutThisPos;
+ pgbOut->dwValidStart = 0;
+ pgbOut->dwValidLen = dwOutUsed;
+ } else {
+ INSURE (g->iOwner < 0); /* mid inbuf must be unowned here */
+ g->iOwner = iXform + 1; /* next xform hereby owns mid inbuf */
+ /* swap input and output midbuf pointers */
+ pbTemp = g->pbMidInBuf;
+ g->pbMidInBuf = g->pbMidOutBuf;
+ g->pbMidOutBuf = pbTemp;
+ g->dwMidValidLen = dwOutUsed;
+ }
+ }
+
+ /**** Handle Results of Conversion Call ****/
+
+ selectCnvState = FALSE;
+
+ if (pXform->eState == XS_PARSING_HEADER) {
+
+ if (result & IP_DONE) {
+ PRINT0 (_T("ipConvert: xform %d is done parsing header\n"), iXform);
+ pXform->pXform->getActualBufSizes (pXform->hXform,
+ &pXform->dwMinInBufLen, &pXform->dwMinOutBufLen);
+
+ if (atTheHead) {
+ /* allocate new input genbuf, and xfer data into it */
+ n = pXform->dwMinInBufLen;
+ if (n < MIN_GENBUF_LEN)
+ n = MIN_GENBUF_LEN;
+ if (n < pgbIn->dwValidLen)
+ n = pgbIn->dwValidLen;
+ PRINT0 (_T("ipConvert: alloc new input genbuf, ")
+ _T("old len=%d, new len=%d\n"), pgbIn->dwBufLen, n);
+ PRINT0 (_T(" dwMinInBufLen=%d, dwValidLen=%d\n"),
+ pXform->dwMinInBufLen, pgbIn->dwValidLen);
+ IP_MEM_ALLOC (n, pbTemp);
+ memcpy (pbTemp,
+ pgbIn->pbBuf + pgbIn->dwValidStart,
+ pgbIn->dwValidLen);
+ IP_MEM_FREE (pgbIn->pbBuf);
+ pgbIn->pbBuf = pbTemp;
+ pgbIn->dwBufLen = n;
+ pgbIn->dwValidStart = 0;
+ }
+
+ /* boost size of midbufs if necessary (also 1st malloc of them) */
+ n = atTheHead ? 0 : pXform->dwMinInBufLen;
+ if (!atTheTail && pXform->dwMinOutBufLen > n)
+ n = pXform->dwMinOutBufLen;
+ /* note: the code below (correctly) does not create mid-bufs if
+ * n is 0, which occurs if there's only one xform in the list */
+ if (n > g->dwMidLen) {
+ /* delete both mid-bufs, and (re) allocate them */
+ /* copy data from old to new, if necessary */
+ PBYTE pbOldMidInBuf = g->pbMidInBuf;
+ g->pbMidInBuf = NULL;
+ PRINT0 (_T("ipConvert: alloc mid-bufs, old len=%d, new len=%d\n"),
+ g->dwMidLen, n);
+ deleteMidBufs (g);
+ IP_MEM_ALLOC (n, g->pbMidInBuf );
+ IP_MEM_ALLOC (n, g->pbMidOutBuf);
+ if (pbOldMidInBuf != NULL) {
+ memcpy (g->pbMidInBuf, pbOldMidInBuf, g->dwMidLen);
+ IP_MEM_FREE (pbOldMidInBuf);
+ }
+ g->dwMidLen = n;
+ }
+
+ if (atTheTail) {
+ /* allocate output genbuf */
+ n = pXform->dwMinOutBufLen;
+ if (n < MIN_GENBUF_LEN)
+ n = MIN_GENBUF_LEN;
+ PRINT0 (_T("ipConvert: alloc output genbuf, len=%d, minlen=%d\n"),
+ n, pXform->dwMinOutBufLen);
+ IP_MEM_ALLOC (n, pgbOut->pbBuf);
+ pgbOut->dwBufLen = n;
+ pgbOut->dwValidStart = 0;
+ pgbOut->dwValidLen = 0;
+
+ /* At this point it is permissible to call ipGetImageTraits
+ * to obtain output traits because all xforms are past the
+ * parsing-header state, and thus the output traits are known.
+ * So tell caller that we're done parsing the header. */
+ ipResult |= IP_PARSED_HEADER;
+ }
+
+ selectCnvState = TRUE;
+ }
+
+ } else { /* state is XS_CONVERTING or XS_CONV_NOT_RFD or XS_FLUSHING */
+
+ if (atTheHead) {
+ /* handle status bits pertaining to the input data */
+ if (result & IP_CONSUMED_ROW) {
+ g->lInRows += 1;
+ ipResult |= IP_CONSUMED_ROW;
+ }
+ if (result & IP_NEW_OUTPUT_PAGE) {
+ /* a new *output* page for the input xform is a new *input* page
+ * for the IP as a whole */
+ g->iInPages += 1;
+ ipResult |= IP_NEW_INPUT_PAGE;
+ }
+ }
+
+ if (atTheTail) {
+ /* handle status bits pertaining to the output data */
+ ipResult |= (result & (IP_PRODUCED_ROW | IP_NEW_OUTPUT_PAGE));
+ if (result & IP_PRODUCED_ROW)
+ g->lOutRows += 1;
+ if (result & IP_NEW_OUTPUT_PAGE)
+ g->iOutPages += 1;
+ if (result & IP_WRITE_INSERT_OK & g->wResultMask)
+ g->pendingInsert = TRUE;
+ } else if (result & IP_NEW_OUTPUT_PAGE) {
+ /* this xform hit end of page, so tell next xform about it */
+ PRINT0 (_T("ipConvert: xform %d hit end of page\n"), iXform);
+ pNextXform->pXform->newPage (pNextXform->hXform);
+ }
+
+ if (result & IP_DONE) {
+ PRINT0 (_T("ipConvert: xform %d is done\n"), iXform);
+ pXform->eState = XS_DONE;
+ } else if (pXform->eState != XS_FLUSHING)
+ selectCnvState = TRUE;
+ } /* if state is 'parsing header' */
+
+ if (selectCnvState) {
+ /* go to one of the two 'converting' states */
+ if ((result & IP_READY_FOR_DATA) == 0)
+ PRINT1 (_T("ipConvert: xform %d is not ready for data\n"), iXform);
+ pXform->eState = (result & IP_READY_FOR_DATA)
+ ? XS_CONVERTING : XS_CONV_NOT_RFD;
+ }
+
+ } /* end of while (TRUE) */
+ exitLoop: ;
+
+ /********************/
+ /* End of Main Loop */
+ /********************/
+
+ *pdwInputNextPos = pgbIn->dwFilePos + pgbIn->dwValidLen;
+
+ /* After headers are parsed, parsed-header bit should always be set */
+ if (g->xfArray[g->xfCount-1].eState >= XS_CONVERTING)
+ ipResult |= IP_PARSED_HEADER;
+
+ PRINT0 (_T("ipConvert: ipResult=%04x, returning %04x, InputUsed=%d InputNextPos=%d OutputUsed=%d OutputThisPos=%d\n"),
+ ipResult, ipResult & g->wResultMask, *pdwInputUsed, *pdwInputNextPos, *pdwOutputUsed, *pdwOutputThisPos);
+
+#ifdef HPIP_DEBUG
+ if (pbInputBuf && *pdwInputUsed)
+ write(infd, pbInputBuf, *pdwInputUsed);
+
+ if (*pdwOutputUsed)
+ write(outfd, pbOutputBuf, *pdwOutputUsed);
+#endif
+
+ return ipResult & g->wResultMask;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ipMirrorBytes - Swaps bits in each byte of buffer
+ * (bits 0<->7, 1<->6, etc.)
+ *
+\*****************************************************************************/
+
+static const BYTE baMirrorImage[256] =
+{
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+VOID ipMirrorBytes(PBYTE pbInputBuf,DWORD dwInputAvail) {
+ while (dwInputAvail>0) {
+ *pbInputBuf=baMirrorImage[*pbInputBuf];
+ pbInputBuf++;
+ dwInputAvail--;
+ }
+}
+
+/* End of File */
diff --git a/ip/xbi2gray.c b/ip/xbi2gray.c
new file mode 100644
index 0000000..a250811
--- /dev/null
+++ b/ip/xbi2gray.c
@@ -0,0 +1,453 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xbi2gray.c - Converts bilevel into gray (8-bit gray or 24-bit gray)
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * yBi2GrayTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_BI_2_GRAY_OUTPUT_BPP] = format of output:
+ * 8 = output 8-bit gray,
+ * 24 = output 24-bit gray.
+ * aXformInfo[IP_BI_2_GRAY_WHITE_PIXEL] =
+ * an RGBQUAD representing a white output pixel.
+ * aXformInfo[IP_BI_2_GRAY_BLACK_PIXEL] =
+ * an RGBQUAD representing a black output pixel.
+ *
+ * Each bilevel pixel is output as a full white or full black pixel.
+ * This xform needs to know what values to use for those white and
+ * black output pixels. Hence the two RGBQUAD items above.
+ * For 8-bit gray output, only the rgbRed field is used in each.
+ *
+ * Capabilities and Limitations:
+ *
+ * Translates each white or black bilevel input pixel into an 8-bit
+ * or 24-bit output white or black output pixel.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * must be 1 8 or 24
+ * iComponentsPerPixel * must be 1 1 or 3
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Mar 1998 Mark Overton -- wrote code
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x1ce5ca7e
+
+typedef struct {
+ IP_IMAGE_TRAITS inTraits; /* traits of the input image */
+ UINT uRowsDone; /* number of rows converted so far */
+ WORD wOutBitsPerPixel; /* bits/pixel to output (8 or 24) */
+ RGBQUAD rgbWhite; /* value of an output white */
+ RGBQUAD rgbBlack; /* value of an output black */
+ DWORD dwInRowBytes; /* # bytes per input row */
+ DWORD dwOutRowBytes; /* # bytes per output row */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} B2G_INST, *PB2G_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * bi2gray_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD bi2gray_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PB2G_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(B2G_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(B2G_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * bi2gray_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD bi2gray_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PB2G_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Insure that values we care about are correct */
+ INSURE (pTraits->iBitsPerPixel == 1);
+ INSURE (pTraits->iComponentsPerPixel == 1);
+ INSURE (pTraits->iPixelsPerRow > 0);
+
+ g->inTraits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * bi2gray_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD bi2gray_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PB2G_INST g;
+ UINT nBits;
+
+ HANDLE_TO_PTR (hXform, g);
+ nBits = aXformInfo[IP_BI_2_GRAY_OUTPUT_BPP].dword;
+ INSURE (nBits==8 || nBits==24);
+ g->wOutBitsPerPixel = (WORD)nBits;
+ g->rgbWhite = aXformInfo[IP_BI_2_GRAY_WHITE_PIXEL].rgbquad;
+ g->rgbBlack = aXformInfo[IP_BI_2_GRAY_BLACK_PIXEL].rgbquad;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * bi2gray_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD bi2gray_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * bi2gray_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD bi2gray_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PB2G_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pInTraits = g->inTraits; /* structure copies */
+ *pOutTraits = g->inTraits;
+ pOutTraits->iBitsPerPixel = g->wOutBitsPerPixel;
+ pOutTraits->iComponentsPerPixel = g->wOutBitsPerPixel==8 ? 1 : 3;
+
+ g->dwInRowBytes = (g->inTraits.iPixelsPerRow+7) / 8;
+ g->dwOutRowBytes = g->inTraits.iPixelsPerRow * pOutTraits->iComponentsPerPixel;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * bi2gray_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD bi2gray_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PB2G_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = g->dwInRowBytes;
+ *pdwMinOutBufLen = g->dwOutRowBytes;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * bi2gray_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD bi2gray_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PB2G_INST g;
+ PBYTE pIn, pOut, pInAfter;
+ BYTE bMask, bBilevel;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("bi2gray_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ INSURE (dwInputAvail >= g->dwInRowBytes );
+ INSURE (dwOutputAvail >= g->dwOutRowBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pInAfter = pIn + g->dwInRowBytes;
+
+ while (pIn < pInAfter) {
+ bBilevel = *pIn++;
+
+ if (g->wOutBitsPerPixel == 24) {
+ for (bMask=0x80u; bMask!=0; bMask>>=1) {
+ *(RGBQUAD*)pOut = (bMask & bBilevel)
+ ? g->rgbBlack
+ : g->rgbWhite;
+ pOut += 3;
+ }
+ } else { /* 8 bits per output pixel */
+ for (bMask=0x80u; bMask!=0; bMask>>=1) {
+ *pOut++ = (bMask & bBilevel)
+ ? g->rgbBlack.rgbRed
+ : g->rgbWhite.rgbRed;
+ }
+ }
+ }
+
+ *pdwInputUsed = g->dwInRowBytes;
+ g->dwInNextPos += g->dwInRowBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = g->dwOutRowBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += g->dwOutRowBytes;
+
+ g->uRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * bi2gray_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD bi2gray_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * bi2gray_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD bi2gray_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PB2G_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * bi2gray_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD bi2gray_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PB2G_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * bi2grayTbl - Jump-table for encoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL bi2grayTbl = {
+ bi2gray_openXform,
+ bi2gray_setDefaultInputTraits,
+ bi2gray_setXformSpec,
+ bi2gray_getHeaderBufSize,
+ bi2gray_getActualTraits,
+ bi2gray_getActualBufSizes,
+ bi2gray_convert,
+ bi2gray_newPage,
+ bi2gray_insertedData,
+ bi2gray_closeXform
+};
+
+/* End of File */
diff --git a/ip/xchgbpp.c b/ip/xchgbpp.c
new file mode 100644
index 0000000..dd8a454
--- /dev/null
+++ b/ip/xchgbpp.c
@@ -0,0 +1,627 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xchangeBPP.c - Changes bits per pixel
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * changeBPPTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_CHANGE_BPP_OUTPUT_BPP] = bits/pixel to output
+ *
+ * Capabilities and Limitations:
+ *
+ * 1 bpp is assumed to be bilevel (0=white, 1=black).
+ * 8 and 16 bpp are assumed to be grayscale.
+ * 24 and 48 bpp are assumed to be 3-component color (rgb is assumed when
+ * we convert from color into grayscale).
+ * Among the above supported bpp values, any bpp can be changed into any
+ * other bpp. Changing into bi-level (bpp=1) performs simple thresholding.
+ * Use xgray2bi if you want error-diffusion.
+ * If the input and output bpp values are the same, this xform merely passes
+ * the pixels through unexamined.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * anything changed as specified
+ * iComponentsPerPixel * 1 or 3 can be changed to 3
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Mar 1998 Mark Overton -- wrote code (for 1 -> 8/24 only)
+ * Apr 2000 Mark Overton -- generalized as a change-BPP xform
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+#include "assert.h"
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x1ce5ca7e
+
+typedef struct {
+ IP_IMAGE_TRAITS inTraits; /* traits of the input image */
+ UINT uRowsDone; /* number of rows converted so far */
+ WORD wOutBitsPerPixel; /* bits/pixel to output */
+ DWORD dwInRowBytes; /* # bytes per input row */
+ DWORD dwOutRowBytes; /* # bytes per output row */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} CBPP_INST, *PCBPP_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * changeBPP_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD changeBPP_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PCBPP_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(CBPP_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(CBPP_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * changeBPP_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD changeBPP_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PCBPP_INST g;
+ int bpp;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Insure that values we care about are correct */
+ bpp = pTraits->iBitsPerPixel;
+ INSURE (bpp==1 || bpp==8 || bpp==16 || bpp==24 || bpp==48);
+ INSURE (pTraits->iComponentsPerPixel==1 || pTraits->iComponentsPerPixel==3);
+ INSURE (pTraits->iPixelsPerRow > 0);
+
+ g->inTraits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * changeBPP_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD changeBPP_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PCBPP_INST g;
+ UINT nBits;
+
+ HANDLE_TO_PTR (hXform, g);
+ nBits = aXformInfo[IP_CHANGE_BPP_OUTPUT_BPP].dword;
+ g->wOutBitsPerPixel = (WORD)nBits;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * changeBPP_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD changeBPP_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * changeBPP_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD changeBPP_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PCBPP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pInTraits = g->inTraits; /* structure copies */
+ *pOutTraits = g->inTraits;
+ pOutTraits->iBitsPerPixel = g->wOutBitsPerPixel;
+ pOutTraits->iComponentsPerPixel = g->wOutBitsPerPixel<24 ? 1 : 3;
+
+ g->dwInRowBytes = (g->inTraits.iPixelsPerRow*g->inTraits.iBitsPerPixel + 7) / 8;
+ g->dwOutRowBytes = (g->inTraits.iPixelsPerRow*g->wOutBitsPerPixel + 7) / 8;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * changeBPP_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD changeBPP_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PCBPP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = g->dwInRowBytes;
+ *pdwMinOutBufLen = g->dwOutRowBytes;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * changeBPP_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD changeBPP_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PCBPP_INST g;
+ PBYTE pIn, pOut, pInAfter;
+ unsigned rv, gv, bv;
+ BYTE bMask, bBilevel;
+ BYTE bPixels;
+ WORD wPixels;
+ DWORD dwPixels;
+
+ #define OUTPUT_THRESHOLDED_BIT(grayParam) { \
+ int gray = grayParam; \
+ if (gray < 128) bBilevel |= bMask; \
+ bMask >>= 1; \
+ if (bMask == 0) { \
+ *pOut++ = (BYTE)bBilevel; \
+ bBilevel = 0; \
+ bMask = (BYTE)0x80; \
+ } \
+ }
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("changeBPP_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ INSURE (dwInputAvail >= g->dwInRowBytes );
+ INSURE (dwOutputAvail >= g->dwOutRowBytes);
+
+ bMask = 0x80;
+ bBilevel = 0;
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pInAfter = pIn + g->dwInRowBytes;
+
+ if (g->inTraits.iBitsPerPixel == g->wOutBitsPerPixel) {
+ /* no change in bpp; just copy the buffer */
+ memcpy (pOut, pIn, g->dwInRowBytes);
+ } else if (g->inTraits.iBitsPerPixel == 1) {
+ while (pIn < pInAfter) {
+ bBilevel = *pIn++;
+
+ if (g->wOutBitsPerPixel == 48) {
+ for (bMask=0x80u; bMask!=0; bMask>>=1) {
+ dwPixels = (bMask & bBilevel)
+ ? 0 /* black */
+ : 0xffffffff; /* white */
+ *(DWORD*)pOut = dwPixels;
+ *(WORD*)(pOut+4) = (WORD)dwPixels;
+ pOut += 6;
+ }
+ } else if (g->wOutBitsPerPixel == 24) {
+ for (bMask=0x80u; bMask!=0; bMask>>=1) {
+ *(DWORD*)pOut = (bMask & bBilevel)
+ ? 0 /* black */
+ : 0xffffffff; /* white */
+ pOut += 3;
+ }
+ } else if (g->wOutBitsPerPixel == 16) {
+ for (bMask=0x80u; bMask!=0; bMask>>=1) {
+ *(WORD*)pOut = (bMask & bBilevel)
+ ? 0 /* black */
+ : 0xffff; /* white */
+ pOut += 2;
+ }
+ } else if (g->wOutBitsPerPixel == 8) {
+ for (bMask=0x80u; bMask!=0; bMask>>=1) {
+ *pOut++ = (bMask & bBilevel)
+ ? 0 /* black */
+ : 0xff; /* white */
+ }
+ } else
+ assert (0);
+ }
+ }
+ else if (g->inTraits.iBitsPerPixel == 8) {
+ if (g->wOutBitsPerPixel == 48) {
+ while (pIn < pInAfter) {
+ wPixels = (*pIn++ << 8);
+ *(WORD*)(pOut+0) = wPixels;
+ *(WORD*)(pOut+2) = wPixels;
+ *(WORD*)(pOut+4) = wPixels;
+ pOut += 6;
+ }
+ } else if (g->wOutBitsPerPixel == 24) {
+ while (pIn < pInAfter) {
+ bPixels = *pIn++;
+ *pOut++ = bPixels;
+ *pOut++ = bPixels;
+ *pOut++ = bPixels;
+ }
+ } else if (g->wOutBitsPerPixel == 16) {
+ while (pIn < pInAfter) {
+ wPixels = (*pIn++ << 8);
+ *(WORD*)pOut = wPixels;
+ pOut += 2;
+ }
+ } else if (g->wOutBitsPerPixel == 1) {
+ while (pIn < pInAfter) {
+ OUTPUT_THRESHOLDED_BIT (*pIn);
+ pIn++;
+ }
+ } else
+ assert (0);
+ }
+ else if (g->inTraits.iBitsPerPixel == 16) {
+ if (g->wOutBitsPerPixel == 48) {
+ while (pIn < pInAfter) {
+ wPixels = *(WORD*)pIn;
+ *(WORD*)(pOut+0) = wPixels;
+ *(WORD*)(pOut+2) = wPixels;
+ *(WORD*)(pOut+4) = wPixels;
+ pIn += 2;
+ pOut += 6;
+ }
+ } else if (g->wOutBitsPerPixel == 24) {
+ while (pIn < pInAfter) {
+ bPixels = (*(WORD*)pIn) >> 8;
+ pIn += 2;
+ *pOut++ = bPixels;
+ *pOut++ = bPixels;
+ *pOut++ = bPixels;
+ }
+ } else if (g->wOutBitsPerPixel == 8) {
+ while (pIn < pInAfter) {
+ *pOut++ = (*(WORD*)pIn) >> 8;
+ pIn += 2;
+ }
+ } else if (g->wOutBitsPerPixel == 1) {
+ while (pIn < pInAfter) {
+ OUTPUT_THRESHOLDED_BIT ((*(WORD*)pIn) >> 8);
+ pIn += 2;
+ }
+ } else
+ assert (0);
+ }
+ else if (g->inTraits.iBitsPerPixel == 24) {
+ if (g->wOutBitsPerPixel == 48) {
+ while (pIn < pInAfter) {
+ *(WORD*)(pOut+0) = (WORD)(*pIn++) << 8;
+ *(WORD*)(pOut+2) = (WORD)(*pIn++) << 8;
+ *(WORD*)(pOut+4) = (WORD)(*pIn++) << 8;
+ pOut += 6;
+ }
+ } else if (g->wOutBitsPerPixel == 16) {
+ /* converting rgb color (24) to grayscale (16) */
+ while (pIn < pInAfter) {
+ rv = (*pIn++) << 8;
+ gv = (*pIn++) << 8;
+ bv = (*pIn++) << 8;
+ *(WORD*)pOut = NTSC_LUMINANCE (rv, gv, bv);
+ pOut += 2;
+ }
+ } else if (g->wOutBitsPerPixel == 8) {
+ /* converting rgb color (24) to grayscale (8) */
+ while (pIn < pInAfter) {
+ rv = *pIn++;
+ gv = *pIn++;
+ bv = *pIn++;
+ *pOut++ = NTSC_LUMINANCE (rv, gv, bv);
+ }
+ } else if (g->wOutBitsPerPixel == 1) {
+ /* converting rgb color (24) to bi-level */
+ while (pIn < pInAfter) {
+ rv = *pIn++;
+ gv = *pIn++;
+ bv = *pIn++;
+ OUTPUT_THRESHOLDED_BIT (NTSC_LUMINANCE(rv,gv,bv));
+ }
+ } else
+ assert (0);
+ }
+ else if (g->inTraits.iBitsPerPixel == 48) {
+ if (g->wOutBitsPerPixel == 24) {
+ while (pIn < pInAfter) {
+ *pOut++ = ((WORD*)pIn)[0] >> 8;
+ *pOut++ = ((WORD*)pIn)[1] >> 8;
+ *pOut++ = ((WORD*)pIn)[2] >> 8;
+ pIn += 6;
+ }
+ } else if (g->wOutBitsPerPixel == 16) {
+ /* converting rgb color (48) to grayscale (16) */
+ while (pIn < pInAfter) {
+ rv = ((WORD*)pIn)[0];
+ gv = ((WORD*)pIn)[1];
+ bv = ((WORD*)pIn)[2];
+ *(WORD*)pOut = NTSC_LUMINANCE (rv, gv, bv);
+ pIn += 6;
+ pOut += 2;
+ }
+ } else if (g->wOutBitsPerPixel == 8) {
+ /* converting rgb color (48) to grayscale (8) */
+ while (pIn < pInAfter) {
+ rv = ((WORD*)pIn)[0];
+ gv = ((WORD*)pIn)[1];
+ bv = ((WORD*)pIn)[2];
+ *pOut++ = NTSC_LUMINANCE (rv, gv, bv) >> 8;
+ pIn += 6;
+ }
+ } else if (g->wOutBitsPerPixel == 1) {
+ /* converting rgb color (48) to bi-level */
+ while (pIn < pInAfter) {
+ rv = ((WORD*)pIn)[0];
+ gv = ((WORD*)pIn)[1];
+ bv = ((WORD*)pIn)[2];
+ OUTPUT_THRESHOLDED_BIT (NTSC_LUMINANCE(rv,gv,bv) >> 8);
+ pIn += 6;
+ }
+ } else
+ assert (0);
+ }
+
+ if (g->inTraits.iBitsPerPixel>1 && g->wOutBitsPerPixel==1 && bMask!=(BYTE)0x80)
+ *pOut = bBilevel; /* output any partially-filled byte */
+
+ *pdwInputUsed = g->dwInRowBytes;
+ g->dwInNextPos += g->dwInRowBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = g->dwOutRowBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += g->dwOutRowBytes;
+
+ g->uRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * changeBPP_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD changeBPP_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * changeBPP_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD changeBPP_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PCBPP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * changeBPP_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD changeBPP_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PCBPP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * changeBPPTbl - Jump-table for xform
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL changeBPPTbl = {
+ changeBPP_openXform,
+ changeBPP_setDefaultInputTraits,
+ changeBPP_setXformSpec,
+ changeBPP_getHeaderBufSize,
+ changeBPP_getActualTraits,
+ changeBPP_getActualBufSizes,
+ changeBPP_convert,
+ changeBPP_newPage,
+ changeBPP_insertedData,
+ changeBPP_closeXform
+};
+
+/* End of File */
diff --git a/ip/xcolrspc.c b/ip/xcolrspc.c
new file mode 100644
index 0000000..98a60b8
--- /dev/null
+++ b/ip/xcolrspc.c
@@ -0,0 +1,1191 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xcolrspc.c - Converts between color spaces
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * colorTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV] = Which color-space conversion to do:
+ * IP_CNV_YCC_TO_CIELAB = ycc -> cielab
+ * IP_CNV_CIELAB_TO_YCC = cielab -> ycc
+ * IP_CNV_YCC_TO_SRGB = ycc -> srgb
+ * IP_CNV_SRGB_TO_YCC = srgb -> ycc
+ * IP_CNV_LHS_TO_SRGB = lhs -> srgb
+ * IP_CNV_SRGB_TO_LHS = srgb -> lhs
+ * IP_CNV_BGR_SWAP = rgb<->bgr swap
+ *
+ * aXformInfo[IP_CNV_COLOR_SPACE_GAMMA] = Gamma value for gamma correction,
+ * in 16.16 fixed-point.
+ * In the YCC->CIELab conversion, the data will be
+ * inverse-gamma corrected using 1/Gamma.
+ * In the CIELab->YCC conversion, it will be gamma corrected
+ * using Gamma.
+ * This Gamma value is ignored in the other conversions.
+ * A value of 0.0 makes us use a default Gamma of 2.2.
+ * You must set this to 1.0 if you want to disable Gamma.
+ *
+ * Gamma is done here because the pixels are in RGB at one
+ * point in the YCC<->CIELab conversions. Since you can't do
+ * Gamma on YCC or CIELab data, it can't be done outside
+ * this xform for those two conversions.
+ *
+ * Capabilities and Limitations:
+ *
+ * Does the space conversions listed above. Conversions will only be done on
+ * 24-bit data; monochrome data are passed through unchanged.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * must be <= 24 same as default input
+ * iComponentsPerPixel passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Feb 1998 Mark Overton -- wrote original code, with dummy conversions
+ * Apr 1998 Mark Overton -- added actual conversion code, adapted from
+ * Cindy Samson's code
+ *
+\******************************************************************************/
+
+#include "math.h" // needed for pow and floor
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+#include "assert.h"
+
+/* xsc_clean[Uu]p.h: */
+
+int Send_yTable[100] = {
+210,212,213,214,215,216,
+217,218,219,220,221,223,
+224,225,226,228,230,232,
+233,234,235,237,238,239,
+240,242,243,244,245,246,
+247,248,249,250,251,252,
+253,254,255,255,255,255,
+255,255,255,255};
+
+/* end xsc_clean[Uu]p.h */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input image */
+ IP_WHICH_CNV which_cnv; /* which space-conversion to do */
+ BYTE bGammaTbl[256]; /* Gamma-correction table */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} COL_INST, *PCOL_INST;
+
+static BOOL fInited = FALSE;
+
+//Neutral Shift Data Definition
+#define NEUTRAL_SHIFT_SEND TRUE
+
+
+// constants to convert [r,g,b] into Y
+#define RGBTOY_R_FAC 0.30078125f
+#define RGBTOY_G_FAC 0.5859375f
+#define RGBTOY_B_FAC 0.11328125f
+
+// constants to convert [y,cb,cr] into [r,g,b]
+#define YCCTORGB_CR_TO_R 1.39946f
+#define YCCTORGB_CB_TO_G -0.344228f
+#define YCCTORGB_CR_TO_G -0.717202f
+#define YCCTORGB_CB_TO_B 1.77243f
+
+
+// The above constants used for converting between RGB and YCC are based
+// on the following conversion matrices. The code assumes that the
+// 0.003 and 0.006 below are zero.
+#if 0
+ static float RGBtoYCC[3][3]= { // input is RGB
+ 0.30078125f, 0.5859375f, 0.11328125f, // Y
+ -0.16796875f, -0.33203125f, 0.5f, // Cb
+ 0.5f, -0.41796875f, -0.08203125f // Cr
+ };
+
+ static float YCCtoRGB[3][3]= { // input is YCbCr
+ 1.0f, 0.003f, 1.39946f, // R
+ 1.0f, -0.344228f, -0.717202f, // G
+ 1.0f, 1.77243f, 0.006f // B
+ };
+#endif
+
+
+#define X_SCALE (255.0/244.0)
+#define Y_SCALE (255.0/255.0)
+#define Z_SCALE (255.0/210.0)
+
+#define DEFAULT_GAMMA 2.2f
+#define SLIGHT_BOOST (255.0/253.0) // todo - get rid of this
+
+
+/****************************************************************************\
+ ****************************************************************************
+ ** **
+ ** W O R K E R R O U T I N E S **
+ ** **
+ ****************************************************************************
+\****************************************************************************/
+
+
+
+#define CLIP(wilma) ((wilma>255) ? 255 : ((wilma<0) ? 0 : (wilma)))
+
+#define TERM_FRAC_BITS 4 // # frac bits in temp x/y/z terms
+#define CONV_FRAC_BITS 4 // # frac bits in "_fix" conversion tables
+#define CONV_FRAC_ROUND (1L<<(CONV_FRAC_BITS-1))
+#define TBL33_FRAC_BITS 16 // # bits of fraction in 3x3 tables
+#define TABLE_FRAC_SCALE (1L << TBL33_FRAC_BITS)
+
+
+// these tables are computed by initTables
+
+static BYTE YtoL [256]; // these are for to/from CIELab
+static BYTE LtoY [256];
+static short cubeRoot [256];
+static BYTE cube [256];
+
+static short cb2b [256]; // these are for [y,cb,cr]->[r,g,b]
+static short cr2r [256];
+static short cr2g_fix [256];
+static short cb2g_fix [256];
+
+static short r2y_fix [256]; // these are for [r,g,b]->Y
+static short g2y_fix [256];
+static short b2y_fix [256];
+
+static BYTE by2cb [2*256]; // these are for [r,g,b]->CbCr
+static BYTE ry2cr [2*256];
+
+
+
+// VectMult - Multiplies a pixel by a 3x3 matrix, with fixed-point math
+//
+static void VectMult(
+ int inPixel[3], // in: input pixel
+ int outPixel[3], // out: output pixel
+ long *pMat) // in: 3x3 matrix with TBL33_FRAC_BITS of fraction
+{
+ int i;
+
+ for (i=0; i<3; i++) {
+ outPixel[i] = (int)( pMat[0]*inPixel[0] +
+ pMat[1]*inPixel[1] +
+ pMat[2]*inPixel[2] + (1L<<(TBL33_FRAC_BITS-1))
+ ) >> TBL33_FRAC_BITS;
+ pMat += 3;
+ }
+}
+
+
+
+// initTables - Computes look-up tables
+//
+// CIE Illuminant D50 white point Xn=96.422 Yn=100 Zn=82.521
+// CIE Illuminant D65 white point Xn=95.04 Yn=100 Zn=108.89
+// FAX gamut Range:
+// L* = [0,100]
+// a* = [-85, 85]
+// b* = [-75, 125]
+//
+// NL = 255/100*l
+// Na = 255/170 x a* + 128
+// Nb = 255/200 x b* + 96
+//
+
+static void initTables (void)
+{
+ int val;
+ int icr, icb;
+ float fval;
+ float t;
+
+ for (val=0; val<=255; val++)
+ {
+ fval = (float)val / 255.0f;
+
+ // compute Y->L array
+
+ if (fval > 0.008856f) t = 116.0f*(float)pow(fval,1.0/3.0) - 16.0f;
+ else t = 903.3f*fval;
+ t = (255.0f/100.0f)*t;
+ if (t < 0.0f) t = 0.0f;
+ if (t > 255.0f) t = 255.0f;
+ YtoL[val] = (BYTE)(t + 0.5f);
+
+ // compute L->Y array
+
+ if (val <= 7)
+ t = val * (100.0f/903.3f);
+ else {
+ t = (fval*100.0f+16.0f) / 116.0f;
+ t = 255.0f*t*t*t;
+ }
+ LtoY[val] = (BYTE)(t + 0.5f);
+
+ // compute cube-root array.
+ // Input is 0..255. We divide it by 255 so it's 0..1, take cube root,
+ // and scale result to 0..255. Adjustment is for small numbers.
+
+ if (fval > 0.008856f) t = (float)pow(fval, 1.0f/3.0f);
+ else t = 7.7867f*fval + 16.0f/116.0f;
+ cubeRoot[val] = (short)(t*255.0f*(1L<<TERM_FRAC_BITS) + 0.5f);
+
+ cube[val] = (BYTE)(255.0f*fval*fval*fval);
+ // above, we don't round because we won't reach full black in lab->ycc conv
+
+ // compute ycc<->rgb conversion tables
+
+ fval = (float)val;
+
+ r2y_fix[val] = (short)(SLIGHT_BOOST*RGBTOY_R_FAC*fval*(1<<CONV_FRAC_BITS));
+ g2y_fix[val] = (short)(SLIGHT_BOOST*RGBTOY_G_FAC*fval*(1<<CONV_FRAC_BITS));
+ b2y_fix[val] = (short)(SLIGHT_BOOST*RGBTOY_B_FAC*fval*(1<<CONV_FRAC_BITS));
+
+ fval -= 128.0f;
+
+ cb2b [val] = (short)(floor(YCCTORGB_CB_TO_B*fval + 0.5));
+ cr2r [val] = (short)(floor(YCCTORGB_CR_TO_R*fval + 0.5));
+ cb2g_fix[val] = (short)(YCCTORGB_CB_TO_G*fval*(1<<CONV_FRAC_BITS));
+ cr2g_fix[val] = (short)(YCCTORGB_CR_TO_G*fval*(1<<CONV_FRAC_BITS));
+ }
+
+
+ for (val=0; val<=2*255; val++)
+ {
+ fval = (float)val - 255.0f;
+
+ icb = (int)floor(fval/YCCTORGB_CB_TO_B + 0.5);
+ if (icb>=-4 && icb<=4) // make sure white is white
+ icb = 0;
+ icb += 128;
+ by2cb[val] = (BYTE)CLIP(icb);
+
+ icr = (int)floor(fval/YCCTORGB_CR_TO_R + 0.5);
+ if (icr>=-4 && icr<=4) // make sure white is white.
+ icr = 0;
+ icr += 128;
+ ry2cr[val] = (BYTE)CLIP(icr);
+ }
+}
+
+
+
+static void calcGammaTable (
+ PCOL_INST g,
+ DWORD dwGamma) /* Gamma value in 16.16 fixed-point */
+{
+ #define MAX_GAMMA_SLOPE 4
+
+ int i;
+ int maxval;
+ float fGamma, f, gamval;
+ BYTE bGamVal;
+
+ fGamma = (dwGamma == 0) ? DEFAULT_GAMMA : (float)dwGamma/(1L<<16);
+
+ switch (g->which_cnv) {
+ case IP_CNV_YCC_TO_CIELAB:
+ /* YCC is assumed to have been Gamma corrected. So we must do
+ * inverse Gamma when converting to CIELab
+ */
+ fGamma = 1.0f / fGamma;
+ break;
+
+ case IP_CNV_CIELAB_TO_YCC:
+ /* CIELab has not been Gamma corrected, so we must do forward
+ * Gamma when going to YCC.
+ */
+ break;
+
+ default:
+ /* No Gamma for the other conversions */
+ fGamma = 1.0f;
+ }
+
+ if (fGamma == 1.0f) {
+ /* No gamma correction: use identity table */
+ for (i=0; i<=255; i++)
+ g->bGammaTbl[i] = i;
+ } else {
+ fGamma = 1.0f / fGamma;
+ for (i=0; i<=255; i++) {
+ f = (float)i / 255.0f;
+ gamval = (float)pow(f, fGamma);
+ bGamVal = (BYTE)(255.0f*gamval + 0.5f);
+ maxval = (int)(i * MAX_GAMMA_SLOPE);
+ if (fGamma<1.0f && bGamVal>maxval)
+ bGamVal = maxval;
+ g->bGammaTbl[i] = bGamVal;
+ }
+ }
+}
+
+
+
+/****************************************************************************\
+ ****************************************************************************
+ ** **
+ ** YCC -> sRGB and YCC -> CIELAB **
+ ** **
+ ****************************************************************************
+\****************************************************************************/
+
+
+/* Table for Molokai (and Wizard, I think) */
+#if 0
+static long RGBtoXYZ50[9] = {
+ (long)(0.4358530*X_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.3840300*X_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.1431260*X_SCALE*TABLE_FRAC_SCALE + 0.5),
+
+ (long)(0.2225640*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.7200520*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.0607176*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
+
+ (long)(0.0139307*Z_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.0973260*Z_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.7142870*Z_SCALE*TABLE_FRAC_SCALE + 0.5)
+};
+#endif
+
+
+/* Table for Polaris and Avalon */
+#if 1
+static long RGBtoXYZ50[9] = {
+ (long)(0.464700*X_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.339211*X_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.156961*X_SCALE*TABLE_FRAC_SCALE + 0.5),
+
+ (long)(0.220615*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.700919*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.053199*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
+
+ (long)(0.005146*Z_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.050405*Z_SCALE*TABLE_FRAC_SCALE + 0.5),
+ (long)(0.774384*Z_SCALE*TABLE_FRAC_SCALE + 0.5)
+};
+#endif
+
+
+
+// YCCToCIELab - Converts a pixel (3 unsigned bytes) from YCC to fax LAB
+//
+// Conversions done herein:
+// YCC -> sRGB -> inverse Gamma -> XYZ(d65) -> XYZ(d50) -> LAB
+// Some of the above steps are combined for speed.
+//
+static void YCCToCIELab (
+ PBYTE pYCC, // in: YCC pixel (3 unsigned bytes)
+ PBYTE pCIELab, // out: LAB pixel (3 unsigned bytes)
+ PBYTE pGamma) // in: inverse Gamma table
+{
+ int iy, icb,icr;
+ int sR, sG, sB;
+ int sRGBval[3];
+ int XYZ50val[3];
+ int x, y, z;
+ int xterm, yterm, zterm;
+ int L, a, b;
+ int absCr, absCb; //Neutral Shift Purpose
+
+
+ iy = pYCC[0];
+ icb = pYCC[1];
+ icr = pYCC[2];
+
+#ifdef NEUTRAL_SHIFT_SEND
+
+ absCb = abs(icb-128);
+ absCr = abs(icr-128);
+
+ if (iy>=210)
+ {
+ iy = Send_yTable[iy-210];
+ }
+
+ if (iy ==255)
+ {
+
+ if ((absCb < 5) && (absCr <5))
+ {
+ icr = icb = 128;
+ }
+ }
+ else if (iy>240)
+ {
+ if ((absCb < 4) && (absCr <4))
+ {
+ icr=icb=128;
+ iy = 255;
+ }
+ else if ((absCb < 3) && (absCr <3))
+ {
+ icr=icb=128;
+ }
+ }
+ else if (iy>230)
+ {
+ if ((absCb < 3) && (absCr <3))
+ {
+ icr=icb=128;
+ iy = 250;
+ }
+ }
+ else if (iy>220)
+ {
+ if ((absCb < 3) && (absCr <3))
+ {
+ icr=icb=128;
+ iy = 240;
+ }
+ }
+ else if (iy >60)
+ {
+ if ((absCb <3) && (absCr <3))
+ {
+ icr=icb=128;
+ }
+ }
+
+ #endif
+
+/* END NEUTRAL SHIFT */
+ // iy=77; icb=85; icr=255; // solid red
+ // ycc=29,255,107 is solid blue
+
+
+ /**** Convert YCC to sRGB ****/
+
+ sR = iy + cr2r[icr];
+ sR = CLIP(sR);
+
+ sG = iy + ((cr2g_fix[icr] + cb2g_fix[icb] + CONV_FRAC_ROUND) >> CONV_FRAC_BITS);
+ sG = CLIP(sG);
+
+ sB = iy + cb2b[icb];
+ sB = CLIP(sB);
+
+ /**** Inverse Gamma correction, and Convert sRGB(d65) to XYZ(d50) ****/
+
+ sRGBval[0] = (long)pGamma[sR];
+ sRGBval[1] = (long)pGamma[sG];
+ sRGBval[2] = (long)pGamma[sB];
+
+ VectMult (sRGBval, XYZ50val, RGBtoXYZ50);
+
+ x = CLIP(XYZ50val[0]);
+ y = CLIP(XYZ50val[1]);
+ z = CLIP(XYZ50val[2]);
+
+ /**** Convert XYZ(d50) to fax LAB ****/
+
+ pCIELab[0] = L = YtoL[y];
+ xterm = cubeRoot[x];
+ yterm = cubeRoot[y];
+ zterm = cubeRoot[z];
+
+ b = yterm - zterm;
+ b += (96<<TERM_FRAC_BITS) + (1<<(TERM_FRAC_BITS-1));
+ b >>= TERM_FRAC_BITS;
+ pCIELab[2] = (BYTE)CLIP(b);
+
+ if (b < 0) { /* todo - adjustment for out-of-gamut bright blue */
+ /* xterm and L factors below of 6,1 -> rgb of 32,31,229 */
+ /* xterm and L factors below of 8,2 -> rgb of 84,80,255 */
+ /* xterm and L factors below of 6,0.5 are visually best */
+ xterm += 6*b;
+ L -= b>>1;
+ pCIELab[0] = (BYTE)CLIP(L);
+ }
+
+ // a = (long)((1<<10)*500.0/170.0) * (xterm-yterm) >> 10;
+ // the 3*a - a/16 below is close enough to (500.0/170.0)*a
+ a = xterm - yterm;
+ a = a + a + a - (a>>4); // multiply by approx 500/170
+ a += (128<<TERM_FRAC_BITS) + (1<<(TERM_FRAC_BITS-1));
+ a >>= TERM_FRAC_BITS;
+ pCIELab[1] = (BYTE)CLIP(a);
+}
+
+
+
+// YCCTosRGB - Converts a pixel (3 unsigned bytes) from YCC to sRGB
+//
+static void YCCTosRGB (
+ PBYTE pYCC, // in: YCC pixel (3 unsigned bytes)
+ PBYTE psRGB) // out: sRGB pixel (3 unsigned bytes)
+{
+ int iy, icb, icr;
+ int sR, sG, sB;
+
+ iy = pYCC[0];
+ icb = pYCC[1];
+ icr = pYCC[2];
+
+ sR = iy + cr2r[icr];
+ psRGB[0] = (BYTE)CLIP(sR);
+
+ sG = iy + ((cr2g_fix[icr] + cb2g_fix[icb] + CONV_FRAC_ROUND) >> CONV_FRAC_BITS);
+ psRGB[1] = (BYTE)CLIP(sG);
+
+ sB = iy + cb2b[icb];
+ psRGB[2] = (BYTE)CLIP(sB);
+}
+
+
+
+/****************************************************************************\
+ ****************************************************************************
+ ** **
+ ** sRGB -> YCC and CIELAB -> YCC **
+ ** **
+ ****************************************************************************
+\****************************************************************************/
+
+
+static long XYZ50tosRGB[9] = {
+ (long)( 3.1344500*TABLE_FRAC_SCALE /* *(255.0/248.0) */ /X_SCALE + 0.5),
+ (long)(-1.6177000*TABLE_FRAC_SCALE /* *(255.0/248.0) */ /Y_SCALE - 0.5),
+ (long)(-0.4905000*TABLE_FRAC_SCALE /* *(255.0/248.0) */ /Z_SCALE - 0.5),
+
+ (long)(-0.9788600*TABLE_FRAC_SCALE /* *(255.0/258.0) */ /X_SCALE - 0.5),
+ (long)( 1.9164800*TABLE_FRAC_SCALE /* *(255.0/258.0) */ /Y_SCALE + 0.5),
+ (long)( 0.0334962*TABLE_FRAC_SCALE /* *(255.0/258.0) */ /Z_SCALE + 0.5),
+
+ (long)( 0.0719813*TABLE_FRAC_SCALE /* *(255.0/254.0) */ /X_SCALE + 0.5),
+ (long)(-0.2290660*TABLE_FRAC_SCALE /* *(255.0/254.0) */ /Y_SCALE - 0.5),
+ (long)( 1.4050500*TABLE_FRAC_SCALE /* *(255.0/254.0) */ /Z_SCALE + 0.5)
+};
+
+
+
+// CIELabToYCC - Converts a pixel (3 unsigned bytes) from fax LAB to YCC
+//
+// Conversions done herein:
+// LAB(d50) -> XYZ(d50) -> XYZ(d65) -> sRGB -> Gamma -> YCC
+// Some of the above steps are combined for speed.
+//
+static void CIELabToYCC (
+ PBYTE pCIELab, // in: LAB pixel (3 unsigned bytes)
+ PBYTE pYCC, // out: YCC pixel (3 unsigned bytes)
+ PBYTE pGamma) // in: Gamma table
+{
+ int a, b, xterm, yterm, zterm;
+ int Y;
+ long factor;
+ int XYZ50[3];
+ int sRGB[3];
+ int sR,sG,sB;
+ int iy;
+ int icr, icb;
+
+ /**** LAB -> XYZ, both in d50 ****/
+
+ factor = (long)((1L<<16)*170.0/500.0);
+ a = (int)(((((long)pCIELab[1]-128) * factor) + 0x8000L) >> 16);
+ b = (int)pCIELab[2] - 96;
+
+ XYZ50[1] = Y = LtoY[pCIELab[0]];
+ yterm = (cubeRoot[Y] + (1<<(TERM_FRAC_BITS-1))) >> TERM_FRAC_BITS;
+
+ xterm = a + yterm;
+ XYZ50[0] = cube[CLIP(xterm)];
+
+ zterm = yterm - b;
+ XYZ50[2] = cube[CLIP(zterm)];
+
+ /**** XYZ(d50)->XYZ(d65)->sRGB via 3x3 matrix, then Gamma correct ****/
+
+ VectMult (XYZ50, sRGB, XYZ50tosRGB);
+
+ sR = pGamma[CLIP(sRGB[0])];
+ sG = pGamma[CLIP(sRGB[1])];
+ sB = pGamma[CLIP(sRGB[2])];
+
+ /**** sRGB -> YCC ****/
+
+ iy = r2y_fix[sR] + g2y_fix[sG] + b2y_fix[sB];
+ iy = (iy + CONV_FRAC_ROUND) >> CONV_FRAC_BITS;
+ iy = CLIP(iy);
+
+ //It is done inside the Neutral Shift area
+ //pYCC[0] = (BYTE)iy;
+
+ //pYCC[1] = (by2cb+255)[sB-iy];
+ // pYCC[2] = (ry2cr+255)[sR-iy];
+ icb = (int)((by2cb+255)[sB-iy]); //it is pYCC[1]
+ icr = (int)((ry2cr+255)[sR-iy]); //it is pYCC[2]
+
+ pYCC[0] = (BYTE)iy;
+ pYCC[1] = (BYTE)icb;
+ pYCC[2] = (BYTE)icr;
+
+
+
+}
+
+
+
+// sRGBToYCC - Converts a pixel (3 unsigned bytes) from sRGB to YCC
+//
+static void sRGBToYCC (
+ PBYTE psRGB, // in: sRGB pixel (3 unsigned bytes)
+ PBYTE pYCC) // out: YCC pixel (3 unsigned bytes)
+{
+ int sR, sG, sB;
+ int iy;
+
+ sR = psRGB[0];
+ sG = psRGB[1];
+ sB = psRGB[2];
+
+ iy = r2y_fix[sR] + g2y_fix[sG] + b2y_fix[sB];
+ iy = (iy + CONV_FRAC_ROUND) >> CONV_FRAC_BITS;
+ iy = CLIP(iy);
+ pYCC[0] = (BYTE)iy;
+
+ pYCC[1] = (by2cb+255)[sB-iy];
+ pYCC[2] = (ry2cr+255)[sR-iy];
+}
+
+
+
+/****************************************************************************\
+ ****************************************************************************
+ ** **
+ ** sRGB -> HLS and HLS -> YCC **
+ ** **
+ ****************************************************************************
+\****************************************************************************/
+
+
+
+// sRGBToLHS - Converts a pixel (3 unsigned bytes) from sRGB to LHS
+//
+static void sRGBToLHS (
+ PBYTE psRGB, // in: sRGB pixel (3 unsigned bytes)
+ PBYTE pLHS) // out: LHS pixel (3 unsigned bytes)
+{
+ int R, G, B;
+ int L, H, S; // these are in 0..255
+ int maxVal, minVal, diff, sum, numerator;
+
+ R = (unsigned)psRGB[0];
+ G = (unsigned)psRGB[1];
+ B = (unsigned)psRGB[2];
+
+ maxVal = IP_MAX (R, G);
+ maxVal = IP_MAX (maxVal, B);
+ minVal = IP_MIN (R, G);
+ minVal = IP_MIN (minVal, B);
+ diff = maxVal - minVal;
+ sum = maxVal + minVal;
+ L = sum >> 1;
+
+ if (diff <= 1) {
+ S = 0;
+ H = 0;
+ } else {
+ // below is really 255*diff / (...), but avoiding the multiply
+ S = ((diff<<9) - diff - diff) / (L<=127 ? sum : 510-sum);
+ S = (S+1) >> 1; // round to 8 bits
+
+ // determine the hue
+ if (R == maxVal) {
+ numerator = (maxVal-B) - (maxVal-G);
+ H = 0; // red is at 0 degrees
+ } else if (G == maxVal) {
+ numerator = (maxVal-R) - (maxVal-B);
+ H = (1<<12)*1/3; // green is at 120 degrees
+ } else { // blue-dominant
+ numerator = (maxVal-G) - (maxVal-R);
+ H = (1<<12)*2/3; // blue is at 240 degrees
+ }
+
+ // The line below is same as: hue += ((1<<12)/6) * numerator / diff;
+ // but is faster and more accurate.
+ H += (numerator<<11) / (diff+diff+diff);
+ H = (H + (1<<3)) >> 4; // rounds 12 bits down to 8 bits
+ }
+
+ pLHS[0] = (unsigned char)L;
+ pLHS[1] = (unsigned char)H;
+ pLHS[2] = (unsigned char)S;
+}
+
+
+
+// LHSTosRGB - Converts a pixel (3 unsigned bytes) from LHS to sRGB
+//
+static void LHSTosRGB (
+ PBYTE pLHS, // in: LHS pixel (3 unsigned bytes)
+ PBYTE psRGB) // out: sRGB pixel (3 unsigned bytes)
+{
+ int L, H, S;
+ int R=0, G=0, B=0;
+ int hbase, hfrac, product, maxVal, minVal, midVal;
+
+ L = (unsigned)pLHS[0]; // 1.0 is at 255
+ H = (unsigned)pLHS[1]; // 1.0 is at 255 (which is 360 degrees)
+ S = (unsigned)pLHS[2]; // 1.0 is at 255
+
+ // In RGB_to_HLS, L=sum/2, which truncates. The average error from this
+ // truncation is 0.25, which is the (1<<4) added below.
+ L = (L<<6) + (1<<4); // now 1.0 is at 255*(1<<6), 6 bits of frac
+ S = S<<6;
+
+ H *= 6;
+ hbase = H >> 8; // in 0..5, and is the basic hue
+ hfrac = H & 0x00ff; // fractional offset from basic hue to next basic hue
+
+ product = L*S;
+ product = (product + (product>>8)) >> (8+6); // approx division by 255*(1<<6)
+ if (L <= (127<<6)+(1<<4)) maxVal = L + product;
+ else maxVal = L + S - product;
+
+ minVal = L + L - maxVal;
+ midVal = minVal + (((maxVal-minVal) * ((hbase&1) ? 256-hfrac : hfrac)) >> 8);
+
+ // round the results to 8 bits by shifting out the 6 frac bits
+ minVal = (minVal+(1<<5)) >> 6;
+ midVal = (midVal+(1<<5)) >> 6;
+ maxVal = (maxVal+(1<<5)) >> 6;
+
+ // I ran this routine with all possible h-l-s values (2^24 of them!), and
+ // none produced a value outside 0..255, so we don't do the checks below.
+ // if (maxVal < 0) maxVal=0; else if (maxVal > 255) maxVal = 255;
+ // if (midVal < 0) midVal=0; else if (midVal > 255) midVal = 255;
+ // if (minVal < 0) minVal=0; else if (minVal > 255) minVal = 255;
+
+ switch (hbase)
+ {
+ case 0: R = maxVal; G = midVal; B = minVal; break;
+ case 1: R = midVal; G = maxVal; B = minVal; break;
+ case 2: R = minVal; G = maxVal; B = midVal; break;
+ case 3: R = minVal; G = midVal; B = maxVal; break;
+ case 4: R = midVal; G = minVal; B = maxVal; break;
+ case 5: R = maxVal; G = minVal; B = midVal; break;
+ }
+
+ psRGB[0] = (BYTE)R;
+ psRGB[1] = (BYTE)G;
+ psRGB[2] = (BYTE)B;
+}
+
+
+
+/****************************************************************************\
+ ****************************************************************************
+ ** **
+ ** E N T R Y P O I N T S **
+ ** **
+ ****************************************************************************
+\****************************************************************************/
+
+
+
+/*****************************************************************************\
+ *
+ * color_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD color_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PCOL_INST g;
+
+ if (! fInited) {
+ initTables ();
+ fInited = TRUE;
+ }
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(COL_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(COL_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * color_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD color_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PCOL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Insure that values we care about are correct */
+ INSURE (pTraits->iBitsPerPixel <= 24);
+ INSURE (pTraits->iPixelsPerRow > 0);
+
+ g->traits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * color_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD color_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PCOL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->which_cnv = (IP_WHICH_CNV)aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword;
+ calcGammaTable (g, aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword);
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * color_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD color_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * color_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD color_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PCOL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pIntraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * color_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD color_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PCOL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = *pdwMinOutBufLen =
+ (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * color_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD color_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PCOL_INST g;
+ int nBytes;
+ PBYTE pIn, pOut, pOutAfter;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("color_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ INSURE (dwInputAvail >= (DWORD)nBytes );
+ INSURE (dwOutputAvail >= (DWORD)nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pOutAfter = pOut + nBytes;
+
+ if (g->traits.iBitsPerPixel < 24) {
+ /* grayscale data; pass through unchanged */
+ memcpy (pOut, pIn, nBytes);
+ } else if (g->which_cnv == IP_CNV_BGR_SWAP) {
+ while (pOut < pOutAfter) {
+ pOut[0] = pIn[2];
+ pOut[1] = pIn[1];
+ pOut[2] = pIn[0];
+ pIn += 3;
+ pOut += 3;
+ }
+ } else {
+ while (pOut < pOutAfter) {
+ switch (g->which_cnv) {
+ case IP_CNV_YCC_TO_CIELAB: YCCToCIELab (pIn, pOut, g->bGammaTbl); break;
+ case IP_CNV_CIELAB_TO_YCC: CIELabToYCC (pIn, pOut, g->bGammaTbl); break;
+ case IP_CNV_YCC_TO_SRGB: YCCTosRGB (pIn, pOut); break;
+ case IP_CNV_SRGB_TO_YCC: sRGBToYCC (pIn, pOut); break;
+ case IP_CNV_LHS_TO_SRGB: LHSTosRGB (pIn, pOut); break;
+ case IP_CNV_SRGB_TO_LHS: sRGBToLHS (pIn, pOut); break;
+ default: goto fatal_error;
+ }
+
+ pIn += 3;
+ pOut += 3;
+ }
+ }
+
+ *pdwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * color_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD color_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * color_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD color_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PCOL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * color_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD color_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PCOL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * colorTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL colorTbl = {
+ color_openXform,
+ color_setDefaultInputTraits,
+ color_setXformSpec,
+ color_getHeaderBufSize,
+ color_getActualTraits,
+ color_getActualBufSizes,
+ color_convert,
+ color_newPage,
+ color_insertedData,
+ color_closeXform
+};
+
+/* End of File */
diff --git a/ip/xconvolve.c b/ip/xconvolve.c
new file mode 100644
index 0000000..56d420d
--- /dev/null
+++ b/ip/xconvolve.c
@@ -0,0 +1,658 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xconvolve.c - convolution using any number or rows and columns up to max
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * convolveTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_CONVOLVE_NROWS ] = # rows in convolution matrix (odd)
+ * aXformInfo[IP_CONVOLVE_NCOLS ] = # columns in convolution matrix (odd)
+ * aXformInfo[IP_CONVOLVE_MATRIX ] = ptr to convolution matrix
+ * aXformInfo[IP_CONVOLVE_DIVISOR] = divide by this after summing products
+ *
+ * The matrix is an array of int's, ordered left to right, top to bottom.
+ * After the pixels are multiplied by the elements in the matrix and these
+ * products summed together, the sum is divided by the integer divisor.
+ *
+ * If you set nRows and nCols to 7, then this xform is identical to the
+ * "User defined filter" feature in Paint Shop Pro.
+ *
+ * This xform makes a copy of the given matrix, so its memory can be freed
+ * after you've called setXformSpec.
+ *
+ * IP_CONVOLVE_MAXSIZE is the max number of rows or columns.
+ *
+ * Capabilities and Limitations:
+ *
+ * The input data must be grayscale (8 or 16 bits/pixel), or color (24 or
+ * 48 bits/pixel) in a luminance-chrominance color-space. This xform only
+ * changes the first component of color data (assumed to be the luminance).
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * 8, 16, 24 or 48 same as default input
+ * iComponentsPerPixel * 1 or 3 same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+/* Use the #define below if this transform will exist in a dll outside of the
+ * image pipeline. This will allow the functions to be exported.
+ * #define EXPORT_TRANFORM 1
+ */
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+#ifdef EXPORT_TRANSFORM
+#define FUNC_STATUS __declspec (dllexport)
+#else
+#define FUNC_STATUS static
+#endif
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input and output image */
+ DWORD dwBytesPerRow; /* # of bytes in each row */
+ int iBytesPerPixel; /* # bytes in each pixel */
+ DWORD dwRowsRead; /* number of rows read so far */
+ DWORD dwRowsWritten; /* number of rows output so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ int nCols; /* # columns in the matrix (must be odd) */
+ int nRows; /* # rows in the matrix (must be odd) */
+ int nRowsFilled; /* # rows filled so far in the matrix */
+ int iDivisor; /* divide sum of products by this */
+ int matrix[IP_CONVOLVE_MAXSIZE*IP_CONVOLVE_MAXSIZE]; /* the matrix */
+ PBYTE apRows[IP_CONVOLVE_MAXSIZE]; /* ptrs to buffered rows */
+ DWORD dwValidChk; /* struct validity check value */
+} CONV_INST, *PCONV_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD convolve_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PCONV_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(CONV_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(CONV_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD convolve_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PCONV_INST g;
+ int bpp;
+ int comps;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are valid */
+ bpp = pTraits->iBitsPerPixel;
+ comps = pTraits->iComponentsPerPixel;
+ INSURE ((comps==1 && (bpp==8 || bpp==16)) ||
+ (comps==3 && (bpp==24 || bpp==48)));
+ INSURE (pTraits->iPixelsPerRow > 0);
+
+ g->traits = *pTraits; /* a structure copy */
+ g->iBytesPerPixel = g->traits.iBitsPerPixel / 8;
+ g->dwBytesPerRow = g->traits.iPixelsPerRow * g->iBytesPerPixel;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD convolve_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PCONV_INST g;
+ int i, n;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->nRows = aXformInfo[IP_CONVOLVE_NROWS ].dword;
+ g->nCols = aXformInfo[IP_CONVOLVE_NCOLS ].dword;
+ g->iDivisor = aXformInfo[IP_CONVOLVE_DIVISOR].dword;
+
+ INSURE ((g->nRows&1)!=0 && g->nRows>0 && g->nRows<=IP_CONVOLVE_MAXSIZE);
+ INSURE ((g->nCols&1)!=0 && g->nCols>0 && g->nCols<=IP_CONVOLVE_MAXSIZE);
+ INSURE (g->iDivisor != 0);
+ INSURE (aXformInfo[IP_CONVOLVE_MATRIX].pvoid != 0);
+
+ n = g->nRows * g->nCols;
+ for (i=0; i<n; i++)
+ g->matrix[i] = ((int*)(aXformInfo[IP_CONVOLVE_MATRIX].pvoid))[i];
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD convolve_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD convolve_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PCONV_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pIntraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * convolve_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+FUNC_STATUS WORD convolve_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PCONV_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * CopyRow - Copies row to row-buffer, filling over-run zone on sides
+ *
+\*****************************************************************************/
+
+static void CopyRow (
+ PCONV_INST g, /* ptr to our instance variables */
+ PBYTE pbSrc, /* input buffer */
+ PBYTE pbDest) /* output buffer in apRows (with side-zones allocated) */
+{
+ int nSidePixels;
+ int i;
+
+ nSidePixels = g->nCols / 2;
+
+ /* copy leftmost pixel into all pixels in left side-zone */
+ for (i=0; i<nSidePixels; i++) {
+ memcpy (pbDest, pbSrc, g->iBytesPerPixel);
+ pbDest += g->iBytesPerPixel;
+ }
+
+ /* copy the buffer */
+ memcpy (pbDest, pbSrc, g->dwBytesPerRow);
+ pbDest += g->dwBytesPerRow;
+ pbSrc += g->dwBytesPerRow - g->iBytesPerPixel; /* leave at rightmost pixel */
+
+ /* copy rightmost pixel into all pixels in right side-zone */
+ for (i=0; i<nSidePixels; i++) {
+ memcpy (pbDest, pbSrc, g->iBytesPerPixel);
+ pbDest += g->iBytesPerPixel;
+ }
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_bytes - performs convolution on a row pixels with 8 or 24 bits each
+ *
+\*****************************************************************************/
+
+static void convolve_bytes (
+ PCONV_INST g, /* ptr to our instance variables */
+ PBYTE pbDest) /* output buffer */
+{
+ PBYTE pbSrc, pbDestAfter;
+ int iSrcOffset, iSideOffset, iSum;
+ int *pMatrix;
+ int row, col;
+
+ pbDestAfter = pbDest + g->dwBytesPerRow;
+ iSrcOffset = 0;
+ iSideOffset = g->iBytesPerPixel * (g->nCols>>1);
+
+ while (pbDest < pbDestAfter) /* for each output pixel ... */
+ {
+ iSum = 0;
+ pMatrix = g->matrix;
+
+ for (row=0; row<g->nRows; row++) {
+ pbSrc = g->apRows[row] + iSrcOffset;
+ for (col=0; col<g->nCols; col++) {
+ iSum += (*pMatrix++) * (int)(unsigned)(*pbSrc);
+ pbSrc += g->iBytesPerPixel;
+ }
+ }
+
+ iSum = (iSum + (g->iDivisor>>1)) / g->iDivisor;
+ if (iSum < 0) iSum = 0; else if (iSum > 255) iSum = 255;
+ *pbDest++ = (BYTE)iSum;
+
+ if (g->iBytesPerPixel == 3) {
+ /* copy chrominance values from the center pixel to the output pixel */
+ pbSrc = g->apRows[g->nRows>>1] + (iSideOffset + iSrcOffset + 1);
+ *pbDest++ = *pbSrc++;
+ *pbDest++ = *pbSrc++;
+ }
+
+ iSrcOffset += g->iBytesPerPixel;
+ }
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_words - performs convolution on a row pixels with 16 or 48 bits each
+ *
+\*****************************************************************************/
+
+static void convolve_words (
+ PCONV_INST g, /* ptr to our instance variables */
+ PWORD pwDest) /* output buffer */
+{
+ PWORD pwSrc, pwDestAfter;
+ int iSrcOffset, iSideOffset, iSum;
+ int *pMatrix;
+ int row, col;
+
+ pwDestAfter = pwDest + (g->dwBytesPerRow>>1);
+ iSrcOffset = 0;
+ iSideOffset = g->traits.iComponentsPerPixel * (g->nCols>>1);
+
+ while (pwDest < pwDestAfter) /* for each output pixel ... */
+ {
+ iSum = 0;
+ pMatrix = g->matrix;
+
+ for (row=0; row<g->nRows; row++) {
+ pwSrc = (WORD*)(g->apRows[row]) + iSrcOffset;
+ for (col=0; col<g->nCols; col++) {
+ iSum += (*pMatrix++) * (int)(unsigned)(*pwSrc);
+ pwSrc += g->traits.iComponentsPerPixel;
+ }
+ }
+
+ iSum = (iSum + (g->iDivisor>>1)) / g->iDivisor;
+ if (iSum < 0) iSum = 0; else if (iSum > 0x00ffff) iSum = 0x00ffff;
+ *pwDest++ = (WORD)iSum;
+
+ if (g->traits.iComponentsPerPixel == 3) {
+ /* copy chrominance values from the center pixel to the output pixel */
+ pwSrc = (WORD*)(g->apRows[g->nRows>>1]) + (iSideOffset + iSrcOffset + 1);
+ *pwDest++ = *pwSrc++;
+ *pwDest++ = *pwSrc++;
+ }
+
+ iSrcOffset += g->traits.iComponentsPerPixel;
+ }
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_convert - Converts one row
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD convolve_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PCONV_INST g;
+ WORD wFlags;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ wFlags = 0;
+
+ /**** We'll always consume an input row, so update its vars ****/
+
+ if (pbInputBuf != NULL) {
+ INSURE (dwInputAvail >= g->dwBytesPerRow);
+ *pdwInputUsed = g->dwBytesPerRow;
+ g->dwInNextPos += g->dwBytesPerRow;
+ *pdwInputNextPos = g->dwInNextPos;
+ g->dwRowsRead += 1;
+ wFlags |= IP_CONSUMED_ROW | IP_READY_FOR_DATA;
+ }
+
+ /**** Fill the row-buffers ****/
+
+ if (g->nRowsFilled < g->nRows) { /* This is the initial fill */
+ INSURE (pbInputBuf != NULL); /* not allowed to flush now */
+ do {
+ IP_MEM_ALLOC (g->dwBytesPerRow + g->iBytesPerPixel*g->nCols,
+ g->apRows[g->nRowsFilled]);
+ CopyRow (g, pbInputBuf, g->apRows[g->nRowsFilled]);
+ g->nRowsFilled += 1;
+ } while (g->nRowsFilled < (g->nRows+1)/2);
+
+ if (g->nRowsFilled < g->nRows)
+ return wFlags; /* we're not done with initial fill */
+ } else {
+ /* rotate buffer-pointers, and copy new row to bottom row */
+ int i;
+ PBYTE pBottomRow;
+
+ if (pbInputBuf == NULL) {
+ /* flushing */
+ if (g->dwRowsRead == g->dwRowsWritten)
+ return IP_DONE;
+ pbInputBuf = g->apRows[g->nRows-1]; /* duplicate prior row */
+ }
+
+ pBottomRow = g->apRows[0]; /* new bottom row overwrites oldest top row */
+ for (i=1; i<g->nRows; i++)
+ g->apRows[i-1] = g->apRows[i];
+ g->apRows[g->nRows-1] = pBottomRow;
+
+ CopyRow (g, pbInputBuf, pBottomRow);
+ }
+
+ /**** Output a Row ****/
+
+ INSURE (dwOutputAvail >= g->dwBytesPerRow);
+
+ if (g->traits.iBitsPerPixel==8 || g->traits.iBitsPerPixel==24)
+ convolve_bytes (g, pbOutputBuf);
+ else
+ convolve_words (g, (WORD*)pbOutputBuf);
+
+ *pdwOutputUsed = g->dwBytesPerRow;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += g->dwBytesPerRow;
+ g->dwRowsWritten += 1;
+ wFlags |= IP_PRODUCED_ROW;
+
+ return wFlags;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD convolve_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD convolve_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PCONV_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolve_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD convolve_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PCONV_INST g;
+ int i;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* free any rows that were allocated */
+ for (i=0; i<IP_CONVOLVE_MAXSIZE; i++)
+ if (g->apRows[i] != NULL)
+ IP_MEM_FREE (g->apRows[i]);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * convolveTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+
+#ifdef EXPORT_TRANSFORM
+__declspec (dllexport)
+#endif
+IP_XFORM_TBL convolveTbl = {
+ convolve_openXform,
+ convolve_setDefaultInputTraits,
+ convolve_setXformSpec,
+ convolve_getHeaderBufSize,
+ convolve_getActualTraits,
+ convolve_getActualBufSizes,
+ convolve_convert,
+ convolve_newPage,
+ convolve_insertedData,
+ convolve_closeXform
+};
+
+/* End of File */
+
+
+/*****************************************************************************\
+ *
+ * ipGetXformTable - Returns pointer to the jump table
+ *
+\*****************************************************************************/
+
+#ifdef EXPORT_TRANSFORM
+EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL pXform)
+{
+ WORD wRet = IP_DONE;
+
+ if (pXform)
+ *pXform = clrmapTbl;
+ else
+ wRet = IP_FATAL_ERROR;
+
+ return wRet;
+}
+#endif
diff --git a/ip/xcrop.c b/ip/xcrop.c
new file mode 100644
index 0000000..2613b98
--- /dev/null
+++ b/ip/xcrop.c
@@ -0,0 +1,470 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xcrop.c - Crops all four sides of the input image
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * cropTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_CROP_LEFT ] = left: # of pixels to remove from left side
+ * aXformInfo[IP_CROP_RIGHT ] = right: # of pixels to remove from right side
+ * aXformInfo[IP_CROP_TOP ] = top: # of rows to remove from top
+ * aXformInfo[IP_CROP_MAXOUTROWS] = maxOutRows: max # of rows to output
+ *
+ * Any (or even all) of the above values may be zero. If maxOutRows is
+ * zero, then an unlimited number of rows can be output.
+ *
+ * Capabilities and Limitations:
+ *
+ * Crops all four sides of the image.
+ * The image data must be fixed-length rows of uncompressed pixels.
+ * For bilevel data, the "left" value is changed to the nearest multiple
+ * of 8, and the "right" value is changed so the resulting row-width
+ * does not change.
+ * If all crop-amounts above are 0, this xform becomes merely a pass-thru.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * used input width - horiz crop
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows used if known output height, if input known
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input image */
+ DWORD dwLeft, dwRight; /* # pixels to crop, left and right sides */
+ DWORD dwTop; /* # rows to crop from top */
+ DWORD dwMaxOutRows; /* max # rows to output */
+ DWORD dwInBytesPerRow; /* # bytes in each input row */
+ DWORD dwOutBytesPerRow; /* # bytes in each output row */
+ DWORD dwLeftCropBytes; /* # bytes to toss from left side of each row */
+ DWORD dwInRows; /* number of rows input so far */
+ DWORD dwOutRows; /* number of rows output so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} CROP_INST, *PCROP_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * crop_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD crop_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PCROP_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(CROP_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(CROP_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * crop_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD crop_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PCROP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
+ g->traits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * crop_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD crop_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PCROP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwLeft = aXformInfo[IP_CROP_LEFT].dword;
+ g->dwRight = aXformInfo[IP_CROP_RIGHT].dword;
+ g->dwTop = aXformInfo[IP_CROP_TOP].dword;
+ g->dwMaxOutRows = aXformInfo[IP_CROP_MAXOUTROWS].dword;
+
+ if (g->dwMaxOutRows == 0)
+ g->dwMaxOutRows = 0x7ffffffful; /* 0 -> infinite */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * crop_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD crop_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * crop_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD crop_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PCROP_INST g;
+ int left, right, shift;
+ int inWidth, outWidth;
+ int bpp;
+ long actualOut, maxOut;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ /* Compute the crop info */
+
+ bpp = g->traits.iBitsPerPixel;
+ left = g->dwLeft;
+ right = g->dwRight;
+ inWidth = g->traits.iPixelsPerRow;
+ outWidth = inWidth - left - right;
+ INSURE (outWidth >= 0);
+
+ if (bpp == 1) {
+ /* shift to start at nearest byte boundary */
+ shift = ((left+4) & ~7) - left;
+ left += shift; /* this is now a multiple of 8 */
+ right += shift;
+ }
+
+ g->dwInBytesPerRow = (bpp*inWidth + 7) / 8;
+ g->dwOutBytesPerRow = (bpp*outWidth + 7) / 8;
+ g->dwLeftCropBytes = (bpp*left + 7) / 8;
+
+ /* Report the traits */
+
+ *pInTraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+ pOutTraits->iPixelsPerRow = outWidth;
+
+ /* compute the output lNumRows, if possible */
+ if (pInTraits->lNumRows > 0) {
+ maxOut = g->dwMaxOutRows;
+ actualOut = pInTraits->lNumRows - (long)g->dwTop;
+ INSURE (actualOut >= 0);
+ pOutTraits->lNumRows = actualOut<maxOut ? actualOut : maxOut;
+ }
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * crop_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD crop_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PCROP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = g->dwInBytesPerRow;
+ *pdwMinOutBufLen = g->dwOutBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * crop_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD crop_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PCROP_INST g;
+ DWORD dwOutBytes;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("crop_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Check if we should discard the row (vertical cropping) ****/
+
+ dwOutBytes = (g->dwInRows < g->dwTop || g->dwOutRows >= g->dwMaxOutRows)
+ ? 0 : g->dwOutBytesPerRow;
+
+ /**** Output a Row ****/
+
+ INSURE (dwInputAvail >= g->dwInBytesPerRow);
+ INSURE (dwOutputAvail >= dwOutBytes);
+
+ if (dwOutBytes > 0) {
+ memcpy (pbOutputBuf, pbInputBuf+g->dwLeftCropBytes, dwOutBytes);
+ g->dwOutRows += 1;
+ }
+
+ g->dwInRows += 1;
+
+ *pdwInputUsed = g->dwInBytesPerRow;
+ g->dwInNextPos += g->dwInBytesPerRow;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = dwOutBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += dwOutBytes;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * crop_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD crop_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * crop_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD crop_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PCROP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * crop_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD crop_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PCROP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * cropTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL cropTbl = {
+ crop_openXform,
+ crop_setDefaultInputTraits,
+ crop_setXformSpec,
+ crop_getHeaderBufSize,
+ crop_getActualTraits,
+ crop_getActualBufSizes,
+ crop_convert,
+ crop_newPage,
+ crop_insertedData,
+ crop_closeXform
+};
+
+/* End of File */
diff --git a/ip/xfakemono.c b/ip/xfakemono.c
new file mode 100644
index 0000000..e21a862
--- /dev/null
+++ b/ip/xfakemono.c
@@ -0,0 +1,465 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xfakemono.c - Simulates grayscale or bilevel in 24-bit data.
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * fakeMonoTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_FAKE_MONO_BPP] = 8 or 1, to simulate grayscale or mono
+ *
+ * Capabilities and Limitations:
+ *
+ * The input and output image are 24-bits per pixel. But the output image
+ * will *appear* to be grayscale if aXformInfo[0] == 8, or bilevel if it == 1.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * must be 24 24
+ * iComponentsPerPixel * must be 3 3
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+// Use the #define below if this transform will exist in a dll outside of the
+// image pipeline. This will allow the functions to be exported.
+// #define EXPORT_TRANFORM 1
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+#ifdef EXPORT_TRANSFORM
+#define FUNC_STATUS __declspec (dllexport)
+#else
+#define FUNC_STATUS static
+#endif
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input and output image */
+ int iFakeDPI; /* dpi to fake (8 or 1) */
+ DWORD dwBytesPerRow; /* # of bytes in each row */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} FMON_INST, *PFMON_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * fakeMono_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD fakeMono_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PFMON_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(FMON_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(FMON_INST));
+ g->dwValidChk = CHECK_VALUE;
+ g->iFakeDPI = 8;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * fakeMono_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD fakeMono_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PFMON_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow > 0 &&
+ pTraits->iBitsPerPixel == 24 &&
+ pTraits->iComponentsPerPixel == 3);
+
+ g->traits = *pTraits; /* a structure copy */
+ g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * fakeMono_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD fakeMono_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PFMON_INST g;
+ HANDLE_TO_PTR (hXform, g);
+ g->iFakeDPI = aXformInfo[IP_FAKE_MONO_BPP].dword;
+ INSURE (g->iFakeDPI==1 || g->iFakeDPI==8);
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * fakeMono_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD fakeMono_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * fakeMono_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD fakeMono_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PFMON_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pIntraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * fakeMono_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+FUNC_STATUS WORD fakeMono_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PFMON_INST g;
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * fakeMono_convert - Converts one row
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD fakeMono_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PFMON_INST g;
+ int nBytes;
+ PBYTE pIn, pInAfter, pOut;
+ unsigned rv, gv, bv;
+ int gray;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("fakeMono_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = g->dwBytesPerRow;
+ INSURE (dwInputAvail >= (DWORD)nBytes );
+ INSURE (dwOutputAvail >= (DWORD)nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pInAfter = pIn + nBytes;
+
+ if (g->iFakeDPI == 1) { // faking bi-level
+ while (pIn < pInAfter) {
+ rv = *pIn++;
+ gv = *pIn++;
+ bv = *pIn++;
+ gray = NTSC_LUMINANCE (rv, gv, bv);
+ gray = (gray >= 128) ? 255 : 0;
+ *pOut++ = (BYTE)gray;
+ *pOut++ = (BYTE)gray;
+ *pOut++ = (BYTE)gray;
+ }
+ } else { // faking grayscale
+ while (pIn < pInAfter) {
+ rv = *pIn++;
+ gv = *pIn++;
+ bv = *pIn++;
+ gray = NTSC_LUMINANCE (rv, gv, bv);
+ *pOut++ = (BYTE)gray;
+ *pOut++ = (BYTE)gray;
+ *pOut++ = (BYTE)gray;
+ }
+ }
+
+ *pdwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * fakeMono_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD fakeMono_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * fakeMono_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD fakeMono_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PFMON_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * fakeMono_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD fakeMono_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PFMON_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * fakeMonoTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+#ifdef EXPORT_TRANSFORM
+__declspec (dllexport)
+#endif
+IP_XFORM_TBL fakeMonoTbl = {
+ fakeMono_openXform,
+ fakeMono_setDefaultInputTraits,
+ fakeMono_setXformSpec,
+ fakeMono_getHeaderBufSize,
+ fakeMono_getActualTraits,
+ fakeMono_getActualBufSizes,
+ fakeMono_convert,
+ fakeMono_newPage,
+ fakeMono_insertedData,
+ fakeMono_closeXform
+};
+
+/* End of File */
+
+
+/*****************************************************************************\
+ *
+ * ipGetXformTable - Returns pointer to the jump table
+ *
+\*****************************************************************************/
+
+#ifdef EXPORT_TRANSFORM
+EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL pXform)
+{
+ WORD wRet = IP_DONE;
+
+ if (pXform)
+ *pXform = clrmapTbl;
+ else
+ wRet = IP_FATAL_ERROR;
+
+ return wRet;
+}
+#endif
diff --git a/ip/xfax.c b/ip/xfax.c
new file mode 100644
index 0000000..1c23de9
--- /dev/null
+++ b/ip/xfax.c
@@ -0,0 +1,3566 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*****************************************************************************\
+ *
+ * xfax.c - encoder and decoder for fax data (MH, MR and MMR)
+ *
+ *****************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * faxEncodeTbl = the encoder,
+ * faxDecodeTbl = the decoder.
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_FAX_FORMAT]: Format of data (both encoder & decoder).
+ * Values are: IP_FAX_MH, IP_FAX_MR, IP_FAX_MMR.
+ *
+ * aXformInfo[IP_FAX_NO_EOLS]: No EOLs in the data?
+ * 0 = EOLs are in data as usual;
+ * 1 = no EOLs in data.
+ * This tells the encoder whether to output EOLs.
+ * This tells the decoder if there are EOLs in the data.
+ *
+ * aXformInfo[IP_FAX_MIN_ROW_LEN]: Minimum # bits to put in each output row
+ * (MH & MR only).
+ * Only the encoder needs this, and guarantees that each
+ * row it outputs contains at least this many bits. It
+ * inserts fill 0's as needed. The fax standard needs
+ * this to insure that a row consumes a minimum amout of
+ * time when sent over the modem, hence there's a minimum
+ * number of bits to be transmitted per row.
+ *
+ * Capabilities and Limitations:
+ *
+ * Bits per pixel must be 1 (bi-level only).
+ * Encodes and decodes MH, MR and MMR per the fax standard.
+ * Encoding MR uses a k-factor of 2 if vert dpi < 150, else k-factor is 4.
+ * If an error occurs in MH or MR data, the previous good row is returned.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * For both encoder and decoder:
+ *
+ * trait default input output
+ * ------------------- ------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * must be 1 1
+ * iComponentsPerPixel passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Mark Overton, Jan 1998
+ *
+\*****************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+#include "assert.h" /* todo: eliminate all asserts */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stdout, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x1ce5ca7e
+
+
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@ @@
+@@ @@
+@@ U T I L I T I E S @@
+@@ @@
+@@ @@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+*/
+
+
+/* baLeftZeroesTbl returns number of leading zeroes in byte index */
+
+static const BYTE baLeftZeroesTbl[256] =
+{
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+/* baRightZeroesTbl returns number of trailing zeroes in byte index */
+
+static const BYTE baRightZeroesTbl[256] =
+{
+ 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | scan_to | Scan pixels rightward until hitting desired color (white/black) |
+ |_________|__________________________________________________________________|
+ | |
+ | Pos, the initial search position, must not be negative nor greater than |
+ | pixels_in_row+1. This function will not return a value greater than |
+ | pixels_in_row. |
+ | |
+ | WARNING: Before calling this routine, the first byte after the end of the |
+ | buffer must be set to alternating zeroes and ones (such as 0x55).|
+ | This allows us to scan bytes for a pixel-change without doing |
+ | the end-of-buffer boundary-check. |
+ | |
+ | Function return value: index of first pixel of desired color. |
+ |____________________________________________________________________________|
+*/
+static int scan_to (
+ UINT skip, /* color to skip over (FF=black, 00=white) */
+ BYTE *buf_p, /* buffer in which to search */
+ int start_pos, /* start-index for search (0=leftmost pixel in buf) */
+ int pixels_in_row) /* # pixels in the buffer */
+{
+ /**************************************************************************
+ *
+ * PERFORMANCE NOTE
+ *
+ * This routine skips all-white and all-black areas a *byte* at a time
+ * using a three-instruction loop. The old routine did this a *word*
+ * (2 bytes) at a time using a three-instruction loop. But this routine
+ * results in faster G3/G4 encoding/decoding, even for mostly white areas,
+ * because it has so little overhead outside the loop. Also, its small
+ * size doesn't toss as much other G3/G4 code out of the cache, improving
+ * performance even more.
+ *
+ * Seconds to MMR encode+decode 1000 rows of 1728 pixels (bench_fax.c):
+ *
+ * black density: 0% 10% 20% 50%
+ * old routine: 2.1 10.2 18.8 45.1
+ * this routine: 2.2 7.4 12.8 29.9
+ * inlining this routine: 2.2 7.9 13.8 32.4
+ *
+ * Inlining this routine *hurt* performance a little because more MMR
+ * code was kicked out of the cache.
+ *
+ *************************************************************************/
+
+ BYTE *cur_p;
+ UINT byte_mask;
+ UINT byte;
+ int pos;
+
+ byte_mask = 0x00FFu;
+ cur_p = buf_p + (start_pos >> 3);
+ skip &= byte_mask;
+ byte = (*cur_p ^ skip) & (byte_mask >> (start_pos & 7));
+
+ if (byte == 0) {
+ do {
+ cur_p += 1;
+ byte = *cur_p;
+ } while (byte == skip);
+ byte ^= skip;
+ }
+
+ pos = ((cur_p-buf_p)<<3) + baLeftZeroesTbl[byte];
+
+ if (pos > pixels_in_row)
+ pos = pixels_in_row;
+ return pos;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | worst_buf_size | calculates worst buffer-usage for a compressed row |
+ |________________|___________________________________________________________|
+*/
+/* worst-case failure of compression (which is expansion) */
+#define WORST_EXPAND_1D (9<<1) /* = 4.5 in 14.2 fixed-point */
+#define WORST_EXPAND_2D (6<<2) /* = 6.0 in 14.2 fixed-point */
+
+static int worst_buf_size (
+ WORD wFmt, /* fax format (IP_FAX_MH/MR/MMR) */
+ int iRowWidth) /* width of each row of bitmap (# pixels) */
+{
+ return ( ( (wFmt==IP_FAX_MH ? WORST_EXPAND_1D : WORST_EXPAND_2D)
+ * ((iRowWidth+7)/8)
+ ) >> 2
+ ) + 4;
+}
+
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@ @@
+@@ @@
+@@ E N C O D E R @@
+@@ @@
+@@ @@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+*/
+
+
+/* ENC_INST - our instance variables */
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the image */
+ DWORD dwValidChk; /* struct validity check value */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ int iRowLen; /* # pixels in each uncompressed input row */
+ BYTE wOutFmt; /* output format (IP_FAX_MH/FAX_MR/FAX_MMR) */
+ BOOL fNoEOLs; /* don't output any EOLs? */
+ UINT w12Cycle; /* (MR only) # rows in [1d,2d,2d...] cycle */
+ UINT wMinBits; /* minimum # bits to output in each row */
+ int iRowNum; /* current row-number of output, 0 is first */
+ BYTE *prior_p; /* (MR/MMR only) the prior row */
+
+ /* Variables for "Outputting Bits" section */
+ BYTE *pbBufStart; /* beginning of output buffer */
+ BYTE *pbOutByte; /* current byte in output buffer */
+ DWORD dwBitBuffer; /* buffer of bits (to be written to pbOutByte) */
+ UINT wBitsAvail; /* # of unused bits in dwBitBuffer */
+} ENC_INST, *PENC_INST;
+
+
+
+/*****************************************************************************
+ * *
+ * O U T P U T T I N G B I T S *
+ * *
+ *****************************************************************************
+
+
+Interface into this section:
+ put_init - initializes this section
+ put_bits - outputs a variable-number of bits (buffered)
+ put_fill_bits - Outputs fill bits (if necessary) to reach the minimum
+ put_grab - gives all bytes except the partial one to caller
+ put_new_buf - tells us to use a new buffer (after put_grab was called)
+ put_done - writes any remaining bits in the buffer
+*/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | put_init | Initializes this 'put' section |
+ |__________|_________________________________________________________________|
+*/
+static void put_init (
+ ENC_INST *g,
+ BYTE *pbOutBuf)
+{
+ g->dwBitBuffer = 0;
+ g->wBitsAvail = 32;
+ g->pbOutByte = pbOutBuf;
+ g->pbBufStart = pbOutBuf;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | put_bits | Outputs (buffered) the low-order 'length' bits in 'bits' |
+ |__________|_________________________________________________________________|
+ | |
+ | 'length' must be no larger than 25. |
+ | The bits in 'bits' that are not to be written must be zeroes. |
+ | |
+ | This routine lets dwBitBuffer fill up until data won't fit. Then it |
+ | writes out as many bytes as possible from the buffer in a loop. I |
+ | did it this way so the byte-write code would be in cache for more of |
+ | the writes, and so 'write_bytes' will be called as seldom as possible. |
+ |____________________________________________________________________________|
+*/
+
+static void write_bytes (ENC_INST *g)
+{
+ /* PERFORMANCE NOTE: inlining this routine slows down the encoder
+ * due to worse cache usage.
+ */
+ BYTE *byte_p;
+ DWORD bitbuf;
+ UINT bitsavail;
+
+ /* assert (g->wBitsAvail <= 24); */
+ byte_p = g->pbOutByte;
+ bitbuf = g->dwBitBuffer;
+ bitsavail = g->wBitsAvail;
+
+ do {
+ *byte_p++ = (BYTE )(bitbuf >> 24);
+ bitbuf <<= 8;
+ bitsavail += 8;
+ } while (bitsavail <= 24);
+
+ g->pbOutByte = byte_p;
+ g->dwBitBuffer = bitbuf;;
+ g->wBitsAvail = bitsavail;
+}
+
+
+#define put_bits(g, length_par, bits_par) \
+do { \
+ UINT length_loc = length_par; \
+ DWORD bits_loc = bits_par; \
+ \
+ if (length_loc > g->wBitsAvail) \
+ write_bytes (g); \
+ \
+ g->wBitsAvail -= length_loc; \
+ g->dwBitBuffer |= bits_loc << g->wBitsAvail; \
+} while (0)
+
+
+static void put_bits_routine (
+ ENC_INST *g,
+ UINT length,
+ DWORD bits)
+{
+ put_bits (g, length, bits);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | put_flush | Writes out all bytes containing any data in dwBitBuffer |
+ |___________|________________________________________________________________|
+*/
+static void put_flush (ENC_INST *g)
+{
+ if (g->wBitsAvail < 32) {
+ g->wBitsAvail &= ~7ul; /* reduce to a multiple of 8 (byte-boundary) */
+ write_bytes (g);
+ }
+
+ assert (g->wBitsAvail == 32);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | put_fill_bits | Outputs fill bits (if necessary) to reach the minimum |
+ |_______________|____________________________________________________________|
+ | |
+ | We want put_grab to return the minimum # of bits, but it returns an |
+ | array of bytes (not bits). So this routine insures that at least |
+ | the minimum # of bits have been written (as bytes) into the output |
+ | buffer. |
+ |____________________________________________________________________________|
+*/
+static void put_fill_bits (ENC_INST *g)
+{
+ int iMore;
+
+ put_flush (g);
+
+ /* write out zero-bytes until we're at (or past) the minimum # bits */
+
+ iMore = (int)g->wMinBits - 8*(g->pbOutByte - g->pbBufStart);
+ if (iMore > 0) {
+ iMore = (iMore+7) / 8;
+ memset (g->pbOutByte, 0, iMore);
+ g->pbOutByte += iMore;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | put_grab | Returns # of bytes written so far, and restarts at buffer-start |
+ |__________|_________________________________________________________________|
+ | |
+ | The caller is expected to copy N bytes from the buffer, where N is the |
+ | number this function returns. |
+ |____________________________________________________________________________|
+*/
+static int put_grab (ENC_INST *g)
+{
+ int n;
+
+ n = g->pbOutByte - g->pbBufStart;
+ g->pbOutByte = g->pbBufStart; /* next byte goes into beginning of buffer */
+ return n;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | put_new_buf | Use a new buffer (must be called after put_grab) |
+ |_____________|______________________________________________________________|
+*/
+static void put_new_buf (
+ ENC_INST *g,
+ BYTE *pbOutBuf)
+{
+ assert (g->pbOutByte == g->pbBufStart);
+ g->pbOutByte = pbOutBuf;
+ g->pbBufStart = pbOutBuf;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | put_done | Writes any buffered bits, and returns total # of bytes written |
+ |__________|_________________________________________________________________|
+*/
+static int put_done (
+ ENC_INST *g)
+{
+ put_flush (g);
+ return g->pbOutByte - g->pbBufStart;
+}
+
+
+
+/*
+ *****************************************************************************
+ * *
+ * E N C O D I N G R O W S *
+ * *
+ *****************************************************************************
+
+
+Interface into this section:
+ encode_row_1d - compresses a row into 1-dim format for MH and MR
+ encode_row_2d - compresses a row into 2-dim format for MR and MMR
+*/
+
+
+
+/* Structure for storing G3 codes */
+
+typedef struct {
+ USHORT bits;
+ USHORT length;
+} huff_t;
+
+
+/* run-length = index, index is in 0..63 */
+static const huff_t MHWhiteRuns[] = {
+ {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}
+};
+
+
+/* run-length = 64*(index+1), index is in 0..26 */
+static const huff_t MHMakeupWhite[] = {
+ {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}
+};
+
+
+/* run-length = index, index is in 0..63 */
+static const huff_t MHBlackRuns[] = {
+ {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}
+};
+
+
+/* run-length = 64*(index+1), index is in 0..26 */
+static const huff_t MHMakeupBlack[] = {
+ {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}
+};
+
+
+/* run-length = 64*(index+28), index is in 0..12 */
+static const huff_t MHExtMakeup[] = {
+ {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}
+};
+
+
+/* vertical-offset = index-3 */
+static const huff_t VertTbl[] = {
+ {2, 7},
+ {2, 6},
+ {2, 3},
+ {1, 1},
+ {3, 3},
+ {3, 6},
+ {3, 7}
+};
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | put_run | Outputs a white or black run |
+ |_________|__________________________________________________________________|
+*/
+static void put_run_routine(
+ ENC_INST *g,
+ int iRunLen,
+ const huff_t *makeup_tbl,
+ const huff_t *code_tbl)
+{
+ huff_t te;
+
+ while (iRunLen >= 1792) {
+ int tpos;
+ tpos = (iRunLen>>6) - (1792>>6);
+ if (tpos > 12)
+ tpos = 12;
+ te = MHExtMakeup [tpos];
+ put_bits_routine (g, te.length, te.bits);
+ iRunLen -= (tpos+(1792>>6)) << 6;
+ }
+
+ if (iRunLen >= 64) {
+ te = makeup_tbl [(iRunLen>>6) - 1];
+ put_bits_routine (g, te.length, te.bits);
+ iRunLen &= 63;
+ }
+
+ te = code_tbl [iRunLen];
+ put_bits_routine (g, te.length, te.bits);
+}
+
+#define put_run(g, par_run_len, par_makeup_tbl, par_code_tbl) \
+do { \
+ huff_t te; \
+ int loc_run_len = par_run_len; \
+ \
+ if (loc_run_len >= 64) \
+ put_run_routine (g, loc_run_len, par_makeup_tbl, par_code_tbl); \
+ else { \
+ te = par_code_tbl [loc_run_len]; \
+ put_bits (g, te.length, te.bits); \
+ } \
+} while (0)
+
+
+
+#define PutWhiteRun(g, iRunLen) \
+ put_run (g, iRunLen, MHMakeupWhite, MHWhiteRuns)
+
+
+#define PutBlackRun(g, iRunLen) \
+ put_run (g, iRunLen, MHMakeupBlack, MHBlackRuns)
+
+
+static void PutEOL(ENC_INST *g) /* output the EOL code (11 zeroes and a one) */
+{
+ put_bits_routine (g, 12, 0x001);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | encode_row_1d | Converts a pixel-row into MH (CCITT G3) format |
+ |_______________|____________________________________________________________|
+ | |
+ | Before calling this routine, you must call put_init. |
+ | After calling this routine, you must call put_grab/put_done. |
+ | This routine puts the EOL at the beginning of the line. |
+ |____________________________________________________________________________|
+*/
+static void encode_row_1d (
+ ENC_INST *g,
+ BYTE *pbPixelRow, /* ptr to pixel-row */
+ int iPixels, /* # of pixels in above row */
+ BOOL fDoingMR) /* Sending MR? Ie, send a 1d/2d tag-bit after EOL? */
+{
+ int iStartPos;
+ int iChange;
+ UINT skip; /* the color we're skipping over; 0x00=black, 0xFF=white */
+
+ PutEOL (g);
+ if (fDoingMR)
+ put_bits_routine (g,1,1); /* tag-bit after EOL means 1-dim row-data */
+
+ pbPixelRow[iPixels>>3] = 0x55u; /* scan_to requires this */
+ iStartPos = 0;
+ skip = 0;
+
+ while (iStartPos < iPixels) {
+ iChange = scan_to (skip, pbPixelRow, iStartPos, iPixels);
+ if (skip) PutBlackRun (g, iChange-iStartPos);
+ else PutWhiteRun (g, iChange-iStartPos);
+ iStartPos = iChange;
+ skip = ~skip;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | encode_row_2d | Converts a pixel-row into 2-dimensional format |
+ |_______________|____________________________________________________________|
+ | |
+ | Before calling this routine, you must call put_init. |
+ | After calling this routine, you must call put_grab/put_done. |
+ | For MR data, this routine puts the EOL+tag at the beginning of the line. |
+ |____________________________________________________________________________|
+*/
+/*
+ * The variable 'need' below is a bit-array telling us which values (a1, b0,
+ * etc) are needed. It is determined by the cases below.
+ *
+ * b0 is not in the standard. I've defined it as, "A pixel on the reference
+ * line above or to the right of a0, and to the left of b1." Since b1 is the
+ * first changing pixel, b0 must be the same color as a0. b0 is the point at
+ * which the search for b1 begins.
+ *
+ * In the code below, b0 uses the b1 variable because if we're using b0, then
+ * b1 is not known, so it's okay to clobber it.
+ *
+ * Below, a0, a1, b0, b1 etc denote positions before coding, and A0, A1,
+ * B0, B1, etc denote positions after coding.
+ *
+ * Pass Mode:
+ *
+ * B0
+ * b1 b2
+ * - - - X X X - - -
+ * X - - - - - - X -
+ * a0 a1
+ * A0 A1
+ *
+ * A0 = b2, specified by the standard.
+ * A1 = a1, because A0 is to the left of a1, a1 does not move.
+ * B0 = b2, which is known to be the same color as A0.
+ *
+ * Needed: B1 and B2.
+ *
+ * Vertical Mode:
+ *
+ * Normal case:
+ *
+ * B1
+ * b1 b2
+ * - - - X X X - - -
+ * - - X X - - - - -
+ * a0 a1
+ * A0
+ *
+ * A0 = a1, specified by the standard.
+ * B1 = b2, the first changing pixel of opposite color as A0.
+ *
+ * Needed: A1, B2.
+ *
+ * An exception (a1=b2):
+ *
+ * b1 b2
+ * - - - X - - - - -
+ * - - - - X - - - -
+ * a0 a1
+ * A0
+ *
+ * Here, b2 is above A0, and therefore cannot be used as B1.
+ * And its color is opposite A0, so it's not even usable as B0.
+ * So B0 and B1 must be scanned.
+ *
+ * Needed: A1, B0, B1, B2.
+ *
+ * A subtle exception (a1 is at least 2 pixels to the left of b1):
+ *
+ * B1 B2
+ * b1 b2
+ * - - X X X - X - -
+ * - - - - X - - - -
+ * a0 a1
+ * A0
+ *
+ * b1 and b2 move *backwards* after coding.
+ * B1 = b1-1, and B2=b1. Since it's not worth the time to check
+ * for this rare pixel-arrangement, we'll just rescan B0, B1 and B2.
+ *
+ * Needed: A1, B0, B1, B2.
+ *
+ * Horizontal Mode:
+ *
+ * First case (a2 > b2):
+ *
+ * b1 b2
+ * - - - - - X - - -
+ * - X X X X X X - -
+ * a0 a1 a2
+ * A0
+ *
+ * Since b2 is left of A0, we know nothing about what's above A0.
+ * So everything must be scanned.
+ *
+ * Needed: A1, B0, B1, B2.
+ *
+ * Second case: (a2 <= b2):
+ *
+ * B0
+ * b1 b2
+ * - - - - - X X X -
+ * - X X X X X X - -
+ * a0 a1 a2
+ * A0
+ *
+ * A0 = a2, specified by the standard.
+ * B0 = b2, because it's the same color as A0, and not to left of A0.
+ *
+ * Needed: A1, B1, B2.
+ *
+ * Exception to above case (a2 < b1):
+ *
+ * B1 B2
+ * b1 b2
+ * - - - - - - X X -
+ * - X X X X - - - -
+ * a0 a1 a2
+ * A0
+ *
+ * b1 is to the right of A0, so b1 and b2 don't move.
+ * This case is common because it occurs whenever a row with some
+ * data follows a blank row.
+ *
+ * Needed: A1.
+ */
+static void encode_row_2d (
+ ENC_INST *g,
+ BYTE *pbPixelRow, /* ptr to pixel-row */
+ BYTE *pbRefRow, /* ptr to reference-row */
+ int iPixels, /* # of pixels in above row */
+ BOOL fDoingMR) /* Sending MR? Ie, output an EOL + tag-bit? */
+{
+ #define A1 1
+ #define B0 2
+ #define B1 4
+ #define B2 8
+
+ int a0, a1, a2;
+ int b1, b2;
+ int iDelta;
+ UINT skip; /* the color we're skipping over; 00=white, FF=black */
+ UINT need;
+
+ if (fDoingMR) {
+ PutEOL (g);
+ put_bits_routine (g,1,0); /* tag-bit after EOL means 2-dim row-data */
+ }
+
+ pbPixelRow[iPixels>>3] = 0x55u; /* scan_to requires this */
+ pbRefRow [iPixels>>3] = 0x55u; /* scan_to requires this */
+
+ /* The imaginary pixel before the first is considered a white pixel.
+ * So if the first pixel in the row is black, it is considered
+ * a "changing" pixel (white->black).
+ */
+ a1 = scan_to ( 0x00, pbPixelRow, 0, iPixels);
+ b1 = scan_to ( 0x00, pbRefRow, 0, iPixels);
+ b2 = scan_to ((UINT)~0x00, pbRefRow, b1+1, iPixels);
+ skip = (UINT)~0x00u; /* white, initially */
+ a0 = 0;
+
+ while (TRUE) {
+
+ /* output one of the modes */
+
+ iDelta = a1 - b1;
+
+ if (b2 < a1) { /* pass mode */
+ put_bits (g,4,1);
+ need = B1 | B2;
+ a0 = b2;
+ b1 = b2;
+ } else if (-3<=iDelta && iDelta<=3) { /* vertical mode */
+ huff_t te = VertTbl[iDelta+3];
+ put_bits (g, te.length, te.bits);
+ need = A1 | B2;
+ if (b2==a1 || iDelta<=-2)
+ need = A1 | B0 | B1 | B2;
+ a0 = a1;
+ b1 = b2;
+ skip = ~skip;
+ } else { /* horizontal mode */
+ a2 = scan_to (skip, pbPixelRow, a1+1, iPixels);
+ put_bits (g,3,1);
+ if (skip) {
+ PutWhiteRun (g,a1-a0);
+ PutBlackRun (g,a2-a1);
+ } else {
+ PutBlackRun (g,a1-a0);
+ PutWhiteRun (g,a2-a1);
+ }
+ if (a2 > b2) {
+ need = A1 | B0 | B1 | B2;
+ } else if (a2 < b1) {
+ need = A1;
+ } else {
+ b1 = b2;
+ need = A1 | B1 | B2;
+ }
+ a0 = a2;
+ }
+
+ if (a0 >= iPixels)
+ break;
+
+ /* compute next a1, b1, b2 */
+
+ if (need & A1) a1 = scan_to (~skip, pbPixelRow, a0+1, iPixels);
+ if (need & B0) b1 = scan_to ( skip, pbRefRow, a0, iPixels);
+ if (need & B1) b1 = scan_to (~skip, pbRefRow, b1+1, iPixels);
+ if (need & B2) b2 = scan_to ( skip, pbRefRow, b1+1, iPixels);
+ }
+}
+
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@ @@
+@@ @@
+@@ E N C O D E R @@
+@@ @@
+@@ @@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+*/
+
+
+
+/*****************************************************************************\
+ *
+ * faxEncode_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD faxEncode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PENC_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(ENC_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(ENC_INST));
+ g->dwValidChk = CHECK_VALUE;
+ put_init (g, NULL); /* put_new_buf will be called later */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxEncode_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD faxEncode_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PENC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Insure that values we actually use or care about are known */
+ INSURE (pTraits->iPixelsPerRow > 0); /* we need the row-length */
+ INSURE (pTraits->iBitsPerPixel == 1); /* image must be bi-level */
+
+ g->traits = *pTraits; /* a structure copy */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxEncode_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD faxEncode_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PENC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->wOutFmt = (BYTE)aXformInfo[IP_FAX_FORMAT].dword;
+ g->fNoEOLs = (BOOL)aXformInfo[IP_FAX_NO_EOLS].dword;
+ g->wMinBits = (WORD)aXformInfo[IP_FAX_MIN_ROW_LEN].dword;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxEncode_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD faxEncode_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxEncode_getActualTraits - Parses header, and returns input & output traits
+ *
+ *****************************************************************************
+ *
+ * For this fax xform driver, this routine merely returns input traits.
+ *
+\*****************************************************************************/
+
+static WORD faxEncode_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PENC_INST g;
+ int inBytes;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ /* Since we don't change traits, just copy out the default traits */
+
+ *pInTraits = g->traits;
+ *pOutTraits = g->traits;
+
+ /* Compute some stuff */
+
+ g->iRowLen = g->traits.iPixelsPerRow; /* todo: eliminate redundant var */
+
+ /* below, if vert dpi is unknown (negative), we use cycle-len of 2 */
+ g->w12Cycle = (g->traits.lVertDPI < (150l<<16)) ? 2 : 4;
+
+ /* Allocate the prior-row buffer, if needed */
+
+ if (g->wOutFmt != IP_FAX_MH) {
+ if (g->prior_p != NULL)
+ IP_MEM_FREE (g->prior_p);
+ inBytes = (g->iRowLen+7) / 8;
+ IP_MEM_ALLOC (inBytes, g->prior_p);
+ memset (g->prior_p, 0, inBytes);
+ }
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * faxEncode_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD faxEncode_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PENC_INST g;
+ UINT uWorstBuf, uMinBytes;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = (g->iRowLen+7) / 8;
+
+ uWorstBuf = worst_buf_size (g->wOutFmt, g->iRowLen);
+ uMinBytes = (g->wMinBits+7) / 8;
+ *pdwMinOutBufLen = uWorstBuf > uMinBytes ? uWorstBuf : uMinBytes;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxEncode_convert - the work-horse routine
+ *
+ *****************************************************************************
+ *
+ * This routine (actually put_bits) hangs onto the last 1-3 bytes of
+ * encoded row-data due to its buffering method.
+ *
+\*****************************************************************************/
+
+static WORD faxEncode_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PENC_INST g;
+ int inBytes;
+ int i;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ put_new_buf (g, pbOutputBuf);
+
+ /********************************************************/
+ /* If we're being told to flush, output the ending EOLs */
+ /********************************************************/
+
+ if (dwInputAvail == 0) {
+
+ switch (g->wOutFmt) {
+ case IP_FAX_MH:
+ for (i=6; i>0; i--)
+ PutEOL (g);
+ break;
+
+ case IP_FAX_MR:
+ for (i=6; i>0; i--) {
+ PutEOL (g);
+ put_bits_routine (g,1,1);
+ }
+ break;
+
+ case IP_FAX_MMR:
+ PutEOL (g);
+ PutEOL (g);
+ break;
+ }
+
+ *pdwInputUsed = 0;
+ *pdwOutputUsed = put_done (g);
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /******************************/
+ /* Normal Case (not flushing) */
+ /******************************/
+
+ inBytes = (g->iRowLen+7) / 8;
+ INSURE (dwInputAvail >= (DWORD)inBytes);
+ INSURE (dwOutputAvail > 0);
+
+ switch (g->wOutFmt) {
+ case IP_FAX_MH:
+ encode_row_1d (g, pbInputBuf, g->iRowLen, FALSE);
+ put_fill_bits (g);
+ break;
+
+ case IP_FAX_MR:
+ if (g->iRowNum % g->w12Cycle == 0)
+ encode_row_1d (g, pbInputBuf, g->iRowLen, TRUE);
+ else
+ encode_row_2d (g, pbInputBuf, g->prior_p, g->iRowLen, TRUE);
+ put_fill_bits (g);
+ break;
+
+ case IP_FAX_MMR:
+ encode_row_2d (g, pbInputBuf, g->prior_p, g->iRowLen, FALSE);
+ break;
+ }
+
+ if (g->prior_p != NULL)
+ memcpy (g->prior_p, pbInputBuf, inBytes);
+
+ *pdwInputUsed = inBytes;
+ g->dwInNextPos += inBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = put_grab (g);
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += *pdwOutputUsed;
+ g->iRowNum += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxEncode_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD faxEncode_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxEncode_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD faxEncode_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PENC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: output EOLs to mark a new page */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxEncode_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD faxEncode_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PENC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ if (g->prior_p != NULL)
+ IP_MEM_FREE (g->prior_p);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxEncodeTbl - Jump-table for encoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL faxEncodeTbl = {
+ faxEncode_openXform,
+ faxEncode_setDefaultInputTraits,
+ faxEncode_setXformSpec,
+ faxEncode_getHeaderBufSize,
+ faxEncode_getActualTraits,
+ faxEncode_getActualBufSizes,
+ faxEncode_convert,
+ faxEncode_newPage,
+ faxEncode_insertedData,
+ faxEncode_closeXform
+};
+
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@ @@
+@@ @@
+@@ D E C O D E R @@
+@@ @@
+@@ @@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+*/
+
+
+/* white/nonwhite might be put in interface later on */
+#define NONWHITE_ROW 0x0000 /* row is not all white */
+#define WHITE_ROW 0x0000 /* row is all white */
+
+#define MAX_CODE_LEN 13 /* length of longest code */
+#define EOL_LEN 12 /* EOL is 11 zeroes and a one */
+#define EOLS_FOR_MH_MR 3 /* the std says 6, but some might be zapped */
+#define EOLS_FOR_MMR 1 /* the std says 2, but we'll stop at first because
+ * we might not be able to fetch the second EOL from
+ * the cache because we won't fetch anything unless
+ * it contains 13 bits, and an EOL is only 12 */
+
+/* Huffman tables (at end of file): */
+
+extern const BYTE fax_vert_huff_index[];
+extern const USHORT fax_vert_huff[];
+extern const BYTE fax_black_huff_index[];
+extern const USHORT fax_black_huff[];
+extern const BYTE fax_white_huff_index[];
+extern const USHORT fax_white_huff[];
+
+#define MAX_BLACK_CODELEN 13
+#define MAX_WHITE_CODELEN 12
+#define MAX_VERT_CODELEN 7
+
+#define CODELEN_SHIFT 12
+#define VALUE_MASK 0x0fffu
+
+/* items only in fax_vert_huff table: */
+#define LAST_VERT 6
+#define PASS_MODE 7
+#define HORIZ_MODE 8
+
+enum {
+ RET_GOT_CODE, /* we parsed a good code (ret in *piResult) */
+ RET_BAD_CODE, /* trash in row-data */
+ RET_FILL, /* got some fill-zeroes */
+ RET_HIT_EOL, /* hit EOL; no row-data was parsed or returned */
+ RET_NEED_MORE /* need more input-bytes to complete the row */
+};
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Type-definition of our instance-variables |
+ |____________________________________________________________________________|
+*/
+
+typedef enum {
+ NORMAL_2D,
+ HORIZ_1ST,
+ HORIZ_2ND
+} STATE_2D;
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the image */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+
+ /* Variables for getting bits: */
+ BYTE *gb_buf_p; /* beginning of our buffer */
+ BYTE *gb_buf_after_p; /* 1st byte after our buffer */
+ BYTE *gb_byte_p; /* ptr to next byte */
+ int gb_cache_cnt; /* # of available bits in gb_cache */
+ DWORD gb_cache; /* 32-bit buffer to cache the next few bits */
+ /* is also pos of next avail bit; msb=32, lsb=1 */
+ int gb_num_zeroes; /* # of successive zero-bits we've gotten */
+
+ /* Variables for row-decoding functions: */
+ int pixel_pos; /* coordinate of next pixel; 0 is leftmost */
+ BYTE white; /* doing a white run? (00=black, FF=white) */
+ STATE_2D state_2d; /* state of the 2-dim decoder */
+ int a0; /* pixel before 1st is an imaginary white pixel */
+ BYTE *prior_p; /* buffer containing prior row */
+ BOOL ref_row_invalid; /* (MR only) reference row invalid due to error?*/
+
+ /* Variables for the exported functions: */
+ BYTE input_format; /* input format (IP_FAX_MH/MR/MMR) */
+ BYTE num_eols; /* number of successive EOLs we've gotten */
+ BOOL no_eols; /* are EOLs not present in input? */
+ BOOL toss_everything; /* are we discarding all data due to prior err? */
+ BOOL flushing_to_eol; /* are we ignoring bits until an EOL? */
+ BOOL got_fill; /* gotten any fill-zeroes? */
+ BOOL got_black; /* set any black pixels in the row? */
+ BOOL two_dim; /* next row is 2-dimensional encoding? */
+ int row_len; /* # pixels in each row */
+ int bytes_in_row; /* # bytes in each row */
+} DEC_INST, *PDEC_INST;
+
+
+
+/*****************************************************************************
+ * *
+ * F E T C H I N G B I T S *
+ * *
+ *****************************************************************************
+
+
+Interface into this section:
+
+ bits_init - inits this section
+ bits_buf_open - gives us (this section) a buffer to consume
+ BITS_REFILL_CACHE - fills cache; must be called before parsing
+ BITS_IN_CACHE - returns # bits currently in the cache
+ BITS_LOAD - returns next N bits of input (no advance is done)
+ BITS_ADVANCE - advances input by the given # of bits
+ bits_buf_close - returns # bytes consumed in buffer
+ bits_flush - discards all unread bits
+ bits_flush_to_eol - flushes input bits until EOL is encountered
+*/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | bits_init | initializes this "fetching bits" section |
+ |___________|________________________________________________________________|
+*/
+static void bits_init (DEC_INST *g)
+{
+ g->gb_num_zeroes = 0;
+ g->gb_cache_cnt = 0; /* the cache is empty */
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | bits_buf_open | gives us (this section) a buffer to consume |
+ |_______________|____________________________________________________________|
+*/
+static void bits_buf_open (
+ DEC_INST *g,
+ BYTE *buf_p,
+ int num_bytes)
+{
+ g->gb_byte_p = buf_p;
+ g->gb_buf_p = buf_p;
+ g->gb_buf_after_p = buf_p + num_bytes;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | bits_buf_close | returns # bytes consumed in buffer |
+ |________________|___________________________________________________________|
+*/
+static UINT bits_buf_close (DEC_INST *g)
+{
+ return (g->gb_byte_p - g->gb_buf_p);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | bits_flush | discards all unread bits |
+ |____________|_______________________________________________________________|
+*/
+static void bits_flush (DEC_INST *g)
+{
+ g->gb_cache_cnt = 0;
+ g->gb_byte_p = g->gb_buf_after_p;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | BITS_REFILL_CACHE | fills cache as full as possible |
+ |___________________|________________________________________________________|
+*/
+#define BITS_REFILL_CACHE(g) \
+{ \
+ int cache_cnt = g->gb_cache_cnt; \
+ DWORD cache = g->gb_cache; \
+ BYTE *byte_p = g->gb_byte_p; \
+ BYTE *buf_after_p = g->gb_buf_after_p; \
+ \
+ while (cache_cnt<=24 && byte_p<buf_after_p) { \
+ cache = (cache << 8) | (*byte_p++); \
+ cache_cnt += 8; \
+ } \
+ \
+ g->gb_cache_cnt = cache_cnt; \
+ g->gb_cache = cache; \
+ g->gb_byte_p = byte_p; \
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | BITS_IN_CACHE | returns # bits currently in the bit-cache |
+ |_______________|____________________________________________________________|
+*/
+#define BITS_IN_CACHE(g) (g->gb_cache_cnt)
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | bits_flush_to_eol | flushes input bits until EOL is encountered |
+ |___________________|________________________________________________________|
+ | |
+ | If got_fill is TRUE, then we merely scan for a set bit. |
+ | Otherwise, we first count leading zeroes until it reaches 11. |
+ | |
+ | Return value: TRUE = We hit an EOL. In this case, if leave_a_bit is |
+ | TRUE, the cache will contain at least one bit so |
+ | you can fetch a 1-dim/2-dim bit. |
+ | FALSE = We need more input data. |
+ |____________________________________________________________________________|
+*/
+static BOOL bits_flush_to_eol (
+ DEC_INST *g, /* our instance vars */
+ BOOL got_fill, /* have we gotten fill zeroes? */
+ BOOL leave_a_bit) /* after hitting EOL, insure that cache isn't empty? */
+{
+ #define CLEAR_UNUSED_CACHE_BITS \
+ if (g->gb_cache_cnt < 32) \
+ g->gb_cache &= (1lu << g->gb_cache_cnt) - 1lu;
+
+ DWORD bit;
+ BYTE byt;
+
+ /*********************************************/
+ /* Scan input until 11 zeroes have been seen */
+ /*********************************************/
+
+ if (g->gb_num_zeroes >= 11)
+ got_fill = TRUE;
+
+ if (! got_fill)
+ {
+ if (g->gb_cache_cnt != 0) {
+ for (bit = (1lu<<(g->gb_cache_cnt-1));
+ bit != 0;
+ bit >>= 1) {
+ g->gb_cache_cnt -= 1;
+ if (bit & g->gb_cache)
+ g->gb_num_zeroes =0;
+ else {
+ g->gb_num_zeroes += 1;
+ if (g->gb_num_zeroes >= 11)
+ break;
+ }
+ }
+ }
+
+ /* the cache is now empty; start scanning bytes */
+
+ while (TRUE) {
+ if (g->gb_byte_p >= g->gb_buf_after_p)
+ return FALSE;
+ byt = *(g->gb_byte_p)++;
+ g->gb_num_zeroes += baLeftZeroesTbl[byt];
+ if (g->gb_num_zeroes >= 11) {
+ g->gb_byte_p -= 1;
+ break;
+ }
+ if (byt != 0)
+ g->gb_num_zeroes = baRightZeroesTbl[byt];
+ }
+ }
+
+ /*******************************************/
+ /* Scan input until a non-zero bit is seen */
+ /*******************************************/
+
+ while (TRUE)
+ {
+ BITS_REFILL_CACHE (g)
+ if (g->gb_cache_cnt==0 || (leave_a_bit && g->gb_cache_cnt==1))
+ return FALSE;
+
+ CLEAR_UNUSED_CACHE_BITS
+
+ if (g->gb_cache == 0)
+ g->gb_cache_cnt = 0; /* cache is all zeroes; discard it */
+ else {
+ /* we hit the EOL */
+ for (bit = (1lu<<(g->gb_cache_cnt-1));
+ (bit & g->gb_cache) == 0;
+ bit >>= 1)
+ g->gb_cache_cnt -= 1; /* discard the 0's before the 1 */
+
+ /* After discarding the set bit, if leave_a_bit is TRUE, we want
+ * the cache to be non-empty so that a 1-dim/2-dim bit can then
+ * be fetched. Hence the check for 2 bits in cache below.
+ */
+ if (!leave_a_bit || g->gb_cache_cnt>=2) {
+ g->gb_cache_cnt -= 1; /* discard the set bit we found above */
+ g->gb_num_zeroes = 0;
+ return TRUE;
+ }
+ }
+
+ /* discard zero bytes */
+
+ /* Warning: If fax_decode_convert_row was told to flush, both
+ * pointers gb_byte_p and gb_buf_after_p can be NULL. So the
+ * pointer-compare below must be *before* the dereference in the
+ * test of the while loop, to avoid dereferencing a NULL pointer.
+ */
+ if (g->gb_cache_cnt == 0)
+ while (g->gb_byte_p<g->gb_buf_after_p && *(g->gb_byte_p)==0)
+ g->gb_byte_p++;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | BITS_LOAD | returns the next num_bits of input, with NO advance |
+ |___________|________________________________________________________________|
+*/
+#define BITS_LOAD(g, num_bits, par_result) { \
+ int n_bits = (int)(num_bits); \
+ \
+ par_result = (g->gb_cache >> (g->gb_cache_cnt-n_bits)) \
+ & ((1u<<n_bits) - 1u); \
+}
+
+#if 0
+
+#define BITS_LOAD(g, num_bits, par_result) { \
+ int n_bits = (int)(num_bits); \
+ \
+ par_result = g->gb_cache; \
+ \
+ asm ("extract %1,%2,%0" \
+ : "=d" (par_result) \
+ : "dI" (g->gb_cache_cnt - n_bits), "dI" (n_bits), "0" (par_result)); \
+}
+
+#endif
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | BITS_ADVANCE | advances input by num_bits bits |
+ |______________|_____________________________________________________________|
+*/
+#define BITS_ADVANCE(g, num_bits) { \
+ g->gb_cache_cnt -= (num_bits); \
+}
+
+
+
+/*****************************************************************************
+ * *
+ * U T I L I T I E S *
+ * *
+ *****************************************************************************/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_code_routine | Parses a Huffman code using the given code tables |
+ |____________________|_______________________________________________________|
+ | |
+ | Function return values: RET_GOT_CODE |
+ | RET_BAD_CODE |
+ | RET_FILL |
+ | RET_HIT_EOL |
+ | RET_NEED_MORE |
+ | |
+ | This function must NOT be called to scan for an EOL after it has |
+ | returned RET_BAD_CODE or RET_FILL. |
+ | |
+ | Warning: When this returns RET_HIT_EOL, it must guarantee that the |
+ | bit-cache is not empty so a 1-dim/2-dim bit can be fetched. |
+ |____________________________________________________________________________|
+*/
+
+static UINT parse_code_routine (
+ DEC_INST *g,
+ int bits_in_index, /* in: # bits in index for index_tbl */
+ const BYTE index_tbl[], /* in: contains indices into value_tbl */
+ const USHORT value_tbl[], /* in: contains [codelen, value] pairs */
+ int *value_p) /* out: the value corresponding to the code */
+{
+ UINT blob, values;
+
+ BITS_REFILL_CACHE(g)
+ if (BITS_IN_CACHE(g) < bits_in_index)
+ return RET_NEED_MORE;
+
+ BITS_LOAD (g, bits_in_index, blob);
+ values = value_tbl[index_tbl[blob]];
+
+ if (values != 0) {
+ /* normal case: we got a valid code */
+ BITS_ADVANCE (g, values >> CODELEN_SHIFT);
+ *value_p = values & VALUE_MASK;
+ return RET_GOT_CODE;
+ }
+
+ if (BITS_IN_CACHE(g) < MAX_CODE_LEN)
+ return RET_NEED_MORE;
+
+ BITS_LOAD (g, EOL_LEN, blob);
+
+ if (blob == 1) {
+ BITS_ADVANCE (g, EOL_LEN);
+ return RET_HIT_EOL;
+ }
+
+ if (blob == 0) {
+ BITS_ADVANCE (g, EOL_LEN);
+ return RET_FILL;
+ }
+
+ return RET_BAD_CODE;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | PARSE_CODE | A fast macro for parsing Huffman codes |
+ |____________|_______________________________________________________________|
+*/
+#define PARSE_CODE( \
+ g, \
+ bits_in_index, /* in: # bits in index for index_tbl */ \
+ index_tbl, /* in: contains indices into value_tbl */ \
+ value_tbl, /* in: contains [codelen, value] pairs */ \
+ out_result, /* out: RET_GOT_CODE, RET_BAD_CODE, etc */ \
+ out_value) /* out: the value corresponding to the code */ \
+do { \
+ UINT blob, values; \
+ \
+ if (BITS_IN_CACHE(g) < bits_in_index) \
+ goto call##value_tbl; \
+ \
+ BITS_LOAD (g, bits_in_index, blob); \
+ values = value_tbl[index_tbl[blob]]; \
+ \
+ if (values == 0) { \
+ call##value_tbl: \
+ out_result = parse_code_routine \
+ (g, bits_in_index, index_tbl, value_tbl, &out_value); \
+ } else { \
+ BITS_ADVANCE (g, values >> CODELEN_SHIFT); \
+ out_result = RET_GOT_CODE; \
+ out_value = values & VALUE_MASK; \
+ } \
+} while (0)
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | runs_array | all possible runs that fit in 16 bits |
+ |____________|_______________________________________________________________|
+ | |
+ | This array is indexed by (leftbit<<4)+rightbit. |
+ | Leftbit and rightbit are in 0..15. 0=msb, 15=lsb. |
+ |____________________________________________________________________________|
+*/
+
+static const USHORT runs_array_le[256] = { /* little-endian array */
+ 0x0080, 0x00c0, 0x00e0, 0x00f0, 0x00f8, 0x00fc, 0x00fe, 0x00ff,
+ 0x80ff, 0xc0ff, 0xe0ff, 0xf0ff, 0xf8ff, 0xfcff, 0xfeff, 0xffff,
+ 0x0000, 0x0040, 0x0060, 0x0070, 0x0078, 0x007c, 0x007e, 0x007f,
+ 0x807f, 0xc07f, 0xe07f, 0xf07f, 0xf87f, 0xfc7f, 0xfe7f, 0xff7f,
+ 0x0000, 0x0000, 0x0020, 0x0030, 0x0038, 0x003c, 0x003e, 0x003f,
+ 0x803f, 0xc03f, 0xe03f, 0xf03f, 0xf83f, 0xfc3f, 0xfe3f, 0xff3f,
+ 0x0000, 0x0000, 0x0000, 0x0010, 0x0018, 0x001c, 0x001e, 0x001f,
+ 0x801f, 0xc01f, 0xe01f, 0xf01f, 0xf81f, 0xfc1f, 0xfe1f, 0xff1f,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x000c, 0x000e, 0x000f,
+ 0x800f, 0xc00f, 0xe00f, 0xf00f, 0xf80f, 0xfc0f, 0xfe0f, 0xff0f,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0006, 0x0007,
+ 0x8007, 0xc007, 0xe007, 0xf007, 0xf807, 0xfc07, 0xfe07, 0xff07,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0003,
+ 0x8003, 0xc003, 0xe003, 0xf003, 0xf803, 0xfc03, 0xfe03, 0xff03,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001,
+ 0x8001, 0xc001, 0xe001, 0xf001, 0xf801, 0xfc01, 0xfe01, 0xff01,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x7f00,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x2000, 0x3000, 0x3800, 0x3c00, 0x3e00, 0x3f00,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x1000, 0x1800, 0x1c00, 0x1e00, 0x1f00,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0800, 0x0c00, 0x0e00, 0x0f00,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0400, 0x0600, 0x0700,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100,
+};
+
+static const USHORT runs_array_be[256] = { /* big-endian array */
+ 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
+ 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
+ 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x7f00,
+ 0x7f80, 0x7fc0, 0x7fe0, 0x7ff0, 0x7ff8, 0x7ffc, 0x7ffe, 0x7fff,
+ 0x0000, 0x0000, 0x2000, 0x3000, 0x3800, 0x3c00, 0x3e00, 0x3f00,
+ 0x3f80, 0x3fc0, 0x3fe0, 0x3ff0, 0x3ff8, 0x3ffc, 0x3ffe, 0x3fff,
+ 0x0000, 0x0000, 0x0000, 0x1000, 0x1800, 0x1c00, 0x1e00, 0x1f00,
+ 0x1f80, 0x1fc0, 0x1fe0, 0x1ff0, 0x1ff8, 0x1ffc, 0x1ffe, 0x1fff,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0800, 0x0c00, 0x0e00, 0x0f00,
+ 0x0f80, 0x0fc0, 0x0fe0, 0x0ff0, 0x0ff8, 0x0ffc, 0x0ffe, 0x0fff,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0400, 0x0600, 0x0700,
+ 0x0780, 0x07c0, 0x07e0, 0x07f0, 0x07f8, 0x07fc, 0x07fe, 0x07ff,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300,
+ 0x0380, 0x03c0, 0x03e0, 0x03f0, 0x03f8, 0x03fc, 0x03fe, 0x03ff,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100,
+ 0x0180, 0x01c0, 0x01e0, 0x01f0, 0x01f8, 0x01fc, 0x01fe, 0x01ff,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0080, 0x00c0, 0x00e0, 0x00f0, 0x00f8, 0x00fc, 0x00fe, 0x00ff,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0040, 0x0060, 0x0070, 0x0078, 0x007c, 0x007e, 0x007f,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0020, 0x0030, 0x0038, 0x003c, 0x003e, 0x003f,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0010, 0x0018, 0x001c, 0x001e, 0x001f,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x000c, 0x000e, 0x000f,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0006, 0x0007,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0003,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001,
+};
+
+static const USHORT *runs_array = runs_array_le;
+
+static void initRunArray(void) {
+ int iTest=1;
+ char *pcTest=((char *)(&iTest));
+
+ if (*pcTest==1) {
+ runs_array = runs_array_le;
+ } else {
+ runs_array = runs_array_be;
+ }
+}
+
+
+/*____________________________________________________________________________
+ | | |
+ | set_run | Sets a run of pixels to black |
+ |_________|__________________________________________________________________|
+ | |
+ | This routine does bounds-checking to avoid setting any pixels outside the |
+ | given buffer. |
+ | |
+ | Since this is called often, it's written to be as fast as I could make it. |
+ |____________________________________________________________________________|
+*/
+static void set_run (
+ BYTE *buf_p, /* buffer in which we're to set the run */
+ int start_pos, /* pixel-index of left side of run */
+ int run_len, /* # of pixels in the run (non-negative) */
+ int row_len) /* # of pixels in the buffer */
+{
+ /*************************************************************************
+ *
+ * PERFORMANCE NOTE
+ *
+ * Inlining this routine slows it down a little.
+ * Seconds to MMR encode+decode 1000 rows of 1728 pixels (bench_fax.c):
+ *
+ * black density: 0% 10% 20% 50%
+ * calling this routine: 2.2 7.4 12.8 29.9
+ * inlining this routine: 2.2 7.5 13.2 30.6
+ *
+ * Inlining this routine *hurt* performance a little because more MMR
+ * code was kicked out of the cache.
+ *
+ *************************************************************************/
+
+ int end_pos; /* pixel-index of rightmost pixel in run */
+ int start_index; /* byte-index of first byte in run */
+ BYTE *left_p; /* ptr to byte containing leftmost pixel in run */
+ BYTE *right_p; /* ptr to byte containing rightmost pixel in run */
+
+ end_pos = start_pos + run_len - 1;
+
+ if (end_pos >= row_len)
+ end_pos = row_len - 1;
+
+ start_index = start_pos >> 4;
+
+ if ((end_pos >> 4) == start_index) {
+ /* the run is contained within an even-aligned 2-byte word */
+ ((USHORT*)buf_p)[start_index] |=
+ runs_array [((start_pos & 15)<<4) | (end_pos & 15)];
+ } else if (end_pos > start_pos) {
+ /* the run spans two or more bytes */
+ left_p = buf_p + (start_pos >> 3);
+ right_p = buf_p + (end_pos >> 3);
+
+ *left_p |= (BYTE )0xFFu >> (UINT)( start_pos & 7u );
+ *right_p = (BYTE )0xFFu << (UINT)(7u - (end_pos & 7u));
+ left_p++;
+
+ while (left_p < right_p)
+ *left_p++ = 0xFFu;
+ }
+}
+
+
+/*****************************************************************************
+ * *
+ * DECODING ROW-DATA *
+ * *
+ *****************************************************************************
+
+
+ Interface into this section:
+
+ decode_row_init - inits instance-vars for this section
+ decode_row_1d - parses a row of 1-dim data
+ decode_row_2d - parses a row of 2-dim data
+
+ The parsing routines return these bit-values:
+
+ IP_PRODUCED_ROW
+ IP_INPUT_ERROR
+ DECODE_HIT_EOL (defined below, not in the public interface)
+ DECODE_HIT_FILL (ditto)
+
+ A return-value of zero (ie, none of the above bits are set) means that the
+ routine wants to be called again with more input-bytes.
+
+ These routines fetch input by calling BITS_LOAD, so bits_init and
+ bits_buf_open must have already been called.
+*/
+
+#define DECODE_HIT_EOL 0x4000u
+#define DECODE_HIT_FILL 0x8000u
+
+
+/*____________________________________________________________________________
+ | | |
+ | decode_row_init | inits instance-variables for this section |
+ |_________________|__________________________________________________________|
+*/
+static void decode_row_init (DEC_INST *g)
+{
+ g->pixel_pos = 0;
+ g->white = 0xFFu; /* start with a white run */
+ g->state_2d = NORMAL_2D;
+ g->a0 = -1; /* pixel before 1st is an imaginary white pixel */
+ g->got_black = FALSE; /* haven't gotten any black pixels */
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | decode_row_1d | Decodes a row of MH (1-dimensional G3) data |
+ |_______________|____________________________________________________________|
+*/
+static UINT decode_row_1d (
+ DEC_INST *g, /* in: pointer to our instance-variables */
+ BYTE *pbPrevOutBuf, /* in: prev output row (for error-handling) */
+ BYTE *pbOutBuf) /* out: output buf */
+{
+ int run_len; /* # pixels in current run */
+ UINT white;
+ int pixel_pos;
+ UINT result;
+ UINT ret_val = 0; /* init to zap a compiler warning */
+ int index_length;
+ const BYTE *index_tbl_p;
+ const USHORT *value_tbl_p;
+
+ if (g->pixel_pos == 0) {
+ memset (pbOutBuf, 0, g->bytes_in_row); /* set whole row to white */
+ g->ref_row_invalid = TRUE;
+ }
+
+ white = (UINT)(int )(signed char)g->white; /* must be all 0's or all 1's */
+ pixel_pos = g->pixel_pos;
+
+ while (TRUE) {
+
+ if (white) {
+ index_length = MAX_WHITE_CODELEN;
+ index_tbl_p = fax_white_huff_index;
+ value_tbl_p = fax_white_huff;
+ } else {
+ index_length = MAX_BLACK_CODELEN;
+ index_tbl_p = fax_black_huff_index;
+ value_tbl_p = fax_black_huff;
+ }
+
+ PARSE_CODE (g, index_length, index_tbl_p, value_tbl_p, result, run_len);
+ PRINT (_T("pc result=%d, len=%d\n"), result, run_len);
+
+ if (result == RET_GOT_CODE) {
+ /* todo: below, we call set_run for EVERY make-up code (slow) */
+ if (! white) {
+ set_run (pbOutBuf, pixel_pos, run_len, g->row_len);
+ g->got_black = TRUE;
+ }
+
+ pixel_pos += run_len;
+ if (run_len <= 63) /* this is a final run (not a make-up) */
+ white = ~white;
+ continue; /* go to top of main 'while' loop */
+ }
+
+ switch (result) { /* handle unusual condition */
+
+ case RET_NEED_MORE:
+ ret_val = 0;
+ goto bail_out;
+ break;
+
+ case RET_BAD_CODE:
+ memcpy (pbOutBuf, pbPrevOutBuf, g->bytes_in_row);
+ ret_val = IP_PRODUCED_ROW | IP_INPUT_ERROR;
+ goto bail_out;
+ break;
+
+ case RET_FILL:
+ case RET_HIT_EOL:
+ ret_val = result==RET_FILL ? DECODE_HIT_FILL : DECODE_HIT_EOL;
+ if (pixel_pos == 0)
+ goto bail_out;
+ if (pixel_pos == g->row_len) {
+ ret_val |= IP_PRODUCED_ROW;
+ g->ref_row_invalid = FALSE;
+ goto bail_out;
+ }
+ memcpy (pbOutBuf, pbPrevOutBuf, g->bytes_in_row);
+ ret_val |= IP_PRODUCED_ROW | IP_INPUT_ERROR;
+ goto bail_out;
+ break;
+
+ default:
+ assert (FALSE);
+ } /* end of switch */
+ } /* end of while */
+
+ bail_out:
+
+ g->white = white;
+ g->pixel_pos = pixel_pos;
+
+ return ret_val;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | decode_row_2d | Decodes a row of MR/MMR (2-dimensional) data |
+ |_______________|____________________________________________________________|
+*/
+static UINT decode_row_2d (
+ DEC_INST *g, /* in: pointer to our instance-variables */
+ BYTE *pbPrevBuf, /* in: prev output row ("reference row") */
+ BYTE *pbOutBuf) /* out: output buffer */
+{
+ UINT group4;
+ int iAction;
+ UINT white;
+ UINT result = 0; /* the 0 eliminates a compiler warning */
+ int row_len;
+ int run_len;
+ int a0, a1;
+ int b1=0, b2; /* the 0 eliminates a compiler warning */
+ UINT need_b0;
+ UINT ret_val = 0; /* the 0 eliminates a compiler warning */
+
+ group4 = (g->input_format == IP_FAX_MMR);
+ row_len = g->row_len;
+ white = (UINT)(int)(signed char)g->white; /* must be all 0's or all 1's so sign extend */
+ a0 = g->a0;
+
+ if (a0 < 0) {
+ memset (pbOutBuf, 0, g->bytes_in_row); /* set whole row to white */
+ pbPrevBuf[g->bytes_in_row] = 0x55u; /* scan_to requires this */
+ }
+
+ while (TRUE) {
+
+ /****************************************/
+ /* Process a usual code -- normal state */
+ /****************************************/
+
+ need_b0 = TRUE;
+
+ while (g->state_2d == NORMAL_2D) {
+
+ if (a0>=row_len && group4) {
+ /* ret_val = IP_PRODUCED_ROW; goto bail_out;
+ * todo: undelete the line above? */
+ if (a0 == row_len) ret_val = IP_PRODUCED_ROW;
+ else ret_val = IP_INPUT_ERROR;
+ goto bail_out;
+ }
+
+ PARSE_CODE (g, MAX_VERT_CODELEN, fax_vert_huff_index,
+ fax_vert_huff, result, iAction);
+ if (result != RET_GOT_CODE)
+ goto unusual_condition;
+
+ if (iAction == HORIZ_MODE) {
+ g->state_2d = HORIZ_1ST;
+ break;
+ }
+
+ if (a0 < 0) {
+ a0 = 0;
+ b1 = -1; /* a kludge so scan below will start at pixel 0 */
+ } else if (need_b0)
+ b1 = scan_to (white, pbPrevBuf, a0, row_len);
+
+ b1 = scan_to (~white, pbPrevBuf, b1+1, row_len);
+
+ if (iAction <= LAST_VERT) { /* vertical mode */
+ iAction -= 3;
+ a1 = b1 + iAction;
+ need_b0 = (iAction<-1 || iAction>0);
+ if (! white) {
+ set_run (pbOutBuf, a0, a1-a0, row_len);
+ g->got_black = TRUE;
+ }
+ if (a1<a0 || a1>row_len) goto corrupt;
+ a0 = a1;
+ white = ~white;
+ } else { /* pass mode */
+ b2 = scan_to (white, pbPrevBuf, b1+1, row_len);
+ if (! white) {
+ set_run (pbOutBuf, a0, b2-a0, row_len);
+ g->got_black = TRUE;
+ }
+ need_b0 = FALSE;
+ a0 = b2;
+ b1 = b2;
+ }
+ } /* while NORMAL_2D */
+
+ /*******************************************/
+ /* Process a usual code -- horizontal mode */
+ /*******************************************/
+
+ while (TRUE) { /* HORIZ_1ST or HORIZ_2ND */
+ int index_length;
+ const BYTE *index_tbl_p;
+ const USHORT *value_tbl_p;
+
+ do {
+ if (white) {
+ index_length = MAX_WHITE_CODELEN;
+ index_tbl_p = fax_white_huff_index;
+ value_tbl_p = fax_white_huff;
+ } else {
+ index_length = MAX_BLACK_CODELEN;
+ index_tbl_p = fax_black_huff_index;
+ value_tbl_p = fax_black_huff;
+ }
+
+ PARSE_CODE (g, index_length, index_tbl_p, value_tbl_p,
+ result, run_len);
+
+ if (result != RET_GOT_CODE)
+ goto unusual_condition;
+ if (a0 < 0) /* Exception: See Fascicle VII.3, */
+ a0 = 0; /* rec T.4, section 4.2.1.3.4 */
+ /* todo: below, we call set_run for EVERY make-up code (slow) */
+ if (! white) {
+ set_run (pbOutBuf, a0, run_len, row_len);
+ g->got_black = TRUE;
+ }
+ a0 += run_len;
+ } while (run_len > 63);
+
+ white = ~white;
+ if (g->state_2d == HORIZ_1ST)
+ g->state_2d = HORIZ_2ND;
+ else {
+ g->state_2d = NORMAL_2D;
+ if (a0 > row_len) goto corrupt;
+ break; /* exit while */
+ }
+ }
+
+ continue; /* no unusual condition, so resume main while loop */
+
+ /*****************************/
+ /* Handle unusual conditions */
+ /*****************************/
+
+ corrupt:
+ result = RET_BAD_CODE;
+
+ unusual_condition:
+
+ switch (result) {
+
+ case RET_GOT_CODE:
+ /* normal case: was handled in the block of code above */
+ break;
+
+ case RET_NEED_MORE:
+ ret_val = 0;
+ goto bail_out;
+ break;
+
+ case RET_BAD_CODE:
+ g->state_2d = NORMAL_2D;
+ memcpy (pbOutBuf, pbPrevBuf, g->bytes_in_row);
+ ret_val = IP_PRODUCED_ROW | IP_INPUT_ERROR;
+ g->ref_row_invalid = TRUE;
+ goto bail_out;
+ break;
+
+ case RET_FILL:
+ case RET_HIT_EOL:
+ ret_val = result==RET_FILL ? DECODE_HIT_FILL : DECODE_HIT_EOL;
+ g->state_2d = NORMAL_2D;
+
+ if (group4) {
+ /* We should only hit EOL when no row-data is present */
+ /* todo: Always report error if fill-zeroes were seen? */
+ if (a0 >= 0)
+ ret_val |= IP_INPUT_ERROR;
+ } else {
+ if (!g->ref_row_invalid && a0==row_len)
+ ret_val |= IP_PRODUCED_ROW;
+ else if (a0 >= 0) {
+ memcpy (pbOutBuf, pbPrevBuf, g->bytes_in_row);
+ ret_val |= IP_PRODUCED_ROW | IP_INPUT_ERROR;
+ g->ref_row_invalid = TRUE;
+ }
+ }
+ goto bail_out;
+ break;
+
+ default:
+ assert (FALSE);
+
+ } /* end of switch to handle unusual condition */
+ } /* end of while */
+
+ bail_out:
+
+ /* save variables needed in next call */
+ g->a0 = a0;
+ g->white = white;
+
+ return ret_val;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxDecode_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD faxDecode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PDEC_INST g;
+
+ initRunArray();
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(DEC_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(DEC_INST));
+ g->dwValidChk = CHECK_VALUE;
+
+ bits_init (g);
+ decode_row_init (g);
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxDecode_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD faxDecode_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Insure that values we actually use or care about are known */
+ INSURE (pTraits->iPixelsPerRow > 0); /* we need the row-length */
+ INSURE (pTraits->iBitsPerPixel == 1); /* image must be bi-level */
+
+ g->traits = *pTraits; /* a structure copy */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxDecode_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD faxDecode_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->input_format = (BYTE)aXformInfo[IP_FAX_FORMAT].dword;
+ g->no_eols = (BOOL)aXformInfo[IP_FAX_NO_EOLS].dword;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxDecode_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD faxDecode_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxDecode_getActualTraits - Parses header, and returns input & output traits
+ *
+ *****************************************************************************
+ *
+ * There is no header, so this routine merely computes some stuff
+ *
+\*****************************************************************************/
+
+static WORD faxDecode_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PDEC_INST g;
+ int inBytes;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ /* Since we don't change traits, just copy out the default traits */
+
+ *pInTraits = g->traits;
+ *pOutTraits = g->traits;
+
+ /* Compute some stuff */
+
+ g->row_len = g->traits.iPixelsPerRow; /* todo: zap redundant var */
+ g->bytes_in_row = inBytes = (g->row_len+7) / 8;
+ g->two_dim = (g->input_format == IP_FAX_MMR);
+
+ /* For MH and MR: Discard bits before the first EOL */
+ g->flushing_to_eol = ! g->two_dim;
+
+ /* allocate the prior-row buffer */
+
+ if (g->prior_p != NULL)
+ IP_MEM_FREE (g->prior_p);
+ IP_MEM_ALLOC (inBytes, g->prior_p);
+ memset (g->prior_p, 0, inBytes);
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * faxDecode_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD faxDecode_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = 1;
+ *pdwMinOutBufLen = g->bytes_in_row;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxDecode_convert - the work-horse routine
+ *
+\*****************************************************************************/
+
+static WORD faxDecode_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PDEC_INST g;
+ UINT bit;
+ UINT ret_val; /* return-value of this function */
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwOutputUsed = 0;
+
+ if (dwInputAvail==0 && BITS_IN_CACHE(g)<MAX_CODE_LEN) {
+ /* We're being told to flush; indicate we're done. */
+ /* Our only buffer is the cache */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ if (g->toss_everything) {
+ *pdwInputUsed = dwInputAvail;
+ *pdwInputNextPos = g->dwInNextPos = g->dwInNextPos + dwInputAvail;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_READY_FOR_DATA;
+ }
+
+ bits_buf_open (g, pbInputBuf, dwInputAvail);
+
+ if (g->flushing_to_eol) {
+ ret_val = bits_flush_to_eol(g, g->got_fill,
+ (BOOL)(g->input_format==IP_FAX_MR))
+ ? DECODE_HIT_EOL : 0;
+ } else {
+ if (g->two_dim) ret_val = decode_row_2d(g, g->prior_p, pbOutputBuf);
+ else ret_val = decode_row_1d(g, g->prior_p, pbOutputBuf);
+ PRINT (_T("decoder returned %x\n"), ret_val, 0);
+ }
+
+ if (ret_val & IP_INPUT_ERROR) {
+ if (g->input_format == IP_FAX_MMR) {
+ bits_flush (g);
+ g->toss_everything = TRUE;
+ /* This isn't fatal any more. We merely toss all following data */
+ /* ret_val |= IP_INPUT_ERROR; */
+ } else {
+ g->flushing_to_eol = TRUE;
+ g->num_eols = 0;
+ }
+ }
+
+ if (ret_val & IP_PRODUCED_ROW) {
+ if (g->got_black) ret_val |= NONWHITE_ROW | IP_CONSUMED_ROW;
+ else ret_val |= WHITE_ROW | IP_CONSUMED_ROW;
+ *pdwOutputUsed = g->bytes_in_row;
+ memcpy (g->prior_p, pbOutputBuf, g->bytes_in_row);
+ decode_row_init (g);
+ g->num_eols = 0; /* ignore all EOLs before the row */
+ }
+
+ if (ret_val & DECODE_HIT_FILL) {
+ g->flushing_to_eol = TRUE;
+ g->got_fill = TRUE;
+ }
+
+ if (ret_val & DECODE_HIT_EOL) {
+ if (g->input_format == IP_FAX_MR) {
+ /* read the tag-bit for 1-dim/2-dim */
+ BITS_LOAD (g, 1, bit)
+ g->two_dim = (bit == 0);
+ BITS_ADVANCE (g, 1)
+ }
+
+ decode_row_init (g);
+ g->flushing_to_eol = FALSE;
+ g->got_fill = FALSE;
+ g->num_eols += 1;
+
+ if (g->num_eols>=EOLS_FOR_MH_MR ||
+ (g->input_format==IP_FAX_MMR && g->num_eols>=EOLS_FOR_MMR)) {
+ /* WE HIT END OF PAGE */
+ g->num_eols = 0;
+ bits_flush (g);
+ ret_val |= IP_NEW_OUTPUT_PAGE;
+ }
+ }
+
+ *pdwInputUsed = bits_buf_close (g);
+ g->dwInNextPos += *pdwInputUsed;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = (ret_val & IP_PRODUCED_ROW) ? g->bytes_in_row : 0;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += *pdwOutputUsed;
+
+#if 0
+ {
+ int i;
+ for (i=0; i<*pdwInputUsed; i++)
+ PRINT (_T("%02x "), pbInputBuf[i], 0);
+ }
+#endif
+
+ return (ret_val | IP_READY_FOR_DATA)
+ & (IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA |
+ /* NONWHITE_ROW | WHITE_ROW | */
+ IP_NEW_OUTPUT_PAGE |
+ IP_INPUT_ERROR | IP_FATAL_ERROR);
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxDecode_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD faxDecode_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxDecode_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD faxDecode_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: flush bits until we see a page boundary */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxDecode_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD faxDecode_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ if (g->prior_p != NULL)
+ IP_MEM_FREE (g->prior_p);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * faxDecodeTbl - Jump-table for Decoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL faxDecodeTbl = {
+ faxDecode_openXform,
+ faxDecode_setDefaultInputTraits,
+ faxDecode_setXformSpec,
+ faxDecode_getHeaderBufSize,
+ faxDecode_getActualTraits,
+ faxDecode_getActualBufSizes,
+ faxDecode_convert,
+ faxDecode_newPage,
+ faxDecode_insertedData,
+ faxDecode_closeXform
+};
+
+
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ @
+@ T A B L E S F O R D E C O D E R @
+@ @
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+*/
+
+
+
+const USHORT fax_white_huff[105] = { 0,
+ 0x4002, 0x4003, 0x4004, 0x4005, 0x4006, 0x4007, 0x500a, 0x500b,
+ 0x5080, 0x5008, 0x5009, 0x5040, 0x600d, 0x6001, 0x600c, 0x60c0,
+ 0x6680, 0x6010, 0x6011, 0x600e, 0x600f, 0x7016, 0x7017, 0x7014,
+ 0x7013, 0x701a, 0x7015, 0x701c, 0x701b, 0x7012, 0x7018, 0x7019,
+ 0x7100, 0x801d, 0x801e, 0x802d, 0x802e, 0x802f, 0x8030, 0x8021,
+ 0x8022, 0x8023, 0x8024, 0x8025, 0x8026, 0x801f, 0x8020, 0x8035,
+ 0x8036, 0x8027, 0x8028, 0x8029, 0x802a, 0x802b, 0x802c, 0x803d,
+ 0x803e, 0x803f, 0x8000, 0x8140, 0x8180, 0x803b, 0x803c, 0x8031,
+ 0x8032, 0x8033, 0x8034, 0x8037, 0x8038, 0x8039, 0x803a, 0x81c0,
+ 0x8200, 0x8280, 0x8240, 0x95c0, 0x9600, 0x9640, 0x96c0, 0x92c0,
+ 0x9300, 0x9340, 0x9380, 0x93c0, 0x9400, 0x9440, 0x9480, 0x94c0,
+ 0x9500, 0x9540, 0x9580, 0xb700, 0xb740, 0xb780, 0xc7c0, 0xc800,
+ 0xc840, 0xc880, 0xc8c0, 0xc900, 0xc940, 0xc980, 0xc9c0, 0xca00,
+};
+
+
+const BYTE fax_white_huff_index[4096] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 92, 92, 95, 96, 97, 98, 99, 100, 93, 93, 94, 94, 101, 102, 103, 104,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77,
+ 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+ 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+ 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 80, 80, 80, 80, 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, 81,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 82, 82, 82, 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, 83,
+ 84, 84, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, 85,
+ 86, 86, 86, 86, 86, 86, 86, 86, 87, 87, 87, 87, 87, 87, 87, 87,
+ 88, 88, 88, 88, 88, 88, 88, 88, 89, 89, 89, 89, 89, 89, 89, 89,
+ 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 91,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+};
+
+
+const USHORT fax_black_huff[105] = { 0,
+ 0x2003, 0x2002, 0x3001, 0x3004, 0x4006, 0x4005, 0x5007, 0x6009,
+ 0x6008, 0x700a, 0x700b, 0x700c, 0x800d, 0x800e, 0x900f, 0xa012,
+ 0xa040, 0xa010, 0xa011, 0xa000, 0xb700, 0xb740, 0xb780, 0xb018,
+ 0xb019, 0xb017, 0xb016, 0xb013, 0xb014, 0xb015, 0xc7c0, 0xc800,
+ 0xc840, 0xc880, 0xc8c0, 0xc900, 0xc940, 0xc980, 0xc9c0, 0xca00,
+ 0xc034, 0xc037, 0xc038, 0xc03b, 0xc03c, 0xc140, 0xc180, 0xc1c0,
+ 0xc035, 0xc036, 0xc032, 0xc033, 0xc02c, 0xc02d, 0xc02e, 0xc02f,
+ 0xc039, 0xc03a, 0xc03d, 0xc100, 0xc030, 0xc031, 0xc03e, 0xc03f,
+ 0xc01e, 0xc01f, 0xc020, 0xc021, 0xc028, 0xc029, 0xc080, 0xc0c0,
+ 0xc01a, 0xc01b, 0xc01c, 0xc01d, 0xc022, 0xc023, 0xc024, 0xc025,
+ 0xc026, 0xc027, 0xc02a, 0xc02b, 0xd280, 0xd2c0, 0xd300, 0xd340,
+ 0xd500, 0xd540, 0xd580, 0xd5c0, 0xd600, 0xd640, 0xd680, 0xd6c0,
+ 0xd200, 0xd240, 0xd380, 0xd3c0, 0xd400, 0xd440, 0xd480, 0xd4c0,
+};
+
+
+const BYTE fax_black_huff_index[8192] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 21, 21, 21, 21, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36,
+ 22, 22, 22, 22, 23, 23, 23, 23, 37, 37, 38, 38, 39, 39, 40, 40,
+ 16, 16, 16, 16, 16, 16, 16, 16, 41, 41, 85, 86, 87, 88, 42, 42,
+ 43, 43, 89, 90, 91, 92, 44, 44, 45, 45, 93, 94, 24, 24, 24, 24,
+ 25, 25, 25, 25, 95, 96, 46, 46, 47, 47, 48, 48, 97, 98, 49, 49,
+ 50, 50, 99, 100, 101, 102, 103, 104, 17, 17, 17, 17, 17, 17, 17, 17,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 26, 26, 26, 26, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56,
+ 57, 57, 58, 58, 59, 59, 60, 60, 18, 18, 18, 18, 18, 18, 18, 18,
+ 19, 19, 19, 19, 19, 19, 19, 19, 61, 61, 62, 62, 63, 63, 64, 64,
+ 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 27, 27, 27, 27,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 28, 28, 28, 28,
+ 29, 29, 29, 29, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82,
+ 30, 30, 30, 30, 83, 83, 84, 84, 20, 20, 20, 20, 20, 20, 20, 20,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+
+const USHORT fax_vert_huff[10] = { 0,
+ 0x1003, 0x3008, 0x3002, 0x3004, 0x4007, 0x6001, 0x6005, 0x7000,
+ 0x7006,
+};
+
+
+const BYTE fax_vert_huff_index[128] = {
+ 0, 0, 8, 9, 6, 6, 7, 7, 5, 5, 5, 5, 5, 5, 5, 5,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+/* End of File */
diff --git a/ip/xform.h b/ip/xform.h
new file mode 100644
index 0000000..4ce4829
--- /dev/null
+++ b/ip/xform.h
@@ -0,0 +1,340 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/* xform.h - Interface into the transform drivers
+ *
+ * Mark Overton, Jan 2000 - Extracted from hpojip.h
+ */
+
+#if ! defined XFORM_H_INC
+#define XFORM_H_INC
+
+
+/*****************************************************************************\
+ *****************************************************************************
+ *
+ * TRANSFORM DRIVER interface
+ *
+ *****************************************************************************
+\*****************************************************************************/
+
+
+/* In some ways, this driver interface is very similar to the main ip
+ * interface. Please don't get them confused.
+ *
+ * One of the parameters of the ipOpen function is an array of structures.
+ * Each such structure defines a transform, and contains, among other things,
+ * a pointer to a jump-table for the transform-driver. The jump-table is
+ * a structure containing function-pointers for all the driver's functions.
+ * These functions and the jump-table are defined below.
+ *
+ * Function Call Order
+ *
+ * openXform;
+ * setDefaultInputTraits, setXformSpec, getHeaderBufSize (any order);
+ * getActualTraits (possibly multiple calls);
+ * getActualBufSizes;
+ * convert, insertedData, newPage (usually multiple calls);
+ * closeXform.
+ *
+ * Raw Data Format
+ *
+ * A decoder outputs raw data, an encoder inputs raw data, and all data passed
+ * between xforms consists of raw data.
+ * Such raw raster data consists of fixed-length raster rows of packed pixels.
+ * The pixels are packed as follows:
+ *
+ * bi-level: 8 pixels/byte, left pixel in msb, 0=white, 1=black.
+ * 4-bit gray: 2 pixels/byte, left pixel in hi nibble, 0=black, 15=white.
+ * 8-bit gray: 1 pixel/byte, 0=black, 255=white.
+ * color: three bytes per pixel, in some color space.
+ *
+ * Driver Documentation
+ *
+ * The .c file for an xform driver starts with a comment-section documenting
+ * the following items:
+ *
+ * - the capabilities of the driver, and its limitations.
+ * - the name of the global jump-table (of type IP_XFORM_TBL).
+ * - what should be put in the aXformInfo array passed to setXformSpec.
+ * - which items in default input traits are ignored versus used.
+ * - what the output image traits are.
+ *
+ * Note that image traits, such as pixels per row, should *not* be put in
+ * aXformInfo because such info is provided by setDefaultInputTraits.
+ * Things like the JPEG quality-factor should be in aXformInfo.
+ *
+ * An xform driver is allowed to overrun its input or output buffer by
+ * up to 12 bytes. This is allowed because some image processing algorithms
+ * are faster if they operate on multiple pixels at a time, which will cause
+ * them to read or write a little past the end of the buffer. Reading or
+ * writing before the beginning of a buffer is not allowed.
+ */
+
+
+typedef void* IP_XFORM_HANDLE; /* handle for an xform driver */
+
+
+/* IP_XFORM_TBL - Jump-table for a transform driver (all the entry points)
+ */
+typedef struct IP_XFORM_TBL_s {
+
+ /* openXform - Creates a new instance of the transformer
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ */
+ WORD (*openXform) (
+ IP_XFORM_HANDLE *pXform); /* out: returned handle */
+
+
+ /* setDefaultInputTraits - Specifies default input image traits
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ */
+ WORD (*setDefaultInputTraits) (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits); /* in: default image traits */
+
+
+ /* setXformSpec - Provides xform-specific information
+ *
+ * The aXformInfo array provides the transform-specific info.
+ * For example, for a scaling transform, this array would contain
+ * the horizontal and vertical scaling factors and possibly additional
+ * info about whether to scale quickly by simple pixel-replication.
+ * For a JPEG-encode transform, the array would contain the quality
+ * factor and subsampling information.
+ *
+ * Each transform documents what it needs in aXformInfo.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ */
+ WORD (*setXformSpec) (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]); /* in: xform information */
+
+
+ /* getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+ * Returns size of input buffer that's guaranteed to hold the file
+ * header. If that's too big, the xform code will have to parse the
+ * header across several calls, and return a suitable buffer size.
+ * If there is no header, this function returns 0 in pwInBufLen.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ */
+ WORD (*getHeaderBufSize) (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen); /* out: buf size for parsing header */
+
+
+ /* getActualTraits - Parses header, and returns input & output traits
+ *
+ * This function may need to be called multiple times to parse the
+ * file header. And it can consume input in each call.
+ * Once the header has been parsed, it returns IP_DONE, meaning that
+ * it is not to be called again and that the in-traits and out-traits
+ * structures have been filled in. The output traits are computed based
+ * on the input traits and the xform information provided by setXformSpec.
+ *
+ * See the description of 'convert' below for how the input-buffer
+ * parameters are used. The final value returned in pdwInputNextPos
+ * (where this returns IP_DONE) is the one that applies to the
+ * 'convert' function. This function MUST be called even if there is
+ * no header because you need that pdwInputNextPos value.
+ *
+ * NOTE: In addition to IP_DONE, the IP_READY_FOR_DATA bit must also
+ * be set if the xform will want data on the first call to 'convert'.
+ *
+ * Return value:
+ * 0 = call again with more input,
+ * IP_DONE = normal end (IP_READY_FOR_DATA set if data needed)
+ * IP_INPUT_ERROR = error in input data,
+ * IP_FATAL_ERROR = misc error.
+ */
+ WORD (*getActualTraits) (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits); /* out: output image traits */
+
+
+ /* getActualBufSizes - Returns buf sizes needed for remainder of session
+ *
+ * Since the input and output row-lengths are now known because
+ * getActualTraits has parsed the header, and actual buffer sizes needed
+ * for the remainder of the conversion session can now be fetched.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ */
+ WORD (*getActualBufSizes) (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pwMinInBufLen, /* out: min input buf size */
+ PDWORD pwMinOutBufLen); /* out: min output buf size */
+
+
+ /* convert - The work-horse conversion routine
+ *
+ * This function consumes input data and produces output data via the
+ * input- and output-buffer parameters. And it tells you what's happening
+ * via its function return value.
+ *
+ * On entry, pbInputBuf and wInputAvail specify the location and number of
+ * data-bytes in the input buffer. On return, pwInputUsed tells you how
+ * many of those input bytes were consumed. pdwInputNextPos tells you
+ * where in the input file you should read next for the following call;
+ * 0 is the beginning of the file. This is almost always the current file
+ * position plus pwInputUsed; if not, a file-seek is being requested.
+ *
+ * The output buffer parameters are analogous to the input parameters,
+ * except that pdwOutputThisPos tells you where the bytes just output
+ * should be written in the output file. That is, it applies to *this*
+ * write, not the *next* write, unlike the input arrangement.
+ *
+ * The function return value is a bit-mask that tells you if anything
+ * interesting happened. Multiple bits can be set. This information
+ * should be treated as independent of the data-transfers occuring via
+ * the parameters. The IP_CONSUMED_ROW and IP_PRODUCED_ROW bits can
+ * be used to count how many rows have been input and output.
+ *
+ * The IP_READY_FOR_DATA bit indicates that the next call to 'convert'
+ * definitely will consume data. If this bit is 0, the next call
+ * definitely will NOT consume data. The main converter code that calls
+ * these xform functions uses this ready-for-data info to control the
+ * order of xform calls. The IP_READY_FOR_DATA bit must be set correctly.
+ *
+ * The IP_NEW_INPUT_PAGE bit is set when or after the last row of the
+ * input page has been parsed. It may be a few rows before you get the
+ * corresponding IP_NEW_OUTPUT_PAGE bit.
+ *
+ * The IP_NEW_OUTPUT_PAGE bit is set when or after the last row of the
+ * page has been sent, and before the first row of the following page (if
+ * any) is sent.
+ *
+ * You may wish to insert secret data, such as thumbnails, into the
+ * output stream. When 'convert' returns the IP_WRITE_INSERT_OK bit,
+ * it is giving you permission to write stuff AFTER you write the output
+ * buffer it gave you. After adding your secret data, you must call
+ * insertedData to tell us how many bytes were added.
+ *
+ * When there is no more input data, 'convert' must be called repeatedly
+ * with a NULL pbInputBuf parameter, which tells the xform to flush out
+ * any buffered rows. Keep calling it until it returns the IP_DONE bit.
+ *
+ * Do not call 'convert' again after it has returned either error bit or
+ * IP_DONE.
+ *
+ * If the input or output data consists of fixed-length uncompressed rows,
+ * then it is permissible for the xform to read up to 8 bytes past the
+ * end of the (fixed-length) input row, or to write up to 8 bytes past the
+ * end of the (fixed-length) output row. The caller of the xform routines
+ * allocates at least this many extra overrun-zone bytes so that algorithms
+ * can process pixels multiple-bytes at a time without worrying about
+ * running past the end of the row. These overrun-zone bytes must NOT be
+ * reported by getActualBufSizes, which should report only what's needed
+ * for the actual row-data.
+ *
+ * Return value: Zero or more of these bits may be set:
+ *
+ * IP_CONSUMED_ROW = an input row was parsed
+ * IP_PRODUCED_ROW = an output row was produced
+ * IP_INPUT_ERROR = syntax error in input data
+ * IP_FATAL_ERROR = misc error (internal error or bad param)
+ * IP_NEW_INPUT_PAGE = just finished parsing the input page
+ * IP_NEW_OUTPUT_PAGE = just finished outputting a page
+ * IP_WRITE_INSERT_OK = okay to insert data in output file
+ * IP_DONE = conversion is completed.
+ */
+ WORD (*convert) (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos); /* out: file-pos to write the data */
+
+
+ /* newPage - Tells xform to flush rest of this page, and start a new page
+ *
+ * Uncompressed input-data formats do not have page-boundary info, so
+ * calling this function between rows fed into 'convert' is how you tell
+ * xform to output a page-boundary. After this is called, 'convert' will
+ * first flush any buffered rows, then return the IP_NEW_OUTPUT_PAGE bit,
+ * and finally start a new page.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ */
+ WORD (*newPage) (IP_XFORM_HANDLE hXform);
+
+
+ /* insertedData - Tells us that bytes were inserted into output stream
+ *
+ * See IP_WRITE_INSERT_OK discussion above. You call this routine to tell
+ * the xform code how many bytes were secretly added to the output stream.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ */
+ WORD (*insertedData) (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes);
+
+
+ /* closeXform - destroys instance of xform
+ *
+ * This may be called at any time to remove an instance of the xform.
+ * It deallocates all dynamic memory associated with the xform.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ */
+ WORD (*closeXform)(IP_XFORM_HANDLE hXform);
+
+} IP_XFORM_TBL, *PIP_XFORM_TBL, FAR*LPIP_XFORM_TBL;
+
+#endif
diff --git a/ip/xgamma.c b/ip/xgamma.c
new file mode 100644
index 0000000..4058b91
--- /dev/null
+++ b/ip/xgamma.c
@@ -0,0 +1,760 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xgamma.c - Applies Gamma transform
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * gammaTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[0] = gamma value, in 16.16 fixed point
+ *
+ * Capabilities and Limitations:
+ *
+ * Gamma values must range between 0.0 and 3.5.
+ * Only operates on 8-bit grayscale data.
+ * Uses cubic splines for speed.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * must be 8 8
+ * iComponentsPerPixel * must be 1 1
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Feb 1998 Mark Overton -- ported code to software
+ * early 1997 Mark Overton -- wrote original code for Kodiak firmware
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #define PRINT(msg,arg1,arg2) \
+ fprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input image */
+ BYTE gammaTable[256]; /* the gamma table */
+ WORD wRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} GAM_INST, *PGAM_INST;
+
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | fast_sin fast_cos | fast sine and cosine functions |
+ |___________________|________________________________________________________|
+ | |
+ | Input: Units of angle is fraction of circle (e.g., 1.0 is 360 deg). |
+ | Format is 0.32 fixed-point (i.e., 32 bits of fraction). |
+ | |
+ | Returns: Sine or cosine expressed as 16.16 signed fixed-point. |
+ | |
+ | Accuracy: Max error is 0.000054 (i.e., 14 good bits of fraction). |
+ |____________________________________________________________________________|
+*/
+static long fast_sin (ULONG ang)
+{
+ ULONG ang31, ang30, delta_ang, result;
+ UINT index, base, next;
+
+ /* 90 deg is divided into this many intervals */
+ #define INDEX_BITS 6
+ #define N_INTERVALS (1<<INDEX_BITS)
+ #define HALF_WORST_ERR 3
+
+ static const USHORT sin_table[N_INTERVALS+2] = {
+ 0, 1608, 3216, 4821, 6424, 8022, 9616, 11204,
+ 12785, 14359, 15924, 17479, 19024, 20557, 22078, 23586,
+ 25080, 26558, 28020, 29466, 30893, 32303, 33692, 35062,
+ 36410, 37736, 39040, 40320, 41576, 42806, 44011, 45190,
+ 46341, 47464, 48559, 49624, 50660, 51665, 52639, 53581,
+ 54491, 55368, 56212, 57022, 57798, 58538, 59244, 59914,
+ 60547, 61145, 61705, 62228, 62714, 63162, 63572, 63944,
+ 64277, 64571, 64827, 65043, 65220, 65358, 65457, 65516,
+ 65535, 65535 /* <-- these should be 65536 (won't fit in 16 bits) */
+ };
+
+ /* zero the msb (representing 180 deg), leaving 31 bits */
+ ang31 = (ang << 1) >> 1;
+
+ /* fold angle to first quadrant, leaving 30 bits */
+ ang30 = ang31;
+ if (ang30 >= 0x40000000u)
+ ang30 = 0x80000000u - ang30; /* sin(180-a) = sin(a) */
+
+ index = ang30 >> (30-INDEX_BITS);
+ base = sin_table [index];
+ next = sin_table [index+1];
+ delta_ang = ang30>>(14-INDEX_BITS) & 0x0000ffffu;
+ result = ((next-base)*delta_ang >> 16) + base + HALF_WORST_ERR;
+
+ /* negate result if 180-bit was set in original angle */
+ if ((long)ang < 0)
+ result = (ULONG)(-(long)result);
+
+ return (long)result;
+
+ #undef INDEX_BITS
+ #undef N_INTERVALS
+ #undef HALF_WORST_ERR
+}
+
+
+static /* inline */ int fast_cos (UINT ang)
+{
+ return fast_sin(0x40000000u-ang);
+}
+
+
+#if 0
+
+#include <stdio.h>
+#include <math.h>
+
+void main (void)
+{
+ int i;
+ float err, max_err;
+
+ max_err = 0.0;
+
+ for (i=0; i<=16*65536; i++) {
+ err = sin ((float)i * (2.0*3.1415926535897932384626/(16*65536.0)))
+ - fast_sin(i<<12)/65536.0;
+ if (err < 0) err = -err;
+ if (err > max_err) max_err = err;
+ }
+
+ printf ("max err = %f\n", max_err);
+}
+
+#endif
+
+
+#if 0
+
+#include <stdio.h>
+#include <math.h>
+
+void main (void)
+{
+ int i;
+ float s;
+
+ for (i=0; i<=64; i++) {
+ s = sin ((float)i * (3.1415926535897932384626/(2.0*64.0)));
+ printf ("%5d, ", (int)(s*(1<<16) + 0.5));
+ if (i%8 == 7) puts("");
+ }
+}
+
+#endif
+
+
+
+typedef struct {
+ long a, b, c; /* x = at + bt^2 + ct^3 */
+ long d, e, f; /* y = dt + et^2 + ft^3 */
+} cubic_t;
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | calc_cubic_coeffs | calcs coefficients given start/end angles/velocities |
+ |___________________|________________________________________________________|
+ | |
+ | Units of angle is fraction of circle (e.g., 1.0 is 360 deg). |
+ | Format is 0.32 fixed-point (i.e., 32 bits of fraction). |
+ |____________________________________________________________________________|
+*/
+static void calc_cubic_coeffs (
+ ULONG start_ang,
+ ULONG final_ang,
+ long start_vel, /* velocities are in 16.16 fixed point */
+ long final_vel,
+ cubic_t *p)
+{
+ long start_x, start_y, final_x, final_y;
+
+ /* For both start and final below: vel = vel * 2.0 / (1.0 + cos(ang)),
+ * where vel is 16.16 before calc, and is 20.12 after the calc below.
+ */
+ start_vel = (start_vel<<11) / ((1lu<<14) + (fast_cos(start_ang)>>2));
+ final_vel = (final_vel<<11) / ((1lu<<14) + (fast_cos(final_ang)>>2));
+
+ /* Below: (vel is 20.12) * (cos>>2 is 18.14) yields a 6.26;
+ * the >>10 changes 6.26 into a 16.16.
+ */
+ start_x = start_vel*(fast_cos(start_ang)>>2) >> 10;
+ start_y = start_vel*(fast_sin(start_ang)>>2) >> 10;
+ final_x = final_vel*(fast_cos(final_ang)>>2) >> 10;
+ final_y = final_vel*(fast_sin(final_ang)>>2) >> 10;
+
+ p->a = start_x;
+ p->d = start_y;
+ p->b = (3<<16) - 2*start_x - final_x;
+ p->e = -2*start_y - final_y;
+ p->c = start_x + final_x - (2<<16);
+ p->f = start_y + final_y;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | transform_cubic | makes cubic end at (x_end,y_end) instead of (1,0) |
+ |_________________|__________________________________________________________|
+*/
+static void transform_cubic (
+ int x_end,
+ int y_end,
+ cubic_t *p)
+{
+ cubic_t q;
+
+ q.a = p->a*x_end - p->d*y_end;
+ q.b = p->b*x_end - p->e*y_end;
+ q.c = p->c*x_end - p->f*y_end;
+
+ q.d = p->a*y_end + p->d*x_end;
+ q.e = p->b*y_end + p->e*x_end;
+ q.f = p->c*y_end + p->f*x_end;
+
+ *p = q;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | calc_gamma_from_coeffs | calcs gamma table, given the coefficients |
+ |________________________|___________________________________________________|
+*/
+static void calc_gamma_from_coeffs (
+ cubic_t *p, /* in: coefficients of cubic curve */
+ BYTE tbl[]) /* out: array to receive the gamma table */
+{
+ #define LG_N_INTERVALS 7 /* 7 is the max; 8 causes overflow */
+ #define N_INTERVALS (1u<<LG_N_INTERVALS)
+ #define RND_PROD(p) (((p) + ((1<<LG_N_INTERVALS)-1)) >> LG_N_INTERVALS)
+
+ int t, x, y, xprev=0, yprev=0, xtmp, ytmp;
+
+ for (t=0; t<=N_INTERVALS; t+=1) {
+ x = (((RND_PROD((RND_PROD(p->c*t) + p->b)*t) + p->a)*t
+ >> (LG_N_INTERVALS+15)) + 1) >> 1;
+ y = (((RND_PROD((RND_PROD(p->f*t) + p->e)*t) + p->d)*t
+ >> (LG_N_INTERVALS+15)) + 1) >> 1;
+
+ if (t==0 || x!=xprev) tbl[x] = y;
+
+ if (t > 0) {
+ xtmp = xprev + 1;
+ ytmp = (yprev+y) / 2;
+ while (xtmp < x)
+ tbl[xtmp++] = ytmp;
+ }
+
+ xprev = x; yprev = y;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | calc_gamma_table | calculates gamma table using a cubic curve |
+ |__________________|_________________________________________________________|
+*/
+static void calc_gamma_table (
+ long gamma, /* in: gamma value as 24.8 (0.7 .. 3.5 is useful range) */
+ BYTE tbl[]) /* out: array to receive the gamma table */
+{
+ #define FLOAT_TO_FIX(f) ((short)((f)*0x1000 + 0.5)) /* output is 8.8 */
+ #define FLOAT_TO_ANG(f) ((USHORT)(long)((f)*0x10000/360.0 + 0.5))
+
+ #define MIN_INDEX 0 /* corresponds to gamma=0.0 */
+ #define MAX_INDEX 6 /* corresponds to gamma=3.0 */
+
+ typedef struct { /* ang_base=0.16; all others are 4.12 */
+ short start_vel_base; short start_vel_slope;
+ USHORT start_ang_base; short start_ang_slope;
+ short final_vel_base; short final_vel_slope;
+ USHORT final_ang_base; short final_ang_slope;
+ } spec_t;
+
+ static const spec_t specs[MAX_INDEX-MIN_INDEX+1] = {
+ { /* 0.0 .. 0.5 (just does a straight line) */
+ FLOAT_TO_FIX(1.0), FLOAT_TO_FIX(0.0), /* start vel */
+ FLOAT_TO_ANG(0.0), FLOAT_TO_FIX(0.0), /* start ang */
+ FLOAT_TO_FIX(1.0), FLOAT_TO_FIX(0.0), /* final vel */
+ FLOAT_TO_ANG(0.0), FLOAT_TO_FIX(0.0), /* final ang */
+ },
+ { /* 0.5 .. 1.0 (bogus below about 0.7) */
+ FLOAT_TO_FIX(0.05), FLOAT_TO_FIX(0.5), /* start vel */
+ FLOAT_TO_ANG(-75.0), FLOAT_TO_FIX(150.0/360.0), /* start ang */
+ FLOAT_TO_FIX(2.0), FLOAT_TO_FIX(0.0), /* final vel */
+ FLOAT_TO_ANG(15.0), FLOAT_TO_FIX(-30.0/360.0), /* final ang */
+ },
+ { /* 1.0 .. 1.5 */
+ FLOAT_TO_FIX(0.3), FLOAT_TO_FIX(0.2), /* start vel */
+ FLOAT_TO_ANG(0.0), FLOAT_TO_FIX(60.0/360.0), /* start ang */
+ FLOAT_TO_FIX(2.0), FLOAT_TO_FIX(0.0), /* final vel */
+ FLOAT_TO_ANG(0.0), FLOAT_TO_FIX(-20.0/360.0), /* final ang */
+ },
+ { /* 1.5 .. 2.0 */
+ FLOAT_TO_FIX(0.4), FLOAT_TO_FIX(0.2), /* start vel */
+ FLOAT_TO_ANG(30.0), FLOAT_TO_FIX(20.0/360.0), /* start ang */
+ FLOAT_TO_FIX(2.0), FLOAT_TO_FIX(0.0), /* final vel */
+ FLOAT_TO_ANG(-10.0), FLOAT_TO_FIX(-16.0/360.0), /* final ang */
+ },
+ { /* 2.0 .. 2.5 */
+ FLOAT_TO_FIX(0.5), FLOAT_TO_FIX(0.3), /* start vel */
+ FLOAT_TO_ANG(40.0), FLOAT_TO_FIX(4.0/360.0), /* start ang */
+ FLOAT_TO_FIX(2.0), FLOAT_TO_FIX(0.0), /* final vel */
+ FLOAT_TO_ANG(-18.0), FLOAT_TO_FIX(-8.0/360.0), /* final ang */
+ },
+ { /* 2.5 .. 3.0 */
+ FLOAT_TO_FIX(0.65), FLOAT_TO_FIX(0.4), /* start vel */
+ FLOAT_TO_ANG(42.0), FLOAT_TO_FIX(4.0/360.0), /* start ang */
+ FLOAT_TO_FIX(2.0), FLOAT_TO_FIX(0.0), /* final vel */
+ FLOAT_TO_ANG(-22.0), FLOAT_TO_FIX(-6.0/360.0), /* final ang */
+ },
+ { /* 3.0 .. 3.5 */
+ FLOAT_TO_FIX(0.85), FLOAT_TO_FIX(0.5), /* start vel */
+ FLOAT_TO_ANG(44.0), FLOAT_TO_FIX(1.0/360.0), /* start ang */
+ FLOAT_TO_FIX(2.0), FLOAT_TO_FIX(0.0), /* final vel */
+ FLOAT_TO_ANG(-25.0), FLOAT_TO_FIX(-4.0/360.0), /* final ang */
+ },
+ };
+
+ #define BEGIN_BLACKS 0 /* # of 0's at beginning of gamma table */
+ #define END_WHITES 4 /* # of 255's at final of gamma table */
+
+ const spec_t *p;
+ long start_vel, final_vel;
+ ULONG start_ang, final_ang;
+ cubic_t cubic;
+ int i;
+
+ i = gamma >> 7;
+ if (i > MAX_INDEX) i = MAX_INDEX;
+ p = &specs[i-MIN_INDEX];
+ gamma -= i << 7;
+
+ start_vel = ((long)p->start_vel_base << 4)
+ + (p->start_vel_slope*gamma >> 4);
+ final_vel = ((long)p->final_vel_base << 4)
+ + (p->final_vel_slope*gamma >> 4);
+ start_ang = ((long)p->start_ang_base << 16)
+ + (p->start_ang_slope*gamma << 12);
+ final_ang = ((long)p->final_ang_base << 16)
+ + (p->final_ang_slope*gamma << 12);
+
+ calc_cubic_coeffs (start_ang, final_ang, start_vel, final_vel, &cubic);
+ transform_cubic (255-BEGIN_BLACKS-END_WHITES, 254, &cubic);
+ calc_gamma_from_coeffs (&cubic, tbl);
+
+ memmove (&tbl[BEGIN_BLACKS], &tbl[0], (256-BEGIN_BLACKS)*sizeof(BYTE));
+ tbl[0] = 0;
+ for (i=0; i<BEGIN_BLACKS; i++)
+ tbl[i] = 0;
+
+ for (i=256-END_WHITES; i<=255; i++)
+ tbl[i] = 255;
+}
+
+
+
+
+/*****************************************************************************\
+ *
+ * gamma_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD gamma_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PGAM_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(GAM_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(GAM_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gamma_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD gamma_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PGAM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Insure that values we care about are correct */
+ INSURE (pTraits->iBitsPerPixel == 8);
+ INSURE (pTraits->iComponentsPerPixel == 1);
+ INSURE (pTraits->iPixelsPerRow > 0);
+
+ g->traits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gamma_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD gamma_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PGAM_INST g;
+ DWORD gamma;
+
+ HANDLE_TO_PTR (hXform, g);
+ gamma = aXformInfo[0].dword;
+ INSURE (gamma <= 0x38000u); /* 3.5 is our limit */
+
+ calc_gamma_table ((gamma+0x0080u)>>8, g->gammaTable);
+ /* todo: make calc_gamma_table accept a 16.16 gamma value */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gamma_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD gamma_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gamma_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD gamma_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD wInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PGAM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pIntraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * gamma_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD gamma_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pwMinInBufLen, /* out: min input buf size */
+ PDWORD pwMinOutBufLen) /* out: min output buf size */
+{
+ PGAM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pwMinInBufLen = *pwMinOutBufLen = g->traits.iPixelsPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gamma_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD gamma_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD wInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD wOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PGAM_INST g;
+ int nBytes;
+ PBYTE pIn, pOut, pOutAfter;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT ("gamma_convert: Told to flush.\n", 0, 0);
+ *pwInputUsed = *pwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = g->traits.iPixelsPerRow;
+ INSURE (wInputAvail >= nBytes );
+ INSURE (wOutputAvail >= nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pOutAfter = pOut + nBytes;
+
+ while (pOut < pOutAfter) {
+ pOut[0] = g->gammaTable[pIn[0]];
+ pOut[1] = g->gammaTable[pIn[1]];
+ pOut[2] = g->gammaTable[pIn[2]];
+ pOut[3] = g->gammaTable[pIn[3]];
+ pOut[4] = g->gammaTable[pIn[4]];
+ pOut[5] = g->gammaTable[pIn[5]];
+ pOut[6] = g->gammaTable[pIn[6]];
+ pOut[7] = g->gammaTable[pIn[7]];
+
+ pIn += 8;
+ pOut += 8;
+ }
+
+ *pwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->wRowsDone += 1;
+
+ PRINT ("gamma_convert: Returning, out used = %d\n", out_used, 0);
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gamma_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD gamma_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD wNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gamma_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD gamma_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PGAM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gamma_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD gamma_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PGAM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gammaTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL gammaTbl = {
+ gamma_openXform,
+ gamma_setDefaultInputTraits,
+ gamma_setXformSpec,
+ gamma_getHeaderBufSize,
+ gamma_getActualTraits,
+ gamma_getActualBufSizes,
+ gamma_convert,
+ gamma_newPage,
+ gamma_insertedData,
+ gamma_closeXform
+};
+
+/* End of File */
diff --git a/ip/xgray2bi.c b/ip/xgray2bi.c
new file mode 100644
index 0000000..1946e1b
--- /dev/null
+++ b/ip/xgray2bi.c
@@ -0,0 +1,614 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xgray2bi.c - Error-diffuser and thresholder that's designed to be fast
+ *
+ ******************************************************************************
+ *
+ * Jan 1998 Mark Overton -- ported code into an xform driver
+ * June 1995 Mark Overton -- developed and benchmarked algorithm
+ *
+ * Name of Global Jump-Table:
+ *
+ * gray2biTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_GRAY_2_BI_THRESHOLD] = Threshold.
+ * If threshold is zero, error-diffusion is done.
+ * If non-zero, it is the black/white threshold:
+ * A gray pixel >= to threshold becomes white, else black.
+ *
+ * Capabilities and Limitations:
+ *
+ * Inputs rows of 8-bit gray pixels, and outputs rows of bi-level pixels.
+ * The formats are the standard raw formats described in hpojip.h.
+ * The error-diffusion weights are perturbed by small internally-generated
+ * amounts to break up any pixel patterns that would otherwise occur.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * must be 8 1
+ * iComponentsPerPixel * must be 1 1
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Error-diffusion timings (seconds for one page):
+ *
+ * 386-33 486-33 486-66 P-90 735 image dim task
+ * ------ ------ ------ ---- ----- --------- ---------------------------------
+ * 21.6 9.0 4.4 2.3 1.4 1728x2200 200x200 fax in photo mode
+ * 43. 17.9 8.9 4.6 2.9 2400x3150 300x300 local copy, 1/4" margins
+ * 86. 36. 17.9 9.3 5.7 4800x3150 600x300 local copy, 1/4" margins
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x1ce5ca7e
+
+
+typedef struct {
+ IP_IMAGE_TRAITS inTraits; /* traits of the input image */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ BYTE bThreshold; /* white/black threshold; 0 -> diffuse */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+ short *pErrBuf; /* error-term buffer */
+} G2B_INST, *PG2B_INST;
+
+
+
+/****************************************************************************\
+ *
+ * thresholdRow - work-horse thresholding routine
+ *
+\****************************************************************************/
+
+static void thresholdRow (
+ int iPixelsPerRow, /* in: # of pixels in the row */
+ BYTE bThreshold, /* in: white/black threshold value */
+ BYTE baInBuf [], /* in: input pixels (0=black, 255=white) */
+ BYTE baOutBuf []) /* out: output pixels (0=white, 1=black, 8 per byte) */
+{
+ int iMore;
+ PBYTE pbIn, pbOut;
+ BYTE bOut, bMask;
+
+ pbIn = baInBuf;
+ pbOut = baOutBuf;
+
+ for (iMore=iPixelsPerRow; iMore>0; iMore-=8)
+ {
+ bOut = 0;
+
+ for (bMask=0x80u; bMask!=0; bMask>>=1)
+ {
+ if (*pbIn++ < bThreshold)
+ bOut |= bMask;
+ }
+
+ *pbOut++ = bOut;
+ }
+}
+
+
+
+/****************************************************************************\
+ *
+ * diffuseRow - work-horse error-diffusion routine
+ *
+\****************************************************************************/
+
+static void diffuseRow (
+ int iPixelsPerRow, /* in: # of pixels in the row */
+ short iaErrBuf [], /* in/out: error-term buffer from prior call */
+ BYTE baInBuf [], /* in: input pixels (0=black, 255=white) */
+ BYTE baOutBuf []) /* out: output pixels (0=white, 1=black, 8 per byte) */
+{
+ int rr, r, cur;
+ int br, b, bl, bll;
+ int err;
+ int weight4, weight2, weight1;
+ short *eptr;
+ int noise;
+ BYTE *inptr, *inafter;
+ BYTE *outptr;
+ BYTE outvalue;
+ int mask;
+ BOOL second; /* computing 2nd nibble in byte? */
+
+ /* The diffusion algorithm below uses the following 6 weights:
+ *
+ * X 4 2
+ * 1 3 4 2
+ *
+ * These weights add to 16, so there are shifts by 4 in the code.
+ * weight4 is the 4 above. Likewise with weight2 and weight1.
+ * eptr is positioned at the 1 above.
+ * The macro reads the error at the top 4 above, and writes it at the 1.
+ * bll is positioned at the 1 above. bleft at the 3. below at the low 4.
+ * The noise perturbations add to zero, so no net noise is injected.
+ */
+#if 0
+ #define DIFFUSE(par_outmask) { \
+ mask = cur >> (8*sizeof(cur)-1); /* signed shift */ \
+ outvalue |= par_outmask & mask; \
+ weight4 = (cur - (~mask&0x0ff0)) >> 2; \
+ \
+ noise = (cur & (0x7f<<1)) - 0x7f; \
+ cur = ((unsigned)(*inptr++) << 4) \
+ + eptr[3] + weight2 + weight4 + noise ; \
+ weight2 = (weight4>>1); \
+ weight1 = (weight2>>1); \
+ *eptr++ = bll + weight1 - noise ; \
+ bll = bleft + weight2 + weight1 /* + noise */ ; \
+ bleft = below + weight4 - noise ; \
+ below = weight2 + noise ; \
+ }
+
+ cur = iaErrBuf[2] + ((unsigned)(*inptr++) << 4);
+ bll = 0;
+ bleft = 0;
+ below = 0;
+ weight2 = 0;
+
+#endif
+
+ #define DIFFUSE(par_outmask) { \
+ /* decide if output pixel is black or white */ \
+ mask = (cur-0x800) >> (8*sizeof(cur)-1); /* all 0's or all 1's */ \
+ outvalue |= par_outmask & mask; \
+ \
+ /* compute error, and weights of 4/16, 2/16 and 1/16 */ \
+ err = cur - (~mask&0x0ff0); \
+ /* multiply error by 15/16 so it won't propagate a long distance */ \
+ err = err - (err>>4); \
+ weight4 = err >> 2; \
+ weight2 = weight4 >> 1; \
+ weight1 = weight2 >> 1; \
+ \
+ /* distribute error to neighboring pixels */ \
+ noise = err & 0x00ff; \
+ rr += weight2; \
+ r += weight4 + noise; \
+ br = weight2 + noise; \
+ b += weight4 - noise; \
+ bl += weight2 + weight1; /* the 3 weight */ \
+ bll += weight1 - noise; \
+ \
+ /* advance right one pixel, so move values left one pixel */ \
+ cur = r; \
+ r = rr; \
+ rr = ((unsigned)(*inptr++) << 4) + eptr[2]; \
+ eptr[-2] = bll; \
+ bll = bl; \
+ bl = b; \
+ b = br; \
+ eptr += 1; \
+ }
+
+ inptr = baInBuf;
+ inafter = baInBuf + iPixelsPerRow;
+ outptr = baOutBuf;
+ eptr = iaErrBuf + 2;
+ outvalue = 0;
+ second = FALSE;
+
+ cur = ((unsigned)inptr[0] << 4) + eptr[0];
+ r = ((unsigned)inptr[1] << 4) + eptr[1];
+ rr = ((unsigned)inptr[2] << 4) + eptr[2];
+ inptr += 3;
+ bll = bl = b = br = 0;
+
+ while (inptr < inafter) {
+ DIFFUSE (0x08);
+ DIFFUSE (0x04);
+ DIFFUSE (0x02);
+ DIFFUSE (0x01);
+
+ if (! second) {
+ /* we just computed the left half of the byte */
+ outvalue <<= 4;
+ second = TRUE;
+ } else {
+ /* we just computed the right half of the byte, so store it */
+ *outptr++ = outvalue;
+ outvalue = 0;
+ second = FALSE;
+ }
+ } /* end of for */
+
+ if (second)
+ *outptr = outvalue; /* store final nibble */
+
+ eptr[-2] = bll;
+ eptr[-1] = bl;
+ eptr[ 0] = b;
+
+ #undef DIFFUSE
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gray2bi_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD gray2bi_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PG2B_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(G2B_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(G2B_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gray2bi_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD gray2bi_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PG2B_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Insure that values we care about are correct */
+ INSURE (pTraits->iBitsPerPixel == 8);
+ INSURE (pTraits->iComponentsPerPixel == 1);
+ INSURE (pTraits->iPixelsPerRow > 0);
+
+ g->inTraits = *pTraits; /* a structure copy */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gray2bi_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD gray2bi_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PG2B_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ INSURE ((DWORD)aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword <= 255);
+ g->bThreshold = (BYTE)aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gray2bi_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD gray2bi_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gray2bi_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD gray2bi_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PG2B_INST g;
+ int nBytes;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pInTraits = g->inTraits;
+ *pOutTraits = g->inTraits;
+ pOutTraits->iBitsPerPixel = 1; /* this xform only changes bits/pixel */
+
+ if (g->bThreshold == 0) {
+ nBytes = sizeof(short) * g->inTraits.iPixelsPerRow;
+ IP_MEM_ALLOC (nBytes, g->pErrBuf);
+ memset (g->pErrBuf, 0, nBytes);
+ }
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * gray2bi_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD gray2bi_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PG2B_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = g->inTraits.iPixelsPerRow;
+ *pdwMinOutBufLen = (g->inTraits.iPixelsPerRow + 7) / 8;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gray2bi_convert - error-diffuses one row
+ *
+\*****************************************************************************/
+
+static WORD gray2bi_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PG2B_INST g;
+ int inBytes, outBytes;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("gray2bi_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Convert and Output a Row ****/
+
+ inBytes = g->inTraits.iPixelsPerRow;
+ outBytes = (inBytes + 7) / 8;
+ INSURE (dwInputAvail >= (DWORD)inBytes );
+ INSURE (dwOutputAvail >= (DWORD)outBytes);
+
+ if (g->bThreshold == 0) {
+ INSURE (g->pErrBuf != NULL);
+ diffuseRow (inBytes, g->pErrBuf, pbInputBuf, pbOutputBuf);
+ } else
+ thresholdRow (inBytes, g->bThreshold, pbInputBuf, pbOutputBuf);
+
+ *pdwInputUsed = inBytes;
+ g->dwInNextPos += inBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = outBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += outBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gray2bi_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD gray2bi_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gray2bi_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD gray2bi_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PG2B_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gray2bi_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD gray2bi_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PG2B_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ if (g->pErrBuf != NULL)
+ IP_MEM_FREE (g->pErrBuf);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * gray2biTbl - Jump-table for encoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL gray2biTbl = {
+ gray2bi_openXform,
+ gray2bi_setDefaultInputTraits,
+ gray2bi_setXformSpec,
+ gray2bi_getHeaderBufSize,
+ gray2bi_getActualTraits,
+ gray2bi_getActualBufSizes,
+ gray2bi_convert,
+ gray2bi_newPage,
+ gray2bi_insertedData,
+ gray2bi_closeXform
+};
+
+/* End of File */
diff --git a/ip/xgrayout.c b/ip/xgrayout.c
new file mode 100644
index 0000000..aa379a6
--- /dev/null
+++ b/ip/xgrayout.c
@@ -0,0 +1,495 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xgrayOut.c - Grays out everything outside the given rectangle.
+ *
+ * "Graying out" means changing pixels toward a middle gray value. Everything
+ * outside the given rectangle is grayed-out by this xform. This is useful for
+ * displaying a selected-area in an image (the rectangle).
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * grayOutTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_GRAYOUT_LEFT ] = left
+ * aXformInfo[IP_GRAYOUT_RIGHT ] = right
+ * aXformInfo[IP_GRAYOUT_TOP ] = top
+ * aXformInfo[IP_GRAYOUT_BOTTOM] = bottom
+ *
+ * The four numbers above give the locations of the sides of the rectangle
+ * which is *not* to be grayed-out. Everything outside these boundaries
+ * will be grayed-out. If these coordinates are outside the image, this
+ * xform will behave sensibly.
+ *
+ * Capabilities and Limitations:
+ *
+ * 24-bit, 3-component data only.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * Describe what you do with the default input traits, and how the
+ * output traits are determined.
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * must be 24 24
+ * iComponentsPerPixel * must be 3 3
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+
+#define TARGET_GRAY 0xB0 /* grayed pixels are pushed toward this gray-level */
+
+// Use the #define below if this transform will exist in a dll outside of the
+// image pipeline. This will allow the functions to be exported.
+// #define EXPORT_TRANFORM 1
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+#ifdef EXPORT_TRANSFORM
+#define FUNC_STATUS __declspec (dllexport)
+#else
+#define FUNC_STATUS static
+#endif
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input and output image */
+ DWORD dwBytesPerRow; /* # of bytes in each row */
+ int iLeft, iRight; /* the rectangle to not gray-out */
+ int iTop, iBottom;
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} GRAYOUT_INST, *PGRAYOUT_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * grayOut_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD grayOut_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PGRAYOUT_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(GRAYOUT_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(GRAYOUT_INST));
+ g->dwValidChk = CHECK_VALUE;
+ g->iRight = 1000000;
+ g->iBottom = 1000000;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * grayOut_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD grayOut_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PGRAYOUT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow > 0 &&
+ pTraits->iBitsPerPixel == 24 &&
+ pTraits->iComponentsPerPixel == 3);
+ g->traits = *pTraits; /* a structure copy */
+ g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * grayOut_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD grayOut_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PGRAYOUT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->iLeft = aXformInfo[IP_GRAYOUT_LEFT ].dword;
+ g->iRight = aXformInfo[IP_GRAYOUT_RIGHT ].dword;
+ g->iTop = aXformInfo[IP_GRAYOUT_TOP ].dword;
+ g->iBottom = aXformInfo[IP_GRAYOUT_BOTTOM].dword;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * grayOut_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD grayOut_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * grayOut_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD grayOut_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PGRAYOUT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pIntraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * grayOut_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+FUNC_STATUS WORD grayOut_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PGRAYOUT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * grayOut_convert - Converts one row
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD grayOut_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PGRAYOUT_INST g;
+ int nBytes;
+ PBYTE pIn, pInAfter, pOut, pLeft, pRight;
+
+ #define GRAYOUT_PIXEL \
+ *pOut++ = (BYTE)(((int)(*pIn++)+TARGET_GRAY) >> 1); /* R */ \
+ *pOut++ = (BYTE)(((int)(*pIn++)+TARGET_GRAY) >> 1); /* G */ \
+ *pOut++ = (BYTE)(((int)(*pIn++)+TARGET_GRAY) >> 1); /* B */
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("grayOut_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = g->dwBytesPerRow;
+ INSURE (dwInputAvail >= (DWORD)nBytes );
+ INSURE (dwOutputAvail >= (DWORD)nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pInAfter = pIn + nBytes;
+
+ if ((int)g->dwRowsDone<g->iTop || (int)g->dwRowsDone>g->iBottom) {
+ /* Gray-out the entire row */
+ while (pIn < pInAfter) {
+ GRAYOUT_PIXEL
+ }
+ } else {
+ /* Gray-out portion of row between iLeft and iRight */
+ pLeft = pIn + 3*g->iLeft;
+ pRight = pIn + 3*g->iRight;
+
+ if (pLeft >= pInAfter)
+ pLeft = pInAfter - 3; /* clamp to rightmost pixel */
+ if (pRight >= pInAfter)
+ pRight = pInAfter - 3; /* clamp to rightmost pixel */
+
+ while (pIn < pLeft) { /* gray-out left portion */
+ GRAYOUT_PIXEL
+ }
+ while (pIn <= pRight) { /* copy portion within rect */
+ *pOut++ = *pIn++;
+ *pOut++ = *pIn++;
+ *pOut++ = *pIn++;
+ }
+ while (pIn < pInAfter) { /* gray-out right portion */
+ GRAYOUT_PIXEL
+ }
+ }
+
+ *pdwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * grayOut_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD grayOut_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * grayOut_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD grayOut_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PGRAYOUT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * grayOut_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD grayOut_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PGRAYOUT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * grayOutTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+#ifdef EXPORT_TRANSFORM
+__declspec (dllexport)
+#endif
+IP_XFORM_TBL grayOutTbl = {
+ grayOut_openXform,
+ grayOut_setDefaultInputTraits,
+ grayOut_setXformSpec,
+ grayOut_getHeaderBufSize,
+ grayOut_getActualTraits,
+ grayOut_getActualBufSizes,
+ grayOut_convert,
+ grayOut_newPage,
+ grayOut_insertedData,
+ grayOut_closeXform
+};
+
+/* End of File */
+
+
+/*****************************************************************************\
+ *
+ * ipGetXformTable - Returns pointer to the jump table
+ *
+\*****************************************************************************/
+
+#ifdef EXPORT_TRANSFORM
+EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL pXform)
+{
+ WORD wRet = IP_DONE;
+
+ if (pXform)
+ *pXform = clrmapTbl;
+ else
+ wRet = IP_FATAL_ERROR;
+
+ return wRet;
+}
+#endif
diff --git a/ip/xinvert.c b/ip/xinvert.c
new file mode 100644
index 0000000..a187fa9
--- /dev/null
+++ b/ip/xinvert.c
@@ -0,0 +1,459 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: David Paschal (based on Mark Overton's "xskel" template). */
+
+/******************************************************************************\
+ *
+ * xinvert.c - Inverts bilevel, grayscale, or color data.
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * invertTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * None.
+ *
+ * Capabilities and Limitations:
+ *
+ * For 1-3 bpp, does a NOT operation (complements the bits).
+ * For >3 bpp, does a NEG operation (NEG plus 1).
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * Describe what you do with the default input traits, and how the
+ * output traits are determined.
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel * passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+// Use the #define below if this transform will exist in a dll outside of the
+// image pipeline. This will allow the functions to be exported.
+// #define EXPORT_TRANFORM 1
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+#ifdef EXPORT_TRANSFORM
+#define FUNC_STATUS __declspec (dllexport)
+#else
+#define FUNC_STATUS static
+#endif
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input and output image */
+ DWORD dwBytesPerRow; /* # of bytes in each row */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwAddToNot; /* 0=NOT, 1=NEG operation. */
+ DWORD dwValidChk; /* struct validity check value */
+} INVERT_INST, *PINVERT_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * invert_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD invert_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PINVERT_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(INVERT_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(INVERT_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * invert_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD invert_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PINVERT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
+ g->traits = *pTraits; /* a structure copy */
+ g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ if (pTraits->iBitsPerPixel>3) {
+ g->dwAddToNot=1;
+ } else {
+ g->dwAddToNot=0;
+ }
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * invert_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD invert_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PINVERT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Check your options in aXformInfo here, and save them.
+ * Use the INSURE macro like you'd use assert. INSURE jumps to
+ * fatal_error below if it fails.
+ */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * invert_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD invert_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * invert_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD invert_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PINVERT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+ g->dwInNextPos = 0;
+
+ *pInTraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * invert_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+FUNC_STATUS WORD invert_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PINVERT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * invert_convert - Converts one row
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD invert_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PINVERT_INST g;
+ int nBytes,i;
+ PBYTE pIn, pOut;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("invert_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = g->dwBytesPerRow;
+ INSURE (dwInputAvail >= (DWORD)nBytes );
+ INSURE (dwOutputAvail >= (DWORD)nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+
+ /* At this point, pIn is your input buffer, and pOut is your output buffer.
+ * Do whatever you are going to do here.
+ */
+ for (i=0;i<nBytes;i++) {
+ pOut[i]=~pIn[i]+g->dwAddToNot;
+ }
+
+ *pdwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * invert_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD invert_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * invert_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD invert_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PINVERT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * invert_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD invert_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PINVERT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * invertTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+#ifdef EXPORT_TRANSFORM
+__declspec (dllexport)
+#endif
+IP_XFORM_TBL invertTbl = {
+ invert_openXform,
+ invert_setDefaultInputTraits,
+ invert_setXformSpec,
+ invert_getHeaderBufSize,
+ invert_getActualTraits,
+ invert_getActualBufSizes,
+ invert_convert,
+ invert_newPage,
+ invert_insertedData,
+ invert_closeXform
+};
+
+/* End of File */
+
+
+/*****************************************************************************\
+ *
+ * ipGetXformTable - Returns pointer to the jump table
+ *
+\*****************************************************************************/
+
+#ifdef EXPORT_TRANSFORM
+EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL pXform)
+{
+ WORD wRet = IP_DONE;
+
+ if (pXform)
+ {
+ *pXform = clrmapTbl;
+ }
+ else
+ {
+ wRet = IP_FATAL_ERROR;
+ }
+
+ return wRet;
+}
+#endif
diff --git a/ip/xjpg_dct.c b/ip/xjpg_dct.c
new file mode 100644
index 0000000..b20e17e
--- /dev/null
+++ b/ip/xjpg_dct.c
@@ -0,0 +1,393 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*____________________________________________________________________________
+ | | |
+ | xjpg_dct.c | Computes forward and inverse DCT for JPEG |
+ |____________|_______________________________________________________________|
+ | |
+ | Mark Overton, May 1997 |
+ |____________________________________________________________________________|
+*/
+
+#include "xjpg_dct.h"
+
+
+/*____________________________________________________________________________
+ | | |
+ | SUB_AND_ADD | replaces a with a-b, and b with a+b using no temp registers |
+ |_____________|______________________________________________________________|
+*/
+#define SUB_AND_ADD(a,b) { \
+ b += a; \
+ a += a; \
+ a -= b; \
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | MUL_ROUND | computes x = round(x*c), using no temp registers |
+ |___________|________________________________________________________________|
+ | |
+ | c is assumed to have CONST_FRAC_BITS bits of fraction. |
+ |____________________________________________________________________________|
+*/
+#if (defined _WINDOWS) && !(defined _WIN32)
+
+ /* We are compiling for 16-bit Windows 3.1 */
+
+ #define MUL_ROUND(c,x) { \
+ long product; \
+ product = (long)(x) * ((long)(c) << (16-CONST_FRAC_BITS)); \
+ x = (product+0x8000L) >> 16; \
+ }
+
+#else
+
+ #define MUL_ROUND(c,x) { \
+ x = (short)(x) * (short)(c); \
+ x = ((x)+(1l<<(CONST_FRAC_BITS-1))) >> CONST_FRAC_BITS; \
+ }
+
+#endif
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | dct_forward | computes DCT for JPEG |
+ |_____________|______________________________________________________________|
+ | |
+ | This is the DCT algorithm based on the small FFT Winograd transform |
+ | from Trans. IEICE, vol. E 71(11), 1095-1097, Nov. 1988 |
+ | |
+ | Input: 'block' is 64 level-shifted pixels (-128..127 each). |
+ | |
+ | Output: 'block' is the DCT (64 words). |
+ | These values need to be scaled by the forward correction matrix |
+ | for the Winograd DCT. |
+ |____________________________________________________________________________|
+*/
+void dct_forward (register int *block_p)
+{
+ #define CONST_FRAC_BITS 14 /* bits of frac in CONST_1-CONST_5 below */
+
+ #define CONST_1 (23170/2) /* 15 bits of frac shifted down to 14 */
+ #define CONST_2 (17734/2)
+ #define CONST_3 (23170/2)
+ #define CONST_4 (42813/2) /* this one wouldn't fit with 15 bits of frac */
+ #define CONST_5 (12540/2)
+
+ int *data_p;
+ int d0, d1, d2, d3, d4, d5, d6, d7;
+
+ /******************/
+ /* Transform Rows */
+ /******************/
+
+ for (data_p=block_p; data_p<block_p+64; data_p+=8)
+ {
+ d0 = data_p[0];
+ d1 = data_p[1];
+ d2 = data_p[2];
+ d3 = data_p[3];
+ d4 = data_p[4];
+ d5 = data_p[5];
+ d6 = data_p[6];
+ d7 = data_p[7];
+
+ SUB_AND_ADD (d0, d7)
+ SUB_AND_ADD (d1, d6)
+ SUB_AND_ADD (d2, d5)
+ SUB_AND_ADD (d4, d3)
+
+ SUB_AND_ADD (d7, d3)
+ SUB_AND_ADD (d6, d5)
+
+ SUB_AND_ADD (d3, d5)
+ data_p[4] = d3;
+ data_p[0] = d5;
+
+ d6 += d7;
+ MUL_ROUND (CONST_1, d6)
+ SUB_AND_ADD (d7, d6)
+ data_p[6] = d7;
+ data_p[2] = d6;
+
+ /* At this point, the only live math vars are in: d0, d1, d2, d4 */
+
+ d7 = d1 + d2;
+ MUL_ROUND (CONST_3, d7)
+ d1 += d0;
+ SUB_AND_ADD (d0, d7)
+ d4 -= d2;
+ d6 = d1 + d4;
+ MUL_ROUND (CONST_5, d6)
+ MUL_ROUND (CONST_4, d1)
+ d1 -= d6;
+
+ SUB_AND_ADD (d7, d1)
+ data_p[7] = d7;
+ data_p[1] = d1;
+
+ MUL_ROUND (CONST_2, d4)
+ d4 += d6;
+ SUB_AND_ADD (d0, d4)
+ data_p[5] = d0;
+ data_p[3] = d4;
+ }
+
+ /*********************/
+ /* Transform Columns */
+ /*********************/
+
+ for (data_p=block_p; data_p<block_p+8; data_p++)
+ {
+ d0 = data_p[0*8];
+ d7 = data_p[7*8];
+ SUB_AND_ADD (d0, d7)
+
+ d4 = data_p[4*8];
+ d3 = data_p[3*8];
+ SUB_AND_ADD (d4, d3)
+
+ d1 = data_p[1*8];
+ d6 = data_p[6*8];
+ SUB_AND_ADD (d1, d6)
+
+ d2 = data_p[2*8];
+ d5 = data_p[5*8];
+ SUB_AND_ADD (d2, d5)
+
+ SUB_AND_ADD (d7, d3)
+ SUB_AND_ADD (d6, d5)
+
+ SUB_AND_ADD (d3, d5)
+ data_p[4*8] = d3;
+ data_p[0*8] = d5;
+
+ d6 += d7;
+ MUL_ROUND (CONST_1, d6)
+ SUB_AND_ADD (d7, d6)
+ data_p[6*8] = d7;
+ data_p[2*8] = d6;
+
+ /* At this point, the only live math vars are in: d0, d1, d2, d4 */
+
+ d7 = d1 + d2;
+ MUL_ROUND (CONST_3, d7)
+ d1 += d0;
+ SUB_AND_ADD (d0, d7)
+ d4 -= d2;
+ d6 = d1 + d4;
+ MUL_ROUND (CONST_5, d6)
+ MUL_ROUND (CONST_4, d1)
+ d1 -= d6;
+
+ SUB_AND_ADD (d7, d1)
+ data_p[7*8] = d7;
+ data_p[1*8] = d1;
+
+ MUL_ROUND (CONST_2, d4)
+ d4 += d6;
+ SUB_AND_ADD (d0, d4)
+ data_p[5*8] = d0;
+ data_p[3*8] = d4;
+ }
+
+ #undef CONST_FRAC_BITS
+ #undef CONST_1
+ #undef CONST_2
+ #undef CONST_3
+ #undef CONST_4
+ #undef CONST_5
+} /* end of dct_forward */
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | dct_inverse | computes inverse DCT for JPEG |
+ |_____________|______________________________________________________________|
+ | |
+ | This is the DCT algorithm based on the small FFT Winograd transform |
+ | from Trans. IEICE, vol. E 71(11), 1095-1097, Nov. 1988 |
+ | |
+ | Input: 'block' is the DCT (64 words). |
+ | These values are assumed to have been scaled by the inverse |
+ | correction matrix for the Winograd DCT. |
+ | |
+ | Output: 'block' is 64 level-shifted pixels. These values will have |
+ | as many bits of fraction as the input DCT had. After rounding |
+ | and level-shifting, you must clamp these values to 0..255. |
+ |____________________________________________________________________________|
+*/
+void dct_inverse (register int *block_p)
+{
+ #define CONST_FRAC_BITS 13 /* bits of frac in CONST_1-CONST_5 below */
+
+ #define CONST_1 ((46341+2)/4) /* 15 bits of frac shifted down to 13 */
+ #define CONST_2 ((85627+2)/4)
+ #define CONST_3 ((46341+2)/4)
+ #define CONST_4 ((35468+2)/4)
+ #define CONST_5 ((25080+2)/4)
+
+ int *data_p;
+ int d0, d1, d2, d3, d4, d5, d6, d7, tmp;
+
+ /*********************/
+ /* Transform Columns */
+ /*********************/
+
+ for (data_p=block_p; data_p<block_p+8; data_p++)
+ {
+ d0 = data_p[0*8];
+ d4 = data_p[4*8];
+ SUB_AND_ADD (d0, d4)
+
+ d1 = data_p[1*8];
+ d7 = data_p[7*8];
+ SUB_AND_ADD (d1, d7)
+
+ d2 = data_p[2*8];
+ d6 = data_p[6*8];
+ SUB_AND_ADD (d2, d6)
+
+ d5 = data_p[5*8];
+ d3 = data_p[3*8];
+ SUB_AND_ADD (d5, d3)
+
+ MUL_ROUND (CONST_1, d2)
+ d2 -= d6;
+ SUB_AND_ADD (d0, d2)
+ SUB_AND_ADD (d4, d6)
+ SUB_AND_ADD (d7, d3)
+
+ tmp = d3;
+ SUB_AND_ADD (d6, d3)
+ data_p[7*8] = d6;
+ data_p[0*8] = d3;
+
+ d6 = d5 - d1;
+ MUL_ROUND (CONST_5, d6);
+ MUL_ROUND (CONST_4, d1)
+ d1 -= d6;
+ d1 -= tmp;
+ MUL_ROUND (CONST_3, d7)
+ d7 -= d1;
+ MUL_ROUND (CONST_2, d5)
+ d6 -= d5;
+ d6 += d7;
+
+ SUB_AND_ADD (d2, d1)
+ data_p[6*8] = d2;
+ data_p[1*8] = d1;
+
+ SUB_AND_ADD (d0, d7)
+ data_p[5*8] = d0;
+ data_p[2*8] = d7;
+
+ SUB_AND_ADD (d4, d6)
+ data_p[3*8] = d4;
+ data_p[4*8] = d6;
+ }
+
+ /******************/
+ /* Transform Rows */
+ /******************/
+
+ for (data_p=block_p; data_p<block_p+64; data_p+=8)
+ {
+ d0 = data_p[0];
+ d1 = data_p[1];
+ d2 = data_p[2];
+ d3 = data_p[3];
+ d4 = data_p[4];
+ d5 = data_p[5];
+ d6 = data_p[6];
+ d7 = data_p[7];
+
+ SUB_AND_ADD (d0, d4)
+ SUB_AND_ADD (d1, d7)
+ SUB_AND_ADD (d2, d6)
+ SUB_AND_ADD (d5, d3)
+
+ MUL_ROUND (CONST_1, d2)
+ d2 -= d6;
+ SUB_AND_ADD (d0, d2)
+ SUB_AND_ADD (d4, d6)
+ SUB_AND_ADD (d7, d3)
+
+ tmp = d3;
+ SUB_AND_ADD (d6, d3)
+ data_p[7] = d6;
+ data_p[0] = d3;
+
+ d6 = d5 - d1;
+ MUL_ROUND (CONST_5, d6)
+ MUL_ROUND (CONST_4, d1)
+ d1 -= d6;
+ d1 -= tmp;
+ MUL_ROUND (CONST_3, d7)
+ d7 -= d1;
+ MUL_ROUND (CONST_2, d5)
+ d6 -= d5;
+ d6 += d7;
+
+ SUB_AND_ADD (d2, d1)
+ data_p[6] = d2;
+ data_p[1] = d1;
+
+ SUB_AND_ADD (d0, d7)
+ data_p[5] = d0;
+ data_p[2] = d7;
+
+ SUB_AND_ADD (d4, d6)
+ data_p[3] = d4;
+ data_p[4] = d6;
+ }
+
+ #undef CONST_FRAC_BITS
+ #undef CONST_1
+ #undef CONST_2
+ #undef CONST_3
+ #undef CONST_4
+ #undef CONST_5
+} /* end of dct_inverse */
+
+/* End of File */
diff --git a/ip/xjpg_dct.h b/ip/xjpg_dct.h
new file mode 100644
index 0000000..15fedb8
--- /dev/null
+++ b/ip/xjpg_dct.h
@@ -0,0 +1,50 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*____________________________________________________________________________
+ | | |
+ | xjpg_dct.h | Computes forward and inverse DCT for JPEG |
+ |____________|_______________________________________________________________|
+ | |
+ | Mark Overton, May 1997 |
+ |____________________________________________________________________________|
+*/
+
+void dct_forward (register int *block_p);
+
+void dct_inverse (register int *block_p);
+
+/* End of File */
diff --git a/ip/xjpg_dec.c b/ip/xjpg_dec.c
new file mode 100644
index 0000000..507e11a
--- /dev/null
+++ b/ip/xjpg_dec.c
@@ -0,0 +1,2838 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*****************************************************************************\
+ *
+ * xjpg_dec.c - Decodes a JPEG file into a raw gray image
+ *
+ *****************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * jpgDecodeTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_JPG_DECODE_OUTPUT_SUBSAMPLED]:
+ * Output only subsampled raw data? 0=no, 1=yes.
+ * aXformInfo[IP_JPG_DECODE_FROM_DENALI]:
+ * Data came from a Denali? 0=no, 1=yes.
+ *
+ * The aXformInfo items above may all be set to 0 for typical JPEG files.
+ *
+ * For Denali, we assume the following:
+ * - Every 8x8 block ends with an EOB
+ * - A slight change in the Huffman tables (no 15-bit code)
+ * - Denali sends us a proprietary short header (APP1 marker)
+ *
+ * Capabilities and Limitations:
+ *
+ * Decodes a standard JPEG file. Also handles JFIF 1.0 (APP0 marker).
+ * Also handles the non-standard short header output by OfficeJet firmware
+ * (APP1 marker). Also handles APP1 markers defined by color fax standard.
+ * Will *not* decode a non-interleaved file; it must be interleaved.
+ * Handles 1-4 components per pixel, and 4 Huffman tables, so SOF1 with
+ * 8 bits/component is okay.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * For decoder:
+ *
+ * trait default input output
+ * ------------------- ------------------- ------------------------
+ * iPixelsPerRow ignored based on header
+ * iBitsPerPixel ignored based on header
+ * iComponentsPerPixel ignored based on header
+ * lHorizDPI ignored based on header
+ * lVertDPI ignored based on header
+ * lNumRows ignored based on header
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Kludges:
+ *
+ * Chromafax and other software inserts fill 0's instead of fill 1's
+ * before a marker, such as the all-important EOI marker. So when
+ * we get a syntax error when parsing those 0's, we do not report
+ * an error if there's a following marker, but simply proceed to
+ * process the marker as usual.
+ *
+ * Chromafax uses an SOF1 instead of the correct SOF0, so we allow
+ * that, and also handle four Huffman tables that SOF1 requires.
+ *
+ * Jan 1998 Mark Overton -- Ported to new software Image Processor
+ * Apr 1996 Mark Overton -- Finished software-only JPEG decoder
+ * Feb 1996 Mark Overton -- initial code
+ *
+\*****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "setjmp.h"
+#include "xjpg_dct.h"
+#include "xjpg_mrk.h"
+
+
+#define DUMP_JPEG 0
+
+#if DUMP_JPEG
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define DUMP(msg,arg1,arg2,arg3) \
+ _ftprintf(stdout, msg, (int)(arg1), (int)(arg2), (int)(arg3))
+#else
+ #define DUMP(msg,arg1,arg2,arg3)
+#endif
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stdout, _T("(jpeg) ") msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+
+/*____________________________________________________________________________
+ | |
+ | Constants |
+ |____________________________________________________________________________|
+*/
+
+#define MAX_HUFF_TBLS 4
+
+#define UNEXPECTED_MARKER 1
+#define BAD_MARKER_ID 2
+#define BAD_MARKER_DATA 3
+#define NO_RESTART_MARKER 4
+#define BAD_HUFF_CODE 5
+#define UNEXPECTED_END_OF_DATA 6
+#define NOT_IMPLEMENTED 7
+
+#define MAX_MARKER_LEN 15000 /* large in case marker holds a thumbnail */
+#define MAX_HEADER_SIZE (MAX_MARKER_LEN+2000)
+#define MAX_BLOCKS_IN_MCU 6
+#define MAX_MCU_SIZE (MAX_BLOCKS_IN_MCU*304)
+ /* max encoded MCU size, plus stuff-bytes */
+#define INBUF_NUM_MCUS 2 /* workbuf will be this multiple of max MCU */
+
+#define DC_TBL_INDEX_LEN 9
+#define AC_TBL_INDEX_LEN 12
+
+#define CHECK_VALUE 0x1ce5ca7e
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Instance Variables |
+ |____________________________________________________________________________|
+*/
+
+typedef struct {
+ BYTE size; /* number of bits in the Huff code (code is the index) */
+ BYTE value; /* value that was coded */
+} main_huff_elem_t;
+
+typedef struct {
+ WORD code; /* Huff code to use for the 'value' below */
+ BYTE size; /* number of bits in above Huff 'code' */
+ BYTE value; /* value that was coded */
+} aux_huff_elem_t;
+
+typedef struct {
+ BYTE *index_p;
+ main_huff_elem_t *main_p;
+ aux_huff_elem_t *aux_p;
+} huff_tbl_t;
+
+
+/* Decoding is centered around out_rows_ap. It is indexed by
+ * [color_component_number][row_number].
+ * color_component_number 0 is Y (intensity); mono only has this component.
+ *
+ * Each component in out_rows_ap has a height (# rows) equal to the number of
+ * samples in the MCU, and a width equal to the number of samples in all the
+ * MCUs in a row. That is, pixels are stored in out_rows_ap with NO REPLICATION.
+ * So if a component has sample factors of H and V, it will have 8*V rows and
+ * pixels_in_row*H/max_horiz_samp_fac columns in out_rows_ap.
+ */
+
+typedef struct {
+ BYTE *out_rows_ap[4][32]; /* row-buffers [component][row] */
+
+ /***** Items from SOF, Start Of Frame *****/
+
+ IP_IMAGE_TRAITS traits; /* traits of the image */
+ BYTE num_comps; /* # of components (1 => mono) */
+ BYTE horiz_samp_facs[4]; /* horizontal sampling factors */
+ BYTE vert_samp_facs [4]; /* vertical sampling factors */
+ BYTE max_horiz_samp_fac; /* max sample factors */
+ BYTE max_vert_samp_fac;
+ BYTE which_quant_tbl[4]; /* selects q tbl for component */
+ UINT rows_per_mcu; /* # rows & cols in each MCU */
+ UINT cols_per_mcu;
+ UINT mcus_per_row; /* # of MCUs in each row */
+ UINT rowCountOffset;
+
+ /***** Items from other markers *****/
+
+ WORD restart_interval; /* restart interval (0 -> none) */
+ long quant_tbls[4][64]; /* quantization tables */
+ BYTE which_dc_tbl[4]; /* selects DC tbl for component */
+ BYTE which_ac_tbl[4]; /* selects AC tbl for component */
+ BOOL fColorFax; /* is this from a fax? */
+
+ /***** Huffman tables *****/
+
+ huff_tbl_t dc_tbls[MAX_HUFF_TBLS];
+ huff_tbl_t ac_tbls[MAX_HUFF_TBLS];
+
+ /***** Configuration variables *****/
+
+ BOOL output_subsampled; /* output subsampled data? */
+ BOOL fDenali; /* data is from a Denali? */
+
+ /***** Variables used while decoding *****/
+
+ DWORD dwInNextPos; /* next read pos in input file */
+ DWORD dwOutNextPos; /* next write pos in output file */
+ long rows_done; /* # rows decoded and output */
+ UINT mcus_done; /* # MCUs decoded so far in row */
+ BOOL sending_rows; /* returning the decoded rows? */
+ BOOL got_short_header; /* got an OfficeJet short header? */
+ BOOL got_EOI; /* hit the end-of-image marker? */
+ BYTE restart_cur_marker; /* index of next expected marker */
+ WORD restart_cur_mcu; /* current MCU-count in interval */
+ int prior_dc[4]; /* DC values of prior block */
+ jmp_buf syntax_error; /* jump-target for syntax errors */
+ jmp_buf old_syntax_error;
+ DWORD dwValidChk; /* struct validity check value */
+
+ /***** Reading bits variables *****/
+
+ DWORD rd_bit_buf;
+ /* Bits to be read from inbuf (read left-to-right). */
+
+ int rd_bits_avail;
+ /* Number of bits not yet read in rd_bit_buf (= 32 - number read). */
+
+ BYTE *rd_inbuf_beg;
+ /* The beginning of the input buffer. */
+
+ BYTE *rd_inbuf_next;
+ /* Next byte in inbuf to be read. */
+
+ /***** Decoding 8x8 blocks *****/
+
+ int block[64]; /* scratch-pad 8x8 block */
+ int *block_zz[64+16]; /* zig-zag ptrs into above block */
+
+} JDEC_INST, *PJDEC_INST;
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Forward Routines |
+ |____________________________________________________________________________|
+*/
+
+static void huff_define_table (
+ PJDEC_INST g,
+ BOOL ac, /* defining an AC table? (else DC) */
+ UINT id, /* which table is being defined (0-3) */
+ const BYTE counts[16], /* number of Huffman codes of each length 1-16 */
+ const BYTE values[]); /* values associated with codes of above lengths */
+
+void wino_scale_table (long *tbl_p);
+
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ R E A D I N G
+
+
+ Interface into this section:
+
+ read_init - inits this section
+ read_buf_open - we are being given a (new) input buffer
+ read_buf_close - done with current input buffer; return # bytes used
+ read_byte - returns next input byte (syncs to byte-boundary)
+ read_uint - returns next 2-byte integer (syncs)
+ read_skip_forward - discards the given number of input bytes
+ read_skip_backward - backs up the given number of bytes
+ READ_BITS_LOAD - loads N bits of input into lsb's of a var (no advance)
+ READ_BITS_ADVANCE - advance input N bits; you must call this to eat input
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_init | Inits this section |
+ |___________|________________________________________________________________|
+*/
+static void read_init (PJDEC_INST g)
+{
+ g->rd_bits_avail = 0;
+ g->rd_bit_buf = 0;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_buf_open | We are being given a (new) buffer to read input |
+ |_______________|____________________________________________________________|
+ | |
+ | This routine records the location of the new input buffer. |
+ |____________________________________________________________________________|
+*/
+static void read_buf_open (PJDEC_INST g, BYTE *buf_p)
+{
+ g->rd_inbuf_beg = buf_p;
+ g->rd_inbuf_next = buf_p;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_buf_close | We are done with the current input buffer |
+ |________________|___________________________________________________________|
+ | |
+ | This function returns # bytes read from the input buffer. |
+ |____________________________________________________________________________|
+*/
+static int read_buf_close (PJDEC_INST g)
+{
+ return g->rd_inbuf_next - g->rd_inbuf_beg;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | rd_sync | Empties the bit-cache, and syncs to a byte-boundary |
+ |_________|__________________________________________________________________|
+*/
+static void rd_sync (PJDEC_INST g)
+{
+ g->rd_bits_avail = 0;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_byte | returns next input byte (syncs to byte-boundary) |
+ |___________|________________________________________________________________|
+*/
+static BYTE read_byte (PJDEC_INST g)
+{
+ rd_sync (g);
+ return *(g->rd_inbuf_next)++;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_uint | returns next 2-byte integer (syncs) |
+ |___________|________________________________________________________________|
+*/
+static unsigned read_uint (PJDEC_INST g)
+{
+ UINT uval;
+
+ rd_sync (g);
+ uval = (unsigned)*(g->rd_inbuf_next)++ << 8;
+ return uval | *(g->rd_inbuf_next)++;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_skip_forward | discards the given number of input bytes |
+ |___________________|________________________________________________________|
+*/
+static void read_skip_forward (PJDEC_INST g, UINT n)
+{
+ if (n > MAX_MARKER_LEN)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+ rd_sync (g);
+ g->rd_inbuf_next += n;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_skip_backward | backs up N bytes in the input buffer |
+ |____________________|_______________________________________________________|
+*/
+static void read_skip_backward (PJDEC_INST g, UINT n)
+{
+ rd_sync (g);
+ g->rd_inbuf_next -= n;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | READ_BITS_LOAD | loads next par_n_bits of input into par_value (no advance)|
+ |________________|___________________________________________________________|
+ | |
+ | If a marker is encountered: |
+ | - this macro will goto hit_marker |
+ | - the marker will be the next two bytes in the buffer |
+ | - the cache will be empty (ie, any fill 1's were discarded) |
+ | |
+ | If the JPEG file erroneously has fill 0's (instead of 1's) before a |
+ | marker, we'll parse them as Huffman codes. If such a bogus Huffman code |
+ | has more bits than were in our bit-buffer, the extra non-existent bits |
+ | will be returned as zeroes. |
+ |____________________________________________________________________________|
+*/
+
+#define CANT_LOAD_NEAR_MARKER(g) \
+ (g->rd_bits_avail<=0 || \
+ (g->rd_bits_avail<=7 && (((1u<<g->rd_bits_avail)-1) & ~g->rd_bit_buf) == 0))
+ /* we just parsed past erroneous fill 0's OR */
+ /* cached bits are just fill 1's; toss them */
+
+
+#define READ_BITS_LOAD(g, fixed_len, par_n_bits, par_value, hit_marker) \
+{ \
+ if ((int)(par_n_bits) > g->rd_bits_avail) { \
+ BYTE a_byte; \
+ \
+ do { \
+ a_byte = *(g->rd_inbuf_next)++; \
+ DUMP (_T("<%02x>"), a_byte, 0, 0); \
+ \
+ if (a_byte == (BYTE )0xffu) { \
+ if (*(g->rd_inbuf_next)++ != 0) { /* we hit a marker */ \
+ g->rd_inbuf_next -= 2; \
+ if (CANT_LOAD_NEAR_MARKER(g)) \
+ goto hit_marker; \
+ break; /* exit 'while' loop */ \
+ } \
+ } \
+ \
+ g->rd_bit_buf = (g->rd_bit_buf<<8) | a_byte; \
+ g->rd_bits_avail += 8; \
+ } while (g->rd_bits_avail <= 24); \
+ } \
+ \
+ par_value = (g->rd_bit_buf << (32-g->rd_bits_avail)) >> (32-(par_n_bits)); \
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | READ_BITS_ADVANCE | discards next par_n_bits of input |
+ |___________________|________________________________________________________|
+*/
+#define READ_BITS_ADVANCE(g, par_n_bits) \
+{ \
+ g->rd_bits_avail -= par_n_bits; \
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ M A R K E R S
+
+
+ Interface into this section:
+
+ mar_get - parses and returns next marker-id
+ mar_parse - parses the data associated with the marker
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_factors | parses sample-factors as nibbles into array |
+ |_______________|____________________________________________________________|
+ | |
+ | This is only called by parse_app_short_header below. |
+ | Function return value = maximum sample factor. |
+ |____________________________________________________________________________|
+*/
+static UINT parse_factors (
+ UINT factors, /* in: sample factors, one nibble each, l-to-r */
+ BYTE fac_array[4]) /* out: array of sample factors */
+{
+ int i;
+ UINT fac;
+ UINT max_fac;
+
+ max_fac = 0;
+
+ for (i=3; i>=0; i--) {
+ fac = factors & 0x000fu;
+ factors >>= 4;
+ if (fac > max_fac) max_fac = fac;
+ fac_array[i] = fac;
+ }
+
+ return max_fac;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | calc_quant_table | calculates a quantization table |
+ |__________________|_________________________________________________________|
+ | |
+ | This is only called by parse_app_short_header below. |
+ | Warning: The calculation below should match the firmware. |
+ |____________________________________________________________________________|
+*/
+static void calc_quant_table (
+ PJDEC_INST g,
+ UINT dc_q_fac, /* orig DC is scaled by (dc_q_fac/50) */
+ UINT ac_q_fac, /* orig ACs are scaled by (ac_q_fac/50) */
+ const BYTE *orig_tbl_p, /* original table */
+ UINT which_q_tbl) /* which table is being defined (0-3) */
+{
+ int i;
+ UINT quant;
+ long *tbl_p;
+
+ tbl_p = g->quant_tbls[which_q_tbl];
+
+ for (i=0; i<64; i++) {
+ quant = ((*orig_tbl_p++)*(i==0 ? dc_q_fac : ac_q_fac) + 25u) / 50u;
+ if (quant == 0) quant = 1;
+ if (quant > 255) quant = 255;
+ tbl_p[i] = quant;
+ }
+
+ wino_scale_table (tbl_p);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_get | parses and returns next marker-id |
+ |_________|__________________________________________________________________|
+*/
+static UINT mar_get (PJDEC_INST g)
+{
+ UINT marker = 0; /* init to eliminate a compiler warning */
+ BOOL got_ff;
+
+ got_ff = FALSE;
+
+ while (TRUE) {
+ marker = read_byte (g);
+ if (marker == 0xff) got_ff = TRUE;
+ else break;
+ }
+
+ if (!got_ff || marker==0)
+ longjmp (g->syntax_error, BAD_MARKER_ID);
+
+ return marker;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_flush | discards data associated with current marker |
+ |___________|________________________________________________________________|
+*/
+static void mar_flush (PJDEC_INST g, UINT marker)
+{
+ if (marker==MARKER_SOI || marker==MARKER_EOI ||
+ (marker>=MARKER_RST0 && marker<=MARKER_RST7))
+ return; /* marker has no associated segment */
+
+ read_skip_forward (g, read_uint(g) - 2);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_app_jfif | parses a JFIF APP0 marker |
+ |________________|___________________________________________________________|
+ | |
+ | Sets these fields in 'traits': lHorizDPI, lVertDPI |
+ |____________________________________________________________________________|
+*/
+static void parse_app_jfif (PJDEC_INST g)
+{
+ UINT len;
+ BYTE byt;
+ UINT h_dpi, v_dpi;
+
+ len = read_uint (g);
+ byt = read_byte (g);
+ if (! (len==16 && (byt==(BYTE )'J' || byt==(BYTE )'j'))) {
+ /* This is not a JFIF APP-marker, so silently discard it */
+ read_skip_forward (g, len-3);
+ return;
+ }
+
+ read_skip_forward (g,6); /* discard "FIF\0" + 0x01 + 0x00 */
+ byt = read_byte (g);
+ h_dpi = read_uint (g);
+ v_dpi = read_uint (g);
+ read_skip_forward (g,2); /* discard thumbnail X and Y */
+
+ if (byt == 1) { /* 1 means that units are dots/inch */
+ g->traits.lHorizDPI = (DWORD)h_dpi << 16;
+ g->traits.lVertDPI = (DWORD)v_dpi << 16;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_app_g3fax | parses a color fax APP1 marker |
+ |_________________|__________________________________________________________|
+ | |
+ | Can set these fields in 'traits': lHorizDPI, lVertDPI |
+ |____________________________________________________________________________|
+ */
+static void parse_app_g3fax (PJDEC_INST g)
+{
+ int i;
+ UINT len, dpi;
+ BYTE id_ver[8];
+ const BYTE valid_id_ver[8] = {
+ 0x47, 0x33, 0x46, 0x41, 0x58, 0x00, /* "G3FAX" plus a 0 byte */
+ 0x07, 0xca }; /* version is year of std, 1994 */
+
+ len = read_uint (g);
+ if (len != 12) {
+ /* wrong version, or a gamut or illuminant spec which we ignore */
+ read_skip_forward (g, len-2);
+ return;
+ }
+
+ for (i=0; i<8; i++) /* fax id is 6 bytes; version is 2 bytes */
+ id_ver[i] = read_byte (g);
+
+ dpi = read_uint (g);
+
+ if (memcmp(id_ver,valid_id_ver,8) == 0
+ && (dpi==200 || dpi==300 || dpi==400)) {
+ /* everything is valid (whew!), so save dpi */
+ g->traits.lHorizDPI = g->traits.lVertDPI = (long)dpi << 16;
+ g->fColorFax = TRUE;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_app_short_header | An APP1 marker output by OfficeJet firmware |
+ |________________________|___________________________________________________|
+*/
+static void parse_app_short_header (PJDEC_INST g)
+{
+ /* Since the firmware does not supply tables in its header,
+ * the tables used in the firmware are supplied below. */
+
+ static const BYTE orig_lum_quant[64] = {
+ 16, 11, 12, 14, 12, 10, 16, 14,
+ 13, 14, 18, 17, 16, 19, 24, 40,
+ 26, 24, 22, 22, 24, 49, 35, 37,
+ 29, 40, 58, 51, 61, 60, 57, 51,
+ 56, 55, 64, 72, 92, 78, 64, 68,
+ 87, 69, 55, 56, 80, 109, 81, 87,
+ 95, 98, 103, 104, 103, 62, 77, 113,
+ 121, 112, 100, 120, 92, 101, 103, 99
+ };
+
+
+ static const BYTE orig_chrom_quant[64] = {
+ 17, 18, 18, 24, 21, 24, 47, 26,
+ 26, 47, 99, 66, 56, 66, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+ };
+
+ static const BYTE lum_DC_counts[16] = {
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ static const BYTE lum_DC_values[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+ };
+
+ static const BYTE chrom_DC_counts[16] = {
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ static const BYTE chrom_DC_values[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+ };
+
+ static const BYTE lum_AC_counts[16] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d
+ };
+
+ static const BYTE lum_AC_counts_Denali[16] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x00, 0x7e
+ /* Above, the [01,7d] in the normal table was changed to [00,7e].
+ * This alteration eliminates the sole 15-bit code, and yields
+ * Huffman codes as follows:
+ * - common codes are 12 bits wide or less,
+ * - uncommon codes are exactly 16 bits wide, and all those codes
+ * start with nine '1' bits, leaving seven bits of useful info.
+ * Denali uses a 4K-entry table for the common codes, and a
+ * quick lookup for the 7-bit leftover codes. So parsing of all
+ * codes is simple and fast.
+ */
+ };
+
+ static const BYTE lum_AC_values[162] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+ };
+
+ static const BYTE chrom_AC_counts[16] = {
+ 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+ 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77
+ };
+
+ static const BYTE chrom_AC_values[162] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+ };
+
+ UINT len;
+ UINT dc_q_fac, ac_q_fac;
+ UINT reserved;
+
+ /***** default items not in the short header *****/
+
+ g->restart_interval = 0;
+
+ g->which_quant_tbl[0] = 0;
+ g->which_quant_tbl[1] = 1;
+ g->which_quant_tbl[2] = 1;
+
+ g->which_dc_tbl[0] = 0;
+ g->which_ac_tbl[0] = 0;
+ g->which_dc_tbl[1] = 1;
+ g->which_ac_tbl[1] = 1;
+ g->which_dc_tbl[2] = 1;
+ g->which_ac_tbl[2] = 1;
+
+ huff_define_table (g, FALSE, 0, lum_DC_counts , lum_DC_values);
+ huff_define_table (g, TRUE , 0, g->fDenali ? lum_AC_counts_Denali
+ : lum_AC_counts, lum_AC_values);
+ huff_define_table (g, FALSE, 1, chrom_DC_counts, chrom_DC_values);
+ huff_define_table (g, TRUE , 1, chrom_AC_counts, chrom_AC_values);
+
+ /***** parse the short header *****/
+
+ len = read_uint (g);
+ if (len != 18)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ g->traits.lNumRows = read_uint (g);
+ g->traits.iPixelsPerRow = read_uint (g);
+ g->traits.lHorizDPI = (long)read_uint(g) << 16;
+ g->traits.lVertDPI = (long)read_uint(g) << 16;
+ ac_q_fac = read_byte (g);
+ g->num_comps = read_byte (g);
+ g->max_horiz_samp_fac = parse_factors (read_uint(g), g->horiz_samp_facs);
+ g->max_vert_samp_fac = parse_factors (read_uint(g), g->vert_samp_facs);
+ dc_q_fac = read_byte (g);
+ reserved = read_byte (g); /* should be 0 */
+
+ g->traits.iComponentsPerPixel = g->num_comps;
+ g->traits.iBitsPerPixel = g->num_comps * 8;
+ if (g->traits.lNumRows == 0)
+ g->traits.lNumRows = -1; /* -1 means 'unknown' */
+ if (dc_q_fac == 0)
+ dc_q_fac = ac_q_fac;
+
+ calc_quant_table (g, dc_q_fac, ac_q_fac, orig_lum_quant, 0);
+ calc_quant_table (g, dc_q_fac, ac_q_fac, orig_chrom_quant, 1);
+
+ g->got_short_header = TRUE;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_app | application-specific marker |
+ |_______________|____________________________________________________________|
+ | |
+ | Can set these fields in 'traits': lHorizDPI, lVertDPI |
+ |____________________________________________________________________________|
+ */
+static void mar_parse_app (PJDEC_INST g, UINT marker)
+{
+ UINT len;
+ BYTE id1, id2, id3;
+
+ len = read_uint (g);
+ if (len <= 5) {
+ /* unknown marker; discard it */
+ read_skip_forward (g, len-2);
+ return;
+ }
+
+ id1 = read_byte (g);
+ id2 = read_byte (g);
+ id3 = read_byte (g);
+ read_skip_backward (g, 5);
+
+ if (marker==MARKER_APP+1 && id1==0x47 && id2==0x33 && id3==0x46) {
+ /* G3 color fax APP1 marker */
+ parse_app_g3fax (g);
+ } else if (marker==MARKER_APP+0 && (id1=='J' || id1=='j')
+ && (id2=='F' || id2=='f') && (id3=='I' || id3=='i')) {
+ /* JFIF APP0 marker for generic JPEG files */
+ parse_app_jfif (g);
+ } else if (marker==MARKER_APP+1 && len==18) {
+ /* assume that APP1 marker is a short header */
+ parse_app_short_header (g);
+ } else {
+ /* unrecognized APP marker; discard it */
+ read_skip_forward (g, len);
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_sof | start of frame |
+ |_______________|____________________________________________________________|
+ | |
+ | Sets these fields in 'traits': lNumRows, iPixelsPerRow, iBitsPerPixel, |
+ | iComponentsPerPixel. |
+ | |
+ | Sets these variables: num_comps (equal to iComponentsPerPixel), |
+ | horiz_samp_facs, vert_samp_facs, which_quant_tbl, |
+ | max_horiz_samp_fac, max_vert_samp_fac |
+ |____________________________________________________________________________|
+*/
+static void mar_parse_sof (PJDEC_INST g, UINT marker)
+{
+ UINT len;
+ UINT uBitsPerComp;
+ UINT comp;
+ BYTE comp_id;
+ BYTE hv_samp;
+ BYTE q_table;
+ BYTE h, v;
+
+ len = read_uint (g);
+ uBitsPerComp = read_byte (g);
+ g->rowCountOffset=g->rd_inbuf_next-g->rd_inbuf_beg;
+ g->traits.lNumRows = read_uint (g);
+ g->traits.iPixelsPerRow = read_uint (g);
+ g->traits.iComponentsPerPixel = g->num_comps = read_byte (g);
+ g->traits.iBitsPerPixel = g->num_comps * uBitsPerComp;
+
+ if (g->traits.lNumRows == 0)
+ g->traits.lNumRows = -1; /* -1 means 'unknown' */
+
+ if (len != (8u + 3u*g->num_comps) || g->num_comps==0)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ /* Below, we also check for SOF1 because Chromafax erroneously outputs it */
+ if ((marker!=MARKER_SOF0 && marker!=MARKER_SOF0+1)
+ || uBitsPerComp!=8 || g->num_comps>4)
+ longjmp (g->syntax_error, NOT_IMPLEMENTED);
+
+ g->max_horiz_samp_fac = 1;
+ g->max_vert_samp_fac = 1;
+
+ #if DUMP_JPEG
+ _ftprintf (stderr, _T("\nSOF marker:\n"));
+ _ftprintf (stderr, _T(" bits per sample = %d\n"), uBitsPerComp);
+ _ftprintf (stderr, _T(" number of rows = %d\n"), g->traits.lNumRows);
+ _ftprintf (stderr, _T(" pixels per row = %d\n"), g->traits.iPixelsPerRow);
+ _ftprintf (stderr, _T(" # components = %d\n"), g->num_comps);
+ #endif
+
+ for (comp=0; comp<g->num_comps; comp++) {
+ comp_id = read_byte (g);
+ hv_samp = read_byte (g);
+ q_table = read_byte (g);
+
+ #if DUMP_JPEG
+ _ftprintf (stderr,
+ _T(" %d: comp id = %d, hv samp fac = %02x, which q = %d\n"),
+ comp, comp_id, hv_samp, q_table);
+ #endif
+
+ g->horiz_samp_facs[comp] = h = hv_samp >> 4;
+ g->vert_samp_facs [comp] = v = hv_samp & 0x0fu;
+ g->which_quant_tbl[comp] = q_table;
+
+ if (h > g->max_horiz_samp_fac) g->max_horiz_samp_fac = h;
+ if (v > g->max_vert_samp_fac ) g->max_vert_samp_fac = v;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_dqt | discrete quantization table |
+ |_______________|____________________________________________________________|
+ | |
+ | Sets the following variables: quant_tbls. |
+ |____________________________________________________________________________|
+*/
+static void mar_parse_dqt (PJDEC_INST g)
+{
+ int len, i;
+ BYTE pt;
+ long *tbl_p;
+
+ len = read_uint(g) - 2;
+
+ while (len >= 65) {
+ len -= 65;
+ pt = read_byte (g);
+ if ((pt & 0xfcu) != 0)
+ longjmp (g->syntax_error, NOT_IMPLEMENTED);
+ tbl_p = g->quant_tbls[pt & 3];
+ DUMP (_T("\nDQT marker: table=%d"), pt & 3, 0, 0);
+ for (i=0; i<64; i++) {
+ if ((i & 15) == 0) DUMP(_T("\n "), 0,0,0);
+ tbl_p[i] = read_byte (g);
+ DUMP (_T("%2d "), tbl_p[i], 0, 0);
+ }
+ DUMP (_T("\n"), 0,0,0);
+ wino_scale_table (tbl_p);
+ }
+
+ if (len != 0)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_dht | define Huffman tables |
+ |_______________|____________________________________________________________|
+ | |
+ | Sets the following variables: dc_tbls, ac_tbls. |
+ |____________________________________________________________________________|
+*/
+static void mar_parse_dht (PJDEC_INST g)
+{
+ BYTE num_codes[16];
+ BYTE values[256];
+
+ int len, i, tot_codes;
+ BYTE class_id;
+
+ len = read_uint(g) - 2;
+
+ while (len > 17) {
+ class_id = read_byte (g);
+
+ for (tot_codes=0, i=0; i<=15; i++) {
+ num_codes[i] = read_byte (g);
+ tot_codes += num_codes[i];
+ }
+
+ len -= 17;
+ if (len < tot_codes)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ for (i=0; i<tot_codes; i++)
+ values[i] = read_byte (g);
+ len -= tot_codes;
+
+ #if DUMP_JPEG
+ _ftprintf (stderr, _T("\nDHT marker: class=%d, id=%d\n counts = "),
+ (BOOL )(class_id>>4), class_id & 0x0f);
+ for (i=0; i<16; i++)
+ _ftprintf (stderr, _T("%2d "), num_codes[i]);
+ _ftprintf (stderr, _T("\n values = "));
+ for (i=0; i<tot_codes; i++)
+ _ftprintf (stderr, _T("%02x "), values[i]);
+ _ftprintf (stderr, _T("\n"));
+ #endif
+
+ huff_define_table (g, (BOOL)(class_id>>4), class_id & 0x0f,
+ num_codes, values);
+ }
+
+ if (len != 0)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_dri | define restart interval |
+ |_______________|____________________________________________________________|
+ | |
+ | Sets the following variable: restart_interval. |
+ |____________________________________________________________________________|
+*/
+static void mar_parse_dri (PJDEC_INST g)
+{
+ UINT len;
+
+ len = read_uint (g);
+ if (len != 4)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ g->restart_interval = read_uint (g);
+ DUMP (_T("\nDRI marker: restart interval = %d\n"), g->restart_interval, 0,0);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_sos | start of scan |
+ |_______________|____________________________________________________________|
+*/
+static void mar_parse_sos (PJDEC_INST g)
+{
+ UINT len;
+ UINT comp;
+ UINT cs;
+ UINT dc_ac;
+
+ len = read_uint (g);
+ if (len != 6u+2u*g->num_comps)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ read_byte (g); /* skip Ns value (number of components in scan) */
+
+ DUMP (_T("\nSOS marker:\n"), 0,0,0);
+
+ for (comp=0; comp<g->num_comps; comp++) {
+ cs = read_byte (g); /* skip Cs value (component selector) */
+ dc_ac = read_byte (g);
+ DUMP (_T(" %d: cs = %d, which dc_ac tbl = %02x\n"), comp, cs, dc_ac);
+ g->which_dc_tbl[comp] = dc_ac >> 4;
+ g->which_ac_tbl[comp] = dc_ac & 0x0fu;
+ }
+
+ read_byte (g); /* skip Ss value (start selection) */
+ read_byte (g); /* skip Se value (end selection) */
+ read_byte (g); /* skip AhAl value (approximation bit positions) */
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_dnl | Define Number of Lines |
+ |_______________|____________________________________________________________|
+ | |
+ | Sets the following variable: traits.lNumRows |
+ |____________________________________________________________________________|
+*/
+static void mar_parse_dnl (PJDEC_INST g)
+{
+ UINT len, nRows;
+
+ len = read_uint (g);
+ nRows = read_uint (g);
+
+ if (len!=4u || nRows==0)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ DUMP (_T("\nDNL marker: %d\n"), nRows,0,0);
+ g->traits.lNumRows = nRows;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse | parses the marker, storing results in global variables |
+ |___________|________________________________________________________________|
+*/
+static void mar_parse (PJDEC_INST g, UINT marker)
+{
+ PRINT (_T("mar_parse: marker = %02xh\n"), marker, 0);
+
+ switch (marker)
+ {
+ case MARKER_APP+0:
+ case MARKER_APP+1:
+ case MARKER_APP+2:
+ case MARKER_APP+3:
+ case MARKER_APP+4:
+ case MARKER_APP+5:
+ case MARKER_APP+6:
+ case MARKER_APP+7:
+ case MARKER_APP+8:
+ case MARKER_APP+9:
+ case MARKER_APP+10:
+ case MARKER_APP+11:
+ case MARKER_APP+12:
+ case MARKER_APP+13:
+ case MARKER_APP+14:
+ case MARKER_APP+15:
+ mar_parse_app (g, marker);
+ break;
+
+ case MARKER_COM: /* comment marker */
+ case MARKER_JPG+0:
+ case MARKER_JPG+1:
+ case MARKER_JPG+2:
+ case MARKER_JPG+3:
+ case MARKER_JPG+4:
+ case MARKER_JPG+5:
+ case MARKER_JPG+6:
+ case MARKER_JPG+7:
+ case MARKER_JPG+8:
+ case MARKER_JPG+9:
+ case MARKER_JPG+10:
+ case MARKER_JPG+11:
+ case MARKER_JPG+12:
+ case MARKER_JPG+13:
+ mar_flush (g, marker);
+ break;
+
+ case MARKER_SOF0:
+ case MARKER_SOF1:
+ case MARKER_SOF2:
+ case MARKER_SOF3:
+ case MARKER_SOF5:
+ case MARKER_SOF6:
+ case MARKER_SOF7:
+ case MARKER_SOF8:
+ case MARKER_SOF9:
+ case MARKER_SOFA:
+ case MARKER_SOFB:
+ case MARKER_SOFD:
+ case MARKER_SOFE:
+ case MARKER_SOFF:
+ mar_parse_sof (g, marker);
+ break;
+
+ case MARKER_RST0:
+ case MARKER_RST1:
+ case MARKER_RST2:
+ case MARKER_RST3:
+ case MARKER_RST4:
+ case MARKER_RST5:
+ case MARKER_RST6:
+ case MARKER_RST7:
+ DUMP (_T("\nRST marker.\n"), 0,0,0);
+ break;
+
+ case MARKER_DHT: mar_parse_dht (g); break;
+ case MARKER_DQT: mar_parse_dqt (g); break;
+ case MARKER_DRI: mar_parse_dri (g); break;
+ case MARKER_SOS: mar_parse_sos (g); break;
+ case MARKER_DNL: mar_parse_dnl (g); break;
+
+ case MARKER_DAC:
+ case MARKER_DHP:
+ case MARKER_EXP:
+ longjmp (g->syntax_error, NOT_IMPLEMENTED);
+ break;
+
+ /* The following markers have no data following them */
+
+ case MARKER_SOI:
+ DUMP (_T("\nSOI marker.\n"), 0,0,0);
+ break;
+
+ case MARKER_EOI:
+ DUMP (_T("\nEOI marker.\n"), 0,0,0);
+ break;
+
+ default:
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+ }
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ H U F F M A N
+
+
+ Interface into this section:
+
+ huff_init - inits this section
+ huff_free_tbl - deallocates memory for one table
+ huff_free_all - deallocates memory for all tables
+ huff_define_table - defines a new Huffman table
+ DECODE_HUFF - decodes and returns next Huffman code
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | DECODE_HUFF | Decodes a Huffman code, returning corresponding value |
+ |_____________|______________________________________________________________|
+*/
+#define DECODE_HUFF( \
+ g, \
+ huff_tbl_p, \
+ main_ix_len, \
+ par_result, \
+ hit_marker) \
+{ \
+ UINT tbl_index, code, size; \
+ main_huff_elem_t *elem; \
+ \
+ READ_BITS_LOAD (g, FALSE, main_ix_len, code, hit_marker) \
+ tbl_index = huff_tbl_p->index_p[code]; \
+ elem = &(huff_tbl_p->main_p[tbl_index]); \
+ par_result = elem->value; \
+ size = elem->size; \
+ \
+ if (size == 0) { \
+ par_result = parse_aux_code (g, huff_tbl_p->aux_p); \
+ } else { \
+ DUMP (_T(" %2d-%04x-%3d(main) "), size, code, par_result); \
+ READ_BITS_ADVANCE (g, size) \
+ } \
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_aux_code | Code is not in short-width table; look in aux table |
+ |________________|___________________________________________________________|
+ | |
+ | Returns the value associated with the code. |
+ |____________________________________________________________________________|
+*/
+static UINT parse_aux_code (
+ PJDEC_INST g,
+ aux_huff_elem_t *aux_tbl_par_p)
+{
+ UINT code, size, val;
+ UINT diff;
+ UINT excess;
+ aux_huff_elem_t *lo_p, *hi_p, *mid_p;
+
+ READ_BITS_LOAD (g, FALSE, 16, code, syntax_err)
+
+#if 0 /* we are no longer using ROM tables */
+ if ((BYTE *)aux_tbl_par_p == dec_AC_aux_tbl)
+ {
+ /* We are using our default ROM table */
+ val = dec_AC_aux_tbl [code & 0x7f];
+ DUMP (_T(" %2d-%4x-%3d(aux-rom) "), 16, code, val);
+ if (val==0 || (code & 0xff80)!=0xff80) goto syntax_err;
+ READ_BITS_ADVANCE (g,16)
+ }
+#endif
+
+ lo_p = aux_tbl_par_p;
+ hi_p = lo_p + lo_p->size - 1;
+ lo_p += 1; /* 1st table-entry is a dummy containing above table-size */
+
+ while ((diff=(hi_p-lo_p)) > 1) {
+ mid_p = lo_p + (diff>>1);
+ if (mid_p->code > code) hi_p = mid_p;
+ else lo_p = mid_p;
+ }
+
+ size = lo_p->size;
+ excess = 16u - size;
+ if ((code>>excess) != (UINT)(lo_p->code>>excess)) {
+ lo_p = hi_p;
+ size = lo_p->size;
+ excess = 16u - size;
+ if ((code>>excess) != (UINT)(lo_p->code>>excess)) {
+ PRINT (_T("aux code of %x not found\n"), code, 0);
+ goto syntax_err;
+ }
+ }
+
+ val = lo_p->value;
+ READ_BITS_ADVANCE (g,size)
+ DUMP (_T(" %2d-%4x-%3d(aux) "), size, code, val);
+
+ return val;
+
+ syntax_err:
+ PRINT (_T("parse_aux_code: syntax error\n"), 0, 0);
+ longjmp (g->syntax_error, BAD_HUFF_CODE);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | huff_init | Inits this section |
+ |___________|________________________________________________________________|
+*/
+static void huff_init (PJDEC_INST g)
+{
+ memset (g->dc_tbls, 0, sizeof(g->dc_tbls));
+ memset (g->ac_tbls, 0, sizeof(g->ac_tbls));
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | huff_free_tbl | Frees memory allocated for the given table |
+ |_______________|____________________________________________________________|
+*/
+static void huff_free_tbl (PJDEC_INST g, huff_tbl_t *tbl_p)
+{
+ if (tbl_p->index_p != NULL)
+ IP_MEM_FREE (tbl_p->index_p);
+ if (tbl_p->main_p != NULL)
+ IP_MEM_FREE (tbl_p->main_p);
+ if (tbl_p->aux_p != NULL)
+ IP_MEM_FREE (tbl_p->aux_p);
+
+ tbl_p->index_p = NULL;
+ tbl_p->main_p = NULL;
+ tbl_p->aux_p = NULL;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | huff_free_all | Frees all memory allocated for Huffman tables |
+ |_______________|____________________________________________________________|
+*/
+static void huff_free_all (PJDEC_INST g)
+{
+ int i;
+
+ for (i=0; i<MAX_HUFF_TBLS; i++) {
+ huff_free_tbl (g, &(g->dc_tbls[i]));
+ huff_free_tbl (g, &(g->ac_tbls[i]));
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | calc_table | Defines a Huffman table |
+ |____________|_______________________________________________________________|
+*/
+static void calc_table (
+ const BYTE counts[16], /* in: # Huffman codes of each length 1-16 */
+ const BYTE huffval[], /* in: values for codes of above lengths */
+ UINT main_ix_len, /* in: # bits in main tbl index (0=use max) */
+ huff_tbl_t *huff_tbl_p) /* out: the three tables */
+{
+ BYTE huffsize[257];
+ WORD huffcode[257];
+ int tot_codes;
+ int i;
+ BYTE *index_p;
+ main_huff_elem_t *main_p;
+ aux_huff_elem_t *aux_p;
+
+ /***************************************************/
+ /* Compute a complete Huffman table. */
+ /* output: huffval, huffsize, huffcode, tot_codes */
+ /***************************************************/
+
+ {
+ int i, j, k, code, siz;
+
+ /* Generate size array -- see JPEG document
+ *
+ * Note that list BITS in JPEG doc. has index from 1-16, but this list
+ * is called 'counts', indexed 0-15. This thus BITS[i] is replaced
+ * by counts[i-1]
+ */
+ tot_codes = 0;
+ for (i=1; i<=16; i++)
+ for (j=1; j<=counts[i-1]; j++)
+ huffsize[tot_codes++] = i;
+
+ huffsize[tot_codes] = 0;
+
+ #if 0 /* we now only use RAM tables */
+ if (memcmp(counts, rom_counts, 16) == 0 &&
+ memcmp(huffval, rom_val, tot_codes) == 0) {
+ PRINT (_T("calc_table: using ROM Huffman tables\n"), 0, 0);
+ return FALSE; /* tell caller to use ROM-tables instead */
+ }
+ #endif
+
+ /* Generate code array -- see JPEG document
+ *
+ * The resulting table is sorted by increasing 'code', and also by
+ * increasing 'size'.
+ */
+ k = 0;
+ code = 0;
+ siz = huffsize[0];
+ while (TRUE) {
+ do {
+ huffcode[k++] = code++;
+ } while (huffsize[k]==siz && k<257); /* Overflow Detection */
+ if (huffsize[k] == 0)
+ break; /* all done */
+ do { /* Shift next code to expand prefix */
+ code <<= 1;
+ siz += 1;
+ } while (huffsize[k] != siz);
+ }
+ }
+
+ /****************************************/
+ /* Make the main table (output: main_p) */
+ /****************************************/
+
+ { /* This "main" table is indexed by the output of the "table table",
+ * which is indexed by 'main_ix_len' bits of input.
+ * If the table-entry has a 'size' of 0, the aux table is examined.
+ */
+ int i, nbytes;
+ int extra_bits;
+ UINT first, final, code_plus_junk;
+
+ if (main_ix_len == 0)
+ main_ix_len = huffsize[tot_codes-1];
+
+ nbytes = (tot_codes+1) * sizeof(main_huff_elem_t);
+ IP_MEM_ALLOC (nbytes, main_p);
+ memset (main_p, 0, nbytes);
+
+ nbytes = 1lu << main_ix_len;
+ IP_MEM_ALLOC (nbytes, index_p);
+ memset (index_p, 0, nbytes);
+
+ for (i=0; i<tot_codes && huffsize[i]<=main_ix_len; i++) {
+ main_p[i+1].value = huffval [i];
+ main_p[i+1].size = huffsize[i] ;
+
+ extra_bits = main_ix_len - huffsize[i];
+ first = huffcode[i] << extra_bits;
+ final = first + (1lu << extra_bits) - 1;
+ for (code_plus_junk = first;
+ code_plus_junk <= final;
+ code_plus_junk++)
+ index_p[code_plus_junk] = i+1;
+ }
+ }
+
+ /********************************************/
+ /* Make the auxiliary table (output: aux_p) */
+ /********************************************/
+
+ { /* This is used when an entry in the main table was 0, meaning that
+ * the code is longer than 'main_ix_len'. The aux table consists of
+ * all [code, size, value] triples for sizes > main_ix_len. A binary
+ * search is used to locate the code.
+ * The first table-entry is a dummy whose 'size' field is the number
+ * of table-entries (including the dummy).
+ */
+ int first, n_entries;
+ aux_huff_elem_t *p;
+
+ /* locate first huffsize > main_ix_len */
+ for (first=0; first<tot_codes && huffsize[first]<=main_ix_len; first++);
+
+ if (first == tot_codes) {
+ /* the main table captured everything; no aux table is needed */
+ IP_MEM_ALLOC (1, aux_p);
+ } else {
+ n_entries = tot_codes - first + 1; /* +1 because of dummy entry */
+ IP_MEM_ALLOC (n_entries * sizeof(aux_huff_elem_t), aux_p);
+
+ /* fill-in the dummy entry (contains # entries in table) */
+ p = aux_p;
+ p->size = (UINT) n_entries;
+ p->code = p->value = 0;
+ p += 1;
+
+ for (i=first; i<tot_codes; i++) {
+ p->size = huffsize[i];
+ p->code = huffcode[i] << (16u - p->size);
+ p->value = huffval [i];
+ p += 1;
+ }
+ }
+ }
+
+ #if DUMP_JPEG
+ {
+ int i, n;
+
+ _ftprintf (stderr, _T("\nOriginal size-code-val tuples:\n"));
+ for (i=0; i<tot_codes; i++) {
+ if ((i&7) == 0) _ftprintf(stderr, _T(" "));
+ _ftprintf (stderr, _T("%2d-%04x-%02x "),
+ huffsize[i], huffcode[i], huffval[i]);
+ if ((i&7)==7 || i==tot_codes-1) _ftprintf(stderr, _T("\n"));
+ }
+
+ _ftprintf(stderr, _T("\nIndex table: (%d entries)\n"), 1lu<<main_ix_len);
+ for (i=0; i<(1lu<<main_ix_len); i++) {
+ if ((i&7) == 0) _ftprintf(stderr, _T(" %3d: "), i);
+ _ftprintf (stderr, _T("%3d, "), index_p[i]);
+ if ((i&7) == 7) _ftprintf(stderr, _T("\n"));
+ }
+
+ _ftprintf(stderr, _T("\nMain table: (%d entries)\n"), tot_codes+1);
+ for (i=0; i<tot_codes; i++) {
+ if ((i&7) == 0) _ftprintf(stderr, _T(" %3d: "), i);
+ _ftprintf (stderr, _T("%04x(%2d) "), main_p[i].value, main_p[i].size);
+ if ((i&7)==7 || i==tot_codes-1) _ftprintf(stderr, _T("\n"));
+ }
+
+ if (huffsize[tot_codes-1] > main_ix_len) {
+ n = aux_p[0].size;
+ _ftprintf(stderr, _T("\nAux table: (%d entries of size-code-value)\n"),n);
+ for (i=0; i<n; i++) {
+ if ((i&3) == 0) _ftprintf(stderr, _T(" %3d: "), i);
+ _ftprintf (stderr, _T("%2d-%4x-%3d "),
+ aux_p[i].size, aux_p[i].code, aux_p[i].value);
+ if ((i&3)==3 || i==n-1) _ftprintf(stderr, _T("\n"));
+ }
+ }
+ }
+ #endif
+
+ huff_tbl_p->index_p = index_p;
+ huff_tbl_p->main_p = main_p;
+ huff_tbl_p->aux_p = aux_p;
+ return;
+
+ fatal_error:
+ assert (0); /* todo: eliminate this assert */
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | huff_define_table | Defines the given Huffman table |
+ |___________________|________________________________________________________|
+ | |
+ | Sets the following variables: dc_tbls, ac_tbls. |
+ |____________________________________________________________________________|
+*/
+static void huff_define_table (
+ PJDEC_INST g,
+ BOOL ac, /* defining an AC table? (else DC) */
+ UINT id, /* which table is being defined (0-3) */
+ const BYTE counts[16], /* number of Huffman codes of each length 1-16 */
+ const BYTE values[]) /* values associated with codes of above lengths */
+{
+ huff_tbl_t *tbl_p;
+
+ tbl_p = ac ? &(g->ac_tbls[id]) : &(g->dc_tbls[id]);
+ huff_free_tbl (g,tbl_p);
+
+ DUMP (_T("\nhuff_define_table: ac=%d, id=%d\n"), ac, id, 0);
+ calc_table (counts, values,
+ ac ? AC_TBL_INDEX_LEN : DC_TBL_INDEX_LEN,
+ tbl_p);
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ W I N O G R A D
+
+
+ Interface into this section:
+
+ QNORM_TO_INPUT - adjusts precision of scaled DCT value for wino-input
+ INPUT_PRECISION - scales result of wino_inverse_dct back to pixels
+ wino_scale_table - scale a quantization table into a Winograd table
+ wino_inverse_dct - computes inverse DCT using Winograd's algorithm
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+#define SHIFT_TRUNC(mvalue,mshift) ((mvalue) >> (mshift))
+
+#define QNORM_TO_INPUT(mval) SHIFT_TRUNC(mval, QNORM_PRECISION-INPUT_PRECISION)
+
+#define QNORM_PRECISION 16 /* prec of q-table scaled by Wino norm constants */
+#define INPUT_PRECISION 5 /* prec of input to inverse-DCT */
+#define CONST_PRECISION 9 /* prec of b1-b5 below */
+
+#define b1 724L
+#define b2 1338L
+#define b3 724L
+#define b4 554L
+#define b5 392L
+
+#if 0
+#define CONST_PRECISION 15
+
+#define b1 46341L
+#define b2 85627L
+#define b3 46341L
+#define b4 35468L
+#define b5 25080L
+#endif
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | wino_scale_table | Scales a quantization table into a Winograd table |
+ |__________________|_________________________________________________________|
+ | |
+ | Multiplies all the components of the Quantization matrix by the fractional |
+ | normalization constants as required by the Winograd Transform. The |
+ | results are fixed-point with QNORM_PRECISION bits of fraction. |
+ |____________________________________________________________________________|
+*/
+
+static const float inv_dct_norm[] = {
+ 0.125000f, 0.173380f, 0.173380f, 0.163320f,
+ 0.240485f, 0.163320f, 0.146984f, 0.226532f,
+ 0.226532f, 0.146984f, 0.125000f, 0.203873f,
+ 0.213388f, 0.203873f, 0.125000f, 0.098212f,
+ 0.173380f, 0.192044f, 0.192044f, 0.173380f,
+ 0.098212f, 0.067650f, 0.136224f, 0.163320f,
+ 0.172835f, 0.163320f, 0.136224f, 0.067650f,
+ 0.034566f, 0.093833f, 0.128320f, 0.146984f,
+ 0.146984f, 0.128320f, 0.093833f, 0.034566f,
+ 0.047944f, 0.088388f, 0.115485f, 0.125000f,
+ 0.115485f, 0.088388f, 0.047944f, 0.045162f,
+ 0.079547f, 0.098212f, 0.098212f, 0.079547f,
+ 0.045162f, 0.040645f, 0.067650f, 0.077165f,
+ 0.067650f, 0.040645f, 0.034566f, 0.053152f,
+ 0.053152f, 0.034566f, 0.027158f, 0.036612f,
+ 0.027158f, 0.018707f, 0.018707f, 0.009558f
+};
+
+void wino_scale_table (
+ long *tbl_p)
+{
+ const float *fptr;
+ int i;
+
+ fptr = inv_dct_norm;
+ for (i=0; i<64; i++) {
+ *tbl_p = (long ) ((*tbl_p) * (*fptr++) * (1l<<QNORM_PRECISION) + 0.5);
+ tbl_p += 1;
+ }
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ D E C O D I N G
+
+
+ Interface into this section:
+
+ zero_prior_DC - sets the predicted DC values to zero
+ decode_MCU - decodes a single Minimum Coded Unit
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+static BYTE const zigzag_index_tbl[] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* extra 16 elements in case */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* parse_block overruns */
+};
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | decode_init | inits this section |
+ |_____________|______________________________________________________________|
+*/
+static void decode_init (PJDEC_INST g)
+{
+ BYTE const *zig_p;
+ int **block_pp;
+
+ zig_p = zigzag_index_tbl;
+ for (block_pp=g->block_zz; block_pp<g->block_zz+(64+16); block_pp++)
+ *block_pp = &(g->block[*zig_p++]);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | zero_prior_DC | zeroes the predicted DC values |
+ |_______________|____________________________________________________________|
+*/
+static void zero_prior_DC (PJDEC_INST g)
+{
+ g->prior_dc[0] = g->prior_dc[1] = g->prior_dc[2] = g->prior_dc[3] = 0;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_block | parses an 8x8 block; return data is ready for inverse DCT |
+ |_____________|______________________________________________________________|
+ | |
+ | Return value: TRUE = we parsed a block, |
+ | FALSE = hit a marker. |
+ | Output data is put in 'block' array. |
+ |____________________________________________________________________________|
+*/
+static BOOL parse_block (
+ PJDEC_INST g,
+ int comp) /* in: image component number */
+{
+ /* FIX_TERM - changes a term (fetched from JPEG file) into an integer.
+ * The term is in ones-complement, with the sign-bit (and higher bits)
+ * zeroed. So the leftmost bit within the given size is the opposite of
+ * the desired sign bit. If that bit is 1, the number is positive, and
+ * needs no change. If it's 0, we set the higher bits to 1s, and add 1
+ * to convert from ones-complement to twos-complement.
+ * Select the macro below which is fastest on your computer.
+ */
+
+ #if 1
+ #define FIX_TERM(msize,mterm) { \
+ if ((mterm & (1u<<((msize)-1))) == 0) \
+ mterm = (mterm | (-1 << (msize))) + 1; \
+ }
+ #endif
+
+ #if 0
+ #define FIX_TERM(msize,mterm) { \
+ int mask = -1 << msize; \
+ if (((mterm<<1) & mask) == 0) \
+ mterm += mask + 1; \
+ }
+ #endif
+
+ #if 0
+ #define FIX_TERM(msize,mterm) \
+ mterm += ((mterm>>(msize-1)) - 1) & ~((1<<msize) - 2);
+ #endif
+
+ huff_tbl_t *huff_p;
+ int **block_p;
+ long *dequant_p;
+ UINT siz, run, rl_byte;
+ int dc, ac;
+
+ /* memset (block, 0, 64*sizeof(int)); */
+ {
+ int *block_p, *after_p;
+
+ for (block_p=g->block, after_p=g->block+64; block_p<after_p; ) {
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ }
+ }
+
+ dequant_p = g->quant_tbls[g->which_quant_tbl[comp]];
+ block_p = g->block_zz;
+
+ /**************************************/
+ /* Decode and dequantize the DC value */
+ /**************************************/
+
+ DUMP (_T("\nStart of block for component %d:\n"), comp, 0, 0);
+
+ huff_p = &(g->dc_tbls[g->which_dc_tbl[comp]]);
+ DECODE_HUFF (g, huff_p, DC_TBL_INDEX_LEN, siz, hit_marker)
+
+ if (siz == 0) {
+ DUMP (_T("dc=0, size of dc=0\n"), 0,0,0);
+ dc = 0;
+ } else {
+ READ_BITS_LOAD (g, TRUE, siz, dc, syntax_err)
+ READ_BITS_ADVANCE (g, siz)
+ DUMP (_T("dc=%x, size of dc=%d\n"), dc, siz, 0);
+ FIX_TERM (siz, dc)
+ }
+
+ dc += g->prior_dc[comp];
+ g->prior_dc[comp] = dc;
+ *(*block_p++) = QNORM_TO_INPUT ((long )*dequant_p++ * dc);
+
+ /*************************************************/
+ /* Decode, dezigzag and dequantize the AC values */
+ /*************************************************/
+
+ huff_p = &(g->ac_tbls[g->which_ac_tbl[comp]]);
+
+ /* The two 'hit_marker's below should be 'syntax_error' instead. But
+ * Chromafax and other software erroneously uses fill 0's instead
+ * of fill 1's, so we parse a few of those 0's before hitting the
+ * marker.
+ */
+
+ while (TRUE) {
+ DECODE_HUFF (g, huff_p, AC_TBL_INDEX_LEN, rl_byte, hit_marker);
+ run = rl_byte >> 4;
+ siz = rl_byte & 0x0f;
+ DUMP (_T("rlc: run=%d, size of ac=%d"), run, siz, 0);
+
+ if (siz == 0) {
+ if (run == 15) {
+ DUMP (_T(", run of 16\n"), 0,0,0);
+ block_p += 16;
+ dequant_p += 16;
+ } else if (run == 0) {
+ DUMP (_T(", EOB\n"), 0,0,0);
+ break; /* hit EOB */
+ } else
+ goto syntax_err;
+ } else {
+ block_p += run;
+ dequant_p += run;
+ READ_BITS_LOAD (g, TRUE, siz, ac, hit_marker);
+ READ_BITS_ADVANCE (g, siz);
+ DUMP (_T(", ac=%x\n"), ac, siz, 0);
+ FIX_TERM (siz, ac);
+ *(*block_p++) = QNORM_TO_INPUT ((long )*dequant_p++ * ac);
+ }
+
+ if (block_p >= g->block_zz+64) {
+ if (block_p > g->block_zz+64) {
+ PRINT(_T("parse_block: over 63 AC terms\n"), 0,0);
+ goto syntax_err;
+ }
+ if (! g->fDenali)
+ break; /* 63rd AC term was non-zero */
+ }
+ }
+
+ return TRUE;
+
+ syntax_err:
+ PRINT(_T("parse_block: syntax error\n"), 0,0);
+ longjmp (g->syntax_error, BAD_HUFF_CODE);
+
+ hit_marker:
+ return FALSE;
+
+ #undef FIX_TERM
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | handleMarkerInStream | handles a marker in the data-stream |
+ |______________________|_____________________________________________________|
+ | |
+ | Parses EOI, DNL and RST; other markers cause an error (longjmp). |
+ | For an EOI, g->got_EOI is set to true. |
+ |____________________________________________________________________________|
+*/
+static void handleMarkerInStream (PJDEC_INST g)
+{
+ BYTE marker;
+
+ marker = mar_get(g);
+
+ if (marker == MARKER_EOI) {
+ PRINT (_T("handleMarkerInStream: parsed EOI\n"), 0, 0);
+ g->got_EOI = TRUE;
+ } else if (marker == MARKER_DNL) {
+ PRINT (_T("handleMarkerInStream: parsing DNL\n"), 0, 0);
+ mar_parse_dnl (g);
+ } else if (g->restart_interval > 0
+ && g->restart_cur_mcu == g->restart_interval
+ && (marker-MARKER_RST0) == g->restart_cur_marker)
+ {
+ /* it's a restart, and we expected it at this point in the data */
+ PRINT (_T("handleMarkerInStream: parsed expected RST\n"), 0, 0);
+ g->restart_cur_marker = (g->restart_cur_marker+1) & 7;
+ g->restart_cur_mcu = 0;
+ zero_prior_DC (g);
+ } else {
+ PRINT (_T("handleMarkerInStream: illegal marker=0x%2.2X\n"), marker, 0);
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | LevelShiftAndRound | Level-shifts, rounds, and outputs pixels in 0..255 |
+ |____________________|_______________________________________________________|
+*/
+static void LevelShiftAndRound (int *inBlock_p, BYTE *outBlock_p)
+{
+ BYTE *outAfter;
+ int pixel;
+
+ for (outAfter = outBlock_p + 64;
+ outBlock_p < outAfter;
+ outBlock_p++, inBlock_p++)
+ {
+ pixel = (*inBlock_p +
+ ((1<<(INPUT_PRECISION-1)) + (128<<INPUT_PRECISION)))
+ >> INPUT_PRECISION;
+ if (pixel>>8 != 0)
+ pixel = pixel>0 ? 255 : 0; /* clamp to 0 or 255 */
+ *outBlock_p = (BYTE) pixel;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | decode_MCU | Parses a Minimum Coded Unit, and loads pixels into out_rows_ap|
+ |____________|_______________________________________________________________|
+ | |
+ | The pixels are loaded starting at mcus_done (not incremented). |
+ | This routine handles the restart interval logic, and markers. |
+ | |
+ | Returns TRUE if an MCU was parsed, else FALSE. |
+ |____________________________________________________________________________|
+*/
+static BOOL decode_MCU (PJDEC_INST g)
+{
+ BYTE baPixels[256];
+ BYTE *pPixel;
+ int comp;
+ int h_block, v_block;
+ int ul_row, ul_col;
+ int row;
+ BYTE **row_pp;
+ BYTE *row_p;
+
+ for (comp=0; comp<g->num_comps; comp++) {
+ for (v_block=0; v_block<g->vert_samp_facs[comp]; v_block++) {
+ for (h_block=0; h_block<g->horiz_samp_facs[comp]; h_block++) {
+
+ /***** parse and inverse-dct an 8x8 block *****/
+
+ while (! parse_block(g,comp)) {
+ /* we hit a marker */
+ #if 0
+ /* The error-check below is commented-out to make us
+ * more forgiving of unexpected in-data markers, which
+ * we saw the Genoa color-fax test suite output at the
+ * end of the file.
+ */
+ if (comp>0 || v_block>0 || h_block>0)
+ longjmp (g->syntax_error, UNEXPECTED_MARKER);
+ #endif
+ handleMarkerInStream(g);
+ if (g->got_EOI)
+ return FALSE; /* we're out of data; cannot proceed */
+ }
+
+ dct_inverse (g->block);
+
+ /***** compute output pixels *****/
+
+ LevelShiftAndRound (g->block, baPixels);
+
+ /***** copy block into out_rows_ap *****/
+
+ ul_row = v_block*8;
+ ul_col = (g->mcus_done*g->horiz_samp_facs[comp] + h_block) * 8;
+ row_pp = &(g->out_rows_ap[comp][ul_row]);
+ pPixel = baPixels;
+
+ for (row=0; row<8; row++) {
+ row_p = *row_pp++ + ul_col;
+ /* copy the 8 pixel row quickly, using two dword transfers */
+ *(DWORD*) row_p = *(DWORD*) pPixel;
+ *(DWORD*)(row_p+4) = *(DWORD*)(pPixel+4);
+ pPixel += 8;
+ }
+ }
+ }
+ }
+
+ if (g->restart_interval>0 && g->restart_cur_mcu==g->restart_interval)
+ longjmp (g->syntax_error, NO_RESTART_MARKER);
+ g->restart_cur_mcu += 1;
+
+ return TRUE;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | copy_out_rows | copies a row (or rows) from out_rows_ap to output buffer |
+ |_______________|____________________________________________________________|
+ | |
+ | If output_subsampled is true, we output row data in the same odd order |
+ | which the ASIC outputs it. |
+ | |
+ | View a period as being a group of max_horiz_samp_fac by max_vert_samp_fac |
+ | samples. (BTW, an MCU contains exactly 8x8 periods.) Divide the entire |
+ | image into a grid of such periods. The ASIC outputs the periods left to |
+ | right, top to bottom. It outputs all the data in each period, before |
+ | moving to the next period. Within a period, it outputs the components in |
+ | succession; within a component, it outputs the samples left to right, top |
+ | to bottom. |
+ | |
+ | For example: |
+ | Three components = Y U V |
+ | Horiz sample factors = 2 1 1 |
+ | Vert sample factors = 2 1 1 |
+ | A period is 2x2 samples (i.e., a 2x2 square). |
+ | Each period contains these samples: YYYYUV. |
+ | Bytes output: YYYYUV YYYYUV YYYYUV .... |
+ | |
+ | In this routine, |
+ | |
+ | vert_period = index of which period we're outputting vertically within|
+ | an MCU (0-7). |
+ | |
+ | horiz_period = index of which period we're outputting horizontally; |
+ | since an MCU has 8 periods, this is 0 .. 8*mcus_per_row.|
+ |____________________________________________________________________________|
+*/
+static void copy_out_rows (
+ PJDEC_INST g,
+ UINT row_index, /* in: index of next row to send within MCU */
+ BYTE *outbuf_p, /* out: copied-out row data */
+ UINT *n_rows_p, /* out: # of rows copied out */
+ UINT *n_bytes_p) /* out: # of bytes output */
+{
+ BYTE *out_p;
+ UINT comp;
+ UINT vert_period, vert_mod;
+ UINT row, col;
+ BYTE *row_p;
+
+ vert_period = row_index / g->max_vert_samp_fac;
+ vert_mod = row_index % g->max_vert_samp_fac;
+
+ if (! g->output_subsampled) {
+
+ /*******************************************/
+ /* Perform duplication to undo subsampling */
+ /*******************************************/
+
+ UINT samp_fac;
+ UINT horiz_mod;
+
+ for (comp=0; comp<g->num_comps; comp++) {
+ samp_fac = g->vert_samp_facs[comp];
+ out_p = outbuf_p + comp;
+ row = vert_period*samp_fac +
+ (vert_mod<samp_fac ? vert_mod : samp_fac-1);
+ row_p = g->out_rows_ap[comp][row];
+
+ horiz_mod = 0;
+ samp_fac = g->horiz_samp_facs[comp];
+
+ if (samp_fac == g->max_horiz_samp_fac) {
+
+ /***** fast case: copying all pixels, with no duplication *****/
+
+ if (g->num_comps == 1) {
+ memcpy (out_p, row_p, g->traits.iPixelsPerRow);
+ } else {
+ for (col=0; col<(UINT)g->traits.iPixelsPerRow; col++) {
+ *out_p = *row_p++;
+ out_p += g->num_comps;
+ }
+ }
+
+ } else if (samp_fac==1 && g->max_horiz_samp_fac==2) {
+
+ /***** fast case: duplicating every other pixel *****/
+
+ BYTE prev_pix;
+ for (col=0; col<(UINT)g->traits.iPixelsPerRow; col+=2) {
+ *out_p = prev_pix = *row_p++;
+ out_p += g->num_comps;
+ *out_p = prev_pix;
+ out_p += g->num_comps;
+ }
+
+ } else {
+
+ /***** slow general case *****/
+
+ for (col=0; col<(UINT)g->traits.iPixelsPerRow; col++) {
+ *out_p = horiz_mod<samp_fac ? *row_p++ : row_p[-1];
+ out_p += g->num_comps;
+ horiz_mod += 1;
+ if (horiz_mod == g->max_horiz_samp_fac) horiz_mod = 0;
+ }
+ }
+ }
+
+ *n_rows_p = 1;
+ *n_bytes_p = g->num_comps * g->traits.iPixelsPerRow;
+
+ } else {
+
+ /**********************************************/
+ /* Output subsampled data in ASIC's odd order */
+ /**********************************************/
+
+ UINT horiz_period, periods_per_row;
+ UINT ul_row, ul_col;
+ BYTE *row_y1_p, *row_y2_p, *row_cb_p, *row_cr_p;
+
+ out_p = outbuf_p;
+ periods_per_row = g->mcus_per_row * 8;
+
+ if (g->num_comps==1 && g->max_horiz_samp_fac==1 && g->max_vert_samp_fac==1) {
+
+ /***** fast case: one component; just copy the row *****/
+
+ memcpy (out_p, g->out_rows_ap[0][row_index], g->traits.iPixelsPerRow);
+ out_p += g->traits.iPixelsPerRow;
+
+ } else if (g->num_comps==3 &&
+ (g->horiz_samp_facs[0]==1 &&
+ g->horiz_samp_facs[1]==1 &&
+ g->horiz_samp_facs[2]==1) &&
+ (g->vert_samp_facs[0]==1 &&
+ g->vert_samp_facs[1]==1 &&
+ g->vert_samp_facs[2]==1)) {
+
+ /***** fast case: color with no subsampling *****/
+
+ row_y1_p = g->out_rows_ap[0][vert_period];
+ row_cb_p = g->out_rows_ap[1][vert_period];
+ row_cr_p = g->out_rows_ap[2][vert_period];
+ for (col=0; col<(UINT)g->traits.iPixelsPerRow; col++) {
+ *out_p++ = *row_y1_p++;
+ *out_p++ = *row_cb_p++;
+ *out_p++ = *row_cr_p++;
+ }
+
+ } else if (g->num_comps==3 &&
+ (g->horiz_samp_facs[0]==2 &&
+ g->horiz_samp_facs[1]==1 &&
+ g->horiz_samp_facs[2]==1) &&
+ (g->vert_samp_facs[0]==2 &&
+ g->vert_samp_facs[1]==1 &&
+ g->vert_samp_facs[2]==1)) {
+
+ /***** fast case: 4-1-1 color subsampling *****/
+
+ row_y1_p = g->out_rows_ap[0][2*vert_period];
+ row_y2_p = g->out_rows_ap[0][2*vert_period+1];
+ row_cb_p = g->out_rows_ap[1][vert_period];
+ row_cr_p = g->out_rows_ap[2][vert_period];
+ for (horiz_period=0; horiz_period<periods_per_row; horiz_period++) {
+ *out_p++ = *row_y1_p++;
+ *out_p++ = *row_y1_p++;
+ *out_p++ = *row_y2_p++;
+ *out_p++ = *row_y2_p++;
+ *out_p++ = *row_cb_p++;
+ *out_p++ = *row_cr_p++;
+ }
+
+ } else {
+
+ /***** slow general case *****/
+
+ for (horiz_period=0; horiz_period<periods_per_row; horiz_period++) {
+ for (comp=0; comp<g->num_comps; comp++) {
+ ul_row = vert_period * g->vert_samp_facs[comp];
+ ul_col = horiz_period * g->horiz_samp_facs[comp];
+
+ for (row=ul_row; row<ul_row+ g->vert_samp_facs[comp]; row++)
+ for (col=ul_col; col<ul_col+g->horiz_samp_facs[comp]; col++) {
+ *out_p++ = g->out_rows_ap[comp][row][col];
+ }
+ }
+ }
+ }
+
+ *n_rows_p = g->max_vert_samp_fac;
+ *n_bytes_p = out_p - outbuf_p;
+ }
+}
+
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ E X P O R T E D R O U T I N E S
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PJDEC_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(JDEC_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(JDEC_INST));
+ g->dwValidChk = CHECK_VALUE;
+ decode_init (g);
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PJDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->traits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PJDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->output_subsampled = aXformInfo[IP_JPG_DECODE_OUTPUT_SUBSAMPLED].dword;
+ g->fDenali = aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ PJDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwInBufLen = MAX_HEADER_SIZE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PJDEC_INST g;
+ UINT comp;
+ UINT marker;
+ UINT row_len, n_rows;
+ UINT row;
+ UINT err;
+ BYTE *p;
+
+ /**************/
+ /* Misc. Init */
+ /**************/
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->rows_done = 0;
+ g->mcus_done = 0;
+ g->sending_rows = FALSE;
+ g->got_EOI = FALSE;
+ g->got_short_header = FALSE;
+ read_init (g);
+ huff_init (g);
+ zero_prior_DC (g);
+ g->restart_cur_mcu = 0;
+ g->restart_cur_marker = 0;
+ g->dwOutNextPos = 0;
+
+ /********************/
+ /* Parse the header */
+ /********************/
+
+ if ((err=setjmp(g->syntax_error)) != 0) {
+ PRINT (_T("jpeg_decode_parse_header: syntax error = %d\n"), err, 0);
+ return IP_FATAL_ERROR | IP_INPUT_ERROR;
+ }
+
+ read_buf_open (g, pbInputBuf);
+
+ if (mar_get(g) != MARKER_SOI)
+ return IP_FATAL_ERROR | IP_INPUT_ERROR;
+
+ do {
+ marker = mar_get (g);
+ mar_parse (g, marker);
+ if (marker == MARKER_EOI)
+ return IP_FATAL_ERROR | IP_INPUT_ERROR;
+ } while (!(marker==MARKER_SOS || g->got_short_header));
+
+ *pdwInputNextPos = g->dwInNextPos = *pdwInputUsed = read_buf_close (g);
+
+ /* todo: check that all markers arrived */
+
+ PRINT (_T("jpeg_decode_parse_header: pixels/row=%d, num_rows=%d\n"),
+ g->traits.iPixelsPerRow, g->traits.lNumRows);
+
+ g->cols_per_mcu = g->max_horiz_samp_fac * 8;
+ g->rows_per_mcu = g->max_vert_samp_fac * 8;
+ g->mcus_per_row = (g->traits.iPixelsPerRow + g->cols_per_mcu - 1) / g->cols_per_mcu;
+
+ /*******************************************/
+ /* Allocate the row-buffers in out_rows_ap */
+ /*******************************************/
+
+ memset (g->out_rows_ap, 0, sizeof(g->out_rows_ap));
+
+ for (comp=0; comp<g->num_comps; comp++) {
+ row_len = g->horiz_samp_facs[comp] * g->mcus_per_row * 8;
+ n_rows = g->vert_samp_facs[comp] * 8;
+
+ for (row=0; row<n_rows; row++) {
+ IP_MEM_ALLOC (row_len, p);
+ g->out_rows_ap[comp][row] = p;
+ }
+ }
+
+ /***************/
+ /* Return info */
+ /***************/
+
+ *pInTraits = g->traits;
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * jpgDecode_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD jpgDecode_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PJDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = INBUF_NUM_MCUS * MAX_MCU_SIZE;
+ *pdwMinOutBufLen = g->num_comps * g->traits.iPixelsPerRow;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_convert - the work-horse routine
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PJDEC_INST g;
+ /* The "static" keyword for ret_val and bDecoded is to prevent the
+ * "variable `' might be clobbered by `longjmp' or `vfork'" warning. */
+ static unsigned ret_val;
+ UINT comp, row, row_len, n_rows, n_bytes, trash;
+ int iErrorCode;
+ static BOOL bDecoded;
+ const BYTE ycc_white[4] = { 255, 128, 128, 255 };
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwInputUsed = 0;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ *pdwOutputUsed = 0;
+ ret_val = IP_READY_FOR_DATA;
+
+ if (setjmp(g->syntax_error) != 0) {
+ PRINT (_T("got a syntax error\n"), 0, 0);
+ *pdwInputNextPos = g->dwInNextPos;
+ return IP_FATAL_ERROR | IP_INPUT_ERROR;
+ }
+
+ /**********************/
+ /* Parsing input data */
+ /**********************/
+
+ if (! g->sending_rows) {
+ if (pbInputBuf == NULL) {
+
+ /* We are being told to flush, so we should have consumed the EOI,
+ * and have discarded any bytes following it. */
+ if (! g->got_EOI) {
+ /* Unexpected end of data: we did not get an EOI */
+ ret_val |= IP_INPUT_ERROR;
+ }
+ ret_val |= IP_DONE;
+
+ } else if (g->got_EOI) {
+
+ /* Discard bytes after the EOI. We should report an error here, but
+ * the ASIC+firmware of Denali/Kodiak can send stuff after the EOI. */
+ *pdwInputUsed = dwInputAvail;
+
+ } else {
+
+ if (g->mcus_done == 0) {
+ /* init all row-buffers to white */
+ PRINT (_T("initing all row-buffers to white\n"), 0, 0);
+ for (comp=0; comp<g->num_comps; comp++) {
+ row_len = g->horiz_samp_facs[comp] * g->mcus_per_row * 8;
+ n_rows = g->vert_samp_facs[comp] * 8;
+
+ for (row=0; row<n_rows; row++)
+ memset (g->out_rows_ap[comp][row], ycc_white[comp], row_len);
+ }
+ }
+
+ do {
+ bDecoded = FALSE;
+ read_buf_open (g, pbInputBuf + *pdwInputUsed);
+ memcpy(&(g->old_syntax_error), &(g->syntax_error), sizeof(jmp_buf));
+ iErrorCode = setjmp(g->syntax_error);
+ if (iErrorCode == 0) {
+ bDecoded = decode_MCU(g);
+
+ /* Check for (and handle) a marker (DNL, RST, EOI).
+ * We need to handle DNL here so the sending_rows state below
+ * won't output the pad rows on the bottom of the image
+ */
+ if (! g->got_EOI) {
+ READ_BITS_LOAD (g, FALSE, 8, trash, at_a_marker);
+ goto no_marker;
+ at_a_marker:
+ handleMarkerInStream(g);
+ no_marker:;
+ }
+ }
+ memcpy(&(g->syntax_error), &(g->old_syntax_error), sizeof(jmp_buf));
+ n_bytes = read_buf_close (g);
+
+ *pdwInputUsed += n_bytes;
+ g->dwInNextPos += n_bytes;
+
+ if (*pdwInputUsed > dwInputAvail) {
+ /* Parser read past end of input buffer */
+ *pdwInputUsed = dwInputAvail;
+ g->dwInNextPos += dwInputAvail - n_bytes;
+ /* We will not make this a fatal error because that would
+ * immediately shut down the remaining xforms in the pipeline.
+ * Instead, we assume that the input data was truncated, and
+ * let the pipeline finish up normally so that it'll give a
+ * valid output file.
+ */
+ ret_val |= IP_INPUT_ERROR;
+ } else if (iErrorCode != 0) {
+ /* An error within the data: Make it fatal */
+ longjmp (g->syntax_error, iErrorCode);
+ } else if (g->got_EOI) {
+ ret_val |= IP_NEW_OUTPUT_PAGE;
+ /* Note: we should have just done the final MCU in a row, but
+ * we don't check for this because the firmware of Denali/Kodiak
+ * can't guarantee it. */
+ }
+
+ if (bDecoded) {
+ g->mcus_done += 1;
+
+ if (g->mcus_done >= g->mcus_per_row) {
+ PRINT (_T("done with row of MCUs; starting row-sends\n"), 0, 0);
+ g->sending_rows = TRUE;
+ g->mcus_done = 0;
+ }
+ }
+ } while (!g->got_EOI && !g->sending_rows &&
+ (dwInputAvail-*pdwInputUsed) >= MAX_MCU_SIZE);
+ }
+ }
+
+ /***************************/
+ /* Sending the output rows */
+ /***************************/
+
+ if (g->sending_rows) {
+ if (g->rows_done>=g->traits.lNumRows && g->traits.lNumRows>=0) {
+ /* we've already output all rows, so discard these */
+ g->sending_rows = FALSE;
+ } else {
+ copy_out_rows (
+ g,
+ g->rows_done % g->rows_per_mcu, /* in: index of next row to send */
+ pbOutputBuf, /* out: copied-out row data */
+ &n_rows, /* out: # of rows copied out */
+ &n_bytes); /* out: # of bytes output */
+ PRINT (_T("copied out %d rows\n"), n_rows, 0);
+ *pdwOutputUsed = n_bytes;
+ g->dwOutNextPos += n_bytes;
+ g->rows_done += n_rows;
+
+ if ((g->rows_done>=g->traits.lNumRows && g->traits.lNumRows>=0)
+ || (g->rows_done % g->rows_per_mcu)==0) {
+ g->sending_rows = FALSE;
+ }
+ /* n_rows is 1, unless the never-used output_subsampled feature is used */
+ if (n_rows > 0)
+ ret_val |= IP_CONSUMED_ROW | IP_PRODUCED_ROW;
+ }
+ }
+
+ *pdwInputNextPos = g->dwInNextPos;
+
+ PRINT (_T("jpeg_decode_convert_row: Returning %04x, in_used=%d\n"),
+ ret_val, *pdwInputUsed);
+ return ret_val;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PJDEC_INST g;
+ BYTE **row_pp, **after_pp, *p;
+
+ HANDLE_TO_PTR (hXform, g);
+ PRINT (_T("jpeg_decode_close\n"), 0, 0);
+
+ row_pp = &(g->out_rows_ap[0][0]);
+ after_pp = row_pp + (sizeof(g->out_rows_ap)/sizeof(BYTE *));
+
+ for ( ; row_pp<after_pp; row_pp++) {
+ p = *row_pp;
+ if (p != NULL) {
+ IP_MEM_FREE (p);
+ *row_pp = NULL;
+ }
+ }
+
+ huff_free_all (g);
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_getRowCountInfo - Returns information for determining row count
+ *
+\*****************************************************************************/
+
+WORD jpgDecode_getRowCountInfo(IP_XFORM_HANDLE hXform,
+ int *pRcCountup,int *pRcTraits,int *pSofOffset)
+{
+ PJDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pRcCountup=g->rows_done;
+ *pRcTraits=g->traits.lNumRows;
+ *pSofOffset=g->rowCountOffset;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecodeTbl - Jump-table for decoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL jpgDecodeTbl = {
+ jpgDecode_openXform,
+ jpgDecode_setDefaultInputTraits,
+ jpgDecode_setXformSpec,
+ jpgDecode_getHeaderBufSize,
+ jpgDecode_getActualTraits,
+ jpgDecode_getActualBufSizes,
+ jpgDecode_convert,
+ jpgDecode_newPage,
+ jpgDecode_insertedData,
+ jpgDecode_closeXform
+};
+
+/* End of File */
+
+
+
+
+
+
+
+
+
+
diff --git a/ip/xjpg_enc.c b/ip/xjpg_enc.c
new file mode 100644
index 0000000..a65bddb
--- /dev/null
+++ b/ip/xjpg_enc.c
@@ -0,0 +1,2184 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*****************************************************************************\
+ *
+ * xjpg_enc.c - Converts raw gray image into a valid JPEG file
+ *
+ *****************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * jpgEncodeTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_JPG_ENCODE_QUALITY_FACTORS]:
+ * Quality factors. Each 1..255 (best..worst), normal=20 or 0.
+ * If 2nd least significant byte is non-zero, then it is the
+ * DC factor, and lsb is the AC factor. If 2nd lsb is zero,
+ * then the lsb is both AC and DC factor. Q factors match PML.
+ * aXformInfo[IP_JPG_ENCODE_SAMPLE_FACTORS]:
+ * Sample factors in nibbles: HHHHVVVV, 0 means use defaults.
+ * aXformInfo[IP_JPG_ENCODE_ALREADY_SUBSAMPLED]:
+ * Is raw data already subsampled? 0=no, 1=yes.
+ * aXformInfo[IP_JPG_ENCODE_FOR_DENALI]:
+ * Output is for Denali? 0=no, 1=yes
+ * aXformInfo[IP_JPG_ENCODE_OUTPUT_DNL]:
+ * Output a DNL (Define Number of Lines) marker? 0=no, 1=yes.
+ * aXformInfo[IP_JPG_ENCODE_FOR_COLOR_FAX]:
+ * Output an APP1 per the G3 color fax standard? 0=no, 1=yes.
+ * aXformInfo[IP_JPG_ENCODE_DUMMY_HEADER_LEN]:
+ * # bytes in dummy header. 0 means output normal header.
+ * The firmware discards the header in the first raster data
+ * record. This value is the # data bytes in that record.
+ * This MUST be zero for JPEG files not being sent to firmware.
+ *
+ * The aXformInfo items above may all be set to 0 for typical JPEG files.
+ *
+ * For Denali, the JPEG that's output will be changed thusly:
+ * - An EOB will always follow every 8x8 block
+ * - A small change in the Huffman tables (no 15-bit codes)
+ *
+ * Capabilities and Limitations:
+ *
+ * Encodes a standard JPEG file with a JFIF 1.0 marker.
+ * Will *not* output a non-interleaved file; it's interleaved only.
+ * If the number of rows was unknown in the input traits, this encoder
+ * seeks back to the beginning of the file and fills in the row-count.
+ * A DNL is always output if the always-output-DNL item is set in
+ * the aXformInfo array above.
+ * Handles 8-bit gray, or 3-component 24-bit color.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel * must be 1 or 3 same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Jan 1998: Ported to Image Processor module of Windows software.
+ * Feb 1996: Written for firmware, Mark Overton;
+ * sections of this code were ported from HP-Labs (Hugh P. Nguyen).
+ *
+\*****************************************************************************/
+
+#include <string.h>
+#include "hpip.h"
+#include "ipdefs.h"
+#include "xjpg_dct.h"
+#include "xjpg_mrk.h"
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stdout, _T("(jpeg) ") msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+
+#define RUN_OF_16 0xf0 /* RLE code for run-of-16-zeroes */
+#define MAX_HEADER_SIZE 2000
+#define MAX_BLOCKS_IN_MCU 6
+#define MAX_MCU_SIZE (MAX_BLOCKS_IN_MCU*304)
+ /* max encoded MCU size, plus stuff-bytes */
+#define OUTBUF_NUM_MCUS 2 /* workbuf will be this multiple of max MCU */
+
+#define Q_DEFAULT 20 /* default quality-factor */
+#define MONO_FACTORS 0x10001000u /* default mono sample factors */
+#define COLOR_FACTORS 0x21102110u /* default color sample factors */
+
+#define CHECK_VALUE 0xAceC0de4U
+
+
+/*____________________________________________________________________________
+ | |
+ | Configuration Variables |
+ |____________________________________________________________________________|
+*/
+
+/* Encoding is centered around in_rows_ap. It is indexed by
+ * [color_component_number][row_number].
+ * color_component_number 0 is Y (intensity); mono only has this component.
+ *
+ * Each component in in_rows_ap has a height (# rows) equal to the number of
+ * samples in the MCU, and a width equal to the number of samples in all the
+ * MCUs in a row. That is, pixels are stored in in_rows_ap with NO REPLICATION.
+ * So if a component has sample factors of H and V, it will have 8*V rows and
+ * pixels_in_row*H/max_horiz_sam_fac columns in in_rows_ap.
+ */
+
+typedef struct {
+
+ /**** Configuration ****/
+
+ BYTE lum_quant[64];
+ BYTE chrom_quant[64];
+
+ int wino_lum_quant[64];
+ int wino_lum_quant_thres[64];
+ int wino_chrom_quant[64];
+ int wino_chrom_quant_thres[64];
+
+ BOOL input_subsampled;
+ BOOL fDenali;
+ BOOL fOutputDNL;
+ BOOL fOutputG3APP1;
+ DWORD dwDummyHeaderBytes;
+ UINT rows_in_mcu; /* # rows & cols in each MCU */
+ UINT cols_in_mcu;
+ UINT mcus_in_row; /* # of MCUs in each row */
+ DWORD sample_factors; /* H and V sample factors, one/nibble */
+ BYTE horiz_sam_facs[4]; /* horizontal sampling factors */
+ BYTE vert_sam_facs [4]; /* vertical sampling factors */
+ BYTE max_horiz_sam_fac; /* max sample factors */
+ BYTE max_vert_sam_fac;
+ BYTE dc_q_factor;
+ BYTE ac_q_factor;
+ BYTE comps_in_pixel; /* # components per pixel (1 or 3) */
+ BYTE whitePixel[4]; /* the value of a white pixel */
+ UINT pixels_in_row;
+ int rows_in_page; /* negative means "unknown" */
+ int xRes; /* dots per inch */
+ int yRes;
+
+ /**** Writing Bits ****/
+
+ DWORD wr_bit_buf;
+ /* Bits to be written to outbuf (accumulated left-to-right). */
+
+ int wr_bits_avail;
+ /* Number of bits not yet written in wr_bit_buf (= 32 - number written). */
+
+ BYTE *wr_outbuf_beg;
+ /* The beginning of the output buffer. */
+
+ BYTE *write_buf_next;
+ /* Next byte in outbuf to be written. */
+
+ /**** Encoding Blocks ****/
+
+ int enc_block[64]; /* scratch-pad 8x8 block */
+ int *enc_block_zz[64+16]; /* zig-zag ptrs into above block */
+ int prior_DC[4];
+
+ /**** Top Level Control ****/
+
+ UINT rows_received;
+ UINT rows_loaded;
+ UINT mcus_sent;
+ BOOL loading_rows;
+
+ /**** Miscellaneous ****/
+
+ IP_IMAGE_TRAITS traits;
+ BYTE *in_rows_ap[4][32]; /* row-buffers [component][row] */
+ BOOL fDidHeader; /* output the header yet? */
+ DWORD dwInNextPos; /* next read pos in input file */
+ DWORD dwOutNextPos; /* next write pos in output file */
+ DWORD dwValidChk; /* struct validity check value */
+
+} JENC_INST, *PJENC_INST;
+
+
+/*____________________________________________________________________________
+ | |
+ | Normal Quantization Tables |
+ |____________________________________________________________________________|
+*/
+
+#if 0
+
+static const BYTE orig_lum_quant[64] = {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+};
+
+
+static const BYTE orig_chrom_quant[64] = {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+#endif
+
+
+/*____________________________________________________________________________
+ | |
+ | Zigzag of Normal Quantization Tables |
+ |____________________________________________________________________________|
+*/
+
+static const BYTE orig_lum_quant[64] = {
+ #if 0
+ /* these make color fax look better, but break gray copy
+ * because JPEG is sent to the device, so our tables must
+ * match those in the firmware
+ */
+ 10, 10, 10, 14, 12, 10, 16, 14,
+ #else
+ 16, 11, 12, 14, 12, 10, 16, 14,
+ #endif
+ 13, 14, 18, 17, 16, 19, 24, 40,
+ 26, 24, 22, 22, 24, 49, 35, 37,
+ 29, 40, 58, 51, 61, 60, 57, 51,
+ 56, 55, 64, 72, 92, 78, 64, 68,
+ 87, 69, 55, 56, 80, 109, 81, 87,
+ 95, 98, 103, 104, 103, 62, 77, 113,
+ 121, 112, 100, 120, 92, 101, 103, 99
+};
+
+
+static const BYTE orig_chrom_quant[64] = {
+ #if 0
+ 10, 14, 14, 24, 21, 24, 47, 26,
+ #else
+ 17, 18, 18, 24, 21, 24, 47, 26,
+ #endif
+ 26, 47, 99, 66, 56, 66, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+
+/*____________________________________________________________________________
+ | | |
+ | codesize_array | Array giving # of bits required to represent the index |
+ |________________|___________________________________________________________|
+*/
+
+static const BYTE codesize_array[256] = {
+ 0,
+ 1,
+ 2, 2,
+ 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
+};
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Huffman Tables |
+ |____________________________________________________________________________|
+*/
+
+static const BYTE lum_DC_counts[16] = {
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const BYTE lum_DC_values[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+};
+
+static const BYTE chrom_DC_counts[16] = {
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const BYTE chrom_DC_values[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+};
+
+static const BYTE lum_AC_counts[16] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d
+};
+
+static const BYTE lum_AC_counts_Denali[16] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x00, 0x7e
+ /* Above, the [01,7d] in the normal table was changed to [00,7e].
+ * This alteration eliminates the sole 15-bit code, and yields
+ * Huffman codes as follows:
+ * - common codes are 12 bits wide or less,
+ * - uncommon codes are exactly 16 bits wide, and all those codes
+ * start with nine '1' bits, leaving seven bits of useful info.
+ * Denali uses a 4K-entry table for the common codes, and a
+ * quick lookup for the 7-bit leftover codes. So parsing of all
+ * codes is simple and fast.
+ */
+};
+
+static const BYTE lum_AC_values[162] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+static const BYTE chrom_AC_counts[16] = {
+ 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+ 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77
+};
+
+static const BYTE chrom_AC_values[162] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Huffman tables output by mk_jpg_huff program |
+ |____________________________________________________________________________|
+*/
+
+typedef struct {
+ WORD code; /* the Huff code to use */
+ BYTE size; /* number of bits in above Huff code */
+} huff_elem_t;
+
+
+static const huff_elem_t lum_DC_table[] = {
+ { 0x0000, 2 }, { 0x0002, 3 }, { 0x0003, 3 }, { 0x0004, 3 },
+ { 0x0005, 3 }, { 0x0006, 3 }, { 0x000e, 4 }, { 0x001e, 5 },
+ { 0x003e, 6 }, { 0x007e, 7 }, { 0x00fe, 8 }, { 0x01fe, 9 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, };
+
+
+static const huff_elem_t lum_AC_table[] = {
+ { 0x000a, 4 }, { 0x0000, 2 }, { 0x0001, 2 }, { 0x0004, 3 },
+ { 0x000b, 4 }, { 0x001a, 5 }, { 0x0078, 7 }, { 0x00f8, 8 },
+ { 0x03f6, 10 }, { 0xff82, 16 }, { 0xff83, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x000c, 4 }, { 0x001b, 5 }, { 0x0079, 7 },
+ { 0x01f6, 9 }, { 0x07f6, 11 }, { 0xff84, 16 }, { 0xff85, 16 },
+ { 0xff86, 16 }, { 0xff87, 16 }, { 0xff88, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x001c, 5 }, { 0x00f9, 8 }, { 0x03f7, 10 },
+ { 0x0ff4, 12 }, { 0xff89, 16 }, { 0xff8a, 16 }, { 0xff8b, 16 },
+ { 0xff8c, 16 }, { 0xff8d, 16 }, { 0xff8e, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x003a, 6 }, { 0x01f7, 9 }, { 0x0ff5, 12 },
+ { 0xff8f, 16 }, { 0xff90, 16 }, { 0xff91, 16 }, { 0xff92, 16 },
+ { 0xff93, 16 }, { 0xff94, 16 }, { 0xff95, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x003b, 6 }, { 0x03f8, 10 }, { 0xff96, 16 },
+ { 0xff97, 16 }, { 0xff98, 16 }, { 0xff99, 16 }, { 0xff9a, 16 },
+ { 0xff9b, 16 }, { 0xff9c, 16 }, { 0xff9d, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x007a, 7 }, { 0x07f7, 11 }, { 0xff9e, 16 },
+ { 0xff9f, 16 }, { 0xffa0, 16 }, { 0xffa1, 16 }, { 0xffa2, 16 },
+ { 0xffa3, 16 }, { 0xffa4, 16 }, { 0xffa5, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x007b, 7 }, { 0x0ff6, 12 }, { 0xffa6, 16 },
+ { 0xffa7, 16 }, { 0xffa8, 16 }, { 0xffa9, 16 }, { 0xffaa, 16 },
+ { 0xffab, 16 }, { 0xffac, 16 }, { 0xffad, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x00fa, 8 }, { 0x0ff7, 12 }, { 0xffae, 16 },
+ { 0xffaf, 16 }, { 0xffb0, 16 }, { 0xffb1, 16 }, { 0xffb2, 16 },
+ { 0xffb3, 16 }, { 0xffb4, 16 }, { 0xffb5, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01f8, 9 }, { 0x7fc0, 15 }, { 0xffb6, 16 },
+ { 0xffb7, 16 }, { 0xffb8, 16 }, { 0xffb9, 16 }, { 0xffba, 16 },
+ { 0xffbb, 16 }, { 0xffbc, 16 }, { 0xffbd, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01f9, 9 }, { 0xffbe, 16 }, { 0xffbf, 16 },
+ { 0xffc0, 16 }, { 0xffc1, 16 }, { 0xffc2, 16 }, { 0xffc3, 16 },
+ { 0xffc4, 16 }, { 0xffc5, 16 }, { 0xffc6, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01fa, 9 }, { 0xffc7, 16 }, { 0xffc8, 16 },
+ { 0xffc9, 16 }, { 0xffca, 16 }, { 0xffcb, 16 }, { 0xffcc, 16 },
+ { 0xffcd, 16 }, { 0xffce, 16 }, { 0xffcf, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x03f9, 10 }, { 0xffd0, 16 }, { 0xffd1, 16 },
+ { 0xffd2, 16 }, { 0xffd3, 16 }, { 0xffd4, 16 }, { 0xffd5, 16 },
+ { 0xffd6, 16 }, { 0xffd7, 16 }, { 0xffd8, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x03fa, 10 }, { 0xffd9, 16 }, { 0xffda, 16 },
+ { 0xffdb, 16 }, { 0xffdc, 16 }, { 0xffdd, 16 }, { 0xffde, 16 },
+ { 0xffdf, 16 }, { 0xffe0, 16 }, { 0xffe1, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x07f8, 11 }, { 0xffe2, 16 }, { 0xffe3, 16 },
+ { 0xffe4, 16 }, { 0xffe5, 16 }, { 0xffe6, 16 }, { 0xffe7, 16 },
+ { 0xffe8, 16 }, { 0xffe9, 16 }, { 0xffea, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0xffeb, 16 }, { 0xffec, 16 }, { 0xffed, 16 },
+ { 0xffee, 16 }, { 0xffef, 16 }, { 0xfff0, 16 }, { 0xfff1, 16 },
+ { 0xfff2, 16 }, { 0xfff3, 16 }, { 0xfff4, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x07f9, 11 }, { 0xfff5, 16 }, { 0xfff6, 16 }, { 0xfff7, 16 },
+ { 0xfff8, 16 }, { 0xfff9, 16 }, { 0xfffa, 16 }, { 0xfffb, 16 },
+ { 0xfffc, 16 }, { 0xfffd, 16 }, { 0xfffe, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+};
+
+
+static const huff_elem_t lum_AC_table_Denali[] = {
+ { 0x000a, 4 }, { 0x0000, 2 }, { 0x0001, 2 }, { 0x0004, 3 },
+ { 0x000b, 4 }, { 0x001a, 5 }, { 0x0078, 7 }, { 0x00f8, 8 },
+ { 0x03f6, 10 }, { 0xff81, 16 }, { 0xff82, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x000c, 4 }, { 0x001b, 5 }, { 0x0079, 7 },
+ { 0x01f6, 9 }, { 0x07f6, 11 }, { 0xff83, 16 }, { 0xff84, 16 },
+ { 0xff85, 16 }, { 0xff86, 16 }, { 0xff87, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x001c, 5 }, { 0x00f9, 8 }, { 0x03f7, 10 },
+ { 0x0ff4, 12 }, { 0xff88, 16 }, { 0xff89, 16 }, { 0xff8a, 16 },
+ { 0xff8b, 16 }, { 0xff8c, 16 }, { 0xff8d, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x003a, 6 }, { 0x01f7, 9 }, { 0x0ff5, 12 },
+ { 0xff8e, 16 }, { 0xff8f, 16 }, { 0xff90, 16 }, { 0xff91, 16 },
+ { 0xff92, 16 }, { 0xff93, 16 }, { 0xff94, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x003b, 6 }, { 0x03f8, 10 }, { 0xff95, 16 },
+ { 0xff96, 16 }, { 0xff97, 16 }, { 0xff98, 16 }, { 0xff99, 16 },
+ { 0xff9a, 16 }, { 0xff9b, 16 }, { 0xff9c, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x007a, 7 }, { 0x07f7, 11 }, { 0xff9d, 16 },
+ { 0xff9e, 16 }, { 0xff9f, 16 }, { 0xffa0, 16 }, { 0xffa1, 16 },
+ { 0xffa2, 16 }, { 0xffa3, 16 }, { 0xffa4, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x007b, 7 }, { 0x0ff6, 12 }, { 0xffa5, 16 },
+ { 0xffa6, 16 }, { 0xffa7, 16 }, { 0xffa8, 16 }, { 0xffa9, 16 },
+ { 0xffaa, 16 }, { 0xffab, 16 }, { 0xffac, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x00fa, 8 }, { 0x0ff7, 12 }, { 0xffad, 16 },
+ { 0xffae, 16 }, { 0xffaf, 16 }, { 0xffb0, 16 }, { 0xffb1, 16 },
+ { 0xffb2, 16 }, { 0xffb3, 16 }, { 0xffb4, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01f8, 9 }, { 0xff80, 16 }, { 0xffb5, 16 },
+ { 0xffb6, 16 }, { 0xffb7, 16 }, { 0xffb8, 16 }, { 0xffb9, 16 },
+ { 0xffba, 16 }, { 0xffbb, 16 }, { 0xffbc, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01f9, 9 }, { 0xffbd, 16 }, { 0xffbe, 16 },
+ { 0xffbf, 16 }, { 0xffc0, 16 }, { 0xffc1, 16 }, { 0xffc2, 16 },
+ { 0xffc3, 16 }, { 0xffc4, 16 }, { 0xffc5, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01fa, 9 }, { 0xffc6, 16 }, { 0xffc7, 16 },
+ { 0xffc8, 16 }, { 0xffc9, 16 }, { 0xffca, 16 }, { 0xffcb, 16 },
+ { 0xffcc, 16 }, { 0xffcd, 16 }, { 0xffce, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x03f9, 10 }, { 0xffcf, 16 }, { 0xffd0, 16 },
+ { 0xffd1, 16 }, { 0xffd2, 16 }, { 0xffd3, 16 }, { 0xffd4, 16 },
+ { 0xffd5, 16 }, { 0xffd6, 16 }, { 0xffd7, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x03fa, 10 }, { 0xffd8, 16 }, { 0xffd9, 16 },
+ { 0xffda, 16 }, { 0xffdb, 16 }, { 0xffdc, 16 }, { 0xffdd, 16 },
+ { 0xffde, 16 }, { 0xffdf, 16 }, { 0xffe0, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x07f8, 11 }, { 0xffe1, 16 }, { 0xffe2, 16 },
+ { 0xffe3, 16 }, { 0xffe4, 16 }, { 0xffe5, 16 }, { 0xffe6, 16 },
+ { 0xffe7, 16 }, { 0xffe8, 16 }, { 0xffe9, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0xffea, 16 }, { 0xffeb, 16 }, { 0xffec, 16 },
+ { 0xffed, 16 }, { 0xffee, 16 }, { 0xffef, 16 }, { 0xfff0, 16 },
+ { 0xfff1, 16 }, { 0xfff2, 16 }, { 0xfff3, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x07f9, 11 }, { 0xfff4, 16 }, { 0xfff5, 16 }, { 0xfff6, 16 },
+ { 0xfff7, 16 }, { 0xfff8, 16 }, { 0xfff9, 16 }, { 0xfffa, 16 },
+ { 0xfffb, 16 }, { 0xfffc, 16 }, { 0xfffd, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+};
+
+
+static const huff_elem_t chrom_DC_table[] = {
+ { 0x0000, 2 }, { 0x0001, 2 }, { 0x0002, 2 }, { 0x0006, 3 },
+ { 0x000e, 4 }, { 0x001e, 5 }, { 0x003e, 6 }, { 0x007e, 7 },
+ { 0x00fe, 8 }, { 0x01fe, 9 }, { 0x03fe, 10 }, { 0x07fe, 11 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, };
+
+
+static const huff_elem_t chrom_AC_table[] = {
+ { 0x0000, 2 }, { 0x0001, 2 }, { 0x0004, 3 }, { 0x000a, 4 },
+ { 0x0018, 5 }, { 0x0019, 5 }, { 0x0038, 6 }, { 0x0078, 7 },
+ { 0x01f4, 9 }, { 0x03f6, 10 }, { 0x0ff4, 12 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x000b, 4 }, { 0x0039, 6 }, { 0x00f6, 8 },
+ { 0x01f5, 9 }, { 0x07f6, 11 }, { 0x0ff5, 12 }, { 0xff88, 16 },
+ { 0xff89, 16 }, { 0xff8a, 16 }, { 0xff8b, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x001a, 5 }, { 0x00f7, 8 }, { 0x03f7, 10 },
+ { 0x0ff6, 12 }, { 0x7fc2, 15 }, { 0xff8c, 16 }, { 0xff8d, 16 },
+ { 0xff8e, 16 }, { 0xff8f, 16 }, { 0xff90, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x001b, 5 }, { 0x00f8, 8 }, { 0x03f8, 10 },
+ { 0x0ff7, 12 }, { 0xff91, 16 }, { 0xff92, 16 }, { 0xff93, 16 },
+ { 0xff94, 16 }, { 0xff95, 16 }, { 0xff96, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x003a, 6 }, { 0x01f6, 9 }, { 0xff97, 16 },
+ { 0xff98, 16 }, { 0xff99, 16 }, { 0xff9a, 16 }, { 0xff9b, 16 },
+ { 0xff9c, 16 }, { 0xff9d, 16 }, { 0xff9e, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x003b, 6 }, { 0x03f9, 10 }, { 0xff9f, 16 },
+ { 0xffa0, 16 }, { 0xffa1, 16 }, { 0xffa2, 16 }, { 0xffa3, 16 },
+ { 0xffa4, 16 }, { 0xffa5, 16 }, { 0xffa6, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0079, 7 }, { 0x07f7, 11 }, { 0xffa7, 16 },
+ { 0xffa8, 16 }, { 0xffa9, 16 }, { 0xffaa, 16 }, { 0xffab, 16 },
+ { 0xffac, 16 }, { 0xffad, 16 }, { 0xffae, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x007a, 7 }, { 0x07f8, 11 }, { 0xffaf, 16 },
+ { 0xffb0, 16 }, { 0xffb1, 16 }, { 0xffb2, 16 }, { 0xffb3, 16 },
+ { 0xffb4, 16 }, { 0xffb5, 16 }, { 0xffb6, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x00f9, 8 }, { 0xffb7, 16 }, { 0xffb8, 16 },
+ { 0xffb9, 16 }, { 0xffba, 16 }, { 0xffbb, 16 }, { 0xffbc, 16 },
+ { 0xffbd, 16 }, { 0xffbe, 16 }, { 0xffbf, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01f7, 9 }, { 0xffc0, 16 }, { 0xffc1, 16 },
+ { 0xffc2, 16 }, { 0xffc3, 16 }, { 0xffc4, 16 }, { 0xffc5, 16 },
+ { 0xffc6, 16 }, { 0xffc7, 16 }, { 0xffc8, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01f8, 9 }, { 0xffc9, 16 }, { 0xffca, 16 },
+ { 0xffcb, 16 }, { 0xffcc, 16 }, { 0xffcd, 16 }, { 0xffce, 16 },
+ { 0xffcf, 16 }, { 0xffd0, 16 }, { 0xffd1, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01f9, 9 }, { 0xffd2, 16 }, { 0xffd3, 16 },
+ { 0xffd4, 16 }, { 0xffd5, 16 }, { 0xffd6, 16 }, { 0xffd7, 16 },
+ { 0xffd8, 16 }, { 0xffd9, 16 }, { 0xffda, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01fa, 9 }, { 0xffdb, 16 }, { 0xffdc, 16 },
+ { 0xffdd, 16 }, { 0xffde, 16 }, { 0xffdf, 16 }, { 0xffe0, 16 },
+ { 0xffe1, 16 }, { 0xffe2, 16 }, { 0xffe3, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x07f9, 11 }, { 0xffe4, 16 }, { 0xffe5, 16 },
+ { 0xffe6, 16 }, { 0xffe7, 16 }, { 0xffe8, 16 }, { 0xffe9, 16 },
+ { 0xffea, 16 }, { 0xffeb, 16 }, { 0xffec, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x3fe0, 14 }, { 0xffed, 16 }, { 0xffee, 16 },
+ { 0xffef, 16 }, { 0xfff0, 16 }, { 0xfff1, 16 }, { 0xfff2, 16 },
+ { 0xfff3, 16 }, { 0xfff4, 16 }, { 0xfff5, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x03fa, 10 }, { 0x7fc3, 15 }, { 0xfff6, 16 }, { 0xfff7, 16 },
+ { 0xfff8, 16 }, { 0xfff9, 16 }, { 0xfffa, 16 }, { 0xfffb, 16 },
+ { 0xfffc, 16 }, { 0xfffd, 16 }, { 0xfffe, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+};
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ WRITING-BITS SECTION
+
+ ******************************************************************************
+ ******************************************************************************
+
+
+ Interface into this section:
+
+ write_init - inits this section
+ write_buf_open - we are being given a (new) output buffer
+ write_buf_close - done with current output buffer; return # bytes sent
+ write_buf_next - (a var) the next byte to write in the output buffer
+ WRITE_BITS_OPEN - setup code for WRITE_BITS
+ WRITE_BITS - outputs bits (fast)
+ WRITE_BITS_HIZERO - outputs bits (faster) assuming higher-order bits are 0
+ WRITE_BITS_CLOSE - teardown code for WRITE_BITS
+ write_bits_flush - flushes the bit-cache
+
+ ******************************************************************************/
+
+
+
+#define INITIAL_BITS_AVAIL (8*sizeof(DWORD))
+ /* Number of bits in wr_bit_buf, which is the # of bits in a DWORD . */
+
+
+/*____________________________________________________________________________
+ | | |
+ | PUT_BYTE_STUFF | Puts byte into outbuf, with byte-stuffing as needed |
+ |________________|___________________________________________________________|
+ | |
+ | A 0xff byte within bit-data is always followed by a 0x00 byte to |
+ | distinguish it from markers, which are 0xff followed by a non-zero byte. |
+ | Therefore, PUT_BYTE_STUFF should never be used to write markers. |
+ |____________________________________________________________________________|
+*/
+#define PUT_BYTE_STUFF(g, pbs_byte_expression) { \
+ BYTE pbs_byte; \
+ \
+ pbs_byte = (BYTE)(pbs_byte_expression); \
+ *(g->write_buf_next)++ = pbs_byte; \
+ if (pbs_byte == (BYTE)0xff) \
+ *(g->write_buf_next)++ = 0; \
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | write_init | Inits this package, and registers the "write bytes" callback |
+ |____________|_______________________________________________________________|
+*/
+static void write_init (PJENC_INST g)
+{
+ g->wr_bits_avail = INITIAL_BITS_AVAIL;
+ g->wr_bit_buf = 0;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | write_buf_open | We are being given a (new) buffer to receive output |
+ |________________|___________________________________________________________|
+ | |
+ | This routine records the location of the new output buffer. |
+ |____________________________________________________________________________|
+*/
+static void write_buf_open (PJENC_INST g, BYTE *buf_p)
+{
+ g->wr_outbuf_beg = g->write_buf_next = buf_p;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | write_buf_close | We are done with the current output buffer |
+ |_________________|__________________________________________________________|
+ | |
+ | This function returns # bytes written to the output buffer |
+ |____________________________________________________________________________|
+*/
+static int write_buf_close (PJENC_INST g)
+{
+ return g->write_buf_next - g->wr_outbuf_beg;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | WRITE_BITS | Writes the given number of bits |
+ |____________|_______________________________________________________________|
+ | |
+ | WRITE_BITS_HIZERO assumes that the higher-order bits are all zero. |
+ | WRITE_BITS masks them out for you. |
+ |____________________________________________________________________________|
+*/
+
+#define WRITE_BITS_OPEN(g) \
+ int tmp_bits_avail = g->wr_bits_avail; \
+ DWORD tmp_bit_buf = g->wr_bit_buf;
+
+
+#define WRITE_BITS_HIZERO(g,wb_value,wb_nbits) { \
+ DWORD bits_loc; \
+ int length_loc; \
+ \
+ length_loc = (int)(wb_nbits); \
+ bits_loc = (DWORD)(wb_value); \
+ \
+ if (length_loc > tmp_bits_avail) { \
+ do { \
+ PUT_BYTE_STUFF (g, tmp_bit_buf >> 24) \
+ tmp_bit_buf <<= 8; \
+ tmp_bits_avail += 8; \
+ } while (tmp_bits_avail <= 24); \
+ } \
+ \
+ tmp_bits_avail -= length_loc; \
+ tmp_bit_buf |= bits_loc << tmp_bits_avail; \
+}
+
+
+#define WRITE_BITS(g,wb_value,wb_nbits) { \
+ int len_loc; \
+ \
+ len_loc = (int)(wb_nbits); \
+ WRITE_BITS_HIZERO (g, (DWORD )(wb_value) & ((1ul<<len_loc)-1), len_loc) \
+}
+
+
+#define WRITE_BITS_CLOSE(g) { \
+ g->wr_bits_avail = tmp_bits_avail; \
+ g->wr_bit_buf = tmp_bit_buf; \
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | write_bits_flush | Writes any buffered bits, with buffering via outbuf |
+ |__________________|_________________________________________________________|
+ | |
+ | Bits are right-padded with ones if necessary to a byte-boundary. |
+ |____________________________________________________________________________|
+*/
+static void write_bits_flush (PJENC_INST g)
+{
+ int bits_used;
+
+ if (g->wr_bits_avail != INITIAL_BITS_AVAIL) {
+ /* JPEG wants pad-bits to be 1's */
+ g->wr_bit_buf |= ((DWORD )1 << g->wr_bits_avail) - 1;
+
+ for (bits_used = INITIAL_BITS_AVAIL - g->wr_bits_avail;
+ bits_used > 0;
+ bits_used -= 8) {
+ PUT_BYTE_STUFF (g, g->wr_bit_buf >> 24)
+ g->wr_bit_buf <<= 8;
+ }
+
+ g->wr_bits_avail = INITIAL_BITS_AVAIL;
+ g->wr_bit_buf = 0;
+ }
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ MARKERS SECTION
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Macros |
+ |____________________________________________________________________________|
+*/
+
+
+#define PUT_MARKER(g,marker) \
+do { \
+ *(g->write_buf_next)++ = 0xff; \
+ *(g->write_buf_next)++ = (BYTE)marker; \
+} while (0)
+
+
+#define PUT_INT(g,value) \
+do { \
+ unsigned loc_val = (unsigned)(value); \
+ *(g->write_buf_next)++ = loc_val >> 8; \
+ *(g->write_buf_next)++ = loc_val & 0xff; \
+} while (0)
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | em_write_SOI | Writes Start-Of-Image marker |
+ |______________|_____________________________________________________________|
+*/
+static void em_write_SOI (PJENC_INST g)
+{
+ PUT_MARKER(g, MARKER_SOI);
+}
+
+
+/*____________________________________________________________________________
+ | | |
+ | em_write_EOI | Writes End-Of-Image marker |
+ |______________|_____________________________________________________________|
+*/
+static void em_write_EOI (PJENC_INST g)
+{
+ PUT_MARKER(g, MARKER_EOI);
+}
+
+
+/*____________________________________________________________________________
+ | | |
+ | em_write_JFIF_APP0 | Writes Application marker for JFIF 1,0 |
+ |____________________|_______________________________________________________|
+*/
+static void em_write_JFIF_APP0 (
+ PJENC_INST g,
+ int xRes, /* X resolution of image (number of pixels per inch) */
+ int yRes) /* Y resolution of image (number of pixels per inch) */
+{
+ PUT_MARKER (g, MARKER_APP+0);
+ PUT_INT (g, 16); /* the length */
+
+ /*** ID ***/
+ *(g->write_buf_next)++ = 'J';
+ *(g->write_buf_next)++ = 'F';
+ *(g->write_buf_next)++ = 'I';
+ *(g->write_buf_next)++ = 'F';
+ *(g->write_buf_next)++ = '\0';
+
+ /*** Version 1.0 ***/
+ *(g->write_buf_next)++ = 0x01;
+ *(g->write_buf_next)++ = 0x00;
+
+ /*** Units (dots per inch) ***/
+ *(g->write_buf_next)++ = 0x01;
+
+ PUT_INT(g, xRes);
+ PUT_INT(g, yRes);
+
+ /*** Thumbnail X and Y ***/
+ *(g->write_buf_next)++ = 0x00;
+ *(g->write_buf_next)++ = 0x00;
+}
+
+
+/*____________________________________________________________________________
+ | | |
+ | em_write_G3_APP1 | Writes Application marker for G3 color fax standard |
+ |__________________|_________________________________________________________|
+*/
+static void em_write_G3_APP1 (
+ PJENC_INST g,
+ int res) /* resolution of image (number of pixels per inch) */
+{
+ res = ((res+50)/100)*100; /* round res to the nearest 100 */
+
+ PUT_MARKER (g, MARKER_APP+1);
+ PUT_INT (g, 12); /* the length */
+
+ /*** ID ***/
+ *(g->write_buf_next)++ = 'G';
+ *(g->write_buf_next)++ = '3';
+ *(g->write_buf_next)++ = 'F';
+ *(g->write_buf_next)++ = 'A';
+ *(g->write_buf_next)++ = 'X';
+ *(g->write_buf_next)++ = 0;
+
+ PUT_INT (g, 1994); /* version is year the std was approved */
+ PUT_INT (g, res); /* finally, the DPI */
+}
+
+
+/*____________________________________________________________________________
+ | | |
+ | em_write_SOF | Writes Start-Of-Frame marker |
+ |______________|_____________________________________________________________|
+*/
+static void em_write_SOF (
+ PJENC_INST g,
+ int width, /* width of image (number of pixels per row) */
+ int height, /* height of image (number of rows) */
+ int ncomps, /* # of color components; 1 is gray, 3 is color */
+ BYTE h_sam_facs[], /* horizontal sampling factors */
+ BYTE v_sam_facs[]) /* vertical sampling factors */
+{
+ int i;
+
+ PUT_MARKER(g, MARKER_SOF0);
+ PUT_INT(g, 8 + ncomps*3); /* the length */
+ *(g->write_buf_next)++ = 8;
+ PUT_INT(g, height);
+ PUT_INT(g, width);
+ *(g->write_buf_next)++ = ncomps;
+
+ for (i=0; i<ncomps; i++) {
+ *(g->write_buf_next)++ = i;
+ *(g->write_buf_next)++ = h_sam_facs[i]<<4 | v_sam_facs[i];
+ *(g->write_buf_next)++ = (i==0 ? 0 : 1);
+ }
+}
+
+
+/*____________________________________________________________________________
+ | | |
+ | em_write_DQT | Writes Define-Quantization-Table marker |
+ |______________|_____________________________________________________________|
+*/
+static void em_write_DQT (
+ PJENC_INST g,
+ int precision, /* 0 = 8-bit, 1 = 16-bit */
+ int ident, /* which table, 0-3 */
+ BYTE elements[64])
+{
+ PUT_MARKER(g, MARKER_DQT);
+ PUT_INT(g, 67); /* the length */
+ *(g->write_buf_next)++ = (precision << 4) + ident;
+ memcpy (g->write_buf_next, elements, 64);
+ g->write_buf_next += 64;
+}
+
+
+/*____________________________________________________________________________
+ | | |
+ | em_write_DHTs | Writes Define-Huffman-Tables marker |
+ |_______________|____________________________________________________________|
+*/
+static void em_write_DHTs (
+ PJENC_INST g,
+ int ntables, /* number of tables */
+ BYTE hclass[], /* 0 = DC or lossless table, 1 = AC table */
+ BYTE ident[], /* 0-3 = which Huffman table this is */
+ const BYTE *counts[], /* # Huffman codes of lengths 1-16 */
+ const BYTE *huffval[]) /* list of associated values */
+{
+ int nvals, i, j;
+
+ nvals = 0;
+ for (i=0; i<ntables; i++) {
+ for (j=0; j<16; j++)
+ nvals += counts[i][j];
+ }
+
+ PUT_MARKER(g, MARKER_DHT);
+ PUT_INT(g, 2 + 17*ntables + nvals); /* the length */
+
+ for (i=0; i<ntables; i++) {
+ for (nvals=j=0; j<16; j++)
+ nvals += counts[i][j];
+
+ *(g->write_buf_next)++ = hclass[i]<<4 | ident[i];
+ for (j=0; j<16; j++) *(g->write_buf_next)++ = counts[i][j];
+ for (j=0; j<nvals; j++) *(g->write_buf_next)++ = huffval[i][j];
+ }
+}
+
+
+/*____________________________________________________________________________
+ | | |
+ | em_write_SOS | Writes Start-Of-Scan marker |
+ |______________|_____________________________________________________________|
+*/
+static void em_write_SOS (
+ PJENC_INST g,
+ int ncomps) /* number of color components; 1 (gray) or 3 (color) */
+{
+ int i;
+
+ PUT_MARKER(g, MARKER_SOS);
+ PUT_INT(g, 6 + 2*ncomps); /* the length */
+ *(g->write_buf_next)++ = ncomps;
+
+ for (i=0; i<ncomps; i++) {
+ *(g->write_buf_next)++ = i;
+ *(g->write_buf_next)++ = (i==0 ? 0x00 : 0x11);
+ }
+
+ *(g->write_buf_next)++ = 0;
+ *(g->write_buf_next)++ = 63;
+ *(g->write_buf_next)++ = 0;
+}
+
+
+/*____________________________________________________________________________
+ | | |
+ | em_write_DNL | Writes Define-Number-of-Lines marker |
+ |______________|_____________________________________________________________|
+*/
+static void em_write_DNL (
+ PJENC_INST g,
+ int nlines) /* number of lines (raster rows) in the JPEG file */
+{
+ PUT_MARKER(g, MARKER_DNL);
+ PUT_INT(g, 4); /* the length */
+ PUT_INT(g, nlines);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | em_write_short_header | Writes a short non-standard header |
+ |_______________________|____________________________________________________|
+ | |
+ | This header is also output by the firmware, and is only in this |
+ | JPEG encoder for testing purposes. |
+ |____________________________________________________________________________|
+*/
+static void em_write_short_header (
+ PJENC_INST g,
+ UINT rows_in_page,
+ UINT pixels_in_row,
+ UINT xRes,
+ UINT yRes,
+ UINT dc_q_factor,
+ UINT ac_q_factor,
+ UINT comps_in_pixel,
+ DWORD sample_factors)
+{
+ PUT_MARKER (g, MARKER_SHORT_HEADER);
+ PUT_INT (g, 18); /* the length */
+ PUT_INT (g, rows_in_page);
+ PUT_INT (g, pixels_in_row);
+ PUT_INT (g, xRes);
+ PUT_INT (g, yRes);
+ *(g->write_buf_next)++ = ac_q_factor * 5 / 2;
+ *(g->write_buf_next)++ = comps_in_pixel;
+ PUT_INT (g, sample_factors >> 16); /* horiz sample factors */
+ PUT_INT (g, sample_factors & 0x0000ffffu); /* vert sample factors */
+ *(g->write_buf_next)++ = dc_q_factor * 5 / 2;
+ *(g->write_buf_next)++ = 0; /* reserved for future use */
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ WINOGRAD DCT SECTION
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+#define BITS_IN_DCT_FRAC 15
+#define ROUND(x) (((x)+(1l<<(BITS_IN_DCT_FRAC-1))) >> BITS_IN_DCT_FRAC)
+
+
+/*____________________________________________________________________________
+ | | |
+ | As table | The As multiplication constants used in the Winograd transform |
+ |__________|_________________________________________________________________|
+ | |
+ | These have 15 bits of fraction. |
+ |____________________________________________________________________________|
+*/
+#define a1 23170L
+#define a2 17734L
+#define a3 23170L
+#define a4 42813L
+#define a5 12540L
+
+
+/*____________________________________________________________________________
+ | | |
+ | wino_norm_tbl | DCT scale-factors; this table has been zigzagged |
+ |_______________|____________________________________________________________|
+*/
+/* todo: do this in fixed-point (see image_proc.c in firmware) */
+static float const wino_norm_tbl[] = {
+ 0.125000f, 0.090120f, 0.090120f, 0.095671f,
+ 0.064973f, 0.095671f, 0.106304f, 0.068975f,
+ 0.068975f, 0.106304f, 0.125000f, 0.076641f,
+ 0.073223f, 0.076641f, 0.125000f, 0.159095f,
+ 0.090120f, 0.081361f, 0.081361f, 0.090120f,
+ 0.159095f, 0.230970f, 0.114701f, 0.095671f,
+ 0.090404f, 0.095671f, 0.114701f, 0.230970f,
+ 0.453064f, 0.166520f, 0.121766f, 0.106304f,
+ 0.106304f, 0.121766f, 0.166520f, 0.453064f,
+ 0.326641f, 0.176777f, 0.135299f, 0.125000f,
+ 0.135299f, 0.176777f, 0.326641f, 0.346760f,
+ 0.196424f, 0.159095f, 0.159095f, 0.196424f,
+ 0.346760f, 0.385299f, 0.230970f, 0.202489f,
+ 0.230970f, 0.385299f, 0.453064f, 0.293969f,
+ 0.293969f, 0.453064f, 0.576641f, 0.426777f,
+ 0.576641f, 0.837153f, 0.837153f, 1.642134f
+};
+
+
+/*____________________________________________________________________________
+ | | |
+ | scale_for_wino | Computes quant-table and threshold-table for Wino's DCT |
+ |________________|___________________________________________________________|
+*/
+static void scale_for_wino (
+ BYTE *in, /* in: regular quantization table */
+ int *out, /* out: winograd quantization table */
+ int *thresh) /* out: threshold table */
+{
+ #define FIX(x) ((long) ((x)*(1l<<BITS_IN_DCT_FRAC) + 0.5))
+ float const *fptr;
+ int i, q;
+
+ /* Note that in order for FIX(fptr[i]/in[i]) to fit inside 16-bit signed
+ * int, (fptr[i]/in[i] < 1) => (in[i] > fptr[i]) (1). Since in[i] >= 1,
+ * and (fptr[i] < 1) for i = 0 to 62, (1) is true for i = 0 to 62. For
+ * i = 63, (1) is true only when in[63] >= 2
+ */
+ if (in[63] < 2) in[63] = 2;
+
+ fptr = wino_norm_tbl;
+ for (i=0; i<64; i++) {
+ q = FIX (*fptr++ / (float)(*in++));
+ *out++ = q;
+ if (q == 0) *thresh++ = 32767;
+ else *thresh++ = (1 << (BITS_IN_DCT_FRAC-1)) / q;
+ }
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ E N C O D I N G
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+static const BYTE zigzag_index_table[64] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+
+#define WRITE_HUFF_CODE(g,val,huffman) { \
+ int whc_val = (int)(val); \
+ WRITE_BITS_HIZERO (g, huffman[whc_val].code, huffman[whc_val].size) \
+}
+
+
+
+static void zero_prior_DC (PJENC_INST g)
+{
+ g->prior_DC[0] = g->prior_DC[1] = g->prior_DC[2] = g->prior_DC[3] = 0;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | encode_init | Inits this section |
+ |_____________|______________________________________________________________|
+*/
+static void encode_init (PJENC_INST g)
+{
+ BYTE const *zig_p;
+ int **block_pp;
+
+ zig_p = zigzag_index_table;
+ for (block_pp=g->enc_block_zz; block_pp<g->enc_block_zz+(64+16); block_pp++)
+ *block_pp = &(g->enc_block[*zig_p++]);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | encode_block | Encodes an 8x8 block of pixels into Huffman data |
+ |______________|_____________________________________________________________|
+ | |
+ | The input data is variable 'enc_block' via 'enc_block_zz'. |
+ | |
+ | The data to be quantized is compared to thresh to determine if the |
+ | quantized data will be zero. In most cases, this is true, thus |
+ | eliminating the quantization steps (multiplication + add + shift). |
+ |____________________________________________________________________________|
+*/
+static void encode_block (
+ PJENC_INST g,
+ int comp, /* image component number */
+ const huff_elem_t *dc_huff_p,
+ const huff_elem_t *ac_huff_p,
+ int *quant_p,
+ int *thresh_p)
+{
+ int **block_p;
+ int i, data, absdata, run, siz;
+ int diff, absdiff;
+ WRITE_BITS_OPEN(g)
+
+ /************************************/
+ /* Quantize and Encode DC component */
+ /************************************/
+
+ thresh_p++;
+ block_p = g->enc_block_zz;
+ data = ROUND ((long)*(*block_p++) * (*quant_p++));
+ absdiff = diff = data - g->prior_DC[comp];
+ if (absdiff < 0) absdiff = -absdiff;
+ g->prior_DC[comp] = data;
+
+ if (absdiff < 256) siz = codesize_array[absdiff];
+ else siz = codesize_array[absdiff>>8] + 8;
+
+ WRITE_HUFF_CODE (g, siz, dc_huff_p)
+ WRITE_BITS (g, diff<0 ? diff-1 : diff, siz)
+
+ /************************************************/
+ /* Quantize, Zigzag, and Encode AC coefficients */
+ /************************************************/
+
+ run = 0;
+
+ for (i=63; i>0; i--) /* do 63 times... */
+ {
+ absdata = data = *(*block_p++);
+ if (absdata < 0) absdata = -absdata;
+
+ if (absdata <= *thresh_p++) {
+ /* quantization would be zero */
+ quant_p++;
+ run++; /* increment run-length of zeroes */
+ }
+ else /* need to quantize */
+ {
+ while (run >= 16) {
+ WRITE_HUFF_CODE (g, RUN_OF_16, ac_huff_p)
+ run -= 16;
+ }
+
+ absdata = ROUND ((DWORD )absdata * (DWORD )(*quant_p++));
+ if (absdata < 256) siz = codesize_array[absdata];
+ else siz = codesize_array[absdata>>8] + 8;
+
+ /* output the RLE code, and the AC term */
+ WRITE_HUFF_CODE (g, (run<<4) + siz, ac_huff_p)
+ WRITE_BITS (g, data<0 ? ~absdata : absdata, siz)
+ run = 0;
+ }
+ }
+
+ if (run>0 || g->fDenali)
+ WRITE_HUFF_CODE (g, 0, ac_huff_p) /* output EOB code */
+
+ WRITE_BITS_CLOSE(g)
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | encode_MCU | encodes the given MCU from the input rows in in_rows_ap |
+ |____________|_______________________________________________________________|
+*/
+static void encode_MCU (
+ PJENC_INST g,
+ UINT mcu_index)
+{
+ int *block_p;
+ UINT comp;
+ UINT h_block, v_block;
+ UINT ul_row, ul_col;
+ UINT row;
+ BYTE **row_pp;
+ BYTE *row_p;
+
+ for (comp=0; comp<g->comps_in_pixel; comp++) {
+ for (v_block=0; v_block<g->vert_sam_facs[comp]; v_block++) {
+ for (h_block=0; h_block<g->horiz_sam_facs[comp]; h_block++) {
+
+ /***** level-shift and copy the block into 'enc_block' *****/
+
+ ul_row = v_block*8;
+ ul_col = (mcu_index*g->horiz_sam_facs[comp] + h_block) * 8;
+ row_pp = &(g->in_rows_ap[comp][ul_row]);
+ block_p = g->enc_block;
+
+ for (row=0; row<8; row++) {
+ row_p = *row_pp++ + ul_col;
+
+ *block_p++ = (int)(UINT)*row_p++ - 128;
+ *block_p++ = (int)(UINT)*row_p++ - 128;
+ *block_p++ = (int)(UINT)*row_p++ - 128;
+ *block_p++ = (int)(UINT)*row_p++ - 128;
+ *block_p++ = (int)(UINT)*row_p++ - 128;
+ *block_p++ = (int)(UINT)*row_p++ - 128;
+ *block_p++ = (int)(UINT)*row_p++ - 128;
+ *block_p++ = (int)(UINT)*row_p - 128;
+ }
+
+ dct_forward (g->enc_block);
+
+ /***** encode and output the block *****/
+
+ if (comp == 0) {
+ encode_block (g, comp, lum_DC_table, g->fDenali ? lum_AC_table_Denali : lum_AC_table,
+ g->wino_lum_quant, g->wino_lum_quant_thres);
+ } else {
+ encode_block (g, comp, chrom_DC_table, chrom_AC_table,
+ g->wino_chrom_quant, g->wino_chrom_quant_thres);
+ }
+ }
+ }
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | copy_in_rows | copies a row (or rows) from input buffer to in_rows_ap |
+ |______________|_____________________________________________________________|
+ | |
+ | If input_subsampled is true, the input row data must be in the same odd |
+ | order which the ASIC outputs it. |
+ | |
+ | View a period as being a group of max_horiz_sam_fac by max_vert_sam_fac |
+ | samples. (BTW, an MCU contains exactly 8x8 periods.) Divide the entire |
+ | image into a grid of such periods. The ASIC outputs the periods left to |
+ | right, top to bottom. It outputs all the data in each period, before |
+ | moving to the next period. Within a period, it outputs the components in |
+ | succession; within a component, it outputs the samples left to right, top |
+ | to bottom. |
+ | |
+ | For example: |
+ | Three components = Y U V |
+ | Horiz sample factors = 2 1 1 |
+ | Vert sample factors = 2 1 1 |
+ | A period is 2x2 samples (i.e., a 2x2 square). |
+ | Each period contains these samples: YYYYUV. |
+ | Bytes output: YYYYUV YYYYUV YYYYUV .... |
+ | |
+ | In this routine, |
+ | |
+ | vert_period = index of which period we're inputting vertically within |
+ | an MCU (0-7). |
+ | |
+ | horiz_period = index of which period we're inputting horizontally; |
+ | since an MCU has 8 periods, this is 0 .. 8*mcus_in_row. |
+ |____________________________________________________________________________|
+*/
+static void copy_in_rows (
+ PJENC_INST g,
+ UINT row_index, /* in: index of next row to get within MCU */
+ BYTE *inbuf_p, /* in: input row data */
+ UINT *n_rows_p, /* out: # of rows copied in */
+ UINT *n_bytes_p) /* out: # of bytes copied in */
+{
+ BYTE *in_p;
+ UINT comp;
+ UINT vert_period, vert_mod;
+
+ vert_period = row_index / g->max_vert_sam_fac;
+ vert_mod = row_index % g->max_vert_sam_fac;
+
+ if (!g->input_subsampled || (g->max_vert_sam_fac==1 && g->max_horiz_sam_fac==1))
+ {
+ /********************************************************/
+ /* Perform subsampling (or copying of non-sampled data) */
+ /********************************************************/
+
+ BYTE *row_p;
+ UINT sam_fac;
+ UINT col, horiz_mod;
+ UINT inc;
+
+ for (comp=0; comp<g->comps_in_pixel; comp++) {
+ sam_fac = g->vert_sam_facs[comp];
+
+ if (vert_mod < sam_fac) {
+ in_p = inbuf_p + comp;
+ row_p = g->in_rows_ap[comp][vert_period*sam_fac + vert_mod];
+ horiz_mod = 0;
+ sam_fac = g->horiz_sam_facs[comp];
+
+ if (sam_fac == g->max_horiz_sam_fac) {
+
+ /***** fast case: copying all pixels *****/
+
+ if (g->comps_in_pixel == 1) {
+ memcpy (row_p, in_p, g->pixels_in_row);
+ } else {
+ for (col=0; col<g->pixels_in_row; col+=4) {
+ *row_p++ = *in_p; in_p += g->comps_in_pixel;
+ *row_p++ = *in_p; in_p += g->comps_in_pixel;
+ *row_p++ = *in_p; in_p += g->comps_in_pixel;
+ *row_p++ = *in_p; in_p += g->comps_in_pixel;
+ }
+ }
+
+ } else if (sam_fac==1 && g->max_horiz_sam_fac==2) {
+
+ /***** fast case: copying every other pixel *****/
+
+ inc = 2 * g->comps_in_pixel;
+ for (col=0; col<g->pixels_in_row; col+=8) {
+ *row_p++ = *in_p; in_p += inc;
+ *row_p++ = *in_p; in_p += inc;
+ *row_p++ = *in_p; in_p += inc;
+ *row_p++ = *in_p; in_p += inc;
+ }
+
+ } else {
+
+ /***** slow general case *****/
+
+ for (col=0; col<g->pixels_in_row; col++) {
+ if (horiz_mod < sam_fac) *row_p++ = *in_p;
+ in_p += g->comps_in_pixel;
+ horiz_mod += 1;
+ if (horiz_mod == g->max_horiz_sam_fac) horiz_mod = 0;
+ }
+ }
+ }
+ }
+
+ *n_rows_p = 1;
+ *n_bytes_p = g->comps_in_pixel * g->pixels_in_row;
+
+ } else {
+
+ /************************************************/
+ /* Already subsampled (in the ASIC's odd order) */
+ /************************************************/
+
+ UINT horiz_period, periods_in_row;
+ UINT ul_row, ul_col, row, col;
+ BYTE *row_y1_p, *row_y2_p, *row_cb_p, *row_cr_p;
+
+ in_p = inbuf_p;
+ periods_in_row = g->mcus_in_row * 8;
+
+ if (g->sample_factors == 0x21102110u) { /* fast case: 4-1-1 subsampling */
+ row_y1_p = g->in_rows_ap[0][2*vert_period];
+ row_y2_p = g->in_rows_ap[0][2*vert_period+1];
+ row_cb_p = g->in_rows_ap[1][vert_period];
+ row_cr_p = g->in_rows_ap[2][vert_period];
+ for (horiz_period=0; horiz_period<periods_in_row; horiz_period++) {
+ *row_y1_p++ = *in_p++;
+ *row_y1_p++ = *in_p++;
+ *row_y2_p++ = *in_p++;
+ *row_y2_p++ = *in_p++;
+ *row_cb_p++ = *in_p++;
+ *row_cr_p++ = *in_p++;
+ }
+ } else { /* slow general case */
+
+ for (horiz_period=0; horiz_period<periods_in_row; horiz_period++) {
+ for (comp=0; comp<g->comps_in_pixel; comp++) {
+ ul_row = vert_period * g->vert_sam_facs[comp];
+ ul_col = horiz_period * g->horiz_sam_facs[comp];
+
+ for (row=ul_row; row<ul_row+ g->vert_sam_facs[comp]; row++)
+ for (col=ul_col; col<ul_col+g->horiz_sam_facs[comp]; col++) {
+ g->in_rows_ap[comp][row][col] = *in_p++;
+ }
+ }
+ }
+ }
+
+ *n_rows_p = g->max_vert_sam_fac;
+ *n_bytes_p = in_p - inbuf_p;
+ }
+}
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ EXPORTED ROUTINES
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | scale_q_table | scales a q-table according to the q-factors |
+ |_______________|____________________________________________________________|
+*/
+static void scale_q_table (
+ UINT dc_q_factor,
+ UINT ac_q_factor,
+ const BYTE *in,
+ BYTE *out)
+{
+ #define FINAL_DC_INDEX 9
+
+ UINT i, val;
+ UINT q;
+
+ q = dc_q_factor;
+
+ for (i=0; i<64; i++) {
+ val = ((*in++)*q + Q_DEFAULT/2) / Q_DEFAULT;
+ if (val < 1) val = 1;
+ if (val > 255) val = 255;
+ *out++ = (BYTE)val;
+ if (i == FINAL_DC_INDEX)
+ q = ac_q_factor;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | output_header | outputs the JPEG header |
+ |_______________|____________________________________________________________|
+ | |
+ | Inputs: lum_quant, chrom_quant, xRes, yRes, pixels_in_row, comps_in_pixel,|
+ | horiz_sam_facs, vert_sam_facs |
+ |____________________________________________________________________________|
+*/
+static UINT output_header (
+ PJENC_INST g,
+ BYTE *buf_p)
+{
+ BYTE hclass[4];
+ BYTE ident[4];
+ const BYTE *counts[4];
+ const BYTE *huffval[4];
+
+ hclass [0] = 0;
+ ident [0] = 0;
+ counts [0] = lum_DC_counts;
+ huffval[0] = lum_DC_values;
+
+ hclass [1] = 1;
+ ident [1] = 0;
+ counts [1] = g->fDenali ? lum_AC_counts_Denali : lum_AC_counts;
+ huffval[1] = lum_AC_values;
+
+ hclass [2] = 0;
+ ident [2] = 1;
+ counts [2] = chrom_DC_counts;
+ huffval[2] = chrom_DC_values;
+
+ hclass [3] = 1;
+ ident [3] = 1;
+ counts [3] = chrom_AC_counts;
+ huffval[3] = chrom_AC_values;
+
+ write_buf_open (g, buf_p);
+ em_write_SOI (g);
+
+ if (0 /* todo */ ) {
+ em_write_short_header (g, g->rows_in_page<0 ? 0 : g->rows_in_page,
+ g->pixels_in_row,
+ g->xRes, g->yRes,
+ g->dc_q_factor, g->ac_q_factor,
+ g->comps_in_pixel,
+ g->sample_factors);
+ } else {
+ if (g->fOutputG3APP1)
+ em_write_G3_APP1 (g, g->xRes);
+ else
+ em_write_JFIF_APP0 (g, g->xRes, g->yRes);
+ em_write_SOF (g, g->pixels_in_row, g->rows_in_page<0 ? 0 : g->rows_in_page,
+ g->comps_in_pixel, g->horiz_sam_facs, g->vert_sam_facs);
+ em_write_DQT (g, 0, 0, g->lum_quant);
+ if (g->comps_in_pixel > 1)
+ em_write_DQT (g, 0, 1, g->chrom_quant);
+ em_write_DHTs (g, g->comps_in_pixel==1 ? 2 : 4,
+ hclass, ident, counts, huffval);
+ em_write_SOS (g, g->comps_in_pixel);
+ }
+ return write_buf_close (g);
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgEncode_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD jpgEncode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PJENC_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(JENC_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(JENC_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgEncode_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD jpgEncode_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PJENC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->traits = *pTraits; /* a structure copy */
+
+ INSURE (g->traits.iPixelsPerRow > 0);
+ INSURE (g->traits.iComponentsPerPixel==1 || g->traits.iComponentsPerPixel==3);
+
+ g->pixels_in_row = g->traits.iPixelsPerRow;
+ g->comps_in_pixel = g->traits.iComponentsPerPixel;
+ g->rows_in_page = g->traits.lNumRows;
+ g->xRes = g->traits.lHorizDPI >> 16;
+ g->yRes = g->traits.lVertDPI >> 16;
+ if (g->xRes < 0) g->xRes = 300;
+ if (g->yRes < 0) g->yRes = 300;
+
+ g->fDidHeader = FALSE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgEncode_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD jpgEncode_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PJENC_INST g;
+ UINT qfacs;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ qfacs = aXformInfo[IP_JPG_ENCODE_QUALITY_FACTORS].dword;
+ g->sample_factors = aXformInfo[IP_JPG_ENCODE_SAMPLE_FACTORS].dword;
+ g->input_subsampled = aXformInfo[IP_JPG_ENCODE_ALREADY_SUBSAMPLED].dword;
+ g->fDenali = (BOOL)aXformInfo[IP_JPG_ENCODE_FOR_DENALI].dword;
+ g->fOutputDNL = (BOOL)aXformInfo[IP_JPG_ENCODE_OUTPUT_DNL].dword;
+ g->fOutputG3APP1 = (BOOL)aXformInfo[IP_JPG_ENCODE_FOR_COLOR_FAX].dword;
+ g->dwDummyHeaderBytes = aXformInfo[IP_JPG_ENCODE_DUMMY_HEADER_LEN].dword;
+
+ g->dc_q_factor = (BYTE)(qfacs >> 8);
+ g->ac_q_factor = (BYTE)(qfacs);
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgEncode_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD jpgEncode_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ PJENC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgEncode_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD jpgEncode_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PJENC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ /* Since we don't change traits, just copy out the default traits */
+ *pInTraits = g->traits;
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * jpgEncode_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD jpgEncode_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PJENC_INST g;
+ WORD n;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = g->comps_in_pixel * g->pixels_in_row;
+
+ n = OUTBUF_NUM_MCUS * MAX_MCU_SIZE;
+ if (n < MAX_HEADER_SIZE) n = MAX_HEADER_SIZE;
+ *pdwMinOutBufLen = n;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgEncode_convert - the work-horse routine
+ *
+\*****************************************************************************/
+
+static WORD jpgEncode_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PJENC_INST g;
+ unsigned ret_val;
+ UINT row, n_rows, n_bytes;
+ int comp;
+ UINT row_len;
+ UINT n_loaded;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwInputUsed = 0;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ *pdwOutputUsed = 0;
+ ret_val = IP_READY_FOR_DATA;
+
+ /****************************************************/
+ /* Init and output the Header if we haven't already */
+ /****************************************************/
+
+ if (! g->fDidHeader) {
+ UINT row_len;
+ BYTE *p;
+ DWORD factors;
+ UINT fac;
+
+ /* Init */
+
+ g->rows_loaded = 0;
+ g->mcus_sent = 0;
+ g->loading_rows = TRUE;
+ write_init (g);
+ zero_prior_DC (g);
+ encode_init (g);
+
+ if (g->ac_q_factor == 0)
+ g->ac_q_factor = Q_DEFAULT;
+ if (g->dc_q_factor == 0)
+ g->dc_q_factor = g->ac_q_factor;
+
+ if (g->sample_factors == 0)
+ g->sample_factors = g->comps_in_pixel==1 ? MONO_FACTORS : COLOR_FACTORS;
+
+ factors = g->sample_factors >> 16;
+ g->max_horiz_sam_fac = 0;
+ for (comp=3; comp>=0; comp--) {
+ fac = factors & 0x0fu;
+ if (fac > g->max_horiz_sam_fac) g->max_horiz_sam_fac = fac;
+ g->horiz_sam_facs[comp] = fac;
+ factors >>= 4;
+ }
+
+ factors = g->sample_factors & 0x0000ffffu;
+ g->max_vert_sam_fac = 0;
+ for (comp=3; comp>=0; comp--) {
+ fac = factors & 0x0fu;
+ if (fac > g->max_vert_sam_fac) g->max_vert_sam_fac = fac;
+ g->vert_sam_facs[comp] = fac;
+ factors >>= 4;
+ }
+
+ g->cols_in_mcu = g->max_horiz_sam_fac * 8;
+ g->rows_in_mcu = g->max_vert_sam_fac * 8;
+ g->mcus_in_row = (g->pixels_in_row + g->cols_in_mcu - 1) / g->cols_in_mcu;
+
+ scale_q_table (g->dc_q_factor, g->ac_q_factor, orig_lum_quant, g->lum_quant);
+ scale_q_table (g->dc_q_factor, g->ac_q_factor, orig_chrom_quant, g->chrom_quant);
+
+ /* scale lum_quant & chrom_quant for Wino DCT */
+ scale_for_wino (g->lum_quant, g->wino_lum_quant, g->wino_lum_quant_thres);
+ scale_for_wino (g->chrom_quant, g->wino_chrom_quant, g->wino_chrom_quant_thres);
+
+ g->whitePixel[0] = 255; /* YCC value of a white pixel (color) */
+ g->whitePixel[1] = 128; /* The 255 is white in mono too */
+ g->whitePixel[2] = 128;
+ g->whitePixel[3] = 255;
+
+ g->dwOutNextPos = *pdwOutputUsed = (g->dwDummyHeaderBytes == 0)
+ ? output_header (g,pbOutputBuf)
+ : g->dwDummyHeaderBytes;
+
+ *pdwOutputThisPos = 0;
+
+ /* Allocate the row-buffers in in_rows_ap */
+
+ memset (g->in_rows_ap, 0, sizeof(g->in_rows_ap));
+
+ for (comp=0; comp<(int)g->comps_in_pixel; comp++) {
+ row_len = g->horiz_sam_facs[comp] * g->mcus_in_row * 8;
+ n_rows = g->vert_sam_facs[comp] * 8;
+
+ for (row=0; row<n_rows; row++) {
+ IP_MEM_ALLOC (row_len, p);
+ g->in_rows_ap[comp][row] = p;
+ }
+ }
+
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+ g->dwInNextPos = 0;
+ g->fDidHeader = TRUE;
+
+ return IP_READY_FOR_DATA;
+ }
+
+ /*********************************/
+ /* We are filling the input rows */
+ /*********************************/
+
+ if (g->loading_rows) {
+
+ /***** Init all row-buffers to white if starting new row-set *****/
+
+ n_loaded = g->rows_loaded % g->rows_in_mcu;
+
+ if (n_loaded == 0) {
+ for (comp=0; comp<g->comps_in_pixel; comp++) {
+ row_len = g->horiz_sam_facs[comp] * g->mcus_in_row * 8;
+ n_rows = g->vert_sam_facs[comp] * 8;
+
+ for (row=0; row<n_rows; row++)
+ memset (g->in_rows_ap[comp][row], g->whitePixel[comp], row_len);
+ }
+ }
+
+ if (pbInputBuf == NULL) {
+
+ /***** We are being told to flush *****/
+
+ if (n_loaded != 0) {
+ /* some rows were loaded; start compressing rows now */
+ g->loading_rows = FALSE;
+ /* boost rows_loaded to next multiple of rows_in_mcu so
+ * n_loaded will be 0 next time around */
+ g->rows_loaded += g->rows_in_mcu - n_loaded;
+ } else if ((g->rows_in_page<0 || (int)g->rows_received<g->rows_in_page)
+ && g->dwDummyHeaderBytes == 0) {
+ /* row-count was unknown or too big, output header w/ correct row-count */
+ g->rows_in_page = g->rows_received;
+ *pdwOutputUsed = output_header (g, pbOutputBuf);
+ *pdwOutputThisPos = 0;
+ } else {
+ /* no rows were loaded, and row-count is valid, so we're done */
+ PRINT (_T("jpeg_encode_convert_row: Done\n"),0,0);
+ write_buf_open (g, pbOutputBuf);
+ write_bits_flush (g);
+ if (g->fOutputDNL)
+ em_write_DNL (g, g->rows_received);
+ em_write_EOI (g);
+ *pdwOutputUsed = write_buf_close (g);
+ ret_val |= IP_DONE;
+ }
+ } else {
+
+ /***** Copy the row(s) into in_rows_ap *****/
+
+ copy_in_rows (
+ g,
+ n_loaded, /* in: index of next row to get */
+ pbInputBuf, /* in: copied-in row data */
+ &n_rows, /* out: # of rows copied in */
+ &n_bytes); /* out: # of bytes fetched */
+
+ *pdwInputUsed = n_bytes;
+ *pdwInputNextPos = (g->dwInNextPos += n_bytes);
+ g->rows_loaded += n_rows;
+ g->rows_received += n_rows;
+ n_loaded = g->rows_loaded % g->rows_in_mcu;
+
+ /* it's hard to set IP_PRODUCED_ROW 8 times per 8 rows, so cheat */
+ if (n_rows > 0)
+ ret_val |= IP_CONSUMED_ROW | IP_PRODUCED_ROW;
+
+ /***** Check if all needed rows are loaded *****/
+
+ if (n_loaded == 0) {
+ /* # rows loaded is rows_in_mcu, but the mod wrapped to zero */
+ g->loading_rows = FALSE; /* start compressing rows now */
+ }
+ }
+ }
+
+ /************************************************************/
+ /* Compress as many MCUs as will fit into the output buffer */
+ /************************************************************/
+
+ while (!g->loading_rows &&
+ dwOutputAvail-*pdwOutputUsed > MAX_MCU_SIZE) {
+ PRINT (_T("jpeg_encode_convert_row: Encoding MCU, mcus_sent=%d\n"),
+ g->mcus_sent, 0);
+
+ write_buf_open (g, pbOutputBuf + *pdwOutputUsed);
+ encode_MCU (g, g->mcus_sent);
+ n_bytes = write_buf_close (g);
+
+ g->dwOutNextPos += n_bytes;
+ *pdwOutputUsed += n_bytes;
+
+ g->mcus_sent += 1;
+ if (g->mcus_sent >= g->mcus_in_row) {
+ g->loading_rows = TRUE;
+ g->mcus_sent = 0;
+ }
+ }
+
+ PRINT (_T("jpeg_encode_convert_row: Returning %04x, out_used=%d\n"),
+ ret_val, *pdwOutputUsed);
+ return ret_val;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgEncode_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD jpgEncode_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgEncode_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD jpgEncode_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PJENC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgEncode_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD jpgEncode_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PJENC_INST g;
+ BYTE **row_pp, **after_pp, *p;
+
+ HANDLE_TO_PTR (hXform, g);
+ row_pp = &(g->in_rows_ap[0][0]);
+ after_pp = row_pp + (sizeof(g->in_rows_ap)/sizeof(BYTE*));
+
+ for ( ; row_pp<after_pp; row_pp++) {
+ p = *row_pp;
+ if (p != NULL) {
+ IP_MEM_FREE (p);
+ *row_pp = NULL;
+ }
+ }
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgEncodeTbl - Jump-table for encoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL jpgEncodeTbl = {
+ jpgEncode_openXform,
+ jpgEncode_setDefaultInputTraits,
+ jpgEncode_setXformSpec,
+ jpgEncode_getHeaderBufSize,
+ jpgEncode_getActualTraits,
+ jpgEncode_getActualBufSizes,
+ jpgEncode_convert,
+ jpgEncode_newPage,
+ jpgEncode_insertedData,
+ jpgEncode_closeXform
+};
+
+/* End of File */
diff --git a/ip/xjpg_fix.c b/ip/xjpg_fix.c
new file mode 100644
index 0000000..709fcac
--- /dev/null
+++ b/ip/xjpg_fix.c
@@ -0,0 +1,839 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: David Paschal (based on Mark Overton's "skel" template
+ * and a few bits and pieces from xjpg_{enc,dec}.c). */
+
+/******************************************************************************\
+ *
+ * xjpg_fix.c - Fixes JPEG files to have a standard JFIF APP0 header and
+ * a correct row-count value in the SOF header.
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * jpgFixTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * None.
+ *
+ * Capabilities and Limitations:
+ *
+ * Looks at the header, and converts an OfficeJet APP1 short header to
+ * a standard JFIF APP0 header. Passes the resulting header and data
+ * through to the JPEG decoder in order to count the number of rows in
+ * the image. Discards the decompressed data and passes the original
+ * compressed data (possibly with modified header) to the output. At
+ * the end of the file, seeks back to the SOF header and rewrites the
+ * row count field.
+ *
+ * Able to handle JPEG files with JFIF APP0 or OfficeJet APP1 headers,
+ * but not color-fax APP1 headers or Denali-style compression (in
+ * these cases, you must do the full decode, any necessary color-space
+ * conversion, and encode).
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- ------------------- ------------------------
+ * iPixelsPerRow ignored based on header
+ * iBitsPerPixel ignored based on header
+ * iComponentsPerPixel ignored based on header
+ * lHorizDPI ignored based on header
+ * lVertDPI ignored based on header
+ * lNumRows ignored based on header
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+#include <stdio.h>
+
+#define PRINTF(args...) fprintf(stderr,args)
+
+/* TODO: Move this to a separate .h file: */
+extern IP_XFORM_TBL jpgDecodeTbl;
+extern WORD jpgDecode_getRowCountInfo(IP_XFORM_HANDLE hXform,
+ int *pRcCountup,int *pRcTraits,int *pSofOffset);
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+#define FUNC_STATUS static
+
+#define BEND_GET_SHORT(s) (((s)[0]<<8)|((s)[1]))
+#define BEND_SET_SHORT(s,x) ((s)[0]=((x)>>8)&0xFF,(s)[1]=(x)&0xFF)
+
+typedef struct {
+ IP_XFORM_HANDLE pSlaveXform; /* JPEG-decoder slave transformer. */
+ PBYTE headerBuffer;
+ DWORD outNextPos;
+ DWORD lenHeader;
+ DWORD lenAddedHeader;
+ DWORD lenHeaderBuffer;
+ DWORD readyForSofRewrite;
+ DWORD dwValidChk; /* struct validity check value */
+} JFIX_INST, *PJFIX_INST;
+
+
+/* TODO: Move the tables to a separate common file. */
+
+/* Since the firmware does not supply tables in its header,
+ * the tables used in the firmware are supplied below. */
+
+/*____________________________________________________________________________
+ | |
+ | Zigzag of Normal Quantization Tables |
+ |____________________________________________________________________________|
+*/
+
+static const unsigned char orig_lum_quant[64] = {
+ 16, 11, 12, 14, 12, 10, 16, 14,
+ 13, 14, 18, 17, 16, 19, 24, 40,
+ 26, 24, 22, 22, 24, 49, 35, 37,
+ 29, 40, 58, 51, 61, 60, 57, 51,
+ 56, 55, 64, 72, 92, 78, 64, 68,
+ 87, 69, 55, 56, 80, 109, 81, 87,
+ 95, 98, 103, 104, 103, 62, 77, 113,
+ 121, 112, 100, 120, 92, 101, 103, 99
+};
+
+static const unsigned char orig_chrom_quant[64] = {
+ 17, 18, 18, 24, 21, 24, 47, 26,
+ 26, 47, 99, 66, 56, 66, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+/*____________________________________________________________________________
+ | |
+ | Huffman Tables |
+ |____________________________________________________________________________|
+*/
+
+static const unsigned char lum_DC_counts[16] = {
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char lum_DC_values[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+};
+
+static const unsigned char chrom_DC_counts[16] = {
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char chrom_DC_values[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+};
+
+static const unsigned char lum_AC_counts[16] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d
+};
+
+static const unsigned char lum_AC_values[162] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+static const unsigned char chrom_AC_counts[16] = {
+ 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+ 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77
+};
+
+static const unsigned char chrom_AC_values[162] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+/*____________________________________________________________________________
+ | | |
+ | scale_q_table | scales a q-table according to the q-factors |
+ |_______________|____________________________________________________________|
+*/
+/* TODO: Reference this from a common .h file. */
+void scale_q_table(int dc_q_factor,int ac_q_factor,int ident,
+ unsigned char *out) {
+ static const int Q_DEFAULT=20;
+ static const int FINAL_DC_INDEX=9;
+ int i,val;
+ int q=dc_q_factor;
+ const unsigned char *in=orig_lum_quant;
+ if (ident) in=orig_chrom_quant;
+
+ for (i=0; i<64; i++) {
+ val = ((*in++)*q + Q_DEFAULT/2) / Q_DEFAULT;
+ if (val < 1) val = 1;
+ if (val > 255) val = 255;
+ *out++ = (unsigned char)val;
+ if (i == FINAL_DC_INDEX) {
+ q = ac_q_factor;
+ }
+ }
+}
+
+
+/*****************************************************************************\
+ *
+ * jpgFix_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD jpgFix_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PJFIX_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(JFIX_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(JFIX_INST));
+ if (jpgDecodeTbl.openXform(&g->pSlaveXform)!=IP_DONE) {
+ IP_MEM_FREE(g);
+ goto fatal_error;
+ }
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgFix_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD jpgFix_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PJFIX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ return jpgDecodeTbl.setDefaultInputTraits(g->pSlaveXform,pTraits);
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgFix_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD jpgFix_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PJFIX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Check your options in aXformInfo here, and save them.
+ * Use the INSURE macro like you'd use assert. INSURE jumps to
+ * fatal_error below if it fails.
+ */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgFix_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD jpgFix_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ WORD r;
+ PJFIX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ r=jpgDecodeTbl.getHeaderBufSize(g->pSlaveXform,pdwInBufLen);
+ if (r!=IP_DONE) return r;
+
+ g->lenHeaderBuffer=*pdwInBufLen;
+ IP_MEM_ALLOC(g->lenHeaderBuffer,g->headerBuffer);
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgFix_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+
+//#define MYLOCATE(p) (void *)(p)=(g->headerBuffer+lenAddedHeader)
+#define MYLOCATE(p) (p)=(void *)(g->headerBuffer+lenAddedHeader)
+#define MYWRITE(p) lenAddedHeader+=sizeof(*(p))
+#define MYWRITEBUF(data,datalen) \
+ do { \
+ INSURE((datalen)<=g->lenHeaderBuffer-lenAddedHeader); \
+ memcpy(g->headerBuffer+lenAddedHeader,(char *)(data),(datalen)); \
+ lenAddedHeader+=(datalen); \
+ } while(0)
+
+FUNC_STATUS WORD jpgFix_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ struct shortHeader_s {
+ unsigned char soi[2]; /* 0xFF, 0xD8 */
+
+ unsigned char app1[2]; /* 0xFF, 0xE1 */
+ unsigned char app1Length[2]; /* 0x00, 0x12 */
+ unsigned char height[2];
+ unsigned char width[2];
+ unsigned char xres[2];
+ unsigned char yres[2];
+ unsigned char ac_q_factor;
+ unsigned char numComponents; /* 1=gray, 3=color */
+ unsigned char xSampleFactors[2];
+ unsigned char ySampleFactors[2];
+ unsigned char dc_q_factor;
+ unsigned char reserved; /* 0x00 */
+ } *pInputHeader=(struct shortHeader_s *)pbInputBuf;
+ struct outputSoiApp0_s {
+ unsigned char soi[2]; /* 0xFF, 0xD8 */
+
+ unsigned char app0[2]; /* 0xFF, 0xE0 */
+ unsigned char app0Length[2]; /* 0x00, 0x10 */
+ unsigned char jfif[5]; /* "JFIF\0" */
+ unsigned char majorVersion; /* 0x01 */
+ unsigned char minorVersion; /* 0x00 */
+ unsigned char units; /* 0x01 = DPI */
+ unsigned char xres[2];
+ unsigned char yres[2];
+ unsigned char xthumb; /* 0x00 */
+ unsigned char ythumb; /* 0x00 */
+ } *pOutputSoiApp0;
+ struct {
+ unsigned char sof0[2]; /* 0xFF, 0xC0 */
+ unsigned char sof0Length[2]; /* 0x00, 0x?? */
+ unsigned char eight; /* 0x08 */
+ unsigned char height[2];
+ unsigned char width[2];
+ unsigned char numComponents; /* 1=gray, 3=color */
+ } *pOutputSof0Part1;
+ struct {
+ unsigned char iComponent;
+ unsigned char xySampleFactors;
+ unsigned char isNotFirstComponent;
+ } *pOutputSofComponent;
+ struct {
+ unsigned char dqt[2]; /* 0xFF, 0xDB */
+ unsigned char dqtLength[2]; /* 0x00, 0x43 */
+ unsigned char ident; /* 0=lum., 1=chrom. */
+ unsigned char elements[64];
+ } *pOutputDqt;
+ struct {
+ unsigned char dht[2]; /* 0xFF, 0xC4 */
+ unsigned char dhtLength[2]; /* 0x00, 0x?? */
+ } *pOutputDhtPart1;
+ struct {
+ unsigned char hclass_ident;
+ unsigned char counts[16];
+ /* Variable-length huffval table follows. */
+ } *pOutputDhtPart2;
+ static const struct {
+ unsigned char hclass_ident;
+ const unsigned char *counts;
+ const unsigned char *huffval;
+ } dhtInfo[4]={
+ {0x00,lum_DC_counts,lum_DC_values},
+ {0x10,lum_AC_counts,lum_AC_values},
+ {0x01,chrom_DC_counts,chrom_DC_values},
+ {0x11,chrom_AC_counts,chrom_AC_values}
+ };
+ int dhtCountCounts[4];
+ struct {
+ unsigned char sos[2]; /* 0xFF, 0xDA */
+ unsigned char sosLength[2]; /* 0x00, 0x?? */
+ unsigned char numComponents; /* 1=gray, 3=color */
+ } *pOutputSosPart1;
+ struct {
+ unsigned char iComponent;
+ unsigned char x00x11; /* (i==0 ? 0x00 : 0x11) */
+ } *pOutputSosComponent;
+ struct {
+ unsigned char zero1; /* 0x00 */
+ unsigned char sixtythree; /* 0x3F */
+ unsigned char zero2; /* 0x00 */
+ } *pOutputSosPart2;
+
+ PJFIX_INST g;
+ DWORD lenRemovedHeader=0,lenAddedHeader=0;
+ int imax,i,j,x,y,r,len;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Validate APP1 (OfficeJet short header) record.
+ * If we actually get a JFIF standard APP0 record, then
+ * skip parsing the header. */
+ if (dwInputAvail>=sizeof(*pInputHeader) &&
+ pInputHeader->soi[0]==0xFF && pInputHeader->soi[1]==0xD8 &&
+ pInputHeader->app1[0]==0xFF && pInputHeader->app1[1]==0xE1 &&
+ !pInputHeader->app1Length[0] && pInputHeader->app1Length[1]==0x12) {
+
+ /* Write standard JPEG/JFIF records... */
+ lenRemovedHeader=sizeof(*pInputHeader);
+
+ /* Start Of Image record. */
+ MYLOCATE(pOutputSoiApp0);
+ pOutputSoiApp0->soi[0]=0xFF;
+ pOutputSoiApp0->soi[1]=0xD8;
+ /* APP0 (JFIF header) record. */
+ pOutputSoiApp0->app0[0]=0xFF;
+ pOutputSoiApp0->app0[1]=0xE0;
+ pOutputSoiApp0->app0Length[0]=0x00;
+ pOutputSoiApp0->app0Length[1]=sizeof(*pOutputSoiApp0)-4;
+ strcpy((char *)pOutputSoiApp0->jfif,"JFIF");
+ pOutputSoiApp0->majorVersion=0x01;
+ pOutputSoiApp0->minorVersion=0x00;
+ pOutputSoiApp0->units=0x01;
+ pOutputSoiApp0->xres[0]=pInputHeader->xres[0];
+ pOutputSoiApp0->xres[1]=pInputHeader->xres[1];
+ pOutputSoiApp0->yres[0]=pInputHeader->yres[0];
+ pOutputSoiApp0->yres[1]=pInputHeader->yres[1];
+ pOutputSoiApp0->xthumb=0;
+ pOutputSoiApp0->ythumb=0;
+ MYWRITE(pOutputSoiApp0);
+
+ /* Start Of Frame record. */
+ MYLOCATE(pOutputSof0Part1);
+ pOutputSof0Part1->sof0[0]=0xFF;
+ pOutputSof0Part1->sof0[1]=0xC0;
+ pOutputSof0Part1->sof0Length[0]=0x00;
+ pOutputSof0Part1->sof0Length[1]=sizeof(*pOutputSof0Part1)-2+
+ pInputHeader->numComponents*sizeof(*pOutputSofComponent);
+ pOutputSof0Part1->eight=0x08;
+ pOutputSof0Part1->height[0]=pInputHeader->height[0];
+ pOutputSof0Part1->height[1]=pInputHeader->height[1];
+ pOutputSof0Part1->width[0]=pInputHeader->width[0];
+ pOutputSof0Part1->width[1]=pInputHeader->width[1];
+ pOutputSof0Part1->numComponents=pInputHeader->numComponents;
+ MYWRITE(pOutputSof0Part1);
+ x=BEND_GET_SHORT(pInputHeader->xSampleFactors);
+ y=BEND_GET_SHORT(pInputHeader->ySampleFactors);
+ for (i=0;i<pInputHeader->numComponents;i++) {
+ MYLOCATE(pOutputSofComponent);
+ pOutputSofComponent->iComponent=i;
+ pOutputSofComponent->xySampleFactors=
+ (((x>>(4*(3-i)))&0x0F)<<4) | ((y>>(4*(3-i)))&0x0F);
+ pOutputSofComponent->isNotFirstComponent=(!i?0:1);
+ MYWRITE(pOutputSofComponent);
+ }
+
+ /* Define Quantization Table record. */
+ imax=pInputHeader->numComponents>1?1:0;
+ for (i=0;i<=imax;i++) {
+ MYLOCATE(pOutputDqt);
+ pOutputDqt->dqt[0]=0xFF;
+ pOutputDqt->dqt[1]=0xDB;
+ pOutputDqt->dqtLength[0]=0x00;
+ pOutputDqt->dqtLength[1]=sizeof(*pOutputDqt)-2;
+ pOutputDqt->ident=i; /* Upper nibble=0 for 8-bit table. */
+ scale_q_table(pInputHeader->dc_q_factor,pInputHeader->ac_q_factor,
+ i,pOutputDqt->elements);
+ MYWRITE(pOutputDqt);
+ }
+ imax=pInputHeader->numComponents>1?4:2;
+ x=sizeof(*pOutputDhtPart1)-2;
+ for (i=0;i<imax;i++) {
+ dhtCountCounts[i]=0;
+ x+=sizeof(*pOutputDhtPart2);
+ for (j=0;j<16;j++) {
+ y=dhtInfo[i].counts[j];
+ dhtCountCounts[i]+=y;
+ x+=y;
+ }
+ }
+ MYLOCATE(pOutputDhtPart1);
+ pOutputDhtPart1->dht[0]=0xFF;
+ pOutputDhtPart1->dht[1]=0xC4;
+ BEND_SET_SHORT(pOutputDhtPart1->dhtLength,x);
+ MYWRITE(pOutputDhtPart1);
+ for (i=0;i<imax;i++) {
+ MYLOCATE(pOutputDhtPart2);
+ pOutputDhtPart2->hclass_ident=dhtInfo[i].hclass_ident;
+ memcpy(pOutputDhtPart2->counts,dhtInfo[i].counts,16);
+ MYWRITE(pOutputDhtPart2);
+ MYWRITEBUF(dhtInfo[i].huffval,dhtCountCounts[i]);
+ }
+
+ /* Start Of Scan record. */
+ MYLOCATE(pOutputSosPart1);
+ imax=pInputHeader->numComponents;
+ pOutputSosPart1->sos[0]=0xFF;
+ pOutputSosPart1->sos[1]=0xDA;
+ pOutputSosPart1->sosLength[0]=0;
+ pOutputSosPart1->sosLength[1]=sizeof(*pOutputSosPart1)-2+
+ imax*sizeof(*pOutputSosComponent)+sizeof(*pOutputSosPart2);
+ pOutputSosPart1->numComponents=imax;
+ MYWRITE(pOutputSosPart1);
+ for (i=0;i<imax;i++) {
+ MYLOCATE(pOutputSosComponent);
+ pOutputSosComponent->iComponent=i;
+ pOutputSosComponent->x00x11=(!i?0x00:0x11);
+ MYWRITE(pOutputSosComponent);
+ }
+ MYLOCATE(pOutputSosPart2);
+ pOutputSosPart2->zero1=0;
+ pOutputSosPart2->sixtythree=63;
+ pOutputSosPart2->zero2=0;
+ MYWRITE(pOutputSosPart2);
+ }
+
+ /* Save a copy of the (possibly rewritten) header (plus any residual
+ * data) so we can emit it later. */
+ len=dwInputAvail-(lenAddedHeader-lenRemovedHeader);
+ if (len>g->lenHeaderBuffer-lenAddedHeader) {
+ len=g->lenHeaderBuffer-lenAddedHeader;
+ }
+ memcpy(g->headerBuffer+lenAddedHeader,pbInputBuf+lenRemovedHeader,len);
+
+ /* Pass the (possibly rewritten) header to the slave transformer. */
+ r=jpgDecodeTbl.getActualTraits(g->pSlaveXform,
+ len+lenAddedHeader,g->headerBuffer,
+ pdwInputUsed,pdwInputNextPos,
+ pInTraits,pOutTraits);
+ if ((r&(IP_DONE|IP_READY_FOR_DATA))!=(IP_DONE|IP_READY_FOR_DATA)) {
+ return (r|IP_FATAL_ERROR);
+ }
+
+ g->lenHeader=*pdwInputUsed;
+ g->lenAddedHeader=lenAddedHeader-lenRemovedHeader;
+ *pdwInputUsed-=g->lenAddedHeader;
+ *pdwInputNextPos-=g->lenAddedHeader;
+
+ return r;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * jpgFix_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+FUNC_STATUS WORD jpgFix_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ WORD r;
+ PJFIX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ r=jpgDecodeTbl.getActualBufSizes(g->pSlaveXform,
+ pdwMinInBufLen,pdwMinOutBufLen);
+ if (r==IP_DONE) {
+ INSURE(*pdwMinOutBufLen<=g->lenHeaderBuffer);
+ }
+ *pdwMinOutBufLen=g->lenHeaderBuffer;
+ return r;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgFix_convert - Converts one row
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD jpgFix_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PJFIX_INST g;
+ WORD r=0;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ if (g->outNextPos<g->lenHeader) {
+ DWORD len=g->lenHeader-g->outNextPos;
+ if (len>dwOutputAvail) len=dwOutputAvail;
+ if (len) {
+ memcpy(pbOutputBuf,g->headerBuffer+g->outNextPos,len);
+ }
+ *pdwInputUsed=0;
+ *pdwInputNextPos=g->lenHeader-g->lenAddedHeader;
+ *pdwOutputUsed=len;
+ *pdwOutputThisPos=g->outNextPos;
+ g->outNextPos+=len;
+ r|=IP_READY_FOR_DATA;
+
+ } else if (!g->readyForSofRewrite) {
+ DWORD dwOutputUsed,dwOutputThisPos;
+ r=jpgDecodeTbl.convert(g->pSlaveXform,
+ dwInputAvail,pbInputBuf,pdwInputUsed,pdwInputNextPos,
+ g->lenHeaderBuffer,g->headerBuffer,
+ &dwOutputUsed,&dwOutputThisPos);
+ *pdwInputNextPos-=g->lenAddedHeader;
+ if (r&IP_DONE) {
+ g->readyForSofRewrite=1;
+ if (!*pdwInputUsed) goto rewriteSof;
+ }
+ if (*pdwInputUsed) {
+ INSURE(*pdwInputUsed<=dwOutputAvail);
+ memcpy(pbOutputBuf,pbInputBuf,*pdwInputUsed);
+ }
+ *pdwOutputUsed=*pdwInputUsed;
+ *pdwOutputThisPos=g->outNextPos;
+ g->outNextPos+=*pdwInputUsed;
+
+ } else {
+rewriteSof:
+ r|=IP_DONE;
+ *pdwInputUsed=0;
+ *pdwInputNextPos=g->outNextPos-g->lenAddedHeader;
+ *pdwOutputUsed=0;
+ *pdwOutputThisPos=g->outNextPos;
+ if (g->readyForSofRewrite>0) {
+ int rcCountup,rcTraits,sofOffset;
+ r=jpgDecode_getRowCountInfo(g->pSlaveXform,
+ &rcCountup,&rcTraits,&sofOffset);
+ BEND_SET_SHORT(pbOutputBuf,rcCountup);
+ *pdwOutputUsed=2;
+ *pdwOutputThisPos=sofOffset;
+ g->readyForSofRewrite=-1;
+ }
+ }
+
+ return r;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgFix_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD jpgFix_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgFix_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD jpgFix_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PJFIX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgFix_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD jpgFix_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PJFIX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ if (g->pSlaveXform) jpgDecodeTbl.closeXform(g->pSlaveXform);
+ if (g->headerBuffer) IP_MEM_FREE(g->headerBuffer);
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgFixTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+IP_XFORM_TBL jpgFixTbl = {
+ jpgFix_openXform,
+ jpgFix_setDefaultInputTraits,
+ jpgFix_setXformSpec,
+ jpgFix_getHeaderBufSize,
+ jpgFix_getActualTraits,
+ jpgFix_getActualBufSizes,
+ jpgFix_convert,
+ jpgFix_newPage,
+ jpgFix_insertedData,
+ jpgFix_closeXform
+};
+
+/* End of File */
diff --git a/ip/xjpg_huf.c b/ip/xjpg_huf.c
new file mode 100644
index 0000000..9373577
--- /dev/null
+++ b/ip/xjpg_huf.c
@@ -0,0 +1,558 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*____________________________________________________________________________
+ | | |
+ | xjpg_huf.c | Huffman tables for JPEG encoder and decoder |
+ |____________|_______________________________________________________________|
+ | |
+ | Mark Overton, April 1996 |
+ |____________________________________________________________________________|
+*/
+
+#include "xjpg_huf.h"
+
+
+/*____________________________________________________________________________
+ | |
+ | Histograms and values for Building Huffman Tables |
+ |____________________________________________________________________________|
+*/
+
+const BYTE LuminanceDCCounts[16] = {
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+const BYTE LuminanceDCValues[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+};
+
+#ifdef COLOR_JPEG
+const BYTE ChrominanceDCCounts[16] = {
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+const BYTE ChrominanceDCValues[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+};
+#endif
+
+const BYTE LuminanceACCounts[16] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, /* 0x01, 0x7d */ 0x00, 0x7e
+ /* The alteration above yields Huffman codes as follows:
+ * - common codes are 12 bits wide or less,
+ * - uncommon codes are exactly 16 bits wide, and all those codes
+ * start with nine '1' bits, leaving seven bits of useful info. */
+};
+
+const BYTE LuminanceACValues[162] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+#ifdef COLOR_JPEG
+const BYTE ChrominanceACCounts[16] = {
+ 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+ 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77
+};
+
+const BYTE ChrominanceACValues[162] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+#endif
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Tables output by mk_jpg_huff program |
+ |____________________________________________________________________________|
+*/
+
+
+const enc_huff_elem_t enc_DC_table[] = {
+ { 0x0000, 2 }, { 0x0002, 3 }, { 0x0003, 3 }, { 0x0004, 3 },
+ { 0x0005, 3 }, { 0x0006, 3 }, { 0x000e, 4 }, { 0x001e, 5 },
+ { 0x003e, 6 }, { 0x007e, 7 }, { 0x00fe, 8 }, { 0x01fe, 9 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 },
+};
+
+
+const dec_huff_elem_t dec_DC_table[] = { {0,0},
+ { 2, 0x00 }, { 3, 0x01 }, { 3, 0x02 }, { 3, 0x03 },
+ { 3, 0x04 }, { 3, 0x05 }, { 4, 0x06 }, { 5, 0x07 },
+ { 6, 0x08 }, { 7, 0x09 }, { 8, 0x0a }, { 9, 0x0b },
+};
+
+const BYTE dec_DC_table_index[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 12, 0,
+};
+
+
+const enc_huff_elem_t enc_AC_table[] = {
+ { 0x000a, 4 }, { 0x0000, 2 }, { 0x0001, 2 }, { 0x0004, 3 },
+ { 0x000b, 4 }, { 0x001a, 5 }, { 0x0078, 7 }, { 0x00f8, 8 },
+ { 0x03f6, 10 }, { 0xff81, 16 }, { 0xff82, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x000c, 4 }, { 0x001b, 5 }, { 0x0079, 7 },
+ { 0x01f6, 9 }, { 0x07f6, 11 }, { 0xff83, 16 }, { 0xff84, 16 },
+ { 0xff85, 16 }, { 0xff86, 16 }, { 0xff87, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x001c, 5 }, { 0x00f9, 8 }, { 0x03f7, 10 },
+ { 0x0ff4, 12 }, { 0xff88, 16 }, { 0xff89, 16 }, { 0xff8a, 16 },
+ { 0xff8b, 16 }, { 0xff8c, 16 }, { 0xff8d, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x003a, 6 }, { 0x01f7, 9 }, { 0x0ff5, 12 },
+ { 0xff8e, 16 }, { 0xff8f, 16 }, { 0xff90, 16 }, { 0xff91, 16 },
+ { 0xff92, 16 }, { 0xff93, 16 }, { 0xff94, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x003b, 6 }, { 0x03f8, 10 }, { 0xff95, 16 },
+ { 0xff96, 16 }, { 0xff97, 16 }, { 0xff98, 16 }, { 0xff99, 16 },
+ { 0xff9a, 16 }, { 0xff9b, 16 }, { 0xff9c, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x007a, 7 }, { 0x07f7, 11 }, { 0xff9d, 16 },
+ { 0xff9e, 16 }, { 0xff9f, 16 }, { 0xffa0, 16 }, { 0xffa1, 16 },
+ { 0xffa2, 16 }, { 0xffa3, 16 }, { 0xffa4, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x007b, 7 }, { 0x0ff6, 12 }, { 0xffa5, 16 },
+ { 0xffa6, 16 }, { 0xffa7, 16 }, { 0xffa8, 16 }, { 0xffa9, 16 },
+ { 0xffaa, 16 }, { 0xffab, 16 }, { 0xffac, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x00fa, 8 }, { 0x0ff7, 12 }, { 0xffad, 16 },
+ { 0xffae, 16 }, { 0xffaf, 16 }, { 0xffb0, 16 }, { 0xffb1, 16 },
+ { 0xffb2, 16 }, { 0xffb3, 16 }, { 0xffb4, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01f8, 9 }, { 0xff80, 16 }, { 0xffb5, 16 },
+ { 0xffb6, 16 }, { 0xffb7, 16 }, { 0xffb8, 16 }, { 0xffb9, 16 },
+ { 0xffba, 16 }, { 0xffbb, 16 }, { 0xffbc, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01f9, 9 }, { 0xffbd, 16 }, { 0xffbe, 16 },
+ { 0xffbf, 16 }, { 0xffc0, 16 }, { 0xffc1, 16 }, { 0xffc2, 16 },
+ { 0xffc3, 16 }, { 0xffc4, 16 }, { 0xffc5, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x01fa, 9 }, { 0xffc6, 16 }, { 0xffc7, 16 },
+ { 0xffc8, 16 }, { 0xffc9, 16 }, { 0xffca, 16 }, { 0xffcb, 16 },
+ { 0xffcc, 16 }, { 0xffcd, 16 }, { 0xffce, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x03f9, 10 }, { 0xffcf, 16 }, { 0xffd0, 16 },
+ { 0xffd1, 16 }, { 0xffd2, 16 }, { 0xffd3, 16 }, { 0xffd4, 16 },
+ { 0xffd5, 16 }, { 0xffd6, 16 }, { 0xffd7, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x03fa, 10 }, { 0xffd8, 16 }, { 0xffd9, 16 },
+ { 0xffda, 16 }, { 0xffdb, 16 }, { 0xffdc, 16 }, { 0xffdd, 16 },
+ { 0xffde, 16 }, { 0xffdf, 16 }, { 0xffe0, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x07f8, 11 }, { 0xffe1, 16 }, { 0xffe2, 16 },
+ { 0xffe3, 16 }, { 0xffe4, 16 }, { 0xffe5, 16 }, { 0xffe6, 16 },
+ { 0xffe7, 16 }, { 0xffe8, 16 }, { 0xffe9, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0xffea, 16 }, { 0xffeb, 16 }, { 0xffec, 16 },
+ { 0xffed, 16 }, { 0xffee, 16 }, { 0xffef, 16 }, { 0xfff0, 16 },
+ { 0xfff1, 16 }, { 0xfff2, 16 }, { 0xfff3, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+ { 0x07f9, 11 }, { 0xfff4, 16 }, { 0xfff5, 16 }, { 0xfff6, 16 },
+ { 0xfff7, 16 }, { 0xfff8, 16 }, { 0xfff9, 16 }, { 0xfffa, 16 },
+ { 0xfffb, 16 }, { 0xfffc, 16 }, { 0xfffd, 16 }, { 0x0000, 0 },
+ { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 }, { 0x0000, 0 },
+};
+
+
+const dec_huff_elem_t dec_AC_main_table[] = { {0,0},
+ { 2, 0x01 }, { 2, 0x02 }, { 3, 0x03 }, { 4, 0x00 },
+ { 4, 0x04 }, { 4, 0x11 }, { 5, 0x05 }, { 5, 0x12 },
+ { 5, 0x21 }, { 6, 0x31 }, { 6, 0x41 }, { 7, 0x06 },
+ { 7, 0x13 }, { 7, 0x51 }, { 7, 0x61 }, { 8, 0x07 },
+ { 8, 0x22 }, { 8, 0x71 }, { 9, 0x14 }, { 9, 0x32 },
+ { 9, 0x81 }, { 9, 0x91 }, { 9, 0xa1 }, { 10, 0x08 },
+ { 10, 0x23 }, { 10, 0x42 }, { 10, 0xb1 }, { 10, 0xc1 },
+ { 11, 0x15 }, { 11, 0x52 }, { 11, 0xd1 }, { 11, 0xf0 },
+ { 12, 0x24 }, { 12, 0x33 }, { 12, 0x62 }, { 12, 0x72 },
+};
+
+const BYTE dec_AC_main_table_index[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20,
+ 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+ 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25,
+ 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 30, 30,
+ 31, 31, 32, 32, 33, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+
+const BYTE dec_AC_aux_table[] = {
+ 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35,
+ 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55,
+ 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+ 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,
+ 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85,
+ 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+ 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2,
+ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+ 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+ 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+ 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+ 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
+ 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x00, 0x00,
+};
+
+/* End of File */
diff --git a/ip/xjpg_huf.h b/ip/xjpg_huf.h
new file mode 100644
index 0000000..1dd4be3
--- /dev/null
+++ b/ip/xjpg_huf.h
@@ -0,0 +1,83 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*____________________________________________________________________________
+ | | |
+ | xjpg_huf.h | Huffman tables for JPEG encoder and decoder |
+ |____________|_______________________________________________________________|
+ | |
+ | Mark Overton, April 1996 |
+ |____________________________________________________________________________|
+*/
+
+#include "hpip.h"
+
+typedef struct {
+ WORD code;
+ BYTE size;
+} enc_huff_elem_t;
+
+typedef struct {
+ BYTE size;
+ BYTE value;
+} dec_huff_elem_t;
+
+
+/* Tables used by encoder */
+extern const enc_huff_elem_t enc_DC_table[17];
+extern const enc_huff_elem_t enc_AC_table[256];
+
+/* Tables used by decoder */
+extern const dec_huff_elem_t dec_DC_table[13];
+extern const BYTE dec_DC_table_index[512];
+extern const dec_huff_elem_t dec_AC_main_table[37];
+extern const BYTE dec_AC_main_table_index[4096];
+extern const BYTE dec_AC_aux_table[128];
+
+/* Tables from which Huffman tables are computed */
+extern const BYTE LuminanceDCCounts[16];
+extern const BYTE LuminanceDCValues[12];
+extern const BYTE LuminanceACCounts[16];
+extern const BYTE LuminanceACValues[162];
+
+#if 0
+extern const BYTE ChrominanceDCCounts[16];
+extern const BYTE ChrominanceDCValues[12];
+extern const BYTE ChrominanceACCounts[16];
+extern const BYTE ChrominanceACValues[162];
+#endif
+
+/* End of File */
diff --git a/ip/xjpg_mrk.h b/ip/xjpg_mrk.h
new file mode 100644
index 0000000..29aecc9
--- /dev/null
+++ b/ip/xjpg_mrk.h
@@ -0,0 +1,91 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*____________________________________________________________________________
+ | | |
+ | xjpg_mrk.h | Markers used in JPEG images |
+ |____________|_______________________________________________________________|
+ | |
+ | Mark Overton, Feb 1996 |
+ |____________________________________________________________________________|
+*/
+
+#define MARKER_NONE 0x00
+#define MARKER_END_FILE 0x100
+
+#define MARKER_SOF0 0xc0
+#define MARKER_SOF1 0xc1
+#define MARKER_SOF2 0xc2
+#define MARKER_SOF3 0xc3
+#define MARKER_SOF5 0xc5
+#define MARKER_SOF6 0xc6
+#define MARKER_SOF7 0xc7
+#define MARKER_SOF8 0xc8
+#define MARKER_SOF9 0xc9
+#define MARKER_SOFA 0xca
+#define MARKER_SOFB 0xcb
+#define MARKER_SOFD 0xcd
+#define MARKER_SOFE 0xce
+#define MARKER_SOFF 0xcf
+
+#define MARKER_DHT 0xc4
+#define MARKER_DAC 0xcc
+
+#define MARKER_RST0 0xd0
+#define MARKER_RST1 0xd1
+#define MARKER_RST2 0xd2
+#define MARKER_RST3 0xd3
+#define MARKER_RST4 0xd4
+#define MARKER_RST5 0xd5
+#define MARKER_RST6 0xd6
+#define MARKER_RST7 0xd7
+
+#define MARKER_SOI 0xd8
+#define MARKER_EOI 0xd9
+#define MARKER_SOS 0xda
+#define MARKER_DQT 0xdb
+#define MARKER_DNL 0xdc
+#define MARKER_DRI 0xdd
+#define MARKER_DHP 0xde
+#define MARKER_EXP 0xdf
+
+#define MARKER_APP 0xe0 /* from 0xe0 - 0xef */
+#define MARKER_JPG 0xf0 /* from 0xf0 - 0xfd */
+#define MARKER_COM 0xfe
+
+#define MARKER_SHORT_HEADER (MARKER_APP+1)
+
+/* End of File */
diff --git a/ip/xmatrix.c b/ip/xmatrix.c
new file mode 100644
index 0000000..759f5b0
--- /dev/null
+++ b/ip/xmatrix.c
@@ -0,0 +1,547 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xmatrix.c - runs color data thru a 3x3 matrix (24 or 48 bits/pixel)
+ *
+ * Mark Overton, June 2000
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * matrixTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[0] = pointer to the matrix, which is an array of nine
+ * signed integers (type int) in 8.24 fixed-point. If we pretend that
+ * the array is named 'm', then pixels are computed as follows:
+ *
+ * r_out = m[0]*r_in + m[1]*g_in + m[2]*b_in
+ * g_out = m[3]*r_in + m[4]*g_in + m[5]*b_in
+ * b_out = m[6]*r_in + m[7]*g_in + m[8]*b_in
+ *
+ * Capabilities and Limitations:
+ *
+ * Passes pixels through a 3x3 matrix. 24 or 48 bits/pixel only.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * must be 24 or 48 same as default input
+ * iComponentsPerPixel * must be 3 same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+/* Use the #define below if this transform will exist in a dll outside of the
+ * image pipeline. This will allow the functions to be exported.
+ * #define EXPORT_TRANFORM 1
+ */
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+#ifdef EXPORT_TRANSFORM
+#define FUNC_STATUS __declspec (dllexport)
+#else
+#define FUNC_STATUS static
+#endif
+
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input and output image */
+ DWORD dwBytesPerRow; /* # of bytes in each row */
+ DWORD dwRowsDone; /* number of rows processed so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ int mat[9]; /* the matrix */
+ DWORD dwValidChk; /* struct validity check value */
+} MAT_INST, *PMAT_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * mat_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD mat_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PMAT_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(MAT_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(MAT_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * mat_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD mat_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PMAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow > 0);
+ INSURE (pTraits->iBitsPerPixel==24 || pTraits->iBitsPerPixel==48);
+ INSURE (pTraits->iComponentsPerPixel == 3);
+
+ g->traits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * mat_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD mat_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PMAT_INST g;
+ int *ptr;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ ptr = (int*)aXformInfo[0].pvoid;
+ INSURE (ptr != NULL);
+ memcpy (g->mat, ptr, sizeof(g->mat));
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * mat_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD mat_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * mat_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD mat_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PMAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pIntraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ /* At this point, nothing will change, so compute internal variables */
+ g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+
+ if (g->traits.iBitsPerPixel == 24) {
+ int i;
+ for (i=0; i<9; i++) {
+ /* we'll use 16 bits of fraction instead of 24 */
+ g->mat[i] = (g->mat[i]+(1<<7)) >> 8;
+ }
+ }
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * mat_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+FUNC_STATUS WORD mat_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PMAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * mat_convert - Converts one row
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD mat_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PMAT_INST g;
+ int nBytes;
+ PBYTE pIn, pOut, pOutAfter;
+ int rIn, gIn, bIn, rOut, gOut, bOut;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check for flushing ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("mat_convert: Told to flush.\n"), 0, 0);
+ /* we are done */
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = g->dwBytesPerRow;
+ INSURE (dwInputAvail >= (DWORD)nBytes);
+ INSURE (dwOutputAvail >= (DWORD)nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pOutAfter = pbOutputBuf + nBytes;
+
+ if (g->traits.iBitsPerPixel == 24)
+ {
+ while (pOut < pOutAfter)
+ {
+ rIn = (int)(unsigned)(*pIn++);
+ gIn = (int)(unsigned)(*pIn++);
+ bIn = (int)(unsigned)(*pIn++);
+
+ /* for this 24-bit case, we assume that the matrix has already
+ * been shifted down to just 16 bits of fraction instead of 24 */
+ rOut = rIn*g->mat[0] + gIn*g->mat[1] + bIn*g->mat[2];
+ gOut = rIn*g->mat[3] + gIn*g->mat[4] + bIn*g->mat[5];
+ bOut = rIn*g->mat[6] + gIn*g->mat[7] + bIn*g->mat[8];
+
+ /* we have 16 bits of fraction, so round to integer */
+ rOut = (rOut+(1<<15)) >> 16;
+ gOut = (gOut+(1<<15)) >> 16;
+ bOut = (bOut+(1<<15)) >> 16;
+
+ /* make sure the result fits in a byte */
+ if (rOut > 255) rOut = 255; else if (rOut < 0) rOut = 0;
+ if (gOut > 255) gOut = 255; else if (gOut < 0) gOut = 0;
+ if (bOut > 255) bOut = 255; else if (bOut < 0) bOut = 0;
+
+ *pOut++ = (BYTE)rOut;
+ *pOut++ = (BYTE)gOut;
+ *pOut++ = (BYTE)bOut;
+ }
+ }
+ else /* 48 bits per pixel */
+ {
+ WORD *pwIn, *pwOut;
+ pwIn = (WORD*)pIn;
+ pwOut = (WORD*)pOut;
+
+ while (pwOut < (WORD*)pOutAfter)
+ {
+ int prod0, prod1, prod2;
+
+ /* The fixed-point calculations below are as follows:
+ * 17.15 = input pixel
+ * 8.24 = factor from matrix
+ * 25.39 = result of 32x32->64 multiply of above numbers
+ * 25.7 = result of discarding low 32 bits of 64-bit product
+ * Finally, we add (1<<6) and shift right 7 to round to integer.
+ *
+ * The MUL32HIHALF macro does a signed 32x32->64 multiply, and then
+ * discards the low 32 bits, giving you the high 32 bits.
+ */
+
+ rIn = (int)(unsigned)(*pwIn++) << 15;
+ gIn = (int)(unsigned)(*pwIn++) << 15;
+ bIn = (int)(unsigned)(*pwIn++) << 15;
+
+ MUL32HIHALF (rIn, g->mat[0], prod0);
+ MUL32HIHALF (gIn, g->mat[1], prod1);
+ MUL32HIHALF (bIn, g->mat[2], prod2);
+ rOut = (prod0 + prod1 + prod2 + (1<<6)) >> 7;
+ if (rOut > 0x00ffff) rOut = 0x00ffff; else if (rOut < 0) rOut = 0;
+ *pwOut++ = rOut;
+
+ MUL32HIHALF (rIn, g->mat[3], prod0);
+ MUL32HIHALF (gIn, g->mat[4], prod1);
+ MUL32HIHALF (bIn, g->mat[5], prod2);
+ gOut = (prod0 + prod1 + prod2 + (1<<6)) >> 7;
+ if (gOut > 0x00ffff) gOut = 0x00ffff; else if (gOut < 0) gOut = 0;
+ *pwOut++ = gOut;
+
+ MUL32HIHALF (rIn, g->mat[6], prod0);
+ MUL32HIHALF (gIn, g->mat[7], prod1);
+ MUL32HIHALF (bIn, g->mat[8], prod2);
+ bOut = (prod0 + prod1 + prod2 + (1<<6)) >> 7;
+ if (bOut > 0x00ffff) bOut = 0x00ffff; else if (bOut < 0) bOut = 0;
+ *pwOut++ = bOut;
+ }
+ }
+
+ *pdwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->dwRowsDone += 1;
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * mat_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD mat_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * mat_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD mat_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PMAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * mat_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD mat_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PMAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * matTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+#ifdef EXPORT_TRANSFORM
+__declspec (dllexport)
+#endif
+IP_XFORM_TBL matrixTbl = {
+ mat_openXform,
+ mat_setDefaultInputTraits,
+ mat_setXformSpec,
+ mat_getHeaderBufSize,
+ mat_getActualTraits,
+ mat_getActualBufSizes,
+ mat_convert,
+ mat_newPage,
+ mat_insertedData,
+ mat_closeXform
+};
+
+/* End of File */
+
+
+/*****************************************************************************\
+ *
+ * ipGetXformTable - Returns pointer to the jump table
+ *
+\*****************************************************************************/
+
+#ifdef EXPORT_TRANSFORM
+EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL pXform)
+{
+ WORD wRet = IP_DONE;
+
+ if (pXform)
+ {
+ *pXform = clrmapTbl;
+ }
+ else
+ {
+ wRet = IP_FATAL_ERROR;
+ }
+
+ return wRet;
+}
+#endif
diff --git a/ip/xpad.c b/ip/xpad.c
new file mode 100644
index 0000000..5e32eaa
--- /dev/null
+++ b/ip/xpad.c
@@ -0,0 +1,523 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xpad.c - Pads all four sides of the input image with extra pixels
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * padTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_PAD_LEFT ] = left: # of pixels to add to left side (or negative)
+ * aXformInfo[IP_PAD_RIGHT ] = right: # of pixels to add to right side
+ * aXformInfo[IP_PAD_TOP ] = top: # of rows to add to top (or negative)
+ * aXformInfo[IP_PAD_BOTTOM] = bottom: # of rows to add to bottom
+ * aXformInfo[IP_PAD_VALUE ] = pad value (0-255)
+ * aXformInfo[IP_PAD_MIN_HEIGHT] = minimum # of input rows, pad if needed
+ *
+ * The pad value above (at index 4) is the value of the added pad-pixels.
+ * For color data, all three bytes will be set to this value.
+ * For bi-level data, only the lsb is used.
+ *
+ * If 'left' is negative, then the output width will be forced to be a
+ * multiple of abs(left) pixels.
+ * If 'top' is negative, the same thing is done with the height.
+ *
+ * Capabilities and Limitations:
+ *
+ * Pads all four sides of the image.
+ * The image data must be fixed-length rows of uncompressed pixels.
+ * For bilevel data, the "left" value is changed to the nearest multiple
+ * of 8, and the "right" value is changed so the resulting row-width
+ * does not change.
+ * If all pad-amounts above are 0, this xform becomes merely a pass-thru.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * used input width + horiz pad
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows used if known output height, if input known
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input image */
+ DWORD dwLeft, dwRight; /* # pixels to pad, left and right sides */
+ DWORD dwTop; /* # rows to pad to top */
+ DWORD dwBottom; /* # rows to pad to bottom */
+ DWORD dwMinInRows; /* minimum # input rows, pad if necessary */
+ DWORD dwInBytesPerRow; /* # bytes in each input row */
+ DWORD dwOutBytesPerRow; /* # bytes in each output row */
+ DWORD dwLeftPadBytes; /* # bytes to add to left side of each row */
+ DWORD dwRightPadBytes; /* # bytes to add to right side of each row */
+ BYTE bPadVal; /* value of pad pixels */
+ DWORD dwInRows; /* number of rows input so far */
+ DWORD dwOutRows; /* number of rows output so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} PAD_INST, *PPAD_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * pad_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD pad_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PPAD_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(PAD_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(PAD_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pad_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD pad_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PPAD_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
+ g->traits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pad_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD pad_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PPAD_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwLeft = aXformInfo[IP_PAD_LEFT].dword;
+ g->dwRight = aXformInfo[IP_PAD_RIGHT].dword;
+ g->dwTop = aXformInfo[IP_PAD_TOP].dword;
+ g->dwBottom = aXformInfo[IP_PAD_BOTTOM].dword;
+ g->bPadVal = (BYTE)aXformInfo[IP_PAD_VALUE].dword;
+ g->dwMinInRows = aXformInfo[IP_PAD_MIN_HEIGHT].dword;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pad_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD pad_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pad_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD pad_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PPAD_INST g;
+ int left, right, shift, more;
+ int inWidth, outWidth;
+ int bpp;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ /* Compute the pad info */
+
+ bpp = g->traits.iBitsPerPixel;
+ left = g->dwLeft;
+ right = g->dwRight;
+ inWidth = g->traits.iPixelsPerRow;
+
+ if (left < 0) {
+ left = -left;
+ // pad horizontally so that width is a multiple of left
+ outWidth = ((inWidth+left-1) / left) * left;
+ more = outWidth - inWidth;
+ left = more >> 1;
+ right = more - left;
+ g->dwLeft = left;
+ g->dwRight = right;
+ }
+
+ outWidth = inWidth + left + right;
+
+ if (bpp == 1) {
+ /* shift to start at nearest byte boundary */
+ shift = ((left+4) & ~7) - left;
+ left += shift; /* this is now a multiple of 8 */
+ right += shift;
+
+ g->bPadVal = g->bPadVal & 1 ? 0xffu : 0;
+ }
+
+ g->dwInBytesPerRow = (bpp*inWidth + 7) / 8;
+ g->dwOutBytesPerRow = (bpp*outWidth + 7) / 8;
+ g->dwLeftPadBytes = (bpp*left + 7) / 8;
+ g->dwRightPadBytes = g->dwOutBytesPerRow - g->dwInBytesPerRow - g->dwLeftPadBytes;
+
+ /* Report the traits */
+
+ *pInTraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+ pOutTraits->iPixelsPerRow = outWidth;
+
+ if (pInTraits->lNumRows > 0) {
+ if ((int)g->dwTop < 0) {
+ int top, bot, inHeight, outHeight;
+ top = - (int)g->dwTop;
+ // pad vertically so that #rows is a multiple of top
+ inHeight = pInTraits->lNumRows;
+ outHeight = ((inHeight+top-1) / top) * top;
+ more = outHeight - inHeight;
+ top = more >> 1;
+ bot = more - top;
+ g->dwTop = top;
+ g->dwBottom = bot;
+ }
+
+ pOutTraits->lNumRows = pInTraits->lNumRows + g->dwTop + g->dwBottom;
+ }
+
+ INSURE ((int)g->dwLeft >= 0);
+ INSURE ((int)g->dwTop >= 0);
+
+ return IP_DONE | (g->dwTop>0 ? 0 : IP_READY_FOR_DATA);
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * pad_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD pad_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PPAD_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = g->dwInBytesPerRow;
+ *pdwMinOutBufLen = g->dwOutBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pad_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD pad_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PPAD_INST g;
+ BOOL bWhiteRow;
+
+ HANDLE_TO_PTR (hXform, g);
+ bWhiteRow = FALSE;
+
+ /**** Decide what to do ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("pad_convert: Told to flush.\n"), 0, 0);
+
+ if (g->dwInRows < g->dwMinInRows) {
+ /* We need to output another pad row on the bottom */
+ bWhiteRow = TRUE;
+ g->dwInRows += 1;
+ } else if (g->dwBottom > 0) {
+ /* We need to output another pad row on the bottom */
+ bWhiteRow = TRUE;
+ g->dwBottom -= 1;
+ } else {
+ /* We are done */
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+ } else if (g->dwOutRows < g->dwTop) {
+ /* We need to output another pad row on the top */
+ bWhiteRow = TRUE;
+ }
+
+ /**** Output a Row ****/
+
+ INSURE (bWhiteRow || (dwInputAvail >= g->dwInBytesPerRow));
+ INSURE (dwOutputAvail >= g->dwOutBytesPerRow);
+
+ if (bWhiteRow)
+ memset (pbOutputBuf, g->bPadVal, g->dwOutBytesPerRow);
+ else {
+ BYTE *p = pbOutputBuf;
+ memset (p, g->bPadVal, g->dwLeftPadBytes);
+ p += g->dwLeftPadBytes;
+ memcpy (p, pbInputBuf, g->dwInBytesPerRow);
+ p += g->dwInBytesPerRow;
+ memset (p, g->bPadVal, g->dwRightPadBytes);
+
+ g->dwInRows += 1;
+ *pdwInputUsed = g->dwInBytesPerRow;
+ g->dwInNextPos += g->dwInBytesPerRow;
+ }
+
+ g->dwOutRows += 1;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputUsed = g->dwOutBytesPerRow;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += g->dwOutBytesPerRow;
+
+ return (bWhiteRow ? 0 : IP_CONSUMED_ROW) |
+ IP_PRODUCED_ROW |
+ (g->dwOutRows < g->dwTop ? 0 : IP_READY_FOR_DATA);
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pad_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD pad_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pad_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD pad_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PPAD_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pad_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD pad_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PPAD_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * padTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL padTbl = {
+ pad_openXform,
+ pad_setDefaultInputTraits,
+ pad_setXformSpec,
+ pad_getHeaderBufSize,
+ pad_getActualTraits,
+ pad_getActualBufSizes,
+ pad_convert,
+ pad_newPage,
+ pad_insertedData,
+ pad_closeXform
+};
+
+/* End of File */
diff --git a/ip/xpcx.c b/ip/xpcx.c
new file mode 100644
index 0000000..6a9327c
--- /dev/null
+++ b/ip/xpcx.c
@@ -0,0 +1,1318 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*****************************************************************************\
+ *
+ * xpcx.c - encoder and decoder for PCX files for Image Processor
+ *
+ *****************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * pcxEncodeTbl = the encoder,
+ * pcxDecodeTbl = the decoder.
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * none
+ *
+ * Capabilities and Limitations:
+ *
+ * Handles 1 or 4 bits per pixel.
+ * Decoder discards the palette in the PCX file (todo: keep it).
+ * Encoder assumes input is internal raw format, which means that
+ * 1 and 4 bits/pixel are assumed to be grayscales, where
+ * 1 bit/pixel is [0=white, 1=black], 4 bits/pixel is [0=black, 15=white].
+ * Encoder outputs a palette for the preceding gray-ranges.
+ * If # rows is not known in input traits (negative), the encoder will
+ * re-write the header when # rows is known at the end of the page. So
+ * the output file will have a valid row-count when conversion is done.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * For decoder:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow ignored based on header
+ * iBitsPerPixel ignored based on header (1 or 4)
+ * iComponentsPerPixel ignored 1
+ * lHorizDPI ignored based on header
+ * lVertDPI ignored based on header
+ * lNumRows ignored based on header
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * For encoder:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * must be 1 or 4 same as default input
+ * iComponentsPerPixel passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Mark Overton, Feb 1998
+ *
+\*****************************************************************************/
+
+/* todo: this PCX code encodes/decodes 4-bit gray as one pixel per byte.
+ * it should be two pixels per byte.
+ */
+
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x1ce5ca7e
+
+/* TODO: Make this work for big and little endian. */
+#define LITTLE_ENDIAN (! (defined SNAKES))
+
+
+/* PCX_INST - our instance variables */
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the image */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ BOOL fDidHeader; /* already processed the header? */
+ BYTE *pPlanes; /* buffer containing separated planes */
+ UINT uBytesPerRawRow; /* number of bytes per unencoded row */
+ UINT uBytesPerPlane; /* number of bytes per plane per row */
+ UINT uRowsDone; /* number of rows converted so far */
+ DWORD dwValidChk; /* struct validity check value */
+} PCX_INST, *PPCX_INST;
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | pcx_header_t | Each PCX file starts with this 128-byte header |
+ |______________|_____________________________________________________________|
+*/
+typedef struct {
+ BYTE PcxId; /* must be 0Ah, which means PC Paintbrush */
+ BYTE Version; /* 2=v2.8 w/ palette; 3=v2.8 w/o pal; 5=v3 w/ pal */
+ BYTE EncodingMethod; /* encoding method == 1 */
+ BYTE BitsPerPixel; /* = 1 for fax mode transfers */
+ WORD XMin; /* X position of the upper left corner */
+ WORD YMin; /* Y position of the upper left corner */
+ WORD XMax; /* X position of the bottom right corner */
+ WORD YMax; /* Y position of the bottom right corner */
+ WORD HorizResolution; /* horizontal resolution */
+ WORD VertResolution; /* vertical resolution */
+ BYTE PaletteInfo[48]; /* Palette information */
+ BYTE Reserved1; /* reserved, must be zero */
+ BYTE ColorPlanes; /* number of color planes == 1 */
+ WORD BytesPerPlane; /* bytes per plane per row */
+ BYTE Reserved2[60]; /* reserved, should be zero */
+} pcx_header_t;
+
+#define PCX_ID 0x0A
+#define PCX_VERSION 2
+#define PCX_HEADER_SIZE 128
+
+
+/*____________________________________________________________________________
+ | | |
+ | swap_header_bytes | if big-endian machine, swaps bytes in WORD items |
+ |___________________|________________________________________________________|
+*/
+static void swap_header_bytes (pcx_header_t *head_p)
+{
+#if ! LITTLE_ENDIAN
+ #define SWAP_IT(item) \
+ head_p->item = (head_p->item << 8) | (head_p->item >> 8)
+
+ SWAP_IT (XMin);
+ SWAP_IT (YMin);
+ SWAP_IT (XMax);
+ SWAP_IT (YMax);
+ SWAP_IT (HorizResolution);
+ SWAP_IT (VertResolution);
+ SWAP_IT (BytesPerPlane);
+#endif
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | encode_buffer | encodes inbuf (separated planes) into run-length PCX data |
+ |_______________|____________________________________________________________|
+*/
+static UINT encode_buffer ( /* ret-val is # bytes written to outbuf */
+ PCX_INST *g, /* in: our instance variables */
+ BYTE *inbuf_p, /* in: ptr to inbuf having separated planes */
+ BYTE *outbuf_p) /* in: ptr to outbuf to get PCX run-lens */
+{
+ BYTE *out_p;
+ BYTE *beg_run_p;
+ BYTE *aft_run_p;
+ BYTE *inbuf_aft_p;
+ BYTE byt;
+ UINT run_len;
+
+ out_p = outbuf_p;
+ beg_run_p = inbuf_p;
+ inbuf_aft_p = inbuf_p + g->uBytesPerPlane * g->traits.iBitsPerPixel;
+
+ while (beg_run_p < inbuf_aft_p)
+ {
+ byt = *beg_run_p;
+
+ for (aft_run_p = beg_run_p+1;
+ aft_run_p<inbuf_aft_p && *aft_run_p==byt;
+ aft_run_p++) ;
+
+ run_len = aft_run_p - beg_run_p;
+ if (run_len > 63) {
+ run_len = 63;
+ aft_run_p = beg_run_p + 63;
+ }
+
+ if (run_len>1 || byt>=(BYTE)0xc0)
+ *out_p++ = (BYTE)run_len | (BYTE)0xc0;
+ *out_p++ = byt;
+
+ beg_run_p = aft_run_p;
+ }
+
+ return out_p - outbuf_p;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | decode_buffer | decodes PCX run-length data into separated planes |
+ |_______________|____________________________________________________________|
+*/
+static UINT decode_buffer ( /* ret-val is # bytes read from inbuf */
+ PCX_INST *g, /* in: our instance variables */
+ BYTE *inbuf_p, /* in: ptr to input buffer */
+ BYTE *outbuf_p) /* in: ptr to output buffer */
+{
+ BYTE *in_p;
+ BYTE *out_p;
+ BYTE *out_aft_p;
+ UINT run_len;
+ BYTE byt;
+
+ in_p = inbuf_p;
+ out_p = outbuf_p;
+ out_aft_p = outbuf_p + g->uBytesPerPlane*g->traits.iBitsPerPixel;
+
+ while (out_p < out_aft_p)
+ {
+ byt = *in_p++;
+
+ if (byt < (BYTE)0xc0)
+ *out_p++ = byt;
+ else {
+ run_len = byt & (BYTE)0x3f;
+ if (run_len > (UINT) (out_aft_p - out_p))
+ run_len = out_aft_p-out_p; /* run went past end of outbuf */
+ memset (out_p, *in_p++, run_len);
+ out_p += run_len;
+ }
+ }
+
+ return in_p - inbuf_p;
+}
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Encoding/Decoding Bilevel |
+ |____________________________________________________________________________|
+*/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | flip_pixels | in PCX, 0=black and 1=white, so this flips all the bits |
+ |_____________|______________________________________________________________|
+*/
+static void flip_pixels (
+ PCX_INST *g, /* our instance variables */
+ BYTE *byte_buf_p) /* ptr to buffer to be flipped */
+{
+ ULONG *buf_p;
+ ULONG *buf_aft_p;
+
+ buf_p = (ULONG*)byte_buf_p;
+ buf_aft_p = buf_p + ((g->uBytesPerRawRow+3) >> 2);
+ for ( ; buf_p<buf_aft_p; buf_p++)
+ *buf_p = ~ *buf_p;
+}
+
+
+
+static UINT encode_1 (
+ PCX_INST *g, /* in: our instance variables */
+ BYTE *inbuf_p, /* in: ptr to input buffer */
+ BYTE *outbuf_p) /* in: ptr to output buffer */
+{
+ UINT n_bytes;
+
+ flip_pixels (g, inbuf_p);
+ n_bytes = encode_buffer (g, inbuf_p, outbuf_p);
+ flip_pixels (g, inbuf_p);
+ return n_bytes;
+}
+
+
+
+static UINT decode_1 (
+ PCX_INST *g, /* in: our instance variables */
+ BYTE *inbuf_p, /* in: ptr to input buffer */
+ BYTE *outbuf_p) /* in: ptr to output buffer */
+{
+ UINT used;
+
+ used = decode_buffer (g, inbuf_p, outbuf_p);
+ flip_pixels (g, outbuf_p);
+ return used;
+}
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Encoding/Decoding 16-Level |
+ |____________________________________________________________________________|
+*/
+
+
+#if 0
+
+/*____________________________________________________________________________
+ | | |
+ | pcxtable.c | Outputs table for PCX's 16-level decoder to stdout |
+ |____________|_______________________________________________________________|
+*/
+
+#include <stdio.h>
+#define little_endian 1
+
+void main (void)
+{
+ unsigned nib;
+ long unsigned outlong;
+
+ for (nib=0; nib<=15; nib++) {
+ outlong = 0;
+ if (nib & 0x08) outlong |= 0x10000000;
+ if (nib & 0x04) outlong |= 0x00100000;
+ if (nib & 0x02) outlong |= 0x00001000;
+ if (nib & 0x01) outlong |= 0x00000010;
+
+ if (little_endian)
+ outlong = (outlong & 0xff000000) >> 24 |
+ (outlong & 0x00ff0000) >> 8 |
+ (outlong & 0x0000ff00) << 8 |
+ (outlong & 0x000000ff) << 24;
+
+ _tprintf (_T("0x%08x, "), outlong);
+ if ((nib%4) == 3) _tputs(_T(""));
+ }
+ _tputs (_T(""));
+}
+
+#endif
+
+
+
+static UINT encode_4 (
+ PCX_INST *g, /* in: our instance variables */
+ BYTE *inbuf_p, /* in: ptr to input buffer */
+ BYTE *outbuf_p) /* in: ptr to output buffer */
+{
+ #if LITTLE_ENDIAN
+ #define NIB_0 0x000000f0
+ #define NIB_1 0x0000f000
+ #define NIB_2 0x00f00000
+ #define NIB_3 0xf0000000
+ #else
+ #define NIB_0 0xf0000000
+ #define NIB_1 0x00f00000
+ #define NIB_2 0x0000f000
+ #define NIB_3 0x000000f0
+ #endif
+
+ ULONG *in_p;
+ ULONG *in_aft_p;
+ BYTE *plane_p;
+ ULONG quad;
+ ULONG mask;
+ BYTE byt;
+
+ /* Separate the four planes (into pPlanes) */
+
+ in_aft_p = (ULONG *) (inbuf_p + g->uBytesPerRawRow);
+ plane_p = g->pPlanes;
+ mask = 0x10101010;
+
+ while (TRUE)
+ {
+ for (in_p=(ULONG*)inbuf_p; in_p<in_aft_p; ) {
+ byt = 0;
+ quad = *in_p++ & mask;
+ if (quad & NIB_0) byt = 0x80;
+ if (quad & NIB_1) byt |= 0x40;
+ if (quad & NIB_2) byt |= 0x20;
+ if (quad & NIB_3) byt |= 0x10;
+
+ quad = *in_p++ & mask;
+ if (quad & NIB_0) byt |= 0x08;
+ if (quad & NIB_1) byt |= 0x04;
+ if (quad & NIB_2) byt |= 0x02;
+ if (quad & NIB_3) byt |= 0x01;
+ *plane_p++ = byt;
+ }
+
+ if (mask == 0x80808080)
+ break;
+ mask <<= 1;
+ }
+
+ return encode_buffer (g, g->pPlanes, outbuf_p);
+}
+
+
+
+static UINT decode_4 (
+ PCX_INST *g, /* in: our instance variables */
+ BYTE *inbuf_p, /* in: ptr to input buffer */
+ BYTE *outbuf_p) /* in: ptr to output buffer */
+{
+ #if LITTLE_ENDIAN
+ static const ULONG unscramble[16] = {
+ 0x00000000, 0x10000000, 0x00100000, 0x10100000,
+ 0x00001000, 0x10001000, 0x00101000, 0x10101000,
+ 0x00000010, 0x10000010, 0x00100010, 0x10100010,
+ 0x00001010, 0x10001010, 0x00101010, 0x10101010,
+ };
+ #else
+ static const ULONG unscramble[16] = {
+ 0x00000000, 0x00000010, 0x00001000, 0x00001010,
+ 0x00100000, 0x00100010, 0x00101000, 0x00101010,
+ 0x10000000, 0x10000010, 0x10001000, 0x10001010,
+ 0x10100000, 0x10100010, 0x10101000, 0x10101010,
+ };
+ #endif
+
+ UINT used;
+ BYTE *plane_p;
+ BYTE *plane_aft_p;
+ ULONG *out_p;
+
+ used = decode_buffer (g, inbuf_p, g->pPlanes);
+
+ /* Combine the separated planes (in pPlanes) back into pixels */
+
+ plane_p = g->pPlanes;
+
+ out_p = (ULONG*)outbuf_p;
+ plane_aft_p = plane_p + g->uBytesPerPlane;
+ for (; plane_p<plane_aft_p; plane_p++) {
+ *out_p++ = unscramble[*plane_p >> 4];
+ *out_p++ = unscramble[*plane_p & 15];
+ }
+
+ out_p = (ULONG*)outbuf_p;
+ plane_aft_p = plane_p + g->uBytesPerPlane;
+ for (; plane_p<plane_aft_p; plane_p++) {
+ *out_p++ |= unscramble[*plane_p >> 4] << 1;
+ *out_p++ |= unscramble[*plane_p & 15] << 1;
+ }
+
+ out_p = (ULONG*)outbuf_p;
+ plane_aft_p = plane_p + g->uBytesPerPlane;
+ for (; plane_p<plane_aft_p; plane_p++) {
+ *out_p++ |= unscramble[*plane_p >> 4] << 2;
+ *out_p++ |= unscramble[*plane_p & 15] << 2;
+ }
+
+ out_p = (ULONG*)outbuf_p;
+ plane_aft_p = plane_p + g->uBytesPerPlane;
+ for (; plane_p<plane_aft_p; plane_p++) {
+ *out_p++ |= unscramble[*plane_p >> 4] << 3;
+ *out_p++ |= unscramble[*plane_p & 15] << 3;
+ }
+
+ return used;
+}
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Encoding/Decoding 256-Level |
+ |____________________________________________________________________________|
+*/
+
+
+#if 0
+
+static UINT encode_8 (
+ PCX_INST *g, /* in: our instance variables */
+ BYTE *inbuf_p, /* in: ptr to input buffer */
+ BYTE *outbuf_p) /* in: ptr to output buffer */
+{
+ assert (0);
+ return 0;
+}
+
+
+
+static UINT decode_8 (
+ PCX_INST *g, /* in: our instance variables */
+ BYTE *inbuf_p, /* in: ptr to input buffer */
+ BYTE *outbuf_p) /* in: ptr to output buffer */
+{
+ assert (0);
+ return 0;
+}
+
+#endif /* 256-level stuff */
+
+
+
+/*
+******************************************************************************
+******************************************************************************
+**
+**
+** E N C O D E R
+**
+**
+******************************************************************************
+******************************************************************************
+*/
+
+
+
+/*****************************************************************************\
+ *
+ * pcxEncode_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD pcxEncode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PPCX_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(PCX_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(PCX_INST));
+ g->dwValidChk = CHECK_VALUE;
+ INSURE (sizeof(pcx_header_t) == PCX_HEADER_SIZE);
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxEncode_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD pcxEncode_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PPCX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ INSURE (pTraits->iBitsPerPixel==1 || pTraits->iBitsPerPixel==4);
+ INSURE (pTraits->iPixelsPerRow > 0);
+ g->traits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxEncode_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD pcxEncode_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PPCX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* do nothing, because we don't have any xform-specific info */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxEncode_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD pcxEncode_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ *pdwInBufLen = 0; /* no header on raw input data */
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxEncode_getActualTraits - Parses header, and returns input & output traits
+ *
+ *****************************************************************************
+ *
+ * If depth is 1, a bilevel PCX will be encoded/decoded from/to a
+ * RASTER_BITMAP image.
+ *
+ * If depth is 4, a 16-level PCX will be encoded/decoded from/to gray data.
+ * The 4-bit gray value is in the upper nibble of each byte in the raw gray
+ * data.
+ *
+ * If depth is 8, a 256-level PCX will be encoded/decoded from/to gray data.
+ *
+ * If depth is 24, the PCX will be encoded/decoded from/to RGB data.
+ *
+\*****************************************************************************/
+
+static WORD pcxEncode_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PPCX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no input header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ /* Since we don't change traits, just copy out the default traits */
+ *pInTraits = g->traits;
+ *pOutTraits = g->traits;
+
+ /***************************/
+ /* Process the traits info */
+ /***************************/
+
+ g->uBytesPerPlane = (g->traits.iPixelsPerRow + 7) / 8;
+ g->uBytesPerRawRow = g->traits.iBitsPerPixel == 1
+ ? g->uBytesPerPlane
+ : g->traits.iPixelsPerRow;
+
+ PRINT (_T("pcx_encode_output_header: pixels/row=%d, n_rows=%d\n"),
+ g->traits.iPixelsPerRow, g->traits.lNumRows);
+ PRINT (_T("pcx_encode_output_header: depth=%d, uBytesPerRawRow=%d\n"),
+ g->traits.iBitsPerPixel, g->uBytesPerRawRow);
+
+ if (g->traits.iBitsPerPixel > 1)
+ IP_MEM_ALLOC (g->uBytesPerPlane*g->traits.iBitsPerPixel, g->pPlanes);
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * pcxEncode_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD pcxEncode_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PPCX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = g->uBytesPerRawRow;
+ *pdwMinOutBufLen = g->traits.iBitsPerPixel * g->uBytesPerPlane * 2;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * outputHeader - Only called by pcxEncode_convert
+ *
+\****************************************************************************/
+
+static WORD outputHeader (
+ PPCX_INST g, /* in: ptr to instance structure */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ pcx_header_t *pPCXHeader;
+ PIP_IMAGE_TRAITS pTr;
+ BYTE *pal_p;
+ UINT i;
+
+ *pdwOutputThisPos = 0;
+ *pdwOutputUsed = PCX_HEADER_SIZE;
+ g->dwOutNextPos = PCX_HEADER_SIZE;
+ INSURE (dwOutputAvail >= PCX_HEADER_SIZE);
+
+ pTr = &g->traits;
+ pPCXHeader = (pcx_header_t *)pbOutputBuf;
+
+ pPCXHeader->PcxId = PCX_ID;
+ pPCXHeader->Version = PCX_VERSION;
+ pPCXHeader->EncodingMethod = 1;
+ pPCXHeader->BitsPerPixel = 1;
+ pPCXHeader->XMin = 0;
+ pPCXHeader->YMin = 0;
+ pPCXHeader->XMax = pTr->iPixelsPerRow - 1;
+ pPCXHeader->YMax = pTr->lNumRows<=0 ? 0 : pTr->lNumRows-1;
+ pPCXHeader->HorizResolution = (USHORT)(pTr->lHorizDPI>>16); /* todo: use width */
+ pPCXHeader->VertResolution = (USHORT)(pTr->lVertDPI >>16); /* and height? */
+ pPCXHeader->Reserved1 = 0;
+ pPCXHeader->ColorPlanes = pTr->iBitsPerPixel;
+ pPCXHeader->BytesPerPlane = g->uBytesPerPlane;
+
+ memset (pPCXHeader->Reserved2, 0, 60);
+
+ pal_p = pPCXHeader->PaletteInfo;
+ if (pTr->iBitsPerPixel == 1) {
+ memset (pal_p, 0, 48);
+ pal_p[3] = pal_p[4] = pal_p[5] = 255; /* 0=black, 1=white */
+ } else {
+ /* set the palette to a black-to-white gray ramp */
+ for (i=0; i<=15; i++) {
+ *pal_p++ = i << 4; /* red */
+ *pal_p++ = i << 4; /* green */
+ *pal_p++ = i << 4; /* blue */
+ }
+ }
+
+ swap_header_bytes (pPCXHeader);
+ return IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxEncode_convert - the work-horse routine
+ *
+\*****************************************************************************/
+
+static WORD pcxEncode_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PPCX_INST g;
+ UINT out_used = 0; /* init to zap stupid compiler warning */
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Output the Header if we haven't already ****/
+
+ if (! g->fDidHeader) {
+ g->fDidHeader = TRUE;
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+ return outputHeader (g, dwOutputAvail, pbOutputBuf,
+ pdwOutputUsed, pdwOutputThisPos);
+ }
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("pcx_encode_convert_row: Told to flush.\n"), 0, 0);
+ if (g->traits.lNumRows < 0) {
+ /* # rows wasn't known at first, so output header again
+ * now that we know the number of rows */
+ g->traits.lNumRows = g->uRowsDone;
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ return outputHeader (g, dwOutputAvail, pbOutputBuf,
+ pdwOutputUsed, pdwOutputThisPos);
+ }
+
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ switch (g->traits.iBitsPerPixel) {
+ case 1: out_used = encode_1 (g, pbInputBuf, pbOutputBuf);
+ break;
+
+ case 4: out_used = encode_4 (g, pbInputBuf, pbOutputBuf);
+ break;
+ #if 0
+ case 8: out_used = encode_8 (g, pbInputBuf, pbOutputBuf);
+ break;
+ #endif
+ }
+
+ INSURE (dwInputAvail >= g->uBytesPerRawRow);
+ INSURE (dwOutputAvail >= out_used);
+
+ g->dwInNextPos += g->uBytesPerRawRow;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwInputUsed = g->uBytesPerRawRow;
+ *pdwOutputUsed = out_used;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += out_used;
+
+ g->uRowsDone += 1;
+
+ PRINT (_T("pcx_encode_convert_row: Returning, out used = %d\n"), out_used, 0);
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxEncode_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD pcxEncode_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxEncode_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD pcxEncode_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PPCX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxEncode_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD pcxEncode_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PPCX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ if (g->pPlanes != NULL)
+ IP_MEM_FREE (g->pPlanes);
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxEncodeTbl - Jump-table for encoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL pcxEncodeTbl = {
+ pcxEncode_openXform,
+ pcxEncode_setDefaultInputTraits,
+ pcxEncode_setXformSpec,
+ pcxEncode_getHeaderBufSize,
+ pcxEncode_getActualTraits,
+ pcxEncode_getActualBufSizes,
+ pcxEncode_convert,
+ pcxEncode_newPage,
+ pcxEncode_insertedData,
+ pcxEncode_closeXform
+};
+
+
+
+/*
+******************************************************************************
+******************************************************************************
+**
+**
+** D E C O D E R
+**
+**
+******************************************************************************
+******************************************************************************
+*/
+
+
+
+/*****************************************************************************\
+ *
+ * pcxDecode_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD pcxDecode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ return pcxEncode_openXform(pXform); /* allocs & zeroes a new instance */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxDecode_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD pcxDecode_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PPCX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* the PCX header will overwrite most items in traits below */
+ g->traits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxDecode_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD pcxDecode_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PPCX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* do nothing, because we don't have any xform-specific info */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxDecode_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD pcxDecode_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ *pdwInBufLen = PCX_HEADER_SIZE;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxDecode_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD pcxDecode_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PPCX_INST g;
+ pcx_header_t *pcxhead_p;
+ PIP_IMAGE_TRAITS pTr;
+ WORD ret_val;
+
+ ret_val = IP_DONE | IP_READY_FOR_DATA;
+ HANDLE_TO_PTR (hXform, g);
+
+ INSURE (dwInputAvail >= PCX_HEADER_SIZE);
+ *pdwInputUsed = PCX_HEADER_SIZE;
+ *pdwInputNextPos = PCX_HEADER_SIZE;
+ g->dwInNextPos = PCX_HEADER_SIZE;
+
+ pcxhead_p = (pcx_header_t*)pbInputBuf;
+ pTr = &g->traits;
+
+ swap_header_bytes (pcxhead_p);
+ pTr->lNumRows = pcxhead_p->YMax - pcxhead_p->YMin + 1;
+ pTr->iPixelsPerRow = pcxhead_p->XMax - pcxhead_p->XMin + 1;
+ pTr->iBitsPerPixel = pcxhead_p->ColorPlanes;
+ pTr->lHorizDPI = (ULONG)pcxhead_p->HorizResolution << 16;
+ pTr->lVertDPI = (ULONG)pcxhead_p->VertResolution << 16;
+ pTr->iComponentsPerPixel = 1;
+ g->uBytesPerPlane = pcxhead_p->BytesPerPlane;
+ swap_header_bytes (pcxhead_p);
+
+ g->uBytesPerRawRow = pTr->iBitsPerPixel == 1
+ ? g->uBytesPerPlane
+ : g->traits.iPixelsPerRow;
+
+ if (! (pcxhead_p->PcxId == PCX_ID
+ && pTr->iPixelsPerRow > 1
+ && g->uBytesPerPlane == ((UINT)pTr->iPixelsPerRow+7)/8
+ && (pTr->iBitsPerPixel==1 || pTr->iBitsPerPixel==4)))
+ ret_val |= IP_INPUT_ERROR;
+
+ if (pTr->iBitsPerPixel > 1)
+ IP_MEM_ALLOC (g->uBytesPerPlane*pTr->iBitsPerPixel, g->pPlanes);
+
+ if (pTr->lNumRows <= 1)
+ pTr->lNumRows = -1; /* both YMax and YMin were 0; # rows is unknown */
+
+ *pInTraits = *pOutTraits = g->traits; /* structure copy */
+
+ PRINT (_T("pcx_decode_parse_header: depth=%d, n_rows=%d\n"),
+ g->traits.iBitsPerPixel, g->traits.lNumRows);
+
+ return ret_val;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * pcxDecode_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD pcxDecode_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PPCX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = g->traits.iBitsPerPixel * g->uBytesPerPlane * 2;
+ *pdwMinOutBufLen = g->uBytesPerRawRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxDecode_convert - the work-horse routine
+ *
+\*****************************************************************************/
+
+static WORD pcxDecode_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PPCX_INST g;
+ DWORD in_used=0;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ if (pbInputBuf == NULL) {
+ /* we are being told to flush */
+ PRINT (_T("pcx_decode_convert_row: Told to flush; doing nothing.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ if (g->traits.lNumRows>=0 && g->uRowsDone==(UINT)g->traits.lNumRows) {
+ /* discard extra data after final row */
+ *pdwInputUsed = dwInputAvail;
+ g->dwInNextPos += dwInputAvail;
+ *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return 0;
+ }
+
+ switch (g->traits.iBitsPerPixel) {
+ case 1: in_used = decode_1 (g, pbInputBuf, pbOutputBuf);
+ break;
+
+ case 4: in_used = decode_4 (g, pbInputBuf, pbOutputBuf);
+ break;
+ #if 0
+ case 8: in_used = decode_8 (g, pbInputBuf, pbOutputBuf);
+ break;
+ #endif
+ }
+
+ INSURE (dwInputAvail >= in_used);
+ INSURE (dwOutputAvail >= g->uBytesPerRawRow);
+
+ g->dwInNextPos += in_used;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwInputUsed = in_used;
+ *pdwOutputUsed = g->uBytesPerRawRow;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += g->uBytesPerRawRow;
+
+ g->uRowsDone += 1;
+
+ PRINT (_T("pcx_decode_convert_row: Returning, in used = %d\n"), in_used, 0);
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxDecode_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD pcxDecode_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxDecode_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD pcxDecode_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PPCX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxDecode_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD pcxDecode_closeXform (IP_XFORM_HANDLE hXform)
+{
+ return pcxEncode_closeXform (hXform);
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pcxDecodeTbl - Jump-table for Decoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL pcxDecodeTbl = {
+ pcxDecode_openXform,
+ pcxDecode_setDefaultInputTraits,
+ pcxDecode_setXformSpec,
+ pcxDecode_getHeaderBufSize,
+ pcxDecode_getActualTraits,
+ pcxDecode_getActualBufSizes,
+ pcxDecode_convert,
+ pcxDecode_newPage,
+ pcxDecode_insertedData,
+ pcxDecode_closeXform
+};
+
+/* End of File */
diff --git a/ip/xpnm.c b/ip/xpnm.c
new file mode 100644
index 0000000..5f814df
--- /dev/null
+++ b/ip/xpnm.c
@@ -0,0 +1,591 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: David Paschal (based on Mark Overton's "xskel" template). */
+
+/******************************************************************************\
+ *
+ * xpnm.c - encoder and decoder for PNM (PBM, PGM, PPM) files
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * pnmEncodeTbl = the encoder.
+ * pnmDecodeTbl = the decoder.
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * None.
+ *
+ * Capabilities and Limitations:
+ *
+ * Handles 1, 8, and 24 bits per pixel.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel * passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+#include <stdio.h>
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+#define FUNC_STATUS static
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input and output image */
+ DWORD dwBytesPerRow; /* # of bytes in each row */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+ BOOL fIsEncode; /* false=decode, true=encode */
+ BOOL fDidHeader; /* already sent/processed the header? */
+} PNM_INST, *PPNM_INST;
+
+#define MAX_DECODE_HEADER_SIZE 4096
+#define MAX_ENCODE_HEADER_SIZE 128
+
+
+
+/*****************************************************************************\
+ *
+ * pnm{De,En}code_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD pnmDecode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PPNM_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(PNM_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(PNM_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+FUNC_STATUS WORD pnmEncode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ WORD wResult=pnmDecode_openXform(pXform);
+ if (wResult==IP_DONE) {
+ PPNM_INST g;
+
+ HANDLE_TO_PTR (*pXform, g);
+
+ g->dwOutNextPos=MAX_ENCODE_HEADER_SIZE;
+ g->fIsEncode=TRUE;
+ }
+ return wResult;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+/*****************************************************************************\
+ *
+ * pnm_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD pnm_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PPNM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->traits = *pTraits; /* a structure copy */
+ if (g->fIsEncode) {
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
+ g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ }
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pnm_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD pnm_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PPNM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Check your options in aXformInfo here, and save them.
+ * Use the INSURE macro like you'd use assert. INSURE jumps to
+ * fatal_error below if it fails.
+ */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pnm_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD pnm_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ PPNM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ if (!g->fIsEncode) {
+ *pdwInBufLen = MAX_DECODE_HEADER_SIZE;
+ } else {
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ }
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pnm_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+#define PEEK_CHAR(pc) \
+ do { \
+ if (*pdwInputUsed>=dwInputAvail) { \
+ return IP_INPUT_ERROR; \
+ } \
+ *(pc)=pbInputBuf[*pdwInputUsed]; \
+ } while (0)
+
+#define NEXT_CHAR ((*pdwInputUsed)++)
+
+#define GET_CHAR(pc) \
+ do { \
+ PEEK_CHAR(pc); \
+ NEXT_CHAR; \
+ } while (0)
+
+#define SKIP_WS \
+ do { \
+ unsigned char c; \
+ PEEK_CHAR(&c); \
+ if (c=='#') { \
+ /* NEXT_CHAR; */ \
+ do { \
+ GET_CHAR(&c); \
+ } while (c!='\n'); \
+ PEEK_CHAR(&c); \
+ } \
+ if (c>' ') break; \
+ NEXT_CHAR; \
+ } while (42)
+
+#define GET_INT(pi) \
+ do { \
+ unsigned char c; \
+ *(pi)=0; \
+ SKIP_WS; \
+ while (42) { \
+ GET_CHAR(&c); \
+ c-='0'; \
+ if (c>9) { \
+ break; \
+ } \
+ *(pi)=(*(pi)*10)+c; \
+ } \
+ } while (0)
+
+FUNC_STATUS WORD pnm_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PPNM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* If there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+
+ /* Parse the header for decode operations. */
+ if (!g->fIsEncode) {
+ unsigned char c;
+ unsigned int maxval;
+
+ GET_CHAR(&c);
+ if (c!='P') {
+ return IP_INPUT_ERROR;
+ }
+ GET_CHAR(&c);
+ if (c=='4') {
+ /* PBM */
+ g->traits.iComponentsPerPixel=1;
+ g->traits.iBitsPerPixel=1;
+
+ } else if (c=='5') {
+ /* PGM */
+ g->traits.iComponentsPerPixel=1;
+ g->traits.iBitsPerPixel=0;
+
+ } else if (c=='6') {
+ /* PPM */
+ g->traits.iComponentsPerPixel=3;
+ g->traits.iBitsPerPixel=0;
+
+ } else {
+ /* "Plain" (all-ASCII) formats (1-3) not (yet) supported. */
+ return IP_INPUT_ERROR;
+ }
+
+ GET_INT(&g->traits.iPixelsPerRow);
+ GET_INT(&g->traits.lNumRows);
+ if (!g->traits.iBitsPerPixel) {
+ GET_INT(&maxval);
+ while (maxval) {
+ g->traits.iBitsPerPixel++;
+ maxval>>=1;
+ }
+ }
+ g->traits.iBitsPerPixel*=g->traits.iComponentsPerPixel;
+ g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ }
+
+ *pdwInputNextPos = *pdwInputUsed;
+ g->dwInNextPos = *pdwInputUsed;
+
+ *pInTraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * pnm_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+FUNC_STATUS WORD pnm_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PPNM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pnm_convert - Converts one row
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD pnm_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PPNM_INST g;
+ int nBytes;
+ PBYTE pIn, pOut;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("pnm_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ if (g->fIsEncode && !g->fDidHeader) {
+ BYTE buffer[MAX_ENCODE_HEADER_SIZE];
+ DWORD maxval=(2<<((g->traits.iBitsPerPixel/
+ g->traits.iComponentsPerPixel)-1))-1;
+ int len;
+
+ INSURE(dwOutputAvail>=MAX_ENCODE_HEADER_SIZE);
+
+ memset(pbOutputBuf,' ',MAX_ENCODE_HEADER_SIZE);
+ pbOutputBuf[0]='P';
+ if (g->traits.iComponentsPerPixel==1) {
+ if (maxval==1) {
+ pbOutputBuf[1]='4';
+ } else {
+ pbOutputBuf[1]='5';
+ }
+ } else if (g->traits.iComponentsPerPixel==3) {
+ pbOutputBuf[1]='6';
+ } else {
+ goto fatal_error;
+ }
+
+ snprintf((char *)buffer,MAX_ENCODE_HEADER_SIZE,"\n%d %d\n",
+ g->traits.iPixelsPerRow,g->dwRowsDone);
+ if (g->traits.iComponentsPerPixel>1 || maxval>1) {
+ buffer[MAX_ENCODE_HEADER_SIZE-1]=0;
+ len=strlen((char *)buffer);
+ snprintf((char *)buffer+len,MAX_ENCODE_HEADER_SIZE-len,
+ "%d\n",maxval);
+ }
+
+ buffer[MAX_ENCODE_HEADER_SIZE-1]=0;
+ len=strlen((char *)buffer);
+ memcpy(pbOutputBuf+MAX_ENCODE_HEADER_SIZE-len,buffer,len);
+
+ *pdwOutputUsed=MAX_ENCODE_HEADER_SIZE;
+ *pdwOutputThisPos=0;
+ g->dwOutNextPos=MAX_ENCODE_HEADER_SIZE;
+ g->fDidHeader=1;
+ }
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = g->dwBytesPerRow;
+ INSURE (dwInputAvail >= (DWORD)nBytes );
+ INSURE (dwOutputAvail >= (DWORD)nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+
+ /* At this point, pIn is your input buffer, and pOut is your output buffer.
+ * Do whatever you are going to do here.
+ */
+ memcpy(pOut,pIn,nBytes);
+
+ *pdwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pnm_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD pnm_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pnm_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD pnm_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PPNM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pnm_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD pnm_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PPNM_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * pnmTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+IP_XFORM_TBL pnmDecodeTbl = {
+ pnmDecode_openXform,
+ pnm_setDefaultInputTraits,
+ pnm_setXformSpec,
+ pnm_getHeaderBufSize,
+ pnm_getActualTraits,
+ pnm_getActualBufSizes,
+ pnm_convert,
+ pnm_newPage,
+ pnm_insertedData,
+ pnm_closeXform
+};
+
+IP_XFORM_TBL pnmEncodeTbl = {
+ pnmEncode_openXform,
+ pnm_setDefaultInputTraits,
+ pnm_setXformSpec,
+ pnm_getHeaderBufSize,
+ pnm_getActualTraits,
+ pnm_getActualBufSizes,
+ pnm_convert,
+ pnm_newPage,
+ pnm_insertedData,
+ pnm_closeXform
+};
+
+/* End of File */
diff --git a/ip/xrotate.c b/ip/xrotate.c
new file mode 100644
index 0000000..130b05a
--- /dev/null
+++ b/ip/xrotate.c
@@ -0,0 +1,819 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xrotate.c - Rotates the image
+ *
+ * Mark Overton, Feb 2000
+ *
+ ******************************************************************************
+ *
+ * Imagine a rotated rectangle contained somewhere within the input image, or
+ * even partially outside the input image. This xform outputs that rectangle
+ * unrotated. This xform crops out all image-area outside the rotated rectangle,
+ * and white-fills any part of the rectangle outside the image-area. It is
+ * intended for procuring a selected portion of a scan.
+ *
+ * A rotated rectangle is specified using three points in the input image.
+ * Depending on the orientation of these points, horizontal and/or vertical
+ * flipping can be performed, as well as rotation by any angle.
+ *
+ * Scaling is also performed. The interpolation for rotation also does the
+ * scaling in the same step, resulting in higher quality output than the usual
+ * use of separate rotation and scaling, as well as being faster.
+ *
+ * Rotation can be fast or slow, depending on an aXformInfo flag. If slow,
+ * interpolation (anti-aliasing) is done with superb results. If fast, the
+ * results have jaggies.
+ *
+ * Name of Global Jump-Table:
+ *
+ * rotateTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_ROTATE_UPPER_LEFT] = [xUL,yUL] = pos of upper-left corner of rotated rect
+ * aXformInfo[IP_ROTATE_UPPER_RIGHT] = [xUR,yUR] = pos of upper-right corner of rotated rect
+ * aXformInfo[IP_ROTATE_LOWER_LEFT] = [xLL,yLL] = pos of lower-left corner of rotated rect
+ * aXformInfo[IP_ROTATE_OUTPUT_SIZE] = [outWidth,outHeight] = size of output image (0 = no scaling)
+ * aXformInfo[IP_ROTATE_FAST] = rotate fast? (0=no=interpolated, 1=yes=jaggy)
+ *
+ * The coordinates (xUL,yUL) are in relation to the *input* image (Y increases
+ * downward), and locates what will be the upper-left corner in the output
+ * (before scaling). The other two points are defined similarly. If UL is to
+ * the right of UR, the output image is flipped horizontally. Vertical flipping
+ * can be done similarly.
+ * This rectangle is then scaled to produce outWidth and outHeight pixels.
+ *
+ * Capabilities and Limitations:
+ *
+ * Crops, white-pads, rotates by any angle, scales, mirrors, and flips vertically.
+ * Input data may be 1 bit/pixel, or any multiple of 8 bits/pixel.
+ * Internally, the miniumum amount of memory required for the rotation is
+ * allocated. For small angles, internal allocation will be very small.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * width of scan abs(outWidth)
+ * iBitsPerPixel * 1, or n*8 same as default input
+ * iComponentsPerPixel passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows * height of scan abs(outHeight)
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+/* Use the #define below if this transform will exist in a dll outside of the */
+/* image pipeline. This will allow the functions to be exported. */
+/* #define EXPORT_TRANFORM 1 */
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+#include "math.h" /* for sqrt */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+#ifdef EXPORT_TRANSFORM
+#define FUNC_STATUS __declspec (dllexport)
+#else
+#define FUNC_STATUS static
+#endif
+
+typedef struct {
+ IP_IMAGE_TRAITS inTraits; /* traits of the input image */
+ IP_IMAGE_TRAITS outTraits; /* traits of the output image */
+
+ // Items from aXformInfo:
+ int xUL, yUL; /* UL corner of image */
+ int xUR, yUR; /* UR corner of image */
+ int xLL, yLL; /* LL corner of image */
+ int xLR, yLR; /* LR corner of image (computed) */
+ int iOutWidth; /* width of output image */
+ int iOutHeight; /* height of output image */
+ BOOL bRotateFast; /* rotate fast? (produces worse jaggies) */
+
+ int hSlopeDx, hSlopeDy; /* input-change for moving right 1 pix in output (16.16) */
+ int vSlopeDx, vSlopeDy; /* input-change for moving down 1 pix in output (16.16) */
+ int xLeft, yLeft; /* current left-end of row (input coords) (16.16) */
+ int xRight, yRight; /* current right-end of row (input coords) (16.16) */
+ BYTE *pStrip; /* strip with a portion of input image */
+ BYTE *pStripAfter; /* ptr to 1st byte after the strip-buffer */
+ int stripIndexYTop; /* row-index of stripYTop in the strip */
+ int stripYTop; /* Y-value for topmost row in strip */
+ int stripYBottom; /* Y-value for bottommost row in strip */
+ int stripRows; /* number of rows allocated in the strip */
+ int stripLoaded; /* number of rows actually loaded into the strip */
+ int stripSize; /* number of bytes allocated in the strip */
+ int stripBytesPerRow; /* bytes/row in strip */
+ int inBytesPerRow; /* bytes/row of input image */
+ int outBytesPerRow; /* bytes/row of output image */
+ int bytesPerPixel; /* bytes/pixel (=1 for bilevel; 1 pixel in each byte) */
+ DWORD dwRowsSent; /* number of rows output so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} ROTATE_INST, *PROTATE_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * rotate_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD rotate_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PROTATE_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(ROTATE_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(ROTATE_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * rotate_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD rotate_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PROTATE_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow > 0 &&
+ pTraits->lNumRows > 0 &&
+ pTraits->iBitsPerPixel > 0);
+ g->inTraits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * rotate_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD rotate_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PROTATE_INST g;
+ int i;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ i = aXformInfo[IP_ROTATE_UPPER_LEFT].dword;
+ g->xUL = i >> 16;
+ g->yUL = i & 0xFFFF;
+
+ i = aXformInfo[IP_ROTATE_UPPER_RIGHT].dword;
+ g->xUR = i >> 16;
+ g->yUR = i & 0xFFFF;
+
+ i = aXformInfo[IP_ROTATE_LOWER_LEFT].dword;
+ g->xLL = i >> 16;
+ g->yLL = i & 0xFFFF;
+
+ i = aXformInfo[IP_ROTATE_OUTPUT_SIZE].dword;
+ g->iOutWidth = i >> 16;
+ g->iOutHeight = i & 0xFFFF;
+
+ g->bRotateFast = aXformInfo[IP_ROTATE_FAST].dword == 1;
+
+ INSURE (g->iOutWidth>=0 && g->iOutHeight>=0);
+ g->xLR = g->xUR + (g->xLL - g->xUL);
+ g->yLR = g->yUR + (g->yLL - g->yUL);
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * rotate_getHeaderBufSize - Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD rotate_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * rotate_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD rotate_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PROTATE_INST g;
+ int dxH, dyH, dxV, dyV;
+ double rotWidthSq, rotHeightSq, rotWidth, rotHeight;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /***** Compute Output Traits (and rotation variables) *****/
+
+ memcpy (&g->outTraits, &g->inTraits, sizeof(IP_IMAGE_TRAITS));
+
+ dxH = g->xUR - g->xUL;
+ dyH = g->yUR - g->yUL;
+ dxV = g->xLL - g->xUL;
+ dyV = g->yLL - g->yUL;
+
+ rotWidthSq = dxH*dxH + dyH*dyH;
+ rotWidth = sqrt (rotWidthSq);
+ rotHeightSq = dxV*dxV + dyV*dyV;
+ rotHeight = sqrt (rotHeightSq);
+ INSURE (rotWidth>0.0 && rotHeight>0.0);
+
+ if (g->iOutWidth == 0)
+ g->iOutWidth = (int)(rotWidth+0.5);
+ if (g->iOutHeight == 0)
+ g->iOutHeight = (int)(rotHeight+0.5);
+
+ g->outTraits.iPixelsPerRow = g->iOutWidth;
+ g->outTraits.lNumRows = g->iOutHeight;
+
+ g->bytesPerPixel = g->inTraits.iBitsPerPixel / 8;
+ if (g->bytesPerPixel == 0)
+ g->bytesPerPixel = 1; /* bi-level is expanded to one byte/pixel */
+
+ g->inBytesPerRow = (g->inTraits.iPixelsPerRow*g->inTraits.iBitsPerPixel + 7) / 8;
+ g->outBytesPerRow = (g->iOutWidth *g->inTraits.iBitsPerPixel + 7) / 8;
+
+ g->hSlopeDx = (dxH << 16) / g->iOutWidth;
+ g->hSlopeDy = (dyH << 16) / g->iOutWidth;
+ g->vSlopeDx = (dxV << 16) / g->iOutHeight;
+ g->vSlopeDy = (dyV << 16) / g->iOutHeight;
+
+ /* we start outputting at the upper-left corner of output-image */
+ /* do NOT add 0x8000 because when we're not scaling or rotating,
+ * it causes each pair of rows and each pair of columns to be
+ * averaged together, losing sharpness. */
+ g->xLeft = g->xUL << 16;
+ g->yLeft = g->yUL << 16;
+ g->xRight = g->xUR << 16;
+ g->yRight = g->yUR << 16;
+
+ /* set-up the strip-buffer */
+ g->stripBytesPerRow = g->inTraits.iPixelsPerRow * g->bytesPerPixel;
+ g->stripIndexYTop = 0;
+ g->stripYTop = 0;
+ g->stripYBottom = -1;
+ g->stripLoaded = 0;
+ if (g->vSlopeDy < 0) /* we'll proceed *upward* thru the input image */
+ g->stripRows = IP_MAX(g->yUL, g->yUR) - IP_MIN(g->yLL, g->yLR) + 1;
+ else /* normal case of proceeding *downward* */
+ g->stripRows = IP_MAX(g->yUL, g->yUR) - IP_MIN(g->yUL, g->yUR) + 1;
+ g->stripRows += 2; /* allocate extra row on top & bottom for interpolation */
+ g->stripSize = g->stripRows * g->stripBytesPerRow;
+ IP_MEM_ALLOC (g->stripSize, g->pStrip);
+ g->pStripAfter = g->pStrip + g->stripSize;
+
+ /***** Return Values *****/
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pIntraits = g->inTraits; /* structure copies */
+ *pOutTraits = g->outTraits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * rotate_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+FUNC_STATUS WORD rotate_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PROTATE_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = g->inBytesPerRow;
+ *pdwMinOutBufLen = g->outBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * rotate_convert - Converts one row
+ *
+\*****************************************************************************/
+
+
+
+/* ExpandBilevelRow - Expands 8 bits/pixel (input) to 1 byte/pixel (output) */
+static void ExpandBilevelRow (
+ PBYTE pDest,
+ PBYTE pSrc,
+ int nPixels)
+{
+ BYTE mask, inbyte=0;
+
+ mask = 0;
+
+ while (nPixels > 0) {
+ if (mask == 0) {
+ mask = 0x80u;
+ inbyte = *pSrc++;
+ }
+ *pDest++ = inbyte & mask ? 0 : 255;
+ mask >>= 1;
+ nPixels -= 1;
+ }
+}
+
+
+
+FUNC_STATUS WORD rotate_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ // We need another row if the Y of either endpoint of the current rotated row
+ // is below the bottom of the strip.
+ #define NEED_MORE \
+ ((g->yLeft >>16) >= g->stripYBottom || (g->yRight>>16) >= g->stripYBottom)
+
+ PROTATE_INST g;
+ PBYTE pSrc, pDest;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("rotate_convert: Told to flush.\n"), 0, 0);
+ dwInputAvail = (DWORD)g->inBytesPerRow;
+ if ((long)g->dwRowsSent >= g->outTraits.lNumRows)
+ return IP_DONE;
+ }
+
+ /**** Initial load of strip-buffer ****/
+
+ if (g->stripLoaded < g->stripRows) {
+ if (dwInputAvail == 0)
+ return IP_READY_FOR_DATA;
+ INSURE (dwInputAvail >= (DWORD)g->inBytesPerRow);
+ pDest = g->pStrip + g->stripBytesPerRow*g->stripLoaded;
+ if (g->inTraits.iBitsPerPixel == 1)
+ ExpandBilevelRow (pDest, pbInputBuf, g->inTraits.iPixelsPerRow);
+ else if (pbInputBuf == NULL)
+ memcpy (pDest, pDest - g->stripBytesPerRow, g->stripBytesPerRow);
+ else
+ memcpy (pDest, pbInputBuf, g->stripBytesPerRow);
+ g->stripLoaded += 1;
+ g->stripYBottom += 1;
+ if (g->stripLoaded == 1) {
+ /* first row is *above* top for interpolation; replicate it */
+ memcpy (g->pStrip+g->stripBytesPerRow, g->pStrip, g->stripBytesPerRow);
+ g->stripLoaded += 1;
+ g->stripYBottom += 1;
+ }
+ if (pbInputBuf == NULL)
+ return 0; /* wait for next call to replicate another row and start rotation */
+ *pdwInputUsed = (DWORD)g->inBytesPerRow;
+ g->dwInNextPos += (DWORD)g->inBytesPerRow;
+ *pdwInputNextPos = g->dwInNextPos;
+ return ((g->stripLoaded<g->stripRows || NEED_MORE) ? IP_READY_FOR_DATA : 0)
+ | IP_CONSUMED_ROW;
+ }
+
+ /**** Load next row into strip-buffer ****/
+
+ if (NEED_MORE)
+ {
+ /* we need to load a row into the strip-buffer (a wrapping load) */
+ if (dwInputAvail == 0)
+ return IP_READY_FOR_DATA;
+ INSURE (dwInputAvail >= (DWORD)g->inBytesPerRow);
+ pDest = g->pStrip + g->stripBytesPerRow*g->stripIndexYTop;
+ if (pbInputBuf == NULL) // then white-fill the row
+ memset (pDest, 255, g->stripBytesPerRow);
+ else if (g->inTraits.iBitsPerPixel == 1)
+ ExpandBilevelRow (pDest, pbInputBuf, g->inTraits.iPixelsPerRow);
+ else
+ memcpy (pDest, pbInputBuf, g->stripBytesPerRow);
+ g->stripIndexYTop = (g->stripIndexYTop + 1) % g->stripRows;
+ g->stripYTop += 1;
+ g->stripYBottom += 1;
+ if (pbInputBuf != NULL) {
+ *pdwInputUsed = (DWORD)g->inBytesPerRow;
+ g->dwInNextPos += (DWORD)g->inBytesPerRow;
+ *pdwInputNextPos = g->dwInNextPos;
+ }
+ }
+
+ /**** Output a row ****/
+
+ if ((long)g->dwRowsSent >= g->outTraits.lNumRows)
+ {
+ /* we've outputted all rows; discard any further input */
+ g->stripYBottom = -100000; /* forces strip-loading logic to keep loading */
+ }
+ else if (! NEED_MORE)
+ {
+ int rowIndex, iPix;
+ int xcur,ycur, xint,yint;
+ unsigned xfrac,yfrac;
+ PBYTE pNextRow;
+ BYTE mask;
+
+ INSURE (dwOutputAvail >= (DWORD)g->outBytesPerRow);
+
+ pDest = pbOutputBuf;
+ xcur = g->xLeft;
+ ycur = g->yLeft;
+
+ /* These two lines set-up bi-level packing: */
+ *pDest = 0;
+ mask = 0x80u;
+
+ for (iPix=0; iPix<g->outTraits.iPixelsPerRow; iPix++)
+ {
+ xint = xcur >> 16;
+ yint = (ycur >> 16) - g->stripYTop;
+
+ /* below, unsigned makes negatives huge (therefore not in strip) */
+ /* also, we check stripRows-1; the -1 allows the extra interpolation-row */
+ if ((unsigned)yint < (unsigned)(g->stripRows-1) &&
+ (unsigned)xint < (unsigned)g->inTraits.iPixelsPerRow)
+ {
+ /**** We are inside the strip ****/
+
+ /* Compute address of pixel in the strip */
+ rowIndex = yint + g->stripIndexYTop;
+ if (rowIndex >= g->stripRows)
+ rowIndex -= g->stripRows;
+ pSrc = (rowIndex*g->inTraits.iPixelsPerRow + xint) * g->bytesPerPixel
+ + g->pStrip;
+
+ /**** Output a pixel ****/
+
+ /* The byte at ptrSrcCur is the upper-left byte out of a 2x2 group.
+ * These four bytes are interpolated together based on xfrac and yfrac.
+ */
+ #define INTERPOLATE_BYTE(ptrOut,ptrSrcCur,ptrSrcNex,bpp) { \
+ int xtop, xbot, val; \
+ xtop = (ptrSrcCur)[0]*(256-xfrac) + (ptrSrcCur)[bpp]*xfrac; \
+ xbot = (ptrSrcNex)[0]*(256-xfrac) + (ptrSrcNex)[bpp]*xfrac; \
+ val = xtop*(256-yfrac) + xbot*yfrac; \
+ val = (val + 0x8000) >> 16; /* the add rounds result of shift */ \
+ *(ptrOut) = (BYTE)val; \
+ }
+
+ #define INTERPOLATE_WORD(ptrOut,ptrSrcCur,ptrSrcNex,bpp) { \
+ WORD *wptrOut = (PWORD)(ptrOut ); \
+ WORD *wptrSrcCur = (PWORD)(ptrSrcCur); \
+ WORD *wptrSrcNex = (PWORD)(ptrSrcNex); \
+ unsigned xtop, xbot, val; \
+ xtop = ((wptrSrcCur)[0]*(0x10000-xfrac)>>8) + ((wptrSrcCur)[bpp]*xfrac>>8); \
+ xtop = (xtop+128) >> 8; /* the add rounds result of shift */ \
+ xbot = ((wptrSrcNex)[0]*(0x10000-xfrac)>>8) + ((wptrSrcNex)[bpp]*xfrac>>8); \
+ xbot = (xbot+128) >> 8; \
+ val = (xtop*(0x10000-yfrac)>>8) + (xbot*yfrac>>8); \
+ val = (val+128) >> 8; \
+ *(wptrOut) = (WORD)val; \
+ }
+
+ pNextRow = pSrc + g->stripBytesPerRow;
+ if (pNextRow >= g->pStripAfter)
+ pNextRow -= g->stripSize; /* next row wrapped to top of strip */
+
+ xfrac = (xcur>>8) & 0x0000ff;
+ yfrac = (ycur>>8) & 0x0000ff;
+
+ if (g->bytesPerPixel == 3) {
+ if (g->bRotateFast) {
+ pDest[0] = pSrc[0];
+ pDest[1] = pSrc[1];
+ pDest[2] = pSrc[2];
+ } else {
+ /* interpolate to eliminate jaggies */
+ INTERPOLATE_BYTE (pDest+0, pSrc+0, pNextRow+0, 3)
+ INTERPOLATE_BYTE (pDest+1, pSrc+1, pNextRow+1, 3)
+ INTERPOLATE_BYTE (pDest+2, pSrc+2, pNextRow+2, 3)
+ }
+ pDest += 3;
+ } else if (g->bytesPerPixel == 1) {
+ BYTE byt;
+
+ if (g->bRotateFast)
+ byt = pSrc[0];
+ else
+ INTERPOLATE_BYTE (&byt, pSrc, pNextRow, 1)
+
+ if (g->inTraits.iBitsPerPixel == 8)
+ *pDest++ = byt;
+ else {
+ /* bi-level: pack 8 pixels per byte */
+ if (byt < 128)
+ *pDest |= mask;
+ mask >>= 1;
+ if (mask == 0) {
+ mask = 0x80u;
+ pDest += 1;
+ *pDest = 0;
+ }
+ }
+ } else if (g->bytesPerPixel==2 || g->bytesPerPixel==6) {
+ /* 16-bit grayscale or 48-bit color */
+ if (g->bRotateFast) {
+ memcpy (pDest, pSrc, g->bytesPerPixel);
+ } else {
+ xfrac = xcur & 0x00ffff;
+ yfrac = ycur & 0x00ffff;
+ INTERPOLATE_WORD (pDest+0, pSrc+0, pNextRow+0, g->inTraits.iComponentsPerPixel)
+ if (g->bytesPerPixel == 6) {
+ INTERPOLATE_WORD (pDest+2, pSrc+2, pNextRow+2, 3)
+ INTERPOLATE_WORD (pDest+4, pSrc+4, pNextRow+4, 3)
+ }
+ }
+
+ pDest += g->bytesPerPixel;
+ } else {
+ /* unsupported bits per pixel */
+ INSURE (FALSE);
+ }
+ }
+ else /* current pos is outside strip, so output a white pixel (padding) */
+ {
+ if (g->inTraits.iBitsPerPixel == 1) {
+ mask >>= 1;
+ if (mask == 0) {
+ mask = 0x80u;
+ pDest += 1;
+ *pDest = 0;
+ }
+ } else {
+ memset (pDest, 255, g->bytesPerPixel);
+ pDest += g->bytesPerPixel;
+ }
+ }
+
+ /* Advance to next pixel in input image */
+ xcur += g->hSlopeDx;
+ ycur += g->hSlopeDy;
+ } /* end of for-each-pixel loop */
+
+ *pdwOutputUsed = (DWORD)g->outBytesPerRow;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += (DWORD)g->outBytesPerRow;
+
+ g->dwRowsSent += 1;
+
+ g->xLeft += g->vSlopeDx;
+ g->yLeft += g->vSlopeDy;
+ g->xRight += g->vSlopeDx;
+ g->yRight += g->vSlopeDy;
+ }
+
+ return (*pdwInputUsed !=0 ? IP_CONSUMED_ROW : 0) |
+ (*pdwOutputUsed!=0 ? IP_PRODUCED_ROW : 0) |
+ (NEED_MORE ? IP_READY_FOR_DATA : 0);
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * rotate_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD rotate_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * rotate_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD rotate_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PROTATE_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * rotate_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD rotate_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PROTATE_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ if (g->pStrip != NULL)
+ IP_MEM_FREE (g->pStrip);
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * rotateTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+
+#ifdef EXPORT_TRANSFORM
+__declspec (dllexport)
+#endif
+IP_XFORM_TBL rotateTbl = {
+ rotate_openXform,
+ rotate_setDefaultInputTraits,
+ rotate_setXformSpec,
+ rotate_getHeaderBufSize,
+ rotate_getActualTraits,
+ rotate_getActualBufSizes,
+ rotate_convert,
+ rotate_newPage,
+ rotate_insertedData,
+ rotate_closeXform
+};
+
+
+
+/*****************************************************************************\
+ *
+ * ipGetXformTable - Returns pointer to the jump table
+ *
+\*****************************************************************************/
+
+#ifdef EXPORT_TRANSFORM
+EXPORT(WORD) rotateGetXformTable (LPIP_XFORM_TBL pXform)
+{
+ if (pXform == NULL)
+ return IP_FATAL_ERROR;
+
+ *pXform = clrmapTbl;
+ return IP_DONE;
+}
+#endif
+
+/* End of File */
diff --git a/ip/xsaturation.c b/ip/xsaturation.c
new file mode 100644
index 0000000..472dfda
--- /dev/null
+++ b/ip/xsaturation.c
@@ -0,0 +1,463 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xsaturation.c - Changes the saturation of color data
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * saturationTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_SATURATION_FACTOR] = saturation factor, in 24.8 fixed point (8 bits of frac)
+ *
+ * A conceptual value of 1.0 (aXformInfo[0] = 256) means no change in
+ * saturation. 2.0 doubles it; 0.5 cuts it in half. 0.0 eliminates all
+ * color, outputting RGB grayscale.
+ *
+ * Capabilities and Limitations:
+ *
+ * The incoming data can be 24-bit color or 48-bit color.
+ * The pixels are assumed to be RGB.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Feb 2000 Mark Overton -- wrote original code
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input and output image */
+ DWORD dwSatFac; /* desired saturation factor */
+ DWORD dwBytesPerRow; /* # of bytes in each row */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} SAT_INST, *PSAT_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * saturation_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD saturation_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PSAT_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(SAT_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(SAT_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * saturation_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD saturation_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PSAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow>0
+ && (pTraits->iBitsPerPixel==24 || pTraits->iBitsPerPixel==48));
+ g->traits = *pTraits; /* a structure copy */
+ g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * saturation_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD saturation_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PSAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->dwSatFac = aXformInfo[IP_SATURATION_FACTOR].dword;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * saturation_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD saturation_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * saturation_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD saturation_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PSAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pIntraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * saturation_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD saturation_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PSAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * saturation_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD saturation_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PSAT_INST g;
+ int nBytes;
+ PBYTE pIn, pOut, pOutAfter;
+ int l, rv, gv, bv;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("saturation_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = g->dwBytesPerRow;
+ INSURE (dwInputAvail >= (DWORD)nBytes );
+ INSURE (dwOutputAvail >= (DWORD)nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pOutAfter = pOut + nBytes;
+
+ if (g->traits.iBitsPerPixel == 24) {
+ /* 24-bit color in RGB */
+
+ while (pOut < pOutAfter) {
+ rv = *pIn++;
+ gv = *pIn++;
+ bv = *pIn++;
+
+ l = NTSC_LUMINANCE (rv,gv,bv);
+
+ rv = l + (((rv-l)*(int)g->dwSatFac + (1<<7)) >> 8);
+ gv = l + (((gv-l)*(int)g->dwSatFac + (1<<7)) >> 8);
+ bv = l + (((bv-l)*(int)g->dwSatFac + (1<<7)) >> 8);
+
+ if (rv > 255) rv = 255; else if (rv < 0) rv = 0;
+ if (gv > 255) gv = 255; else if (gv < 0) gv = 0;
+ if (bv > 255) bv = 255; else if (bv < 0) bv = 0;
+
+ *pOut++ = (BYTE)rv;
+ *pOut++ = (BYTE)gv;
+ *pOut++ = (BYTE)bv;
+ }
+ } else { /* 48 bits/pixel */
+ PWORD src = (PWORD)pIn;
+ PWORD dst = (PWORD)pOut;
+ PWORD dstAfter = (PWORD)pOutAfter;
+
+ while (dst < dstAfter) {
+ rv = (unsigned)(*src++);
+ gv = (unsigned)(*src++);
+ bv = (unsigned)(*src++);
+
+ l = NTSC_LUMINANCE (rv,gv,bv);
+
+ rv = l + (((rv-l)*(int)g->dwSatFac + (1<<7)) >> 8);
+ gv = l + (((gv-l)*(int)g->dwSatFac + (1<<7)) >> 8);
+ bv = l + (((bv-l)*(int)g->dwSatFac + (1<<7)) >> 8);
+
+ if (rv > 65535) rv = 65535; else if (rv < 0) rv = 0;
+ if (gv > 65535) gv = 65535; else if (gv < 0) gv = 0;
+ if (bv > 65535) bv = 65535; else if (bv < 0) bv = 0;
+
+ *dst++ = (WORD)rv;
+ *dst++ = (WORD)gv;
+ *dst++ = (WORD)bv;
+ }
+ }
+
+ *pdwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * saturation_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD saturation_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * saturation_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD saturation_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PSAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * saturation_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD saturation_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PSAT_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * saturationTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL saturationTbl = {
+ saturation_openXform,
+ saturation_setDefaultInputTraits,
+ saturation_setXformSpec,
+ saturation_getHeaderBufSize,
+ saturation_getActualTraits,
+ saturation_getActualBufSizes,
+ saturation_convert,
+ saturation_newPage,
+ saturation_insertedData,
+ saturation_closeXform
+};
+
+/* End of File */
diff --git a/ip/xscale.c b/ip/xscale.c
new file mode 100644
index 0000000..0dbd5c7
--- /dev/null
+++ b/ip/xscale.c
@@ -0,0 +1,1277 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux (minus bilevel scaling) by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xscale.c - Scales (and interpolates) bi-level, gray and color
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * scaleTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_SCALE_HORIZ_FACTOR] = Horizontal scale-factor, in 8.24 fixed point
+ *
+ * aXformInfo[IP_SCALE_VERT_FACTOR] = Vertical scale-factor, in 8.24 fixed point
+ *
+ * aXformInfo[IP_SCALE_FAST] = scale fast using simple pixel-replication? 0=no, 1=yes
+ * currently, this only affects bi-level up-scaling.
+ *
+ * Capabilities and Limitations:
+ *
+ * This driver can scale both up and down, independently. That is, one
+ * direction can up-scale while the other direction down-scales. Bi-level
+ * scaling is done using tables to maximize speed. 24-bit color,
+ * 8-bit gray and bi-level pixels can be scaled.
+ *
+ * Color and gray data are interpolated intellegently.
+ * Bi-level data are smoothed when up-scaling (several patents), and
+ * data-loss is avoided when down-scaling (another patent).
+ *
+ * The allowed scale-factor ranges differ based on data type (bi-level,
+ * gray and color). An assert will occur if range is exceeded.
+ * These ranges are:
+ *
+ * bi-level: horiz_fac=[1/2..4.0] vert_fac=[1/16..4.0]
+ * gray: horiz_fac=[1/4..6.0] vert_fac=[1/4..6.0]
+ * color: horiz_fac=[1/4..6.0] vert_fac=[1/4..6.0]
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output computed
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel * passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output computed
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ *
+ * Feb 1998 Mark Overton, ported to new Windows software Image Processor
+ * Jun 1997 Mark Overton, added color scaling
+ * May 1997 Mark Overton, added gray scaling
+ * 1995 Mark Overton, wrote original code (bi-level only)
+ *
+\******************************************************************************/
+
+#include "string.h" /* for memset and memcpy */
+#include "assert.h"
+
+#include "hpip.h"
+#include "ipdefs.h"
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x1ce5ca7e
+#define SC_WHITE_ROW 1 /* was for tracking all-white rows; not used */
+
+
+/*____________________________________________________________________________
+ | |
+ | Things common to all image-types |
+ |____________________________________________________________________________|
+*/
+
+
+#define MAX_ROWS_AP 6 /* Number of entries in rows_ap */
+#define HELD_ARRAY_SIZE 7 /* # entries in apHeldOutRows array */
+
+typedef enum {
+ IM_BILEVEL,
+ IM_GRAY,
+ IM_COLOR
+} IM_TYPE;
+
+
+/* SC_INST contains all the variables for a scaling-instance */
+
+typedef struct {
+ IM_TYPE image_type; /* type of image (bilevel, gray, color) */
+ BOOL fast; /* scale (quickly) using pixel replication? */
+ BYTE nMoreFlush; /* # more flush calls reqd to send buffered rows */
+ ULONG horiz_fac; /* horiz scale-factor (16.16 fixed-pt) */
+ ULONG vert_fac; /* vert scale-factor (16.16 fixed-pt) */
+ long vert_pos; /* current vert pos (16.16; signed, we use neg) */
+ int in_row_nbytes; /* # bytes in each input row */
+ int out_row_nbytes; /* # bytes in each output row */
+ int out_row_pixels; /* # pixels in each output row */
+ int in_nrows; /* number of rows read in so far */
+ int out_nrows; /* number of rows written so far */
+ BYTE *rows_ap[MAX_ROWS_AP]; /* ptrs to successive input rows */
+ int nMaxOutRows; /* max # output rows resulting from one input row*/
+ int nMoreHeldOutRows;/* more output rows needed to be returned */
+ int iNextHeldOutRow; /* index of next output row to be returned */
+ BYTE *apHeldOutRows[HELD_ARRAY_SIZE];
+ /* output rows stored for subsequent returning; */
+ /* index [0] is caller's output buffer */
+ int top_row; /* bilevel: index of top of 3 rows in rows_ap */
+ ULONG post_fac; /* bilevel: additional upscaling */
+ BYTE mid_traits; /* bilevel: trait-bits of middle row */
+
+ ULONG inv_horiz_fac; /* gray: inverse of horiz scaling factor (16.16) */
+ ULONG inv_vert_fac; /* gray: inverse of vert scaling factor (16.16) */
+ long inv_vert_pos; /* cur inv vert pos (16.16; signed, we use neg) */
+ BYTE n_saved_rows; /* gray: # rows saved in rows_ap for vert scaling*/
+ BYTE n_alloced_rows; /* gray: # rows allocated in rows_ap */
+
+ IP_IMAGE_TRAITS inTraits;/* traits of the input image */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} SC_INST, *PSC_INST;
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ DUMMY BILEVEL FUNCTIONS
+
+ ******************************************************************************
+ ******************************************************************************/
+
+/* These functions were removed because they contained patented algorithms.
+ * Therefore, only gray and color (not bilevel) scaling are currently
+ * supported. If this is ever fixed, then remove the assert in
+ * scale_setDefaultInputTraits(). */
+
+void bi_fast_open(PSC_INST g, UINT in_row_len) {
+ fatalBreakPoint();
+}
+
+void bi_scale_open(PSC_INST g, UINT in_row_len) {
+ fatalBreakPoint();
+}
+
+int bi_fast_row(PSC_INST g,PBYTE pbInputBuf,BYTE src_traits,
+ BYTE *apHeldOutRows[],ULONG *pdest_traits) {
+ fatalBreakPoint();
+ return 0;
+}
+
+int bi_scale_row(PSC_INST g,PBYTE pbInputBuf,BYTE src_traits,
+ BYTE *apHeldOutRows[],ULONG *pdest_traits) {
+ fatalBreakPoint();
+ return 0;
+}
+
+void bi_fast_close(PSC_INST g) {
+ fatalBreakPoint();
+}
+
+void bi_scale_close(PSC_INST g) {
+ fatalBreakPoint();
+}
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ CONTONE (GRAY AND COLOR)
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+/*
+ * Scaling Algorithms
+ *
+ * The descriptions below are for the X axis. For the Y axis, substitute
+ * "input row" for "input pixel", and "output row" for "output pixel", and
+ * apply weights to entire rows using the same algorithms.
+ *
+ * Each axis is scaled separately using the these methods. So you can
+ * down-scale in one axis and up-scale in the other, if you wish.
+ *
+ *
+ * Down-scaling Algorithm
+ *
+ * Imagine marking the pixel-boundaries on two rulers, and laying them
+ * next to each other:
+ *
+ * in1 pos in2 in3
+ * |______|______|______|______|______|______|______| <-- input pixels
+ * | | | | | <-- output pixels
+ * 0 out 1
+ *
+ * An output pixel consists of a weighted sum of the input pixels that
+ * it overlaps. The weights are the amount of overlap.
+ *
+ * pos is the right side of the leftmost input pixel that overlaps the
+ * current output pixel. This position is in units of output pixels (a
+ * distance of 1 is the width of an output pixel), and 0 is the left side
+ * of the current output pixel. Since this position is in units of output
+ * pixels, it can be used to easily compute the weights.
+ *
+ * The weights of the overlapping input pixels are:
+ *
+ * leftmost: pos
+ * middle pixels (if any): scale factor (which is less than 1)
+ * rightmost: 1.0 - (sum of above weights)
+ *
+ * Above, the pixel 'out' is computed as:
+ *
+ * out = pos*in1 + scalefactor*in2 + (1-pos-scalefactor)*in3
+ *
+ *
+ * Up-scaling Algorithm
+ *
+ * I first tried an overlap method like that used for down-scaling, but
+ * for large scale-factors, one output pixel would overlap two input
+ * pixels, and many output pixels would overlap just one input pixel.
+ * So the result looked almost as bad as pixel-replication, because many
+ * pixels were indeed just replications.
+ *
+ * So I devised an interpolating algorithm wherein a pos value is the
+ * weight of the next input pixel, and (1-pos) is the weight of the
+ * current input pixel. As pos increases along the current input pixel,
+ * the weight will smoothly shift from it to the next input pixel,
+ * eliminating jaggies.
+ *
+ * 0 in0 1 in1
+ * |___________|___________|___________|___________| <-- input_pixels
+ * | | | out | | | | | <-- output pixels
+ * pos
+ *
+ * pos is the left side of the current output pixel, in units of input
+ * pixels. 0 is the left side of the current input pixel (in0 above).
+ *
+ * pos is advanced by adding 1/scalefactor to it. When it becomes >= 1,
+ * move to the next input pixel, and subtract 1 from pos.
+ *
+ * Above, the pixel 'out' is computed as: out = (1-pos)*in0 + pos*in1
+ */
+
+#define CONTONE_MIN_HORIZ_FAC (ULONG)0x04000 /* 0.25 */
+ /* Minimum horizontal scale-factor (16.16) */
+
+#define CONTONE_MAX_HORIZ_FAC ((ULONG)MAX_ROWS_AP << 16)
+ /* Maximum horizontal scale-factor (arbitrary) */
+
+#define CONTONE_MIN_VERT_FAC (ULONG)0x04000 /* 0.25 */
+ /* Minimum vertical scale-factor (16.16) */
+
+#define CONTONE_MAX_VERT_FAC ((ULONG)MAX_ROWS_AP << 16)
+ /* Maximum vertical scale-factor (16.16) */
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | gray_horiz_scale | Scales the given input row into the given output row |
+ |__________________|_________________________________________________________|
+ | |
+ | Up-scaling is done by interpolation using horiz_pos. |
+ | Down-scaling is done by blending (averaging two or more input pixels |
+ | together, forming an output pixel). |
+ |____________________________________________________________________________|
+*/
+static void gray_horiz_scale (
+ SC_INST *g, /* in: our instance variables */
+ BYTE *src_p, /* in: input row to be scaled */
+ BYTE *dest_p) /* out: output row that we scaled */
+{
+ ULONG horiz_pos, new_pos;
+ BYTE *in_p, *out_p, *out_aft_p;
+ UINT sum, pix;
+ UINT w1, w2;
+ UINT n_pix, u;
+
+ in_p = src_p;
+ out_p = dest_p;
+ out_aft_p = out_p + g->out_row_nbytes;
+ in_p[g->in_row_nbytes] = in_p[g->in_row_nbytes-1]; /* dup right pixel */
+
+ /**************/
+ /* Up-scaling */
+ /**************/
+
+ if (g->horiz_fac >= 0x00010000u)
+ {
+ horiz_pos = 0;
+
+ while (out_p < out_aft_p) {
+ do {
+ w2 = (UINT) (horiz_pos >> 8);
+ w1 = 256 - w2;
+ *out_p++ = (w1*in_p[0] + w2*in_p[1]) >> 8;
+ horiz_pos += g->inv_horiz_fac;
+ } while ((horiz_pos>>16) == 0);
+
+ horiz_pos &= 0x0000ffffu;
+ in_p += 1;
+ }
+ }
+
+ /****************/
+ /* Down-scaling */
+ /****************/
+
+ else if (g->fast)
+ {
+ horiz_pos = 0;
+ while (out_p < out_aft_p) {
+ *out_p++ = *in_p;
+ horiz_pos += g->inv_horiz_fac;
+ in_p += horiz_pos >> 16;
+ horiz_pos &= 0x0000ffffu;
+ }
+ }
+ else // not fast
+ {
+ horiz_pos = g->horiz_fac;
+ w2 = g->horiz_fac >> 8;
+
+ while (out_p < out_aft_p) {
+ new_pos = horiz_pos;
+ n_pix = 1;
+ do {
+ new_pos += g->horiz_fac;
+ n_pix += 1;
+ } while ((new_pos>>16) == 0);
+
+ /* Blend n_pix pixels together using these weights:
+ * 1st pixel: horiz_pos
+ * mid pixels: horiz_fac
+ * final pixel: 1.0 - (sum of above weights)
+ */
+ sum = horiz_pos >> 8;
+ pix = sum * (*in_p++); /* 1st pixel */
+
+ for (u=1; u<=n_pix-2; u++) {
+ pix += w2 * (*in_p++); /* middle pixels */
+ sum += w2;
+ }
+
+ pix += (256-sum) * (*in_p); /* final pixel */
+
+ *out_p++ = pix >> 8;
+ horiz_pos = new_pos & 0x0000ffffu;
+ }
+ } /* end if up-scaling else down-scaling */
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | color_horiz_scale | Scales the given input row into the given output row |
+ |___________________|________________________________________________________|
+ | |
+ | Up-scaling is done by interpolation using horiz_pos. |
+ | Down-scaling is done by blending (averaging two or more input pixels |
+ | together, forming an output pixel). |
+ |____________________________________________________________________________|
+*/
+static void color_horiz_scale (
+ SC_INST *g, /* in: our instance variables */
+ BYTE *src_p, /* in: input row to be scaled */
+ BYTE *dest_p) /* out: output row that we scaled */
+{
+ ULONG horiz_pos, new_pos;
+ BYTE *in_p, *out_p, *out_aft_p, *p;
+ UINT sum, pix_y, pix_u, pix_v;
+ UINT w1, w2;
+ UINT n_pix, u;
+
+ in_p = src_p;
+ out_p = dest_p;
+ out_aft_p = out_p + g->out_row_nbytes;
+
+ p = in_p + g->in_row_nbytes;
+ p[0] = p[-3]; /* dup right pixel */
+ p[1] = p[-2];
+ p[2] = p[-1];
+
+ /**************/
+ /* Up-scaling */
+ /**************/
+
+ if (g->horiz_fac >= 0x00010000u)
+ {
+ horiz_pos = 0;
+
+ while (out_p < out_aft_p) {
+ do {
+ w2 = (UINT) (horiz_pos >> 8);
+ w1 = 256 - w2;
+ *out_p++ = (w1*in_p[0] + w2*in_p[3]) >> 8; /* y component */
+ *out_p++ = (w1*in_p[1] + w2*in_p[4]) >> 8; /* u component */
+ *out_p++ = (w1*in_p[2] + w2*in_p[5]) >> 8; /* v component */
+ horiz_pos += g->inv_horiz_fac;
+ } while ((horiz_pos>>16) == 0);
+
+ horiz_pos &= 0x0000ffffu;
+ in_p += 3;
+ }
+ }
+
+ /****************/
+ /* Down-scaling */
+ /****************/
+
+ else if (g->fast)
+ {
+ int iStep;
+ horiz_pos = 0;
+ while (out_p < out_aft_p) {
+ *out_p++ = in_p[0];
+ *out_p++ = in_p[1];
+ *out_p++ = in_p[2];
+
+ horiz_pos += g->inv_horiz_fac;
+ iStep = horiz_pos >> 16;
+ in_p += iStep + iStep + iStep;
+ horiz_pos &= 0x0000ffffu;
+ }
+ }
+ else // down-scaling, not fast
+ {
+ horiz_pos = g->horiz_fac;
+ w2 = g->horiz_fac >> 8;
+
+ while (out_p < out_aft_p) {
+ new_pos = horiz_pos;
+ n_pix = 1;
+ do {
+ new_pos += g->horiz_fac;
+ n_pix += 1;
+ } while ((new_pos>>16) == 0);
+
+ /* Blend n_pix pixels together using these weights:
+ * 1st pixel: horiz_pos
+ * mid pixels: horiz_fac
+ * final pixel: 1.0 - (sum of above weights)
+ */
+ sum = horiz_pos >> 8;
+ pix_y = sum * (*in_p++); /* 1st pixel */
+ pix_u = sum * (*in_p++);
+ pix_v = sum * (*in_p++);
+
+ for (u=1; u<=n_pix-2; u++) {
+ pix_y += w2 * (*in_p++); /* middle pixels */
+ pix_u += w2 * (*in_p++);
+ pix_v += w2 * (*in_p++);
+ sum += w2;
+ }
+
+ sum = 256 - sum;
+ pix_y += sum * in_p[0]; /* final pixel */
+ pix_u += sum * in_p[1];
+ pix_v += sum * in_p[2];
+
+ *out_p++ = pix_y >> 8;
+ *out_p++ = pix_u >> 8;
+ *out_p++ = pix_v >> 8;
+ horiz_pos = new_pos & 0x0000ffffu;
+ }
+ } /* end if up-scaling else down-scaling */
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | weight_two_rows | Output row is a weighted-average of two rows in rows_ap |
+ |_________________|__________________________________________________________|
+ | |
+ | rows_ap[0] is weighted by first_weight. |
+ | rows_ap[1] is weighted by 1.0 - first_weight. |
+ | The output is written to dest_p. |
+ |____________________________________________________________________________|
+*/
+static void weight_two_rows (
+ SC_INST *g, /* in: our instance variables */
+ ULONG first_weight, /* in: weight for first row (16.16) */
+ BYTE *dest_p) /* out: output row */
+{
+ BYTE *p1, *p2;
+ BYTE *out_p, *out_aft_p;
+
+ p1 = g->rows_ap[0];
+ p2 = g->rows_ap[1];
+ out_p = dest_p;
+ out_aft_p = out_p + g->out_row_nbytes;
+
+#if 0
+ UINT w1, w2;
+ w1 = first_weight >> 8;
+ w2 = 256 - w1;
+ while (out_p < out_aft_p)
+ *out_p++ = (w1*(*p1++) + w2*(*p2++)) >> 8;
+#else
+ switch ((first_weight+(1u<<12)) >> 13) /* round weight to closest 8th */
+ {
+ case 0:
+ memcpy (out_p, p2, g->out_row_nbytes);
+ break;
+ case 1:
+ while (out_p < out_aft_p)
+ *out_p++ = (*p1>>3) + *p2 - (*p2>>3);
+ p1++; p2++;
+ break;
+ case 2:
+ while (out_p < out_aft_p)
+ *out_p++ = (*p1>>2) + *p2 - (*p2>>2);
+ p1++; p2++;
+ break;
+ case 3:
+ while (out_p < out_aft_p)
+ *out_p++ = (*p1>>2) + (*p1>>3) + (*p2>>1) + (*p2>>3);
+ p1++; p2++;
+ break;
+ case 4:
+ while (out_p < out_aft_p)
+ *out_p++ = (*p1>>1) + (*p2>>1);
+ p1++; p2++;
+ break;
+ case 5:
+ while (out_p < out_aft_p)
+ *out_p++ = (*p1>>1) + (*p1>>3) + (*p2>>2) + (*p2>>3);
+ p1++; p2++;
+ break;
+ case 6:
+ while (out_p < out_aft_p)
+ *out_p++ = *p1 - (*p1>>2) + (*p2>>2);
+ p1++; p2++;
+ break;
+ case 7:
+ while (out_p < out_aft_p)
+ *out_p++ = *p1 - (*p1>>3) + (*p2>>3);
+ p1++; p2++;
+ break;
+ case 8:
+ memcpy (out_p, p1, g->out_row_nbytes);
+ break;
+ default:
+ assert (0);
+ }
+#endif
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | weight_n_rows | Blends two or more rows in rows_ap into one output row |
+ |_______________|____________________________________________________________|
+ | |
+ | The weights are: |
+ | 1st row: first_weight |
+ | middle rows: mid_weight |
+ | final row: 1.0 - (sum of above weights) |
+ |____________________________________________________________________________|
+*/
+static void weight_n_rows (
+ SC_INST *g, /* in: our instance variables */
+ UINT n_rows, /* in: number of rows to blend together */
+ ULONG first_weight, /* in: weight of first row (16.16) */
+ ULONG mid_weight, /* in: weight of middle rows (16.16) */
+ BYTE *dest_p) /* out: output row */
+{
+ BYTE *in_p[MAX_ROWS_AP];
+ BYTE *out_p, *out_aft_p;
+ UINT weights[MAX_ROWS_AP];
+ UINT sum;
+ UINT u;
+
+ assert (n_rows>=2 && n_rows<=MAX_ROWS_AP);
+
+ if (n_rows == 2) {
+ weight_two_rows (g, first_weight, dest_p);
+ return;
+ }
+
+ out_p = dest_p;
+ out_aft_p = out_p + g->out_row_nbytes;
+ for (u=0; u<n_rows; u++)
+ in_p[u] = g->rows_ap[u];
+
+ sum = weights[0] = first_weight >> 8;
+ for (u=1; u<=n_rows-2; u++)
+ sum += (weights[u] = mid_weight >> 8);
+ weights[n_rows-1] = 256 - sum;
+
+ while (out_p < out_aft_p) {
+ sum = 0;
+ for (u=0; u<n_rows; u++)
+ sum += weights[u] * (*in_p[u]++);
+ *out_p++ = sum >> 8;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | contone_scale_open | sets up the given scaling job |
+ |____________________|_______________________________________________________|
+*/
+static void contone_scale_open (
+ SC_INST *g, /* ptr to our scaling instance */
+ UINT in_row_len) /* # pixels per input row */
+{
+ ULONG horiz_fac; /* scale-factors in 16.16 fixed-point */
+ ULONG vert_fac;
+ UINT n;
+
+ horiz_fac = g->horiz_fac;
+ vert_fac = g->vert_fac;
+
+ if (! g->fast) {
+ assert (horiz_fac>=CONTONE_MIN_HORIZ_FAC &&
+ horiz_fac<=CONTONE_MAX_HORIZ_FAC);
+ assert ( vert_fac>=CONTONE_MIN_VERT_FAC &&
+ vert_fac<=CONTONE_MAX_VERT_FAC);
+ }
+
+ g->vert_pos = 0;
+ g->in_row_nbytes = in_row_len;
+ g->out_row_pixels = g->out_row_nbytes = (horiz_fac*in_row_len) >> 16;
+
+ if (g->image_type == IM_COLOR) {
+ g->in_row_nbytes *= 3;
+ g->out_row_nbytes *= 3;
+ }
+
+ g->inv_horiz_fac = ((0x80000000u / horiz_fac) << 1) + 1u;
+ g->inv_vert_fac = ((0x80000000u / vert_fac) << 1) + 1u;
+ /* We added 1 to the inverse factors above as an unusual way of rounding */
+
+ if (g->fast) {
+ g->n_alloced_rows = 0;
+ } else if (vert_fac >= 0x00010000u) { /* up-scaling vertically */
+ g->inv_vert_pos = g->inv_vert_fac;
+ g->n_alloced_rows = 2;
+ } else { /* down-scaling vertically */
+ g->n_alloced_rows = (BYTE)((g->inv_vert_fac+0x0000ffffu) >> 16) + 1;
+ g->vert_pos = vert_fac;
+ }
+
+ for (n=0; n<g->n_alloced_rows; n++) {
+ IP_MEM_ALLOC (g->out_row_nbytes, g->rows_ap[n]);
+ memset (g->rows_ap[n], 0xff, g->out_row_nbytes + 4);
+ }
+
+ g->nMoreFlush = 0; /* no flush-calls are needed */
+ return;
+
+ fatal_error:
+ assert (0);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | contone_scale_close | de-allocates scaling instance |
+ |_____________________|______________________________________________________|
+*/
+static void contone_scale_close (SC_INST *g)
+{
+ UINT n;
+
+ for (n=0; n<g->n_alloced_rows; n++)
+ IP_MEM_FREE (g->rows_ap[n]);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | contone_scale_row | scales the given input row into 0 or more output rows |
+ |___________________|________________________________________________________|
+*/
+static int contone_scale_row (
+ SC_INST *g, /* in: ptr to our scaling instance */
+ BYTE *src_row_p, /* in: input row */
+ BYTE *dest_rows_ap[]) /* out: output rows */
+{
+ UINT n_out_rows;
+ UINT u;
+ long weight;
+ long new_pos;
+ BYTE *p;
+
+ assert (src_row_p != NULL);
+
+ if (g->fast && g->vert_fac<=0x00010000u)
+ {
+ /* down-scaling fast */
+ g->vert_pos += g->vert_fac;
+ n_out_rows = g->vert_pos >> 16;
+ g->vert_pos &= 0x0000ffffu;
+
+ if (n_out_rows > 0) {
+ if (g->image_type == IM_GRAY) gray_horiz_scale (g, src_row_p, dest_rows_ap[0]);
+ else color_horiz_scale (g, src_row_p, dest_rows_ap[0]);
+ }
+
+ return n_out_rows;
+ }
+
+ p = g->rows_ap[g->n_saved_rows];
+ if (g->image_type == IM_GRAY) gray_horiz_scale (g, src_row_p, p);
+ else color_horiz_scale (g, src_row_p, p);
+
+ g->n_saved_rows += 1;
+
+ if (g->n_saved_rows == 1) {
+ /* call again to duplicate the first row to get us started */
+ return contone_scale_row (g, src_row_p, dest_rows_ap);
+ }
+
+ /*************************/
+ /* Up-scaling Vertically */
+ /*************************/
+
+ if (g->vert_fac >= 0x00010000u)
+ {
+ n_out_rows = 0;
+
+ if (g->n_saved_rows == 2) {
+#if 0
+ do {
+ weight_two_rows (g, 0x10000u-g->vert_pos,
+ dest_rows_ap[n_out_rows]);
+ n_out_rows += 1;
+ g->vert_pos += g->inv_vert_fac;
+ } while ((g->vert_pos>>16) == 0);
+ g->vert_pos &= 0x0000ffffu;
+#else
+ /* We use vert_pos solely to determine the number of rows.
+ * We use inv_vert_pos to create the weights.
+ * In the commented-out code above, inv_vert_pos did both,
+ * but the problem was that the number of rows output can
+ * off by 1 compared with (num_in_rows*vert_fac), which is
+ * what our callers expect.
+ */
+ g->vert_pos += g->vert_fac;
+ n_out_rows = (UINT)(g->vert_pos >> 16);
+ g->vert_pos &= 0x0000ffffu;
+
+ for (u=0; u<n_out_rows; u++) {
+ weight = 0x10000 - g->inv_vert_pos;
+ if (weight < 0) weight = 0;
+ else if (weight > 0x10000) weight = 0x10000;
+ weight_two_rows (g, weight, dest_rows_ap[u]);
+ g->inv_vert_pos += g->inv_vert_fac;
+ }
+
+ g->inv_vert_pos -= 0x10000;
+#endif
+ /* discard the oldest row */
+ g->n_saved_rows = 1;
+ p = g->rows_ap[0];
+ g->rows_ap[0] = g->rows_ap[1];
+ g->rows_ap[1] = p;
+ }
+ }
+
+ /***************************/
+ /* Down-scaling Vertically */
+ /***************************/
+
+ else
+ {
+ n_out_rows = 0;
+ new_pos = g->vert_pos + (g->n_saved_rows-1)*g->vert_fac;
+
+ if ((new_pos>>16) != 0) {
+ weight_n_rows (g, g->n_saved_rows, g->vert_pos, g->vert_fac,
+ dest_rows_ap[0]);
+ n_out_rows = 1;
+ g->vert_pos = new_pos & 0x0000ffffu;
+
+ /* retain the newest row */
+ p = g->rows_ap[0];
+ g->rows_ap[0] = g->rows_ap[g->n_saved_rows-1];
+ g->rows_ap[g->n_saved_rows-1] = p;
+ g->n_saved_rows = 1;
+ }
+ }
+
+ return n_out_rows;
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ E X P O R T E D R O U T I N E S
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*****************************************************************************\
+ *
+ * scale_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD scale_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PSC_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(SC_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(SC_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * scale_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD scale_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PSC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Insure that values we care about are correct */
+ INSURE ( (pTraits->iBitsPerPixel==24 && pTraits->iComponentsPerPixel==3)
+ || (pTraits->iBitsPerPixel==8 && pTraits->iComponentsPerPixel==1)
+ || (pTraits->iBitsPerPixel==1 && pTraits->iComponentsPerPixel==1));
+ INSURE (pTraits->iPixelsPerRow > 0);
+
+ switch (pTraits->iBitsPerPixel) {
+ case 1: g->image_type = IM_BILEVEL; break;
+ case 8: g->image_type = IM_GRAY; break;
+ case 24: g->image_type = IM_COLOR; break;
+ }
+
+ /* We don't actually support IM_BILEVEL currently. */
+ INSURE(g->image_type != IM_BILEVEL);
+
+ g->inTraits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * scale_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD scale_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PSC_INST g;
+ HANDLE_TO_PTR (hXform, g);
+
+ g->horiz_fac = (aXformInfo[IP_SCALE_HORIZ_FACTOR].dword+0x80) >> 8;
+ g->vert_fac = (aXformInfo[IP_SCALE_VERT_FACTOR].dword+0x80) >> 8;
+ g->fast = aXformInfo[IP_SCALE_FAST].dword;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * scale_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD scale_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * scale_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD scale_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PSC_INST g;
+ int i;
+ UINT in_row_len;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Since there is no header, we'll report no usage of input ****/
+
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ /**** Open the particular type of scaler we'll need ****/
+
+ in_row_len = g->inTraits.iPixelsPerRow;
+
+ switch (g->image_type) {
+ case IM_BILEVEL:
+ if (g->vert_fac < 0x10000u)
+ g->fast = FALSE; /* bi-level down-scale doesn't have fast case */
+ if (g->fast) bi_fast_open (g, in_row_len);
+ else bi_scale_open (g, in_row_len);
+ break;
+
+ case IM_GRAY:
+ case IM_COLOR:
+ if (g->vert_fac > 0x10000u)
+ g->fast = FALSE; /* contone up-scale doesn't have fast case */
+ contone_scale_open (g, in_row_len);
+ break;
+ }
+
+ /**** Allocate the held output rows ****/
+
+ g->nMaxOutRows = (g->vert_fac+0x0000ffffu) >> 16;
+ INSURE (g->nMaxOutRows <= HELD_ARRAY_SIZE);
+ for (i=1; i<g->nMaxOutRows; i++)
+ IP_MEM_ALLOC (g->out_row_nbytes, g->apHeldOutRows[i]);
+
+ /**** Report back input- and output-traits ****/
+
+ *pInTraits = g->inTraits; /* structure copies */
+ *pOutTraits = g->inTraits;
+ pOutTraits->iPixelsPerRow = g->out_row_pixels;
+ if (pInTraits->lNumRows >= 0) {
+ /* use floating point because fixed-point product would
+ * overflow if # rows is over 16 bits */
+ pOutTraits->lNumRows = (long)
+ ((float)pInTraits->lNumRows * g->vert_fac / 65536.0);
+ }
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * scale_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD scale_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PSC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = g->in_row_nbytes;
+ *pdwMinOutBufLen = g->out_row_nbytes;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * scale_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD scale_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PSC_INST g;
+ BYTE src_traits;
+ ULONG dest_traits;
+ int inUsed, outUsed;
+ int n_rows;
+ WORD wResults;
+
+ HANDLE_TO_PTR (hXform, g);
+ inUsed = 0;
+ outUsed = 0;
+
+ /**** Return next stored output-row, if any ****/
+
+ if (g->nMoreHeldOutRows > 0) {
+ memcpy (pbOutputBuf,
+ g->apHeldOutRows[g->iNextHeldOutRow],
+ g->out_row_nbytes);
+ g->nMoreHeldOutRows -= 1;
+ g->iNextHeldOutRow += 1;
+ outUsed = g->out_row_nbytes;
+ goto finish;
+ }
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("scale_convert: Told to flush.\n"), 0, 0);
+ if (g->nMoreFlush == 0)
+ goto finish;
+ g->nMoreFlush -= 1;
+ /* do "scale a row" section below, with pbInputBuf equal to NULL */
+ } else
+ inUsed = g->in_row_nbytes;
+
+ /**** Scale a Row ****/
+
+ g->apHeldOutRows[0] = pbOutputBuf; /* 1st out-row is client's buffer */
+ n_rows = 0; /* init to avoid compiler warning */
+ src_traits = 0;
+
+ switch (g->image_type) {
+ case IM_BILEVEL:
+ if (g->fast)
+ n_rows = bi_fast_row (g, pbInputBuf, src_traits,
+ g->apHeldOutRows, &dest_traits);
+ else
+ n_rows = bi_scale_row (g, pbInputBuf, src_traits,
+ g->apHeldOutRows, &dest_traits);
+ break;
+
+ case IM_GRAY:
+ case IM_COLOR:
+ n_rows = contone_scale_row (g, pbInputBuf, g->apHeldOutRows);
+ break;
+ }
+
+ INSURE (n_rows <= g->nMaxOutRows);
+ if (n_rows > 0) {
+ g->nMoreHeldOutRows = n_rows - 1;
+ g->iNextHeldOutRow = 1;
+ outUsed = g->out_row_nbytes;
+ }
+
+ /**** Report results and return (inUsed and outUsed are valid here) ****/
+
+ finish:
+
+ *pdwInputUsed = (DWORD)inUsed;
+ g->dwInNextPos += (DWORD)inUsed;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = (DWORD)outUsed;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += (DWORD)outUsed;
+
+ wResults = ( inUsed>0 ? IP_CONSUMED_ROW : 0)
+ | (outUsed>0 ? IP_PRODUCED_ROW : 0)
+ | (g->nMoreHeldOutRows==0 ? IP_READY_FOR_DATA : 0)
+ | (pbInputBuf==NULL &&
+ g->nMoreFlush==0 &&
+ g->nMoreHeldOutRows==0 ? IP_DONE : 0);
+ return wResults;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * scale_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD scale_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * scale_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD scale_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PSC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * scale_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD scale_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PSC_INST g;
+ int i;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ switch (g->image_type) {
+ case IM_BILEVEL:
+ if (g->fast) bi_fast_close (g);
+ else bi_scale_close (g);
+ break;
+
+ case IM_GRAY:
+ case IM_COLOR:
+ contone_scale_close (g);
+ break;
+ }
+
+ for (i=1; i<g->nMaxOutRows; i++)
+ IP_MEM_FREE (g->apHeldOutRows[i]);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * scaleTbl - Jump-table for scaler
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL scaleTbl = {
+ scale_openXform,
+ scale_setDefaultInputTraits,
+ scale_setXformSpec,
+ scale_getHeaderBufSize,
+ scale_getActualTraits,
+ scale_getActualBufSizes,
+ scale_convert,
+ scale_newPage,
+ scale_insertedData,
+ scale_closeXform
+};
+
+/* End of File */
diff --git a/ip/xskel.c b/ip/xskel.c
new file mode 100644
index 0000000..930af94
--- /dev/null
+++ b/ip/xskel.c
@@ -0,0 +1,456 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xskel.c - A skeleton xform driver on which new xforms can be based
+ *
+ * You must change "skel" and "SKEL" to your actual xform name.
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * skelTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_SKEL_SPEC_1] = fully describe these options here, if any
+ * aXformInfo[IP_SKEL_SPEC_2] =
+ *
+ * Capabilities and Limitations:
+ *
+ * What does this xform do? What limitations of data types, ranges, etc?
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * Describe what you do with the default input traits, and how the
+ * output traits are determined.
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel * passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+\******************************************************************************/
+
+// Use the #define below if this transform will exist in a dll outside of the
+// image pipeline. This will allow the functions to be exported.
+// #define EXPORT_TRANFORM 1
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+#ifdef EXPORT_TRANSFORM
+#define FUNC_STATUS __declspec (dllexport)
+#else
+#define FUNC_STATUS static
+#endif
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input and output image */
+ DWORD dwBytesPerRow; /* # of bytes in each row */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} SKEL_INST, *PSKEL_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * skel_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD skel_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PSKEL_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(SKEL_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(SKEL_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * skel_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD skel_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PSKEL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
+ g->traits = *pTraits; /* a structure copy */
+ g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * skel_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD skel_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PSKEL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Check your options in aXformInfo here, and save them.
+ * Use the INSURE macro like you'd use assert. INSURE jumps to
+ * fatal_error below if it fails.
+ */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * skel_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD skel_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * skel_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD skel_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PSKEL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+ g->dwInNextPos = 0;
+
+ *pInTraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * skel_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+FUNC_STATUS WORD skel_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PSKEL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * skel_convert - Converts one row
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD skel_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PSKEL_INST g;
+ int nBytes;
+ PBYTE pIn, pOut;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("skel_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = g->dwBytesPerRow;
+ INSURE (dwInputAvail >= (DWORD)nBytes );
+ INSURE (dwOutputAvail >= (DWORD)nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+
+ /* At this point, pIn is your input buffer, and pOut is your output buffer.
+ * Do whatever you are going to do here.
+ */
+ memcpy(pOut,pIn,nBytes);
+
+ *pdwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * skel_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD skel_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * skel_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD skel_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PSKEL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * skel_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+FUNC_STATUS WORD skel_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PSKEL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * skelTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+#ifdef EXPORT_TRANSFORM
+__declspec (dllexport)
+#endif
+IP_XFORM_TBL skelTbl = {
+ skel_openXform,
+ skel_setDefaultInputTraits,
+ skel_setXformSpec,
+ skel_getHeaderBufSize,
+ skel_getActualTraits,
+ skel_getActualBufSizes,
+ skel_convert,
+ skel_newPage,
+ skel_insertedData,
+ skel_closeXform
+};
+
+/* End of File */
+
+
+/*****************************************************************************\
+ *
+ * ipGetXformTable - Returns pointer to the jump table
+ *
+\*****************************************************************************/
+
+#ifdef EXPORT_TRANSFORM
+EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL pXform)
+{
+ WORD wRet = IP_DONE;
+
+ if (pXform)
+ {
+ *pXform = clrmapTbl;
+ }
+ else
+ {
+ wRet = IP_FATAL_ERROR;
+ }
+
+ return wRet;
+}
+#endif
diff --git a/ip/xtable.c b/ip/xtable.c
new file mode 100644
index 0000000..35c85a2
--- /dev/null
+++ b/ip/xtable.c
@@ -0,0 +1,742 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xtable.c - Performs a 256-entry table lookup on all bytes
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * tableTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_TABLE_WHICH] = contents of table to use:
+ * IP_TABLE_USER = user-supplied pointer to a 256-byte table,
+ * IP_TABLE_USER_WORD = user-supplied pointer to a 4096-word table,
+ * IP_TABLE_PASS_THRU = pass-thru table that does nothing,
+ * IP_TABLE_GAMMA = gamma function,
+ * IP_TABLE_THRESHOLD = threshold (snaps each incoming byte to 0 or 255),
+ * IP_TABLE_MIRROR = mirror-image each incoming byte,
+ * IP_TABLE_USER_THREE = three user-supplied table pointers,
+ * IP_TABLE_USER_THREE_WORD = three user-supplied table pointers for 48-bit (see format below),
+ * IP_TABLE_BW_CLIP = white/black clipper (2 thresholds below)
+ *
+ * aXformInfo[IP_TABLE_OPTION] =
+ * parameter based on type of table to use. values:
+ * - (type IP_TABLE_USER) pointer to user table,
+ * this table is copied into this xform's instance,
+ * - (type IP_TABLE_GAMMA) gamma value, in 16.16 fixed-point, a value
+ * less than 1.0 does an inverse gamma, (for
+ * type IP_TABLE_GAMMA above),
+ * - (type IP_TABLE_THRESHOLD) threshold value. if an incoming byte is >=
+ * this value, it changes to 255, else it changes
+ * to 0 (for type IP_TABLE_THRESHOLD above),
+ * - (type IP_TABLE_BW_CLIP) hi word = number of 0 entries at start,
+ * lo word = number of 255 entries at end,
+ *
+ * For option IP_TABLE_USER_THREE above (three user-supplied table pointers),
+ * these three 256-byte tables are for 3-component color data. The pointers are in
+ * aXformInfo[IP_TABLE_COLOR_1], aXformInfo[IP_TABLE_COLOR_2], and aXformInfo[IP_TABLE_COLOR_3].
+ *
+ * For option IP_TABLE_USER_THREE_WORD (three user tables for 48-bit color data),
+ * the pointers are in aXformInfo as with IP_TABLE_USER_THREE.
+ * Each table consists of 4096 words (8192 bytes) which are indexed by the high 12 bits
+ * of each color-channel. The low four bits are interpolated herein. Each table-entry
+ * contains a 16-bit pixel-value, even though it's indexed by just 12 bits.
+ *
+ * IP_TABLE_USER_WORD is like IP_TABLE_USER_THREE_WORD described above.
+ *
+ * For option IP_TABLE_BW_CLIP, the white/black clipper, the table starts with the given
+ * number of 0's, and ends with the given number of 255's, and linearly
+ * progresses between 1 and 254 in between them. This serves to snap
+ * almost-black to black, and almost-white to white. If these numbers
+ * are large, this table also boosts contrast.
+ *
+ * Capabilities and Limitations:
+ *
+ * The incoming data can be any kind of raw pixels of 1, 8, 16, 24 or 48
+ * bits/pixel. Bi-level (1 bit/pixel) data is treated as 8 pixels per byte.
+ * All table-types support all these forms of input data. For 16 bits/channel
+ * data, the tables are interpolated.
+ *
+ * For improved precision, the following define larger (12-bit index) tables:
+ * IP_TABLE_USER_WORD - 16 bits per pixel (grayscale)
+ * IP_TABLE_USER_THREE_WORD - 48 bits per pixel (color)
+ *
+ * Also, IP_TABLE_GAMMA will create a 12-bit table when the input data
+ * is 16 bits/channel.
+ *
+ * 12-bit tables work with 8-bit/channel data, and 8-bit tables work with
+ * 16-bit/channel data. Truncation or interpolation is done as needed.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Apr 1998 Mark Overton -- wrote original code
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+#include "math.h" /* for pow for generating gamma table */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input and output image */
+ BYTE bWhich; /* which table to generate */
+ BYTE bTables[3][256]; /* the 8-bit look-up tables */
+ WORD *pwTables[3]; /* ptrs to 12-bit-index tables (for 16-bits/pixel) */
+ BOOL bBigTable; /* are we using the 12-bit tables? */
+ int nTables; /* # of tables defined (1 or 3) */
+ DWORD dwBytesPerRow; /* # of bytes in each row */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} TBL_INST, *PTBL_INST;
+
+
+typedef enum {
+ TBL_USER,
+ TBL_PASS_THRU,
+ TBL_GAMMA,
+ TBL_THRESHOLD,
+ TBL_MIRROR,
+ TBL_USER_THREE,
+ TBL_BW_CLIP
+} TABLE_TYPE;
+
+
+
+static BOOL generateTable (
+ PTBL_INST g,
+ DWORD_OR_PVOID aXformInfo[])
+{
+ IP_TABLE_TYPE which;
+ DWORD dwparam;
+ PVOID pvparam;
+ float flparam;
+ PBYTE pTable;
+ PWORD pwTable;
+ int nTable;
+
+ g->nTables = 1;
+ g->bBigTable = FALSE;
+ pTable = g->bTables[0];
+ dwparam = aXformInfo[IP_TABLE_OPTION].dword;
+ pvparam = aXformInfo[IP_TABLE_OPTION].pvoid;
+ flparam = aXformInfo[IP_TABLE_OPTION].fl;
+ which = (IP_TABLE_TYPE)aXformInfo[IP_TABLE_WHICH].dword;
+ g->bWhich = (BYTE)which;
+
+ switch (which)
+ {
+ case IP_TABLE_USER:
+ if (pvparam == 0)
+ return FALSE;
+ memcpy (pTable, (PBYTE)pvparam, 256);
+ break;
+
+ case IP_TABLE_USER_WORD:
+ if (pvparam == 0)
+ return FALSE;
+ IP_MEM_ALLOC (4097*sizeof(WORD), pwTable); /* 4097: extra entry at end */
+ g->pwTables[0] = pwTable;
+ memcpy (pwTable, (PWORD)pvparam, 4096*sizeof(WORD));
+ pwTable[4096] = pwTable[4095]; /* extra entry to help interpolation */
+ g->bBigTable = TRUE;
+ break;
+
+ case IP_TABLE_USER_THREE:
+ if (aXformInfo[IP_TABLE_COLOR_1].pvoid==0 ||
+ aXformInfo[IP_TABLE_COLOR_2].pvoid==0 ||
+ aXformInfo[IP_TABLE_COLOR_3].pvoid==0)
+ return FALSE;
+ memcpy (g->bTables[0], (PBYTE)aXformInfo[IP_TABLE_COLOR_1].pvoid, 256);
+ memcpy (g->bTables[1], (PBYTE)aXformInfo[IP_TABLE_COLOR_2].pvoid, 256);
+ memcpy (g->bTables[2], (PBYTE)aXformInfo[IP_TABLE_COLOR_3].pvoid, 256);
+ g->nTables = 3;
+ break;
+
+ case IP_TABLE_USER_THREE_WORD:
+ if (aXformInfo[IP_TABLE_COLOR_1].pvoid==0 ||
+ aXformInfo[IP_TABLE_COLOR_2].pvoid==0 ||
+ aXformInfo[IP_TABLE_COLOR_3].pvoid==0)
+ return FALSE;
+
+ for (nTable=0; nTable<3; nTable++) {
+ IP_MEM_ALLOC (4097*sizeof(WORD), pwTable); /* 4097: extra entry at end */
+ g->pwTables[nTable] = pwTable;
+ memcpy (pwTable, (PWORD)aXformInfo[IP_TABLE_COLOR_1+nTable].pvoid, 4096*sizeof(WORD));
+ pwTable[4096] = pwTable[4095]; /* extra entry to help interpolation */
+ }
+ g->nTables = 3;
+ g->bBigTable = TRUE;
+ break;
+
+ case IP_TABLE_PASS_THRU:
+ {
+ int i;
+
+ for (i=0; i<=255; i++)
+ pTable[i] = i;
+ }
+ break;
+
+ case IP_TABLE_GAMMA:
+ {
+ int index;
+ float fval;
+ float gamma;
+ float gamval;
+
+ gamma = (float)flparam / (float)(1L<<16);
+ if (gamma<=0.0f || gamma>=10.0f)
+ return FALSE;
+ gamma = 1.0f / gamma;
+
+ if (g->traits.iBitsPerPixel==16 || g->traits.iBitsPerPixel==48) {
+ WORD *pwTable;
+ IP_MEM_ALLOC (4097*sizeof(WORD), pwTable); /* 4097: extra entry at end */
+ g->pwTables[0] = pwTable;
+
+ for (index=0; index<=4095u; index++) {
+ fval = (float)index / 4095.0f;
+ gamval = 65535.0f * (float)pow(fval, gamma);
+ pwTable[index] = (WORD)(gamval + 0.5f);
+ }
+
+ pwTable[4096] = pwTable[4095]; /* extra entry to help interpolation */
+ g->bBigTable = TRUE;
+ } else {
+ for (index=0; index<=255u; index++) {
+ fval = (float)index / 255.0f;
+ gamval = 255.0f * (float)pow(fval, gamma);
+ pTable[index] = (BYTE)(gamval + 0.5f);
+ }
+ }
+ }
+ break;
+
+ case IP_TABLE_THRESHOLD:
+ if (dwparam<1 || dwparam>255)
+ return FALSE;
+ memset (pTable, 0, dwparam);
+ memset (pTable+dwparam, 255, 256-dwparam);
+ break;
+
+ case IP_TABLE_MIRROR:
+ {
+ UINT index, mask;
+
+ for (index=0; index<=255; index++) {
+ for (mask=0x01u; mask<=0x80u; mask<<=1) {
+ pTable[index] <<= 1;
+ if (index & mask)
+ pTable[index] += 1;
+ }
+ }
+ }
+ break;
+
+ case IP_TABLE_BW_CLIP:
+ {
+ DWORD nBlack, nWhite, nMid, slopeMid, posMid, index;
+
+ nBlack = dwparam >> 16;
+ nWhite = dwparam & 0xFFFFu;
+
+ if (nBlack+nWhite > 256)
+ return FALSE;
+
+ for (index=0; index<nBlack; index++)
+ pTable[index] = 0;
+
+ for (index=256-nWhite; index<=255; index++)
+ pTable[index] = 255;
+
+ nMid = 256 - nBlack - nWhite;
+ slopeMid = (255ul<<16) / (nMid + 1);
+ posMid = 0x8000u; /* offset for rounding */
+
+ for (index=nBlack; index<256-nWhite; index++) {
+ posMid += slopeMid;
+ pTable[index] = (BYTE)(posMid >> 16);
+ }
+ }
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+
+fatal_error:
+ return FALSE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * table_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD table_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PTBL_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(TBL_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(TBL_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * table_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD table_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PTBL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
+ g->traits = *pTraits; /* a structure copy */
+ g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * table_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD table_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PTBL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ if (! generateTable(g,aXformInfo))
+ goto fatal_error;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * table_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD table_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * table_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD table_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PTBL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pIntraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * table_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD table_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PTBL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * table_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD table_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PTBL_INST g;
+ int nBytes, nTable;
+ PBYTE pIn, pOut, pOutAfter;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("table_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = g->dwBytesPerRow;
+ INSURE (dwInputAvail >= (DWORD)nBytes);
+ INSURE (dwOutputAvail >= (DWORD)nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pOutAfter = pOut + nBytes;
+
+ if (g->bWhich == IP_TABLE_PASS_THRU)
+ {
+ memcpy (pOut, pIn, nBytes);
+ }
+ else if (g->traits.iBitsPerPixel==16 || g->traits.iBitsPerPixel==48)
+ {
+ /* 16 bits per channel -- interpolate between table-entries */
+ int x, xHi, y1, y2;
+ WORD *pwTable, *pwIn, *pwOut, *pwOutAfter;
+ BYTE *pbTable;
+
+ pwIn = (WORD*)pIn;
+ pwOut = (WORD*)pOut;
+ pwOutAfter = (WORD*)pOutAfter;
+
+ if (g->bBigTable)
+ {
+ /* we're using 12-bit table(s) */
+ while (pwOut < pwOutAfter) {
+ for (nTable=0; nTable<g->nTables; nTable++) {
+ pwTable = g->pwTables[nTable];
+ x = (unsigned)(*pwIn++);
+ xHi = x >> 4; /* hi 12 bits is used for indexing into the table */
+ y1 = (unsigned)pwTable[xHi ]; /* index is in 0..4095 */
+ y2 = (unsigned)pwTable[xHi+1]; /* extra entry in table is for index=4096 */
+ /* interpolate the lowest 4 bits */
+ *pwOut++ = (WORD)(((y2-y1)*(x&0x0f)>>4) + y1);
+ }
+ }
+ }
+ else /* we're using 8-bit table(s) */
+ {
+ while (pwOut < pwOutAfter) {
+ for (nTable=0; nTable<g->nTables; nTable++) {
+ pbTable = g->bTables[nTable];
+ x = (unsigned)(*pwIn++);
+ xHi = x >> 8; /* hi 8 bits is used for indexing into the table */
+ y1 = (unsigned)pbTable[xHi]; /* index is in 0..255 for both */
+ y2 = (unsigned)pbTable[xHi==255 ? 255 : xHi+1];
+ /* interpolate the lowest 8 bits */
+ *pwOut++ = (WORD)((y2-y1)*(x&0x0ff) + (y1<<8));
+ }
+ }
+ }
+ }
+ else /* 8 bits per channel -- the normal case */
+ {
+ if (g->bBigTable)
+ {
+ /* using a big table for 8- or 24-bit data, for some reason */
+ while (pOut < pOutAfter)
+ for (nTable=0; nTable<g->nTables; nTable++)
+ *pOut++ = (BYTE)(g->pwTables[nTable][(unsigned)(*pIn++)<<4] >> 8);
+ }
+ else if (g->nTables == 3)
+ {
+ while (pOut < pOutAfter) {
+ /* process two pixels at a time for improved speed */
+ pOut[0] = g->bTables[0][pIn[0]];
+ pOut[1] = g->bTables[1][pIn[1]];
+ pOut[2] = g->bTables[2][pIn[2]];
+ pOut[3] = g->bTables[0][pIn[3]];
+ pOut[4] = g->bTables[1][pIn[4]];
+ pOut[5] = g->bTables[2][pIn[5]];
+
+ pIn += 6;
+ pOut += 6;
+ }
+ }
+ else /* using a single table */
+ {
+ while (pOut < pOutAfter) {
+ /* process eight pixels at a time for improved speed */
+ pOut[0] = g->bTables[0][pIn[0]];
+ pOut[1] = g->bTables[0][pIn[1]];
+ pOut[2] = g->bTables[0][pIn[2]];
+ pOut[3] = g->bTables[0][pIn[3]];
+ pOut[4] = g->bTables[0][pIn[4]];
+ pOut[5] = g->bTables[0][pIn[5]];
+ pOut[6] = g->bTables[0][pIn[6]];
+ pOut[7] = g->bTables[0][pIn[7]];
+
+ pIn += 8;
+ pOut += 8;
+ }
+ }
+ }
+
+ *pdwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * table_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD table_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * table_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD table_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PTBL_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * table_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD table_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PTBL_INST g;
+ int i;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ for (i=0; i<3; i++)
+ if (g->pwTables[i] != NULL)
+ IP_MEM_FREE (g->pwTables[i]);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tableTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL tableTbl = {
+ table_openXform,
+ table_setDefaultInputTraits,
+ table_setXformSpec,
+ table_getHeaderBufSize,
+ table_getActualTraits,
+ table_getActualBufSizes,
+ table_convert,
+ table_newPage,
+ table_insertedData,
+ table_closeXform
+};
+
+/* End of File */
diff --git a/ip/xthumb.c b/ip/xthumb.c
new file mode 100644
index 0000000..f5fb33a
--- /dev/null
+++ b/ip/xthumb.c
@@ -0,0 +1,558 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xthumb.c - Downscales quickly by large factor for generating thumbnail image
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * thumbTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_THUMB_SCALE_SPEC] determines scale-factor indirectly or directly,
+ * depending on whether it's positive or negative.
+ *
+ * positive: value is the maximum output-width in pixels. xthumb will
+ * select the N for the scale-factor of the form 1/N which
+ * results in the largest possible output width not exceeding
+ * the value in aXformInfo[IP_THUMB_SCALE_SPEC].
+ *
+ * negative: absolute value is N for the scale-factor of the form 1/N.
+ * the scale-factor is being specified directly.
+ *
+ * Capabilities and Limitations:
+ *
+ * Downscales any type of raw data quickly by a large scale-factor
+ * specified by aXformInfo[IP_THUMB_SCALE_SPEC]. The pixels are averaged together.
+ * For bilevel input, the output is 8-bit gray, where each gray pixel
+ * is the average blackness of an area of the input bilevel image.
+ * For 8-bit gray and 24-bit color input data, the output data is
+ * the same type as the input.
+ *
+ * The scale-factor is of the form 1/N, where N is an integer.
+ * Warning: If N is 1 or almost 1, the actual output width will be
+ * quite smaller than that requested.
+ *
+ * If input width is smaller than output width, N will be 1 (no
+ * scaling).
+ *
+ * ipGetImageTraits must be called to determine the actual output width.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * used based on scale factor
+ * iBitsPerPixel * must be 1, 8 or 24 8 or 24
+ * iComponentsPerPixel * must be 1 or 3 same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows used if valid based on scale factor
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Mar 1998 Mark Overton -- wrote original code
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+
+typedef struct {
+ IP_IMAGE_TRAITS inTraits; /* traits of the input image */
+ int iFactorSpec; /* factor spec in aXformInfo[0] */
+ WORD wScale; /* the N in scale-factor of 1/N */
+ WORD wPreShift; /* # bits to shift sum right before multiply */
+ DWORD dwSumFac; /* factor to multiply sum by (16.16 fixed-pt) */
+ DWORD dwOutputWidth; /* # pixels per row in output */
+ DWORD dwInRowBytes; /* # bytes in each input row */
+ DWORD dwOutRowBytes; /* # bytes in each output row */
+ WORD wMoreRows2Sum; /* # more rows to be summed together */
+ PULONG pulSums; /* pixel-sums; each pixel is a ULONG */
+ ULONG ulRowsInput; /* # of rows input so far */
+ ULONG ulRowsOutput; /* # of rows output so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} TN_INST, *PTN_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * thumb_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD thumb_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PTN_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(TN_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(TN_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * thumb_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD thumb_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PTN_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ INSURE (pTraits->iPixelsPerRow > 0);
+ g->inTraits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * thumb_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD thumb_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PTN_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->iFactorSpec = (int)aXformInfo[IP_THUMB_SCALE_SPEC].dword;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * thumb_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD thumb_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * thumb_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD thumb_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PTN_INST g;
+ int N;
+ long lMaxSum;
+ long nBytes;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ /* Compute N in our scale-factor of 1/N */
+ if (g->iFactorSpec <= 0) {
+ N = -(g->iFactorSpec);
+ } else {
+ /* the +iFactorSpec-1 below biases N high (cieling function),
+ * so the output width is biased low, so that we'll never go
+ * larger than the requested output width.
+ */
+ N = (g->inTraits.iPixelsPerRow + g->iFactorSpec - 1) / g->iFactorSpec;
+ }
+
+ if (N < 1) N = 1;
+ g->wScale = N;
+
+ /* Compute max summation of N-by-N input pixels */
+ lMaxSum = (long)N*N * (g->inTraits.iBitsPerPixel==1 ? 1 : 255);
+
+ /* Compute pre-shift so that max sum does not exceed 16 bits */
+ if (lMaxSum >= (1L<<28)) g->wPreShift = 16;
+ else if (lMaxSum >= (1L<<24)) g->wPreShift = 12;
+ else if (lMaxSum >= (1L<<20)) g->wPreShift = 8;
+ else if (lMaxSum >= (1L<<16)) g->wPreShift = 4;
+ else g->wPreShift = 0;
+
+ /* Now do the pre-shift on max sum */
+ lMaxSum >>= g->wPreShift;
+ INSURE (lMaxSum < (1L<<16)); /* make sure it fits in 16 bits */
+
+ /* And compute the factor for converting a sum into a 0..255 pixel */
+ g->dwSumFac = (DWORD)((255.0/(float)lMaxSum) * (float)(1L<<16));
+
+ *pInTraits = g->inTraits; /* structure copies */
+ *pOutTraits = g->inTraits;
+
+ if (pOutTraits->iBitsPerPixel == 1)
+ pOutTraits->iBitsPerPixel = 8;
+ pOutTraits->iPixelsPerRow = g->dwOutputWidth = pInTraits->iPixelsPerRow / N;
+ if (pOutTraits->lNumRows >= 0)
+ pOutTraits->lNumRows /= N;
+
+ g->wMoreRows2Sum = N;
+ g->dwInRowBytes =
+ (pInTraits->iPixelsPerRow * pInTraits->iBitsPerPixel + 7) / 8;
+ g->dwOutRowBytes = g->dwOutputWidth * pInTraits->iComponentsPerPixel;
+
+ nBytes = g->dwOutRowBytes * sizeof(ULONG);
+ IP_MEM_ALLOC (nBytes, g->pulSums);
+ memset (g->pulSums, 0, nBytes);
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * thumb_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD thumb_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PTN_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = g->dwInRowBytes;
+ *pdwMinOutBufLen = g->dwOutRowBytes;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * thumb_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD thumb_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PTN_INST g;
+ PBYTE pIn, pOut;
+ BYTE bMask, bVal=0;
+ ULONG ulSum, sum0, sum1, sum2;
+ ULONG *pulSum, *pulSumAfter;
+ UINT u;
+ BOOL fSentRow;
+
+ HANDLE_TO_PTR (hXform, g);
+ pulSumAfter = g->pulSums + g->dwOutRowBytes;
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("thumb_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Sum this Input Row ****/
+
+ INSURE (dwInputAvail >= g->dwInRowBytes);
+ pIn = pbInputBuf;
+
+ switch (g->inTraits.iBitsPerPixel) {
+ case 1: /* bilevel input */
+ bMask = 0;
+ for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum++) {
+ ulSum = *pulSum;
+ for (u=g->wScale; u>0; u--) {
+ if (bMask == 0) {
+ bMask = 0x80u;
+ bVal = *pIn++;
+ }
+ if ((bMask & bVal) == 0) {
+ /* since the sum is a measure of overall whiteness,
+ * increment it for a *white* input pixel (0) */
+ ulSum += 1;
+ }
+ bMask >>= 1;
+ }
+ *pulSum = ulSum;
+ }
+ break;
+
+ case 8: /* 8-bit gray input */
+ for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum++) {
+ ulSum = *pulSum;
+ for (u=g->wScale; u>0; u--)
+ ulSum += (ULONG)(*pIn++);
+ *pulSum = ulSum;
+ }
+ break;
+
+ case 24: /* 3-component color input */
+ for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum+=3) {
+ sum0 = pulSum[0];
+ sum1 = pulSum[1];
+ sum2 = pulSum[2];
+ for (u=g->wScale; u>0; u--) {
+ sum0 += (ULONG)(*pIn++);
+ sum1 += (ULONG)(*pIn++);
+ sum2 += (ULONG)(*pIn++);
+ }
+ pulSum[0] = sum0;
+ pulSum[1] = sum1;
+ pulSum[2] = sum2;
+ }
+ break;
+ } /* switch */
+
+ *pdwInputUsed = g->dwInRowBytes;
+ g->dwInNextPos += g->dwInRowBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+ g->ulRowsInput += 1;
+
+ /**** If it's time, Compute Output Row ****/
+
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->wMoreRows2Sum -= 1;
+
+ if (g->wMoreRows2Sum > 0) {
+ fSentRow = FALSE;
+ *pdwOutputUsed = 0;
+ } else {
+ g->wMoreRows2Sum = g->wScale;
+ fSentRow = TRUE;
+ g->ulRowsOutput += 1;
+ INSURE (dwOutputAvail >= g->dwOutRowBytes);
+ *pdwOutputUsed = g->dwOutRowBytes;
+ g->dwOutNextPos += g->dwOutRowBytes;
+
+ pulSum = g->pulSums;
+ pOut = pbOutputBuf;
+ for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum++) {
+ *pOut++ = (BYTE)((*pulSum >> g->wPreShift) * g->dwSumFac >> 16);
+ }
+
+ memset (g->pulSums, 0, g->dwOutRowBytes*sizeof(ULONG));
+ }
+
+ /**** Return ****/
+
+ return IP_CONSUMED_ROW |
+ IP_READY_FOR_DATA |
+ (fSentRow ? IP_PRODUCED_ROW : 0);
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * thumb_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD thumb_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * thumb_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD thumb_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PTN_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * thumb_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD thumb_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PTN_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ if (g->pulSums != NULL)
+ IP_MEM_FREE (g->pulSums);
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * thumbTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL thumbTbl = {
+ thumb_openXform,
+ thumb_setDefaultInputTraits,
+ thumb_setXformSpec,
+ thumb_getHeaderBufSize,
+ thumb_getActualTraits,
+ thumb_getActualBufSizes,
+ thumb_convert,
+ thumb_newPage,
+ thumb_insertedData,
+ thumb_closeXform
+};
+
+/* End of File */
diff --git a/ip/xtiff.c b/ip/xtiff.c
new file mode 100644
index 0000000..e1338e5
--- /dev/null
+++ b/ip/xtiff.c
@@ -0,0 +1,1338 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*****************************************************************************\
+ *
+ * xtiff.c - encoder and decoder for TIFF files for image processor
+ *
+ *****************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * tifEncodeTbl = the encoder,
+ * tifDecodeTbl = the decoder.
+ *
+ * Encoder: Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_TIFF_FILE_PATH] = pointer to a file-path, or NULL
+ *
+ * If NULL, a one-page TIFF is output in the normal manner.
+ * If not NULL, this must be a pointer to a string containing a file-path.
+ * If the given file does not exist, it will be created and one image will
+ * be put in it. If it does exist, the image will be APPENDED to this file,
+ * and no data will be output by this xform. So if one or more pages are
+ * already in the file, we will add another page to it. This xform does
+ * the opening and closing of the file.
+ *
+ * Decoder: Items in aXformInfo array passed into setXformSpec:
+ *
+ * None.
+ *
+ * Capabilities and Limitations:
+ *
+ * Handles 1, 8, 16, 24 and 48 bits per pixel.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Apr 2000, Mark Overton, ported header-setup from TWAIN source, and added
+ * multi-page capability
+ * Feb 1998, Mark Overton, ported to new Image Processor code
+ * May 1996, Mark Overton, wrote original code
+ * Jun 2000, Mark Overton, wrote a simple decoder that does no file-seeks
+ *
+ *****************************************************************************/
+
+
+#include "stdio.h" /* for FILE operations */
+#include "assert.h"
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h"
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x1ce5ca7e
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Constants pertaining to tags |
+ |____________________________________________________________________________|
+*/
+
+
+/* TIF_INST - our instance variables */
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the image */
+ int iBitsPerSample; /* bits per channel (1, 8 or 16) */
+ BOOL bByteSwap; /* bytes are in wrong endian order, so must swap? */
+ char sFilePath[200]; /* path to the file (empty string means none) */
+ FILE *fileOut; /* handle of opened file */
+ DWORD dwRawRowBytes; /* bytes per raw row */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwValidChk; /* struct validity check value */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ BOOL fDidHeader; /* already sent the header? */
+} TIF_INST, *PTIF_INST;
+
+
+/* Types having known sizes */
+typedef unsigned char TIFF_UBYTE; /* 8 bits */
+typedef unsigned short TIFF_USHORT; /* 16 bits */
+typedef unsigned int TIFF_ULONG; /* 32 bits */
+typedef signed char TIFF_SBYTE; /* 8 bits */
+typedef signed short TIFF_SSHORT; /* 16 bits */
+typedef signed int TIFF_SLONG; /* 32 bits */
+
+/* TIFF file header defines */
+#define INTEL 0x4949
+#define TIFF_VERSION 42
+
+/* TIFF field lengths */
+#define TIFFBYTE 1
+#define TIFFASCII 2
+#define TIFFSHORT 3
+#define TIFFLONG 4
+#define TIFFRATIONAL 5
+#define TIFFSBYTE 6
+#define TIFFUNDEFINED 7
+#define TIFFSSHORT 8
+#define TIFFSLONG 9
+#define TIFFSRATIONAL 10
+
+/* TIFF compression type */
+#define NOCOMPRESSION 1
+
+/* TIFF planar configuration */
+#define CONTIGUOUS 1
+#define PLANAR 2
+
+/* TIFF photometric interpretations */
+#define ZERO_IS_WHITE 0
+#define ZERO_IS_BLACK 1
+#define RGB_COLOR 2
+
+/* TIFF resolution units */
+#define DOTS_PER_INCH 2
+
+
+/* TIFF tags */
+#define NUMTAGS 13
+#define BITS_PER_SAMPLE 258 // 0x0102
+#define COMPRESSION 259 // 0x0103
+#define IMAGE_LENGTH 257 // 0x0101
+#define IMAGE_WIDTH 256 // 0x0100
+#define NEW_SUBFILE 254 // 0x00fe
+#define PHOTO_INTERPRET 262 // 0x0106
+#define RESOLUTION_UNIT 296 // 0x0128
+#define ROWS_PER_STRIP 278 // 0x0116
+#define SAMPLES_PER_PIXEL 277 // 0x0115
+#define STRIP_COUNTS 279 // 0x0117
+#define STRIP_OFFSETS 273 // 0x0111
+#define XRESOLUTION 282 // 0x011A
+#define YRESOLUTION 283 // 0x011B
+
+typedef struct {
+ TIFF_ULONG n;
+ TIFF_ULONG d;
+} __attribute__((packed)) RATIONAL;
+
+typedef union {
+ TIFF_UBYTE b[4];
+ TIFF_USHORT s[2];
+ TIFF_ULONG l;
+ TIFF_ULONG o;
+} __attribute__((packed)) TIFFVALUE;
+
+typedef struct {
+ TIFF_USHORT TagID;
+ TIFF_USHORT Kind;
+ TIFF_ULONG Length; /* number of items, NOT number of bytes */
+ TIFFVALUE Value;
+} __attribute__((packed)) TIFFTAG;
+
+typedef struct {
+ TIFF_USHORT NumTags;
+ TIFFTAG Tag[NUMTAGS];
+ TIFF_ULONG OffsetNextIFD;
+} __attribute__((packed)) TIFFIFD;
+
+typedef struct {
+ TIFF_UBYTE ByteOrder[2];
+ TIFF_USHORT Version;
+ TIFF_ULONG OffsetFirstIFD;
+} __attribute__((packed)) TIFFHEADER;
+
+#define NUMEXTBYTES (2*sizeof(RATIONAL) + 3*sizeof(TIFF_USHORT))
+#define MAX_HEADER_SIZE (sizeof(TIFFHEADER) + sizeof(TIFFIFD) + NUMEXTBYTES)
+
+
+
+/*****************************************************************************\
+ *
+ * tifEncode_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD tifEncode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PTIF_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(TIF_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(TIF_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifEncode_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD tifEncode_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PTIF_INST g;
+ int ppr, bpp;
+
+ HANDLE_TO_PTR (hXform, g);
+ ppr = pTraits->iPixelsPerRow;
+ bpp = pTraits->iBitsPerPixel;
+
+ /* Insure that values we actually use are known */
+ INSURE (ppr > 0);
+ INSURE (bpp > 0);
+
+ g->dwRawRowBytes = (ppr*bpp + 7) / 8;
+ g->traits = *pTraits; /* a structure copy */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifEncode_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD tifEncode_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PTIF_INST g;
+ char *s;
+
+ HANDLE_TO_PTR (hXform, g);
+ s = (char*)aXformInfo[IP_TIFF_FILE_PATH].pvoid;
+ if (s != NULL)
+ strcpy (g->sFilePath, s);
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifEncode_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD tifEncode_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifEncode_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD tifEncode_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PTIF_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ /* Since we don't change traits, just copy out the default traits */
+ *pInTraits = g->traits;
+ *pOutTraits = g->traits;
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * tifEncode_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD tifEncode_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PTIF_INST g;
+ UINT len;
+
+ HANDLE_TO_PTR (hXform, g);
+ len = g->dwRawRowBytes;
+ *pdwMinInBufLen = len;
+
+ if (len < MAX_HEADER_SIZE)
+ len = MAX_HEADER_SIZE;
+ *pdwMinOutBufLen = len;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * outputHeader - Only called by tifEncode_convert
+ *
+\****************************************************************************/
+
+
+
+static void SetTag (TIFFTAG *pTag,
+ unsigned short TagID, short Kind, long Length, int Value)
+{
+ pTag->TagID = (TIFF_USHORT)TagID;
+ pTag->Kind = (TIFF_USHORT)Kind;
+ pTag->Length = (TIFF_ULONG)Length;
+ pTag->Value.l = (TIFF_ULONG)Value; /* assumes little-endian computer */
+}
+
+
+
+static int WriteFileHeader (PBYTE pTIFF)
+{
+ TIFFHEADER *pHead;
+
+ pHead = (TIFFHEADER*) pTIFF;
+ pHead->ByteOrder[0] = 'I';
+ pHead->ByteOrder[1] = 'I'; /* assumes little-endian computer */
+ pHead->Version = 42;
+ pHead->OffsetFirstIFD = 8;
+
+ return 8; /* we output 8 bytes */
+}
+
+
+
+static int WriteIFD (
+ PBYTE pTIFF, /* out: the IFD is written to this buffer */
+ int iStartOffset, /* in: file-offset at which this IFD starts */
+ int WidthBytes, /* in: row-width in bytes */
+ int WidthPixels, /* in: row-width in pixels */
+ int Height, /* in: number of rows */
+ int BPP, /* in: bits per pixel */
+ int XRes, /* in: dpi in X */
+ int YRes) /* in: dpi in Y */
+{
+ TIFFIFD *pIFD;
+ TIFFTAG *pTag;
+ BYTE *pMore;
+ TIFF_USHORT *pBPS;
+ int iBPSOffset, iImageOffset;
+ int SPP, BPS, PI;
+
+ pIFD = (TIFFIFD*)pTIFF;
+ pMore = pTIFF + sizeof(TIFFIFD); /* 1st byte after the IFD */
+
+ /* allocate space for the 3 shorts for the 3 bps values (if needed) */
+ iBPSOffset = iStartOffset + (pMore-pTIFF);
+ pBPS = (TIFF_USHORT*)pMore;
+ pMore += 3*sizeof(TIFF_USHORT);
+
+ /* the pixels are put after the above items */
+ iImageOffset = iStartOffset + (pMore-pTIFF);
+
+ switch (BPP) {
+ case 1:
+ PI = ZERO_IS_WHITE; SPP = 1; BPS = 1; break; /* 1-bit bilevel */
+ case 8:
+ PI = ZERO_IS_BLACK; SPP = 1; BPS = 8; break; /* 8-bit grayscale */
+ case 16:
+ PI = ZERO_IS_BLACK; SPP = 1; BPS = 16; break; /* 16-bit grayscale */
+ case 24:
+ PI = RGB_COLOR; SPP = 3; BPS = 8; break; /* 24-bit color */
+ case 48:
+ PI = RGB_COLOR; SPP = 3; BPS = 16; break; /* 48-bit color */
+ default:
+ PI = RGB_COLOR; SPP = 3; BPS = 8; /* guess 24-bit color */
+ assert (0); /* crash if in debug mode */
+ }
+
+ pIFD->NumTags = NUMTAGS;
+ pTag = pIFD->Tag;
+ SetTag (pTag++, NEW_SUBFILE, TIFFSHORT, 1, 0);
+ SetTag (pTag++, IMAGE_WIDTH, TIFFLONG, 1, WidthPixels);
+ SetTag (pTag++, IMAGE_LENGTH, TIFFLONG, 1, Height);
+ SetTag (pTag++, BITS_PER_SAMPLE, TIFFSHORT, SPP, SPP>1 ? iBPSOffset : BPS);
+ SetTag (pTag++, COMPRESSION, TIFFSHORT, 1, 1);
+ SetTag (pTag++, PHOTO_INTERPRET, TIFFSHORT, 1, PI);
+ SetTag (pTag++, STRIP_OFFSETS, TIFFLONG, 1, iImageOffset);
+ SetTag (pTag++, SAMPLES_PER_PIXEL, TIFFSHORT, 1, SPP);
+ SetTag (pTag++, ROWS_PER_STRIP, TIFFLONG, 1, Height);
+ SetTag (pTag++, STRIP_COUNTS, TIFFLONG, 1, WidthBytes*Height);
+ SetTag (pTag++, XRESOLUTION, TIFFSHORT, 1, XRes);
+ SetTag (pTag++, YRESOLUTION, TIFFSHORT, 1, YRes);
+ SetTag (pTag++, RESOLUTION_UNIT, TIFFSHORT, 1, 2);
+ assert ((pTag - pIFD->Tag) == NUMTAGS);
+ pIFD->OffsetNextIFD = 0L; /* assume there is no next IFD */
+
+ /* Stick Samples Per Pixel here for color; Only used if pointed to by tag */
+ *pBPS++ = BPS;
+ *pBPS++ = BPS;
+ *pBPS++ = BPS;
+
+ return pMore - pTIFF;
+}
+
+
+
+static WORD AppendIFDToFile (
+ PTIF_INST g, /* in: ptr to instance structure */
+ PBYTE pbTempBuf) /* in: temp buffer large enough to hold an IFD */
+{
+ int result;
+ TIFF_ULONG fileEndPos, IFDPos, pointerPos;
+ TIFF_USHORT numTags;
+ int iHeaderLen, iIFDLen, iTotalLen;
+
+ /***** If the file is empty, do usual set-up *****/
+
+ g->fileOut = fopen (g->sFilePath, "a+b");
+ INSURE (g->fileOut != NULL);
+ result = fseek (g->fileOut, 0, SEEK_END);
+ INSURE (result == 0);
+ fileEndPos = ftell (g->fileOut);
+ INSURE (result >= 0);
+
+ if (fileEndPos == 0) {
+ iHeaderLen = WriteFileHeader(pbTempBuf);
+ iIFDLen = WriteIFD (pbTempBuf+iHeaderLen, iHeaderLen,
+ g->dwRawRowBytes, g->traits.iPixelsPerRow,
+ g->traits.lNumRows, g->traits.iBitsPerPixel,
+ g->traits.lHorizDPI>>16, g->traits.lVertDPI>>16);
+
+ iTotalLen = iHeaderLen + iIFDLen;
+ INSURE (iTotalLen <= MAX_HEADER_SIZE);
+
+ result = fwrite (pbTempBuf, 1, iTotalLen, g->fileOut);
+ INSURE (result == iTotalLen);
+
+ return IP_READY_FOR_DATA;
+ }
+
+ /***** Find the last IFD *****/
+
+ result = fseek (g->fileOut, 4, SEEK_SET);
+ INSURE (result == 0);
+ result = fread (&IFDPos, 4, 1, g->fileOut); /* assumes little-endian file */
+ INSURE (result == 1);
+
+ do { /* hop thru the IFDs until we hit the last one */
+ result = fseek (g->fileOut, IFDPos, SEEK_SET);
+ INSURE (result == 0);
+ result = fread (&numTags, 2, 1, g->fileOut); /* assumes little-endian file */
+ INSURE (result==1 && numTags>0);
+ pointerPos = IFDPos + 2 + numTags*sizeof(TIFFTAG);
+ result = fseek (g->fileOut, pointerPos, SEEK_SET);
+ INSURE (result == 0);
+ result = fread (&IFDPos, 4, 1, g->fileOut); /* assumes little-endian file */
+ INSURE (result == 1);
+ } while (IFDPos != 0);
+
+ /***** PointerPos is the final IFD offset in the file; change it *****/
+
+ /* switch to writing from now on */
+ fclose (g->fileOut);
+ g->fileOut = fopen(g->sFilePath, "r+b");
+ INSURE (g->fileOut != NULL);
+
+ result = fseek (g->fileOut, pointerPos, SEEK_SET);
+ INSURE (result == 0);
+ result = fwrite (&fileEndPos, 4, 1, g->fileOut); /* assumes little-endian file */
+ INSURE (result == 1);
+
+ /***** Output a new IFD for the new page *****/
+
+ iIFDLen = WriteIFD (pbTempBuf, fileEndPos,
+ g->dwRawRowBytes, g->traits.iPixelsPerRow,
+ g->traits.lNumRows, g->traits.iBitsPerPixel,
+ g->traits.lHorizDPI>>16, g->traits.lVertDPI>>16);
+
+ result = fseek (g->fileOut, 0, SEEK_END);
+ INSURE (result == 0);
+ result = fwrite (pbTempBuf, 1, iIFDLen, g->fileOut);
+ INSURE (result == iIFDLen);
+ /* leave the file-position at the end, where image-data will go */
+
+ return IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+static WORD outputHeader (
+ PTIF_INST g, /* in: ptr to instance structure */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ int iHeaderLen, iIFDLen, iTotalLen;
+
+ INSURE (dwOutputAvail >= MAX_HEADER_SIZE);
+ *pdwOutputThisPos = 0;
+
+ if (g->sFilePath[0] != 0) {
+ *pdwOutputUsed = 0;
+ return AppendIFDToFile (g, pbOutputBuf);
+ }
+
+ iHeaderLen = WriteFileHeader(pbOutputBuf);
+ iIFDLen = WriteIFD (pbOutputBuf+iHeaderLen, iHeaderLen,
+ g->dwRawRowBytes, g->traits.iPixelsPerRow,
+ g->traits.lNumRows, g->traits.iBitsPerPixel,
+ g->traits.lHorizDPI>>16, g->traits.lVertDPI>>16);
+
+ iTotalLen = iHeaderLen + iIFDLen;
+ INSURE (iTotalLen <= MAX_HEADER_SIZE);
+ *pdwOutputUsed = iTotalLen;
+ *pdwOutputThisPos = 0;
+ g->dwOutNextPos = iTotalLen;
+
+ return IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifEncode_convert - the work-horse routine
+ *
+\*****************************************************************************/
+
+static WORD tifEncode_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PTIF_INST g;
+ UINT n;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Output the Header if we haven't already ****/
+
+ if (! g->fDidHeader) {
+ g->fDidHeader = TRUE;
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+ return outputHeader (g, dwOutputAvail, pbOutputBuf,
+ pdwOutputUsed, pdwOutputThisPos);
+ }
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("tif_encode_convert_row: Told to flush.\n"), 0, 0);
+ if (g->traits.lNumRows < 0) {
+ /* # rows wasn't known at first, so output header again
+ * now that we know the number of rows */
+ INSURE (g->sFilePath[0] == 0);
+ g->traits.lNumRows = g->dwRowsDone;
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ return outputHeader (g, dwOutputAvail, pbOutputBuf,
+ pdwOutputUsed, pdwOutputThisPos);
+ }
+
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ n = g->dwRawRowBytes;
+ INSURE (dwInputAvail >= n);
+ INSURE (dwOutputAvail >= n);
+
+ if (g->sFilePath[0] == 0) {
+ memcpy (pbOutputBuf, pbInputBuf, n);
+
+ *pdwOutputUsed = n;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += n;
+ } else {
+ UINT result;
+ INSURE (g->fileOut != NULL);
+ result = fwrite (pbInputBuf, 1, n, g->fileOut);
+ INSURE (result == n);
+
+ *pdwOutputUsed = 0;
+ *pdwOutputThisPos = 0;
+ g->dwOutNextPos = 0;
+ }
+
+ g->dwInNextPos += n;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwInputUsed = n;
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifEncode_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD tifEncode_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifEncode_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD tifEncode_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PTIF_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifEncode_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD tifEncode_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PTIF_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ if (g->fileOut != NULL)
+ fclose (g->fileOut);
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifEncodeTbl - Jump-table for encoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL tifEncodeTbl = {
+ tifEncode_openXform,
+ tifEncode_setDefaultInputTraits,
+ tifEncode_setXformSpec,
+ tifEncode_getHeaderBufSize,
+ tifEncode_getActualTraits,
+ tifEncode_getActualBufSizes,
+ tifEncode_convert,
+ tifEncode_newPage,
+ tifEncode_insertedData,
+ tifEncode_closeXform
+};
+
+
+
+
+/*****************************************************************************\
+ *****************************************************************************
+ *
+ * D E C O D E R
+ *
+ *****************************************************************************
+\*****************************************************************************/
+
+
+
+
+/*****************************************************************************\
+ *
+ * tifDecode_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD tifDecode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PTIF_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(TIF_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(TIF_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifDecode_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD tifDecode_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PTIF_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->traits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifDecode_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD tifDecode_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PTIF_INST g;
+ char *s;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* file-path is not used, but might be later, so save it */
+ s = (char*)aXformInfo[IP_TIFF_FILE_PATH].pvoid;
+ if (s != NULL)
+ strcpy (g->sFilePath, s);
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifDecode_getHeaderBufSize - Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD tifDecode_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ *pdwInBufLen = MAX_HEADER_SIZE + 10000; /* 10000 gives us huge margin */
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ByteSwap - Reverses endian-type of the given variable (1, 2, 4 or 8 bytes)
+ *
+\*****************************************************************************/
+
+static void ByteSwap (
+ void *pvVar,
+ int nBytes)
+{
+ BYTE b;
+ BYTE *pb = (BYTE*)pvVar;
+
+ switch (nBytes) {
+ case 1:
+ /* do nothing */
+ break;
+ case 2:
+ b = pb[0]; pb[0] = pb[1]; pb[1] = b;
+ break;
+ case 4:
+ b = pb[1]; pb[1] = pb[2]; pb[2] = b;
+ b = pb[0]; pb[0] = pb[3]; pb[3] = b;
+ break;
+ case 8:
+ /* this is actually two longs, so fix each one */
+ ByteSwap (pvVar, 4);
+ ByteSwap ((BYTE*)pvVar+4, 4);
+ break;
+ }
+}
+
+
+
+/*****************************************************************************\
+ *
+ * ParseTag - Parses a tag, putting value in traits or dwImageOffset
+ *
+\*****************************************************************************/
+
+static BOOL ParseTag (
+ PTIF_INST g, /* in: our instance variables */
+ TIFFTAG *pTag, /* in: the tag to parse */
+ BYTE *pbInputBuf, /* in: input buffer containing TIFF header */
+ BYTE *pbBufAfter, /* in: 1st byte after the input buffer */
+ DWORD *pdwImageOffset) /* out: image start offset set by STRIP_OFFSETS */
+{
+ unsigned id;
+ unsigned kind;
+ unsigned count;
+ void *pValue;
+ int value;
+ int nTypeBytes, nValueBytes;
+ int i;
+
+ if (g->bByteSwap) {
+ ByteSwap (&(pTag->TagID ), 2);
+ ByteSwap (&(pTag->Kind ), 2);
+ ByteSwap (&(pTag->Length), 4);
+ }
+
+ id = pTag->TagID;
+ kind = pTag->Kind;
+ count = pTag->Length;
+
+ switch (kind) {
+ case TIFFUNDEFINED: nTypeBytes = 1; break;
+ case TIFFBYTE: nTypeBytes = 1; break;
+ case TIFFSBYTE: nTypeBytes = 1; break;
+ case TIFFSHORT: nTypeBytes = 2; break;
+ case TIFFSSHORT: nTypeBytes = 2; break;
+ case TIFFLONG: nTypeBytes = 4; break;
+ case TIFFSLONG: nTypeBytes = 4; break;
+ case TIFFRATIONAL: nTypeBytes = 8; break;
+ case TIFFSRATIONAL: nTypeBytes = 8; break;
+ default: INSURE(0);
+ }
+
+ nValueBytes = count * nTypeBytes;
+
+ if (nValueBytes <= 4)
+ pValue = &(pTag->Value.l);
+ else {
+ if (g->bByteSwap)
+ ByteSwap (&(pTag->Value.l), 4);
+ pValue = pbInputBuf + pTag->Value.l;
+ }
+ INSURE ((BYTE*)pValue>pbInputBuf && (BYTE*)pValue<pbBufAfter);
+
+ if (g->bByteSwap) {
+ for (i=0; i<(int)count; i++)
+ ByteSwap ((BYTE*)pValue + i*nTypeBytes, nTypeBytes);
+ }
+
+ switch (kind) {
+ case TIFFUNDEFINED: value = *(TIFF_UBYTE *)pValue; break;
+ case TIFFBYTE: value = *(TIFF_UBYTE *)pValue; break;
+ case TIFFSBYTE: value = *(TIFF_SBYTE *)pValue; break;
+ case TIFFSHORT: value = *(TIFF_USHORT*)pValue; break;
+ case TIFFSSHORT: value = *(TIFF_SSHORT*)pValue; break;
+ case TIFFLONG: value = *(TIFF_ULONG *)pValue; break;
+ case TIFFSLONG: value = *(TIFF_SLONG *)pValue; break;
+ case TIFFRATIONAL: value = ((RATIONAL*)pValue)->n / ((RATIONAL*)pValue)->d; break;
+ case TIFFSRATIONAL: value = ((RATIONAL*)pValue)->n / ((RATIONAL*)pValue)->d; break;
+ default: INSURE(0);
+ }
+
+ switch (id) {
+ case NEW_SUBFILE:
+ /* do nothing */
+ break;
+ case IMAGE_WIDTH:
+ g->traits.iPixelsPerRow = value;
+ break;
+ case IMAGE_LENGTH:
+ g->traits.lNumRows = value;
+ break;
+ case BITS_PER_SAMPLE:
+ g->iBitsPerSample = value;
+ break;
+ case COMPRESSION:
+ INSURE (value == 1); /* we only support uncompressed */
+ break;
+ case PHOTO_INTERPRET:
+ /* do nothing */
+ break;
+ case STRIP_OFFSETS:
+ INSURE (count == 1); /* we only support one strip */
+ *pdwImageOffset = value;
+ break;
+ case SAMPLES_PER_PIXEL:
+ g->traits.iComponentsPerPixel = value;
+ break;
+ case ROWS_PER_STRIP:
+ /* do nothing -- we assume entire image is in one strip */
+ break;
+ case STRIP_COUNTS:
+ /* do nothing -- this should be the # bytes in the raw data */
+ break;
+ case XRESOLUTION:
+ g->traits.lHorizDPI = value << 16;
+ break;
+ case YRESOLUTION:
+ g->traits.lVertDPI = value << 16;
+ break;
+ case RESOLUTION_UNIT:
+ /* do nothing -- if it's not DPI, then reported DPI will be wrong */
+ break;
+ default:
+ /* ignore the unknown tag */
+ break;
+ }
+
+ return TRUE;
+
+ fatal_error:
+ return FALSE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifDecode_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD tifDecode_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PTIF_INST g;
+ DWORD dwImageOffset;
+ PBYTE pb;
+ TIFFHEADER *pHead;
+ TIFFIFD *pIFD;
+ int iTag, nTags;
+
+ HANDLE_TO_PTR (hXform, g);
+ pb = pbInputBuf;
+
+ /**** Parse the file-header ****/
+
+ pHead = (TIFFHEADER*)pb;
+ INSURE (pHead->ByteOrder[0]=='I' || pHead->ByteOrder[0]=='M');
+ INSURE (pHead->ByteOrder[1]=='I' || pHead->ByteOrder[1]=='M');
+ g->bByteSwap = pHead->ByteOrder[0] == 'M';
+ if (g->bByteSwap)
+ ByteSwap (&(pHead->OffsetFirstIFD), 4);
+ INSURE (pHead->OffsetFirstIFD < dwInputAvail);
+ /* ignore the file-version */
+ pb = pbInputBuf + pHead->OffsetFirstIFD;
+
+ /**** Parse the IFD (i.e., the tags), setting traits ****/
+
+ pIFD = (TIFFIFD*)pb;
+ if (g->bByteSwap)
+ ByteSwap (&(pIFD->NumTags), 2);
+ nTags = pIFD->NumTags;
+ INSURE (nTags>0 && nTags<100); /* sanity check */
+ INSURE (nTags*sizeof(TIFFTAG) < dwInputAvail);
+ dwImageOffset = 0;
+
+ for (iTag=0; iTag<nTags; iTag++) {
+ if (! ParseTag (g, pIFD->Tag+iTag, pbInputBuf, pbInputBuf+dwInputAvail, &dwImageOffset))
+ goto fatal_error;
+ }
+
+ INSURE (g->iBitsPerSample==1 || g->iBitsPerSample==8 || g->iBitsPerSample==16);
+ g->traits.iBitsPerPixel = g->iBitsPerSample * g->traits.iComponentsPerPixel;
+ INSURE (dwImageOffset <= dwInputAvail);
+ g->dwRawRowBytes = (g->traits.iBitsPerPixel*g->traits.iPixelsPerRow + 7) / 8;
+
+ /**** Finish up ****/
+
+ g->dwInNextPos = dwImageOffset;
+ *pdwInputUsed = dwImageOffset;
+ *pdwInputNextPos = dwImageOffset;
+
+ *pInTraits = g->traits;
+ *pOutTraits = g->traits;
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * tifDecode_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD tifDecode_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PTIF_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = g->dwRawRowBytes;
+ *pdwMinOutBufLen = g->dwRawRowBytes;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifDecode_convert - the work-horse routine
+ *
+\*****************************************************************************/
+
+static WORD tifDecode_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PTIF_INST g;
+ UINT n;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("tif_decode_convert_row: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ n = g->dwRawRowBytes;
+
+ if (dwInputAvail < n) {
+ /* we got a partial row at the end -- just toss it */
+ g->dwInNextPos += dwInputAvail;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwInputUsed = dwInputAvail;
+ *pdwOutputUsed = 0;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_READY_FOR_DATA;
+ }
+
+ INSURE (dwOutputAvail >= n);
+ memcpy (pbOutputBuf, pbInputBuf, n);
+
+ if (g->bByteSwap && g->iBitsPerSample==16) {
+ /* we need to swap bytes in the 16-bit words in the pixels */
+ BYTE *pb, *pbAfter, b;
+ pbAfter = pbInputBuf + n;
+ for (pb=pbInputBuf; pb<pbAfter; pb+=4) {
+ /* process two words at a time for speed */
+ b = pb[0]; pb[0] = pb[1]; pb[1] = b;
+ b = pb[2]; pb[2] = pb[3]; pb[3] = b;
+ }
+ }
+
+ *pdwOutputUsed = n;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += n;
+
+ g->dwInNextPos += n;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwInputUsed = n;
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifDecode_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD tifDecode_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifDecode_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD tifDecode_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PTIF_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifDecode_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD tifDecode_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PTIF_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ if (g->fileOut != NULL)
+ fclose (g->fileOut);
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tifDecodeTbl - Jump-table for decoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL tifDecodeTbl = {
+ tifDecode_openXform,
+ tifDecode_setDefaultInputTraits,
+ tifDecode_setXformSpec,
+ tifDecode_getHeaderBufSize,
+ tifDecode_getActualTraits,
+ tifDecode_getActualBufSizes,
+ tifDecode_convert,
+ tifDecode_newPage,
+ tifDecode_insertedData,
+ tifDecode_closeXform
+};
+
+/* End of File */
diff --git a/ip/xtonemap.c b/ip/xtonemap.c
new file mode 100644
index 0000000..a92080a
--- /dev/null
+++ b/ip/xtonemap.c
@@ -0,0 +1,496 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xtonemap.c - Performs a 256-byte tonemap to grayscale or color data
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * tonemapTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_TONEMAP_POINTER] = pointer to the 256-byte tonemap.
+ * aXformInfo[IP_TONEMAP_LUM_SPACE] = Is color-space luminance-based?
+ * 0: color space is RGB
+ * 1: color space has luminance as first byte (eg, YCC)
+ *
+ * The tonemap is indexed by luminance (0..255), and returns the new
+ * luminance. For color data, the luminance is computed based on r-g-b,
+ * and these are updated based on th new luminance.
+ *
+ * An internal copy is made of the tonemap.
+ *
+ * Capabilities and Limitations:
+ *
+ * The incoming data can be 8-bit gray or 24-bit color or 48-bit color.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * passed into output same as default input
+ * iComponentsPerPixel passed into output same as default input
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Jan 2000 Mark Overton -- wrote original code
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x4ba1dace
+
+
+typedef struct {
+ IP_IMAGE_TRAITS traits; /* traits of the input and output image */
+ BOOL bLumSpace; /* luminance-based color space? (else RGB) */
+ BYTE tonemap[256]; /* the tonemap */
+ DWORD dwBytesPerRow; /* # of bytes in each row */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} TMAP_INST, *PTMAP_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * tonemap_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD tonemap_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PTMAP_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(TMAP_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(TMAP_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tonemap_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD tonemap_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PTMAP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* insure that traits we care about are known */
+ INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>1);
+ g->traits = *pTraits; /* a structure copy */
+ g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tonemap_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD tonemap_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PTMAP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ memcpy (g->tonemap, aXformInfo[IP_TONEMAP_POINTER].pvoid, 256);
+ g->bLumSpace = aXformInfo[IP_TONEMAP_LUM_SPACE].dword;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tonemap_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD tonemap_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tonemap_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD tonemap_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PTMAP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pIntraits = g->traits; /* structure copies */
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * tonemap_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD tonemap_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PTMAP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tonemap_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD tonemap_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PTMAP_INST g;
+ int nBytes;
+ PBYTE pIn, pOut, pOutAfter;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("tonemap_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ nBytes = g->dwBytesPerRow;
+ INSURE (dwInputAvail >= (DWORD)nBytes );
+ INSURE (dwOutputAvail >= (DWORD)nBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pOutAfter = pOut + nBytes;
+
+ if (g->traits.iBitsPerPixel == 8) {
+ /* easiest case */
+ while (pOut < pOutAfter) {
+ *pOut++ = g->tonemap[*pIn++];
+ }
+ } else if (g->traits.iBitsPerPixel == 24) {
+ if (g->bLumSpace) {
+ /* easy case: 24-bit color in a luminance space */
+ while (pOut < pOutAfter) {
+ *pOut = g->tonemap[*pIn];
+ pIn += 3;
+ pOut += 3;
+ }
+ } else {
+ /* 24-bit color in RGB */
+ int rv, gv, bv;
+ int l_old, l_new, dl;
+
+ while (pOut < pOutAfter) {
+ rv = *pIn++;
+ gv = *pIn++;
+ bv = *pIn++;
+
+ l_old = NTSC_LUMINANCE (rv, gv, bv);
+ l_new = g->tonemap[l_old]; /* new luminance */
+ dl = l_new - l_old;
+ rv += dl;
+ gv += dl;
+ bv += dl;
+
+ if (rv > 255) rv = 255; else if (rv < 0) rv = 0;
+ if (gv > 255) gv = 255; else if (gv < 0) gv = 0;
+ if (bv > 255) bv = 255; else if (bv < 0) bv = 0;
+
+ *pOut++ = (BYTE)rv;
+ *pOut++ = (BYTE)gv;
+ *pOut++ = (BYTE)bv;
+ }
+ }
+ } else { /* 48 bits/pixel */
+ PWORD src = (PWORD)pIn;
+ PWORD dst = (PWORD)pOut;
+ PWORD dstAfter = (PWORD)pOutAfter;
+
+ int rv, gv, bv;
+ int l_old, l_old8, l_new1, l_new2, l_new, dl;
+
+ while (dst < dstAfter) {
+ rv = *src++;
+ gv = *src++;
+ bv = *src++;
+
+ /* use linear interpolation between tonemap entries
+ * to compute new luminance (l_new) */
+ l_old = g->bLumSpace ? rv : NTSC_LUMINANCE (rv, gv, bv);
+ l_old8 = l_old >> 8;
+ l_new1 = g->tonemap[l_old8];
+ l_new2 = l_old8<255 ? g->tonemap[l_old8+1] : l_new1;
+ l_new = (l_new2-l_new1)*(l_old&0x00ff) + (l_new1<<8);
+
+ dl = l_new - l_old;
+ rv += dl;
+ if (rv > 65535) rv = 65535; else if (rv < 0) rv = 0;
+
+ if (! g->bLumSpace) {
+ gv += dl;
+ bv += dl;
+ if (gv > 65535) gv = 65535; else if (gv < 0) gv = 0;
+ if (bv > 65535) bv = 65535; else if (bv < 0) bv = 0;
+ }
+
+ *dst++ = (WORD)rv;
+ *dst++ = (WORD)gv;
+ *dst++ = (WORD)bv;
+ }
+ }
+
+ *pdwInputUsed = nBytes;
+ g->dwInNextPos += nBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = nBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += nBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tonemap_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD tonemap_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tonemap_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD tonemap_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PTMAP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tonemap_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD tonemap_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PTMAP_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * tonemapTbl - Jump-table for transform driver
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL tonemapTbl = {
+ tonemap_openXform,
+ tonemap_setDefaultInputTraits,
+ tonemap_setXformSpec,
+ tonemap_getHeaderBufSize,
+ tonemap_getActualTraits,
+ tonemap_getActualBufSizes,
+ tonemap_convert,
+ tonemap_newPage,
+ tonemap_insertedData,
+ tonemap_closeXform
+};
+
+/* End of File */
diff --git a/ip/xyxtract.c b/ip/xyxtract.c
new file mode 100644
index 0000000..b5156e4
--- /dev/null
+++ b/ip/xyxtract.c
@@ -0,0 +1,451 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, 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 than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/******************************************************************************\
+ *
+ * xyxtract.c - Y-extract - Extracts Y-component from YCC color data
+ *
+ ******************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * yXtractTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * xXformInfo[IP_Y_EXTRACT_COLOR_SPACE] tells us something about the color-space
+ * of input data: See the enum IP_Y_EXTRACT_WHICH_SPACE:
+ * IP_Y_EXTRACT_LUM_CHROME = luminance-chrominance, we merely fetch 1st component,
+ * IP_Y_EXTRACT_RGB = input is RGB,
+ * IP_Y_EXTRACT_BGR = input is BGR.
+ *
+ * Capabilities and Limitations:
+ *
+ * Inputs rows of 24-bit color data, and outputs rows of 8-bit gray
+ * consisting of the first component of the color data.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * trait default input output
+ * ------------------- --------------------- ------------------------
+ * iPixelsPerRow * passed into output same as default input
+ * iBitsPerPixel * must be 24 8
+ * iComponentsPerPixel * must be 3 1
+ * lHorizDPI passed into output same as default input
+ * lVertDPI passed into output same as default input
+ * lNumRows passed into output same as default input
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Above, a "*" by an item indicates it must be valid (not negative).
+ *
+ * Jan 1998 Mark Overton -- wrote code
+ *
+\******************************************************************************/
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "string.h" /* for memset and memcpy */
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stderr, msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+#define CHECK_VALUE 0x1ce5ca7e
+
+typedef struct {
+ IP_IMAGE_TRAITS inTraits; /* traits of the input image */
+ IP_Y_EXTRACT_WHICH_SPACE eInputType; /* type of input data */
+ DWORD dwRowsDone; /* number of rows converted so far */
+ DWORD dwInNextPos; /* file pos for subsequent input */
+ DWORD dwOutNextPos; /* file pos for subsequent output */
+ DWORD dwValidChk; /* struct validity check value */
+} YEX_INST, *PYEX_INST;
+
+
+
+/*****************************************************************************\
+ *
+ * yXtract_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD yXtract_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PYEX_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(YEX_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(YEX_INST));
+ g->dwValidChk = CHECK_VALUE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * yXtract_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD yXtract_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PYEX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Insure that values we care about are correct */
+ INSURE (pTraits->iBitsPerPixel == 24);
+ INSURE (pTraits->iComponentsPerPixel == 3);
+ INSURE (pTraits->iPixelsPerRow > 0);
+
+ g->inTraits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * yXtract_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD yXtract_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PYEX_INST g;
+ HANDLE_TO_PTR (hXform, g);
+ g->eInputType = (IP_Y_EXTRACT_WHICH_SPACE)aXformInfo[IP_Y_EXTRACT_COLOR_SPACE].dword;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * yXtract_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD yXtract_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ /* since input is raw pixels, there is no header, so set it to zero */
+ *pdwInBufLen = 0;
+ return IP_DONE;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * yXtract_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD yXtract_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PYEX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /* Since there is no header, we'll report no usage of input */
+ *pdwInputUsed = 0;
+ *pdwInputNextPos = 0;
+
+ *pInTraits = g->inTraits;
+ *pOutTraits = g->inTraits;
+ pOutTraits->iBitsPerPixel = 8;
+ pOutTraits->iComponentsPerPixel = 1;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * yXtract_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD yXtract_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PYEX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = 3 * g->inTraits.iPixelsPerRow;
+ *pdwMinOutBufLen = g->inTraits.iPixelsPerRow;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * yXtract_convert - Converts one row
+ *
+\*****************************************************************************/
+
+static WORD yXtract_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PYEX_INST g;
+ int inBytes, outBytes;
+ PBYTE pIn, pOut, pOutAfter;
+ UINT red, grn, blu;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ /**** Check if we were told to flush ****/
+
+ if (pbInputBuf == NULL) {
+ PRINT (_T("yXtract_convert: Told to flush.\n"), 0, 0);
+ *pdwInputUsed = *pdwOutputUsed = 0;
+ *pdwInputNextPos = g->dwInNextPos;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ return IP_DONE;
+ }
+
+ /**** Output a Row ****/
+
+ outBytes = g->inTraits.iPixelsPerRow;
+ inBytes = 3 * outBytes;
+ INSURE (dwInputAvail >= (DWORD)inBytes );
+ INSURE (dwOutputAvail >= (DWORD)outBytes);
+
+ pIn = pbInputBuf;
+ pOut = pbOutputBuf;
+ pOutAfter = pOut + outBytes;
+
+ switch (g->eInputType) {
+ case IP_Y_EXTRACT_LUM_CHROME:
+ while (pOut < pOutAfter) {
+ *pOut++ = *pIn;
+ pIn += 3;
+ }
+ break;
+
+ case IP_Y_EXTRACT_RGB:
+ while (pOut < pOutAfter) {
+ red = (UINT)(*pIn++);
+ grn = (UINT)(*pIn++);
+ blu = (UINT)(*pIn++);
+ /* the formula below is: Y = (5*R + 9*G + 2*B) / 16 */
+ *pOut++ =
+ (BYTE)((((red<<2)+red) + ((grn<<3)+grn) + (blu<<1) + 8) >> 4);
+ }
+ break;
+
+ case IP_Y_EXTRACT_BGR:
+ while (pOut < pOutAfter) {
+ blu = (UINT)(*pIn++);
+ grn = (UINT)(*pIn++);
+ red = (UINT)(*pIn++);
+ /* the formula below is: Y = (5*R + 9*G + 2*B) / 16 */
+ *pOut++ =
+ (BYTE)((((red<<2)+red) + ((grn<<3)+grn) + (blu<<1) + 8) >> 4);
+ }
+ break;
+
+ default:
+ goto fatal_error;
+ }
+
+ *pdwInputUsed = inBytes;
+ g->dwInNextPos += inBytes;
+ *pdwInputNextPos = g->dwInNextPos;
+
+ *pdwOutputUsed = outBytes;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ g->dwOutNextPos += outBytes;
+
+ g->dwRowsDone += 1;
+
+ return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * yXtract_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD yXtract_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * yXtract_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD yXtract_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ PYEX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ /* todo: return fatal error if convert is called again? */
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+
+}
+
+
+
+/*****************************************************************************\
+ *
+ * yXtract_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD yXtract_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PYEX_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * yXtractTbl - Jump-table for encoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL yXtractTbl = {
+ yXtract_openXform,
+ yXtract_setDefaultInputTraits,
+ yXtract_setXformSpec,
+ yXtract_getHeaderBufSize,
+ yXtract_getActualTraits,
+ yXtract_getActualBufSizes,
+ yXtract_convert,
+ yXtract_newPage,
+ yXtract_insertedData,
+ yXtract_closeXform
+};
+
+/* End of File */