1 /* libhpojip -- HP OfficeJet image-processing library. */
3 /* Copyright (C) 1995-2002 Hewlett-Packard Company
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
13 * NON-INFRINGEMENT. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 * In addition, as a special exception, Hewlett-Packard Company
21 * gives permission to link the code of this program with any
22 * version of the OpenSSL library which is distributed under a
23 * license identical to that listed in the included LICENSE.OpenSSL
24 * file, and distribute linked combinations including the two.
25 * You must obey the GNU General Public License in all respects
26 * for all of the code used other than OpenSSL. If you modify
27 * this file, you may extend this exception to your version of the
28 * file, but you are not obligated to do so. If you do not wish to
29 * do so, delete this exception statement from your version.
32 /* Original author: Mark Overton and others.
34 * Ported to Linux by David Paschal.
37 /*****************************************************************************\
39 * ipmain.c - main control code and entry points for image processor
41 *****************************************************************************
43 * Mark Overton, Dec 1997
45 \*****************************************************************************/
47 #include <sys/types.h>
50 #include <string.h> /* for memcpy, memset, etc. */
63 #define PRINT0(args...) fprintf(stderr, args)
66 #define PRINT1(args...) fprintf(stderr, args)
68 #define PRINT1(args...)
72 #define INSURE(boolexp) \
73 do { if (0) goto fatal_error; assert(boolexp); } while(0)
79 #define PRINT0(args...)
80 #define PRINT1(args...)
85 /*****************************************************************************\
89 \*****************************************************************************/
92 #define CHECK_VALUE 0xACEC0DE4U /* for checking validity of instance struc */
93 #define MIN_GENBUF_LEN 4000 /* arbitrary, but higher boosts speed some */
94 #define PERMANENT_RESULTS \
95 (IP_INPUT_ERROR | IP_FATAL_ERROR | IP_DONE)
99 /*****************************************************************************\
103 \*****************************************************************************/
106 /* XFORM_STATE enum - all possible states of an xform */
109 XS_NONEXISTENT=0, /* xform is not yet instantiated */
110 XS_PARSING_HEADER, /* parsing header (always goes thru this state) */
111 XS_CONVERTING, /* inputting and outputting */
112 XS_CONV_NOT_RFD, /* only outputting; not ready for input */
113 XS_FLUSHING, /* outputting buffered stuff; no more input */
114 XS_DONE /* done and de-instantiated */
118 /* XFORM_INFO type - everything we know about an xform */
121 XFORM_STATE eState; /* state of this xform */
122 PIP_XFORM_TBL pXform; /* ptr to jmp-table for xform */
123 LPIP_PEEK_FUNC pfReadPeek; /* callback when xform dvr reads data */
124 LPIP_PEEK_FUNC pfWritePeek; /* callback when xform dvr writes data */
125 PVOID pUserData; /* Data passed to user in peek functions. */
126 DWORD_OR_PVOID aXformInfo[8]; /* xform-specific information */
127 IP_XFORM_HANDLE hXform; /* handle for the xform */
128 IP_IMAGE_TRAITS inTraits; /* traits of input data into xform */
129 IP_IMAGE_TRAITS outTraits; /* traits of output data from xform */
130 DWORD dwMinInBufLen; /* min # bytes in input buf */
131 DWORD dwMinOutBufLen; /* min # bytes in output buf */
132 } XFORM_INFO, *PXFORM_INFO;
135 /* GENBUF type - a general-purpose buffer which allows one to write or read
136 * varying amounts of data.
139 PBYTE pbBuf; /* ptr to beginning of buffer */
140 DWORD dwBufLen; /* size of entire buffer (# of bytes) */
141 DWORD dwValidStart; /* index of first valid data byte in buffer */
142 DWORD dwValidLen; /* number of valid data bytes in buffer */
143 DWORD dwFilePos; /* file-pos of start of valid data (starts at 0) */
147 /* INST type - all variables in an instance of the image processor */
151 /* genbufs are used for input into the first xform, and to store output
152 * from the last xform. The client's input data is first put into gbIn,
153 * which is then fed into the first xform. The last xform's output is put
154 * into gbOut, which is then copied out to the client's output buffer.
159 /* mid-buffers are simple buffers that handle fixed-length raster-rows
160 * passed between xforms in the xform-list. For an xform, there's an input
161 * and an output buffer. For the next xform, they swap roles, so the old
162 * output buffer becomes the new input buffer, and vice versa. When the
163 * roles are swapped, the two pointers below are swapped.
165 PBYTE pbMidInBuf; /* ptr to beginning of input mid-buf */
166 PBYTE pbMidOutBuf; /* ptr to beginning of output mid-buf */
167 DWORD dwMidLen; /* size of either buffer (# of bytes) */
168 DWORD dwMidValidLen; /* # of bytes of good data in input mid-buf */
169 int iOwner; /* index into xfArray of xform owning (using)
170 * the input mid-buf. negative means no owner
171 * and that pbMidInBuf is empty */
173 /* variables pertaining to the array of xforms */
175 XFORM_INFO xfArray[IP_MAX_XFORMS]; /* the array of xforms */
176 WORD xfCount; /* number of xforms */
180 DWORD dwValidChk; /* struct validity check value */
181 DWORD dwForcedHorizDPI; /* horiz DPI override as 16.16; 0=none */
182 DWORD dwForcedVertDPI; /* vert DPI override as 16.16; 0=none */
183 WORD wResultMask; /* desired ipConvert result bits */
184 long lInRows; /* number of rows we've input */
185 long lOutRows; /* number of rows we've output */
186 int iInPages; /* number of pages we've received */
187 int iOutPages; /* number of pages we've output */
188 BOOL pendingInsert; /* ret IP_WRITE_INSERT_OK after outbuf empty? */
194 /*****************************************************************************\
196 * xformJumpTables - Array of ptrs to all driver jump tables
198 * Warning: This array is indexed by the enum IP_XFORM. If one changes,
199 * the other must change too.
201 \*****************************************************************************/
203 extern IP_XFORM_TBL faxEncodeTbl, faxDecodeTbl;
204 extern IP_XFORM_TBL pcxEncodeTbl, pcxDecodeTbl;
205 /* extern IP_XFORM_TBL bmpEncodeTbl, bmpDecodeTbl; */
206 extern IP_XFORM_TBL jpgEncodeTbl, jpgDecodeTbl, jpgFixTbl;
207 extern IP_XFORM_TBL tifEncodeTbl, tifDecodeTbl;
208 extern IP_XFORM_TBL pnmEncodeTbl, pnmDecodeTbl;
209 extern IP_XFORM_TBL scaleTbl;
210 extern IP_XFORM_TBL gray2biTbl, bi2grayTbl;
211 extern IP_XFORM_TBL colorTbl;
212 extern IP_XFORM_TBL yXtractTbl;
213 /* extern IP_XFORM_TBL headerTbl; */
214 extern IP_XFORM_TBL thumbTbl;
215 extern IP_XFORM_TBL tableTbl;
216 extern IP_XFORM_TBL cropTbl;
217 extern IP_XFORM_TBL tonemapTbl;
218 extern IP_XFORM_TBL saturationTbl;
219 extern IP_XFORM_TBL rotateTbl;
220 extern IP_XFORM_TBL padTbl;
221 extern IP_XFORM_TBL fakeMonoTbl;
222 extern IP_XFORM_TBL grayOutTbl;
223 extern IP_XFORM_TBL changeBPPTbl;
224 extern IP_XFORM_TBL matrixTbl;
225 extern IP_XFORM_TBL convolveTbl;
226 extern IP_XFORM_TBL invertTbl;
227 extern IP_XFORM_TBL skelTbl;
229 static IP_XFORM_TBL * const xformJumpTables[] = {
230 &faxEncodeTbl, &faxDecodeTbl, /* MH, MR and MMR formats */
231 &pcxEncodeTbl, &pcxDecodeTbl,
232 /* &bmpEncodeTbl, &bmpDecodeTbl, */
233 &jpgEncodeTbl, &jpgDecodeTbl, &jpgFixTbl,
234 &tifEncodeTbl, &tifDecodeTbl,
235 &pnmEncodeTbl, &pnmDecodeTbl,
237 &gray2biTbl, &bi2grayTbl,
259 /*****************************************************************************\
261 * fatalBreakPoint - Called when INSURE fails, used for debugger breakpoint
263 \*****************************************************************************/
265 void fatalBreakPoint (void)
271 PRINT0 (_T("\nhit fatalBreakPoint!\n"));
276 /*****************************************************************************\
278 * deleteMidBufs - Frees the two mid-buffers, if they've been allocated
280 \*****************************************************************************/
282 static void deleteMidBufs (PINST g)
284 PRINT0 (_T("deleteMidBufs\n"));
286 if (g->pbMidInBuf != NULL)
287 IP_MEM_FREE (g->pbMidInBuf);
289 if (g->pbMidOutBuf != NULL)
290 IP_MEM_FREE (g->pbMidOutBuf);
292 g->pbMidInBuf = NULL;
293 g->pbMidOutBuf = NULL;
298 /*****************************************************************************\
300 * ipOpen - Opens a new conversion job
302 \*****************************************************************************/
304 EXPORT(WORD) ipOpen (
305 int nXforms, /* in: number of xforms in lpXforms below */
306 LPIP_XFORM_SPEC lpXforms, /* in: the xforms we should perform */
307 int nClientData, /* in: # bytes of additional client data */
308 PIP_HANDLE phJob) /* out: handle for conversion job */
316 char *ipIn = "/tmp/ipIn.dib";
319 PRINT0 (_T("ipOpen: nXforms=%d\n"), nXforms);
320 INSURE (nXforms>0 && lpXforms!=NULL && nClientData>=0 && phJob!=NULL);
323 for (i=0; i<nXforms; i++)
325 switch (lpXforms[i].eXform)
328 PRINT0("Fax_format=%d\n", lpXforms[i].aXformInfo[IP_FAX_FORMAT].dword);
329 ipIn = "/tmp/ipIn.pbm";
332 PRINT0("JPG_decode=%d\n", lpXforms[i].aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword);
333 ipIn = "/tmp/ipIn.jpg";
335 case X_CNV_COLOR_SPACE:
336 PRINT0("Color_space conversion=%d\n", lpXforms[i].aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword);
337 PRINT0("Color_space gamma=%d\n", lpXforms[i].aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword);
340 PRINT0("Crop_left=%d\n", lpXforms[i].aXformInfo[IP_CROP_LEFT].dword);
341 PRINT0("Crop_right=%d\n", lpXforms[i].aXformInfo[IP_CROP_RIGHT].dword);
342 PRINT0("Crop_top=%d\n", lpXforms[i].aXformInfo[IP_CROP_TOP].dword);
343 PRINT0("Crop_maxoutrows=%d\n", lpXforms[i].aXformInfo[IP_CROP_MAXOUTROWS].dword);
346 PRINT0("Pad_left=%d\n", lpXforms[i].aXformInfo[IP_PAD_LEFT].dword);
347 PRINT0("Pad_right=%d\n", lpXforms[i].aXformInfo[IP_PAD_RIGHT].dword);
348 PRINT0("Pad_top=%d\n", lpXforms[i].aXformInfo[IP_PAD_TOP].dword);
349 PRINT0("Pad_bottom=%d\n", lpXforms[i].aXformInfo[IP_PAD_BOTTOM].dword);
350 PRINT0("Pad_value=%d\n", lpXforms[i].aXformInfo[IP_PAD_VALUE].dword);
351 PRINT0("Pad_minheight=%d\n", lpXforms[i].aXformInfo[IP_PAD_MIN_HEIGHT].dword);
354 PRINT0("Unknown xform\n");
359 infd = creat(ipIn, 0600);
360 outfd = creat("/tmp/ipOut.ppm", 0600);
363 /**** Create Instance and Init Misc Variables ****/
365 IP_MEM_ALLOC (sizeof(INST) + nClientData, g);
368 memset (g, 0, sizeof(INST));
369 g->dwValidChk = CHECK_VALUE;
371 g->wResultMask = PERMANENT_RESULTS;
373 /**** Transfer the Xforms to xfArray ****/
375 g->xfCount = (WORD)nXforms;
377 for (i=0; i<nXforms; i++) {
378 src = &(lpXforms[i]);
379 dest = &(g->xfArray[i]);
381 dest->eState = XS_NONEXISTENT;
382 dest->pXform = (src->pXform != NULL)
384 : xformJumpTables[src->eXform];
385 INSURE (dest->pXform != NULL);
386 dest->pfReadPeek = src->pfReadPeek;
387 dest->pfWritePeek = src->pfWritePeek;
388 dest->pUserData = src->pUserData;
389 memcpy (dest->aXformInfo, src->aXformInfo, sizeof(dest->aXformInfo));
395 return IP_FATAL_ERROR;
400 /*****************************************************************************\
402 * ipClose - Destroys the given conversion job, deallocating all its memory
404 \*****************************************************************************/
406 EXPORT(WORD) ipClose (IP_HANDLE hJob)
412 PRINT0 (_T("ipClose: hJob=%p\n"), (void*)hJob);
413 HANDLE_TO_PTR (hJob, g);
415 /**** Delete All Buffers ****/
419 g->dwMidValidLen = 0;
421 if (g->gbIn.pbBuf != NULL) IP_MEM_FREE (g->gbIn.pbBuf);
422 if (g->gbOut.pbBuf != NULL) IP_MEM_FREE (g->gbOut.pbBuf);
424 /**** Delete All Xform Instances ****/
426 for (n=0; n<g->xfCount; n++) {
427 pXform = &(g->xfArray[n]);
428 if (pXform->hXform != NULL)
429 pXform->pXform->closeXform (pXform->hXform);
432 IP_MEM_FREE (g); /* Delete our instance, and we're done */
442 return IP_FATAL_ERROR;
447 /*****************************************************************************\
449 * ipGetClientDataPtr - Returns ptr to client's data in conversion instance
451 \*****************************************************************************/
453 EXPORT(WORD) ipGetClientDataPtr (
454 IP_HANDLE hJob, /* in: handle to conversion job */
455 PVOID *ppvClientData) /* out: ptr to client's memory area */
459 PRINT0 (_T("ipGetClientDataPtr\n"));
460 HANDLE_TO_PTR (hJob, g);
461 *ppvClientData = (PVOID)((PBYTE)g + sizeof(INST));
465 return IP_FATAL_ERROR;
470 /****************************************************************************\
472 * ipResultMask - Selects bit-results to be returned by ipConvert
474 \****************************************************************************/
476 EXPORT(WORD) ipResultMask (
477 IP_HANDLE hJob, /* in: handle to conversion job */
478 WORD wMask) /* in: result bits you are interested in */
482 PRINT0 (_T("ipResultMask: hJob=%p, wMask=%04x\n"), (void*)hJob, wMask);
483 HANDLE_TO_PTR (hJob, g);
484 g->wResultMask = wMask | PERMANENT_RESULTS;
488 return IP_FATAL_ERROR;
493 /*****************************************************************************\
495 * ipSetDefaultInputTraits - Specifies default input image traits
497 *****************************************************************************
499 * The header of the file-type handled by the first transform might not
500 * include *all* the image traits we'd like to know. Those not specified
501 * in the file-header are filled in from info provided by this routine.
503 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
505 \*****************************************************************************/
507 EXPORT(WORD) ipSetDefaultInputTraits (
508 IP_HANDLE hJob, /* in: handle to conversion job */
509 LPIP_IMAGE_TRAITS pTraits) /* in: default image traits */
514 PRINT0 (_T("ipSetDefaultInputTraits: hJob=%p PixelsPerRow=%d BitsPerPixel=%d ComponentsPerPixel=%d HorzDPI=%ld VertDPI=%ld Rows=%ld Pages=%d PageNum=%d\n"),
515 (void*)hJob, pTraits->iPixelsPerRow, pTraits->iBitsPerPixel, pTraits->iComponentsPerPixel, pTraits->lHorizDPI,
516 pTraits->lVertDPI, pTraits->lNumRows, pTraits->iNumPages, pTraits->iPageNum);
517 HANDLE_TO_PTR (hJob, g);
518 INSURE (g->xfArray[0].eState == XS_NONEXISTENT);
519 g->xfArray[0].inTraits = *pTraits; /* a structure copy */
521 /* Convert DPI from integer to 16.16 fixed-pt if necessary */
522 p = &(g->xfArray[0].inTraits);
523 if (p->lHorizDPI < 0x10000) p->lHorizDPI <<= 16;
524 if (p->lVertDPI < 0x10000) p->lVertDPI <<= 16;
529 return IP_FATAL_ERROR;
534 /*****************************************************************************\
536 * ipGetImageTraits - Returns traits of input and output images
538 *****************************************************************************
540 * After the conversion job is done, these traits will contain the actual
541 * number of rows input and output (ipConvert patches traits upon completion).
543 \*****************************************************************************/
545 EXPORT(WORD) ipGetImageTraits (
546 IP_HANDLE hJob, /* in: handle to conversion job */
547 LPIP_IMAGE_TRAITS pInputTraits, /* out: traits of input image */
548 LPIP_IMAGE_TRAITS pOutputTraits) /* out: traits of output image */
553 PRINT0 (_T("ipGetImageTraits: hJob=%p\n"), (void*)hJob);
554 HANDLE_TO_PTR (hJob, g);
555 INSURE (g->xfCount > 0);
556 pTail = &(g->xfArray[g->xfCount-1]);
558 if (pInputTraits != NULL) {
559 INSURE (g->xfArray[0].eState > XS_PARSING_HEADER);
560 *pInputTraits = g->xfArray[0].inTraits;
561 PRINT0 (_T("InputTraits: hJob=%p PixelsPerRow=%d BitsPerPixel=%d ComponentsPerPixel=%d HorzDPI=%ld VertDPI=%ld Rows=%ld Pages=%d PageNum=%d\n"),
562 (void*)hJob, pInputTraits->iPixelsPerRow, pInputTraits->iBitsPerPixel, pInputTraits->iComponentsPerPixel, pInputTraits->lHorizDPI,
563 pInputTraits->lVertDPI, pInputTraits->lNumRows, pInputTraits->iNumPages, pInputTraits->iPageNum);
566 if (pOutputTraits != NULL) {
567 INSURE (pTail->eState > XS_PARSING_HEADER);
568 *pOutputTraits = pTail->outTraits;
569 PRINT0 (_T("OutputTraits: hJob=%p PixelsPerRow=%d BitsPerPixel=%d ComponentsPerPixel=%d HorzDPI=%ld VertDPI=%ld Rows=%ld Pages=%d PageNum=%d\n"),
570 (void*)hJob, pOutputTraits->iPixelsPerRow, pOutputTraits->iBitsPerPixel, pOutputTraits->iComponentsPerPixel, pOutputTraits->lHorizDPI,
571 pOutputTraits->lVertDPI, pOutputTraits->lNumRows, pOutputTraits->iNumPages, pOutputTraits->iPageNum);
577 return IP_FATAL_ERROR;
582 /*****************************************************************************\
584 * ipInsertedData - Client inserted some bytes into our output stream
586 \*****************************************************************************/
588 EXPORT(WORD) ipInsertedData (
589 IP_HANDLE hJob, /* in: handle to conversion job */
590 DWORD dwNumBytes) /* in: # of bytes of additional data written */
595 PRINT0 (_T("ipInsertedData: hJob=%p, dwNumBytes=%d\n"), (void*)hJob, dwNumBytes);
596 HANDLE_TO_PTR (hJob, g);
597 INSURE (g->xfCount > 0);
598 pTail = &(g->xfArray[g->xfCount-1]);
599 INSURE (pTail->eState > XS_PARSING_HEADER);
600 INSURE (g->gbOut.dwValidLen == 0); /* output genbuf must be empty */
602 pTail->pXform->insertedData (pTail->hXform, dwNumBytes);
606 return IP_FATAL_ERROR;
611 /*****************************************************************************\
613 * ipOverrideDPI - Force a different DPI to be reported in the output
615 \*****************************************************************************/
617 EXPORT(WORD) ipOverrideDPI (
618 IP_HANDLE hJob, /* in: handle to conversion job */
619 DWORD dwHorizDPI, /* in: horiz DPI as 16.16; 0 means no override */
620 DWORD dwVertDPI) /* in: vert DPI as 16.16; 0 means no override */
624 PRINT0 (_T("ipOverrideDPI: dwHorizDPI=%x, dwVertDPI=%x\n"),
625 dwHorizDPI, dwVertDPI);
626 HANDLE_TO_PTR (hJob, g);
628 /* Convert from integer to fixed-pt if necessary */
629 if (dwHorizDPI < 0x10000) dwHorizDPI <<= 16;
630 if (dwVertDPI < 0x10000) dwVertDPI <<= 16;
632 g->dwForcedHorizDPI = dwHorizDPI;
633 g->dwForcedVertDPI = dwVertDPI;
637 return IP_FATAL_ERROR;
642 /*****************************************************************************\
644 * ipGetFuncPtrs - Loads jump-table with pointers to the ip entry points
646 \*****************************************************************************/
648 EXPORT(WORD) ipGetFuncPtrs (LPIP_JUMP_TBL lpJumpTbl)
650 PRINT0 (_T("ipGetFuncPtrs\n"));
651 INSURE (lpJumpTbl!=NULL && lpJumpTbl->wStructSize==sizeof(IP_JUMP_TBL));
653 lpJumpTbl->ipOpen = (LPVOID) ipOpen;
654 lpJumpTbl->ipConvert = (LPVOID) ipConvert;
655 lpJumpTbl->ipClose = (LPVOID) ipClose;
656 lpJumpTbl->ipGetClientDataPtr = (LPVOID) ipGetClientDataPtr;
657 lpJumpTbl->ipResultMask = (LPVOID) ipResultMask;
658 lpJumpTbl->ipSetDefaultInputTraits = (LPVOID) ipSetDefaultInputTraits;
659 lpJumpTbl->ipGetImageTraits = (LPVOID) ipGetImageTraits;
660 lpJumpTbl->ipInsertedData = (LPVOID) ipInsertedData;
661 lpJumpTbl->ipOverrideDPI = (LPVOID) ipOverrideDPI;
662 lpJumpTbl->ipGetOutputTraits = (LPVOID) ipGetOutputTraits;
667 return IP_FATAL_ERROR;
672 /*****************************************************************************\
674 * ipGetOutputTraits - Returns the output traits before ipConvert is called
676 *****************************************************************************
678 * If the first xform does not have a header, then you can call this function
679 * *after* calling ipSetDefaultInputTraits to get the output image traits.
680 * Ordinarily, you'd have to call ipConvert a few times and wait until it tells
681 * you that the (non-existent) header has been parsed. But if you need the
682 * output traits before calling ipConvert, this function will return them.
684 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
686 \*****************************************************************************/
688 EXPORT(WORD) ipGetOutputTraits (
689 IP_HANDLE hJob, /* in: handle to conversion job */
690 LPIP_IMAGE_TRAITS pTraits) /* out: output image traits */
693 IP_IMAGE_TRAITS inTraits, outTraits;
698 DWORD dwInUsed, dwInNextPos;
700 HANDLE_TO_PTR (hJob, g);
701 INSURE (g->xfCount>=1);
702 inTraits = g->xfArray[0].inTraits; /* set by SetDefaultInputTraits */
704 for (iXform=0; iXform<g->xfCount; iXform++) {
705 pXform = &(g->xfArray[iXform]);
706 INSURE (pXform->eState == XS_NONEXISTENT);
708 /* Open the xform, set it up, get the traits, and close it */
710 result = pXform->pXform->openXform (&pXform->hXform);
711 INSURE (result == IP_DONE);
713 result = pXform->pXform->setDefaultInputTraits (
714 pXform->hXform, &inTraits);
715 INSURE (result == IP_DONE);
717 result = pXform->pXform->setXformSpec (
718 pXform->hXform, pXform->aXformInfo);
719 INSURE (result == IP_DONE);
721 result = pXform->pXform->getHeaderBufSize (
722 pXform->hXform, &dwHeaderLen);
723 INSURE (result == IP_DONE);
724 INSURE (dwHeaderLen == 0);
726 result = pXform->pXform->getActualTraits (
728 0, NULL, &dwInUsed, &dwInNextPos,
729 &inTraits, &outTraits);
730 INSURE (result & IP_DONE);
732 result = pXform->pXform->closeXform (pXform->hXform);
733 INSURE (result == IP_DONE);
735 inTraits = outTraits;
736 pXform->hXform = NULL;
739 *pTraits = outTraits;
743 return IP_FATAL_ERROR;
748 /*****************************************************************************\
750 * ipConvert - Converts some input data (work-horse function)
752 \*****************************************************************************/
754 EXPORT(WORD) ipConvert (
755 IP_HANDLE hJob, /* in: handle to conversion job */
756 DWORD dwInputAvail, /* in: # avail bytes in input buf */
757 PBYTE pbInputBuf, /* in: ptr to input buffer */
758 PDWORD pdwInputUsed, /* out: # bytes used from input buf */
759 PDWORD pdwInputNextPos, /* out: file-pos to read from next */
760 DWORD dwOutputAvail, /* in: # avail bytes in output buf */
761 PBYTE pbOutputBuf, /* in: ptr to output buffer */
762 PDWORD pdwOutputUsed, /* out: # bytes written in out buf */
763 PDWORD pdwOutputThisPos) /* out: file-pos to write this data */
769 PGENBUF pgbIn, pgbOut;
770 BOOL atTheHead, atTheTail;
771 PXFORM_INFO pXform, pPriorXform, pNextXform;
772 BOOL needInput, selectCnvState;
776 DWORD dwInUsed, dwOutUsed;
777 DWORD dwInNextPos, dwOutThisPos;
778 DWORD dwTheInLen, dwTheOutLen;
780 PBYTE pbTheInBuf, pbTheOutBuf;
783 if (pbOutputBuf == NULL) {
784 /* client wants us to discard all data */
785 pdwOutputUsed = &dwJunk;
786 pdwOutputThisPos = &dwJunk;
787 dwOutputAvail = 0xfffffffu;
790 PRINT0 (_T("ipConvert: hJob=%p, pbInputBuf=%p InputBufSize=%d pbOutputBuf=%p OutputBufSize=%d\n"),
791 (void*)hJob, pbInputBuf, dwInputAvail, pbOutputBuf, dwOutputAvail);
792 INSURE (pdwInputUsed !=NULL && pdwInputNextPos !=NULL &&
793 pdwOutputUsed!=NULL && pdwOutputThisPos!=NULL);
794 HANDLE_TO_PTR (hJob, g);
795 INSURE (g->xfCount>=1);
804 /**************************/
805 /* Beginning of Main Loop */
806 /**************************/
810 /**** Output any data in the output genbuf ****/
812 if (*pdwOutputUsed == 0)
813 *pdwOutputThisPos = pgbOut->dwFilePos;
815 if (pgbOut->dwValidLen != 0) { /* output genbuf is not empty */
818 * 1. If next output file-pos doesn't match output genbuf, exit loop.
820 * 2. Copy as much as possible from output genbuf to clients output buf.
821 * 2.1 decide number of bytes to copy
823 * 2.3 update misc variables
825 * 3. If output genbuf is not empty, exit loop (client's buf is full),
826 * else set wValidStart to 0 because output genbuf is empty.
829 if ((*pdwOutputThisPos+*pdwOutputUsed) != pgbOut->dwFilePos) {
830 PRINT0 (_T("ipConvert: output seek to %d\n"), pgbOut->dwFilePos);
834 dwBytes = pgbOut->dwValidLen;
835 if (dwOutputAvail < dwBytes)
836 dwBytes = dwOutputAvail;
838 if (pbOutputBuf != NULL) {
839 memcpy (pbOutputBuf + *pdwOutputUsed,
840 pgbOut->pbBuf + pgbOut->dwValidStart,
844 *pdwOutputUsed += dwBytes;
845 dwOutputAvail -= dwBytes;
846 pgbOut->dwValidStart += dwBytes;
847 pgbOut->dwFilePos += dwBytes;
848 pgbOut->dwValidLen -= dwBytes;
850 if (pgbOut->dwValidLen != 0)
853 pgbOut->dwValidStart = 0; /* output genbuf is now empty */
856 if (g->pendingInsert) {
857 g->pendingInsert = FALSE;
858 ipResult |= IP_WRITE_INSERT_OK;
861 /**** If ipResult has any returnable bits set, exit loop now ****/
863 if (ipResult & g->wResultMask)
866 /**** Select an xform to run ****/
868 /* select the owner of input midbuf, or negative means 'none selected' */
872 for (i=g->xfCount-1; i>=0; i--) {
873 if (g->xfArray[i].eState == XS_CONV_NOT_RFD) {
874 /* select last xform that's convnotrfd; this xform
875 * is outputting (or thinking) but not inputting */
883 for (i=0; i<g->xfCount; i++) {
884 if (g->xfArray[i].eState != XS_DONE) {
885 /* select first xform that's not done */
893 /* all xforms are done: discard all input, and report that we're done */
894 *pdwInputUsed = dwInputAvail;
896 /* patch the last outtraits with actual # of rows output, so that
897 * ipGetImageTraits will return actual row-count after we're done */
898 g->xfArray[g->xfCount-1].outTraits.lNumRows = g->lOutRows;
899 /* patch first intraits for the same reason */
900 g->xfArray[0].inTraits.lNumRows = g->lInRows;
904 /**** Miscellaneous preparation ****/
906 pXform = &(g->xfArray[iXform]);
907 atTheHead = (iXform == 0);
908 atTheTail = (iXform == g->xfCount-1);
909 pPriorXform = atTheHead ? NULL : &(g->xfArray[iXform-1]);
910 pNextXform = atTheTail ? NULL : &(g->xfArray[iXform+1]);
912 /**** Create the Xform if necessary ****/
914 if (pXform->eState == XS_NONEXISTENT) {
915 PRINT0 (_T("ipConvert: creating xform %d\n"), iXform);
916 INSURE (atTheHead || pPriorXform->eState>=XS_CONVERTING);
919 /* this xform's input traits were set by ipSetDefaultInputTraits */
921 /* this xform's input traits are prior xform's output traits */
922 memcpy (&pXform->inTraits, &pPriorXform->outTraits,
923 sizeof(IP_IMAGE_TRAITS));
926 /* apply any DPI overrides */
927 if (g->dwForcedHorizDPI != 0)
928 pXform->inTraits.lHorizDPI = (long)g->dwForcedHorizDPI;
929 if (g->dwForcedVertDPI != 0)
930 pXform->inTraits.lVertDPI = (long)g->dwForcedVertDPI;
934 result = pXform->pXform->openXform (&pXform->hXform);
935 INSURE (result == IP_DONE);
936 result = pXform->pXform->setDefaultInputTraits (
937 pXform->hXform, &pXform->inTraits);
938 INSURE (result == IP_DONE);
939 result = pXform->pXform->setXformSpec (
940 pXform->hXform, pXform->aXformInfo);
941 INSURE (result == IP_DONE);
942 result = pXform->pXform->getHeaderBufSize (
943 pXform->hXform, &pXform->dwMinInBufLen);
944 INSURE (result == IP_DONE);
947 /* a header is only allowed on first xform */
948 INSURE (pXform->dwMinInBufLen == 0);
950 /* allocate the input genbuf */
951 if (pXform->dwMinInBufLen == 0)
952 pXform->dwMinInBufLen = 1;
953 PRINT0 (_T("ipConvert: alloc input genbuf, len=%d\n"),
954 pXform->dwMinInBufLen);
955 IP_MEM_ALLOC (pXform->dwMinInBufLen, pgbIn->pbBuf);
956 pgbIn->dwBufLen = pXform->dwMinInBufLen;
957 pgbIn->dwValidStart = 0;
958 pgbIn->dwValidLen = 0;
959 pgbIn->dwFilePos = 0;
962 pXform->eState = XS_PARSING_HEADER;
965 /**** Enter flushing state if appropriate ****/
967 if (pXform->eState == XS_CONVERTING &&
968 (( atTheHead && pbInputBuf==NULL && pgbIn->dwValidLen==0) ||
969 (!atTheHead && pPriorXform->eState==XS_DONE && g->iOwner<0))) {
970 /* there will never be any more input to this xform: start flushing */
971 PRINT0 (_T("ipConvert: xform %d is now flushing\n"), iXform);
972 pXform->eState = XS_FLUSHING;
975 /**** Check that input data and output space are available ****/
977 needInput = (pXform->eState==XS_PARSING_HEADER ||
978 pXform->eState==XS_CONVERTING);
982 /* the input midbuf must contain data */
983 INSURE (g->iOwner>=0 && g->dwMidValidLen>0);
984 PRINT1 (_T("not at head, pixels = %08x\n"), *(DWORD*)(g->pbMidInBuf));
985 } else if (pbInputBuf != NULL) {
988 /* left-justify data in input genbuf if necessary */
990 if (pgbIn->dwBufLen-pgbIn->dwValidStart < pXform->dwMinInBufLen) {
991 /* too much wasted space on left end, so left justify */
992 memmove (pgbIn->pbBuf, pgbIn->pbBuf + pgbIn->dwValidStart,
994 pgbIn->dwValidStart = 0;
995 PRINT1 (_T("left just, pixels = %08x\n"), *(DWORD*)(pgbIn->pbBuf));
998 /* put as much client input as possible into the input genbuf */
1000 dwUnusedStart = pgbIn->dwValidStart + pgbIn->dwValidLen;
1001 dwBytes = pgbIn->dwBufLen - dwUnusedStart;
1002 if (dwBytes > dwInputAvail)
1003 dwBytes = dwInputAvail;
1005 memcpy (pgbIn->pbBuf + dwUnusedStart,
1006 pbInputBuf + *pdwInputUsed,
1009 pgbIn->dwValidLen += dwBytes;
1010 *pdwInputUsed += dwBytes;
1011 dwInputAvail -= dwBytes;
1012 *pdwInputNextPos += dwBytes;
1014 /* if input genbuf has insufficient data, exit loop */
1015 if (pgbIn->dwValidLen < pXform->dwMinInBufLen)
1017 PRINT1 (_T("at head, pixels = %08x\n"), *(DWORD*)(pgbIn->pbBuf));
1021 if (atTheTail && pXform->eState!=XS_PARSING_HEADER) {
1022 /* output might be produced; output genbuf must be empty */
1023 INSURE (pgbOut->dwValidLen == 0);
1026 /**** Call the Conversion Routine ****/
1028 pbTheInBuf = atTheHead ? pgbIn->pbBuf + pgbIn->dwValidStart : g->pbMidInBuf;
1029 dwTheInLen = atTheHead ? pgbIn->dwValidLen : g->dwMidValidLen;
1030 pbTheOutBuf = atTheTail ? pgbOut->pbBuf : g->pbMidOutBuf;
1031 dwTheOutLen = atTheTail ? pgbOut->dwBufLen : g->dwMidLen;
1033 if (pXform->eState == XS_PARSING_HEADER) {
1034 result = pXform->pXform->getActualTraits (
1036 dwTheInLen, pbTheInBuf, &dwInUsed, &dwInNextPos,
1038 &pXform->outTraits);
1042 if (pXform->eState == XS_FLUSHING)
1044 result = pXform->pXform->convert (
1046 dwTheInLen, pbTheInBuf, &dwInUsed, &dwInNextPos,
1047 dwTheOutLen, pbTheOutBuf, &dwOutUsed, &dwOutThisPos);
1050 PRINT1 (_T("ipConvert: xform %d returned %04x\n"), iXform, result);
1051 PRINT1 (_T("ipConvert: consumed %d and produced %d bytes\n"),
1052 dwInUsed, dwOutUsed);
1054 if (pbTheOutBuf != NULL)
1055 PRINT1 (_T("ipConvert: out data = %08x\n"), *(DWORD*)pbTheOutBuf);
1057 INSURE ((result & IP_FATAL_ERROR) == 0);
1059 /**** Update Input and Output Buffers ****/
1062 if (pXform->pfReadPeek != NULL) {
1066 pXform->pfReadPeek (hJob, &(pXform->inTraits),
1067 dwInUsed, pbTheInBuf, pgbIn->dwFilePos,
1070 } __except (EXCEPTION_EXECUTE_HANDLER) {
1077 /* We _assume_ that the xform consumed all the data in the midbuf */
1078 g->iOwner = -1; /* input midbuf is consumed and un-owned now */
1079 g->dwMidValidLen = 0;
1083 if (needInput && atTheHead) {
1084 if (dwInUsed >= pgbIn->dwValidLen) {
1085 /* consumed all input; mark input genbuf as empty */
1086 pgbIn->dwValidLen = 0;
1087 pgbIn->dwValidStart = 0;
1088 pgbIn->dwFilePos = dwInNextPos;
1090 /* advance counters in genbuf */
1091 pgbIn->dwValidLen -= dwInUsed;
1092 pgbIn->dwValidStart += dwInUsed;
1093 pgbIn->dwFilePos += dwInUsed;
1096 /* if new genbuf file-pos doesn't match what xform wants,
1097 * discard remainder of buffer */
1098 if (pgbIn->dwFilePos != dwInNextPos) {
1099 PRINT0 (_T("ipConvert: input seek to %d\n"), dwInNextPos);
1100 pgbIn->dwValidLen = 0;
1101 pgbIn->dwValidStart = 0;
1102 pgbIn->dwFilePos = dwInNextPos;
1106 if (dwOutUsed > 0) {
1107 if (pXform->pfWritePeek != NULL) {
1111 pXform->pfWritePeek (hJob, &(pXform->outTraits),
1112 dwOutUsed, pbTheOutBuf, dwOutThisPos,
1115 } __except (EXCEPTION_EXECUTE_HANDLER) {
1122 pgbOut->dwFilePos = dwOutThisPos;
1123 pgbOut->dwValidStart = 0;
1124 pgbOut->dwValidLen = dwOutUsed;
1126 INSURE (g->iOwner < 0); /* mid inbuf must be unowned here */
1127 g->iOwner = iXform + 1; /* next xform hereby owns mid inbuf */
1128 /* swap input and output midbuf pointers */
1129 pbTemp = g->pbMidInBuf;
1130 g->pbMidInBuf = g->pbMidOutBuf;
1131 g->pbMidOutBuf = pbTemp;
1132 g->dwMidValidLen = dwOutUsed;
1136 /**** Handle Results of Conversion Call ****/
1138 selectCnvState = FALSE;
1140 if (pXform->eState == XS_PARSING_HEADER) {
1142 if (result & IP_DONE) {
1143 PRINT0 (_T("ipConvert: xform %d is done parsing header\n"), iXform);
1144 pXform->pXform->getActualBufSizes (pXform->hXform,
1145 &pXform->dwMinInBufLen, &pXform->dwMinOutBufLen);
1148 /* allocate new input genbuf, and xfer data into it */
1149 n = pXform->dwMinInBufLen;
1150 if (n < MIN_GENBUF_LEN)
1152 if (n < pgbIn->dwValidLen)
1153 n = pgbIn->dwValidLen;
1154 PRINT0 (_T("ipConvert: alloc new input genbuf, ")
1155 _T("old len=%d, new len=%d\n"), pgbIn->dwBufLen, n);
1156 PRINT0 (_T(" dwMinInBufLen=%d, dwValidLen=%d\n"),
1157 pXform->dwMinInBufLen, pgbIn->dwValidLen);
1158 IP_MEM_ALLOC (n, pbTemp);
1160 pgbIn->pbBuf + pgbIn->dwValidStart,
1162 IP_MEM_FREE (pgbIn->pbBuf);
1163 pgbIn->pbBuf = pbTemp;
1164 pgbIn->dwBufLen = n;
1165 pgbIn->dwValidStart = 0;
1168 /* boost size of midbufs if necessary (also 1st malloc of them) */
1169 n = atTheHead ? 0 : pXform->dwMinInBufLen;
1170 if (!atTheTail && pXform->dwMinOutBufLen > n)
1171 n = pXform->dwMinOutBufLen;
1172 /* note: the code below (correctly) does not create mid-bufs if
1173 * n is 0, which occurs if there's only one xform in the list */
1174 if (n > g->dwMidLen) {
1175 /* delete both mid-bufs, and (re) allocate them */
1176 /* copy data from old to new, if necessary */
1177 PBYTE pbOldMidInBuf = g->pbMidInBuf;
1178 g->pbMidInBuf = NULL;
1179 PRINT0 (_T("ipConvert: alloc mid-bufs, old len=%d, new len=%d\n"),
1182 IP_MEM_ALLOC (n, g->pbMidInBuf );
1183 IP_MEM_ALLOC (n, g->pbMidOutBuf);
1184 if (pbOldMidInBuf != NULL) {
1185 memcpy (g->pbMidInBuf, pbOldMidInBuf, g->dwMidLen);
1186 IP_MEM_FREE (pbOldMidInBuf);
1192 /* allocate output genbuf */
1193 n = pXform->dwMinOutBufLen;
1194 if (n < MIN_GENBUF_LEN)
1196 PRINT0 (_T("ipConvert: alloc output genbuf, len=%d, minlen=%d\n"),
1197 n, pXform->dwMinOutBufLen);
1198 IP_MEM_ALLOC (n, pgbOut->pbBuf);
1199 pgbOut->dwBufLen = n;
1200 pgbOut->dwValidStart = 0;
1201 pgbOut->dwValidLen = 0;
1203 /* At this point it is permissible to call ipGetImageTraits
1204 * to obtain output traits because all xforms are past the
1205 * parsing-header state, and thus the output traits are known.
1206 * So tell caller that we're done parsing the header. */
1207 ipResult |= IP_PARSED_HEADER;
1210 selectCnvState = TRUE;
1213 } else { /* state is XS_CONVERTING or XS_CONV_NOT_RFD or XS_FLUSHING */
1216 /* handle status bits pertaining to the input data */
1217 if (result & IP_CONSUMED_ROW) {
1219 ipResult |= IP_CONSUMED_ROW;
1221 if (result & IP_NEW_OUTPUT_PAGE) {
1222 /* a new *output* page for the input xform is a new *input* page
1223 * for the IP as a whole */
1225 ipResult |= IP_NEW_INPUT_PAGE;
1230 /* handle status bits pertaining to the output data */
1231 ipResult |= (result & (IP_PRODUCED_ROW | IP_NEW_OUTPUT_PAGE));
1232 if (result & IP_PRODUCED_ROW)
1234 if (result & IP_NEW_OUTPUT_PAGE)
1236 if (result & IP_WRITE_INSERT_OK & g->wResultMask)
1237 g->pendingInsert = TRUE;
1238 } else if (result & IP_NEW_OUTPUT_PAGE) {
1239 /* this xform hit end of page, so tell next xform about it */
1240 PRINT0 (_T("ipConvert: xform %d hit end of page\n"), iXform);
1241 pNextXform->pXform->newPage (pNextXform->hXform);
1244 if (result & IP_DONE) {
1245 PRINT0 (_T("ipConvert: xform %d is done\n"), iXform);
1246 pXform->eState = XS_DONE;
1247 } else if (pXform->eState != XS_FLUSHING)
1248 selectCnvState = TRUE;
1249 } /* if state is 'parsing header' */
1251 if (selectCnvState) {
1252 /* go to one of the two 'converting' states */
1253 if ((result & IP_READY_FOR_DATA) == 0)
1254 PRINT1 (_T("ipConvert: xform %d is not ready for data\n"), iXform);
1255 pXform->eState = (result & IP_READY_FOR_DATA)
1256 ? XS_CONVERTING : XS_CONV_NOT_RFD;
1259 } /* end of while (TRUE) */
1262 /********************/
1263 /* End of Main Loop */
1264 /********************/
1266 *pdwInputNextPos = pgbIn->dwFilePos + pgbIn->dwValidLen;
1268 /* After headers are parsed, parsed-header bit should always be set */
1269 if (g->xfArray[g->xfCount-1].eState >= XS_CONVERTING)
1270 ipResult |= IP_PARSED_HEADER;
1272 PRINT0 (_T("ipConvert: ipResult=%04x, returning %04x, InputUsed=%d InputNextPos=%d OutputUsed=%d OutputThisPos=%d\n"),
1273 ipResult, ipResult & g->wResultMask, *pdwInputUsed, *pdwInputNextPos, *pdwOutputUsed, *pdwOutputThisPos);
1276 if (pbInputBuf && *pdwInputUsed)
1277 write(infd, pbInputBuf, *pdwInputUsed);
1280 write(outfd, pbOutputBuf, *pdwOutputUsed);
1283 return ipResult & g->wResultMask;
1286 return IP_FATAL_ERROR;
1291 /*****************************************************************************\
1293 * ipMirrorBytes - Swaps bits in each byte of buffer
1294 * (bits 0<->7, 1<->6, etc.)
1296 \*****************************************************************************/
1298 static const BYTE baMirrorImage[256] =
1300 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
1301 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
1302 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
1303 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
1304 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
1305 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
1306 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
1307 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
1308 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
1309 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
1310 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
1311 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
1312 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
1313 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
1314 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
1315 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
1316 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
1317 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
1318 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
1319 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
1320 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
1321 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
1322 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
1323 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
1324 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
1325 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
1326 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
1327 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
1328 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
1329 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
1330 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
1331 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
1334 VOID ipMirrorBytes(PBYTE pbInputBuf,DWORD dwInputAvail) {
1335 while (dwInputAvail>0) {
1336 *pbInputBuf=baMirrorImage[*pbInputBuf];