|
|
(8 intermediate revisions by 2 users not shown) |
Line 1: |
Line 1: |
| By [[IBM]]
| | {{PrintDDRef}} |
| | {{IBM-Reprint}} |
| | ===EDM/2 preamble=== |
| | This is the ''Printer Device Driver Reference for OS/2'' as last published by IBM in 1998. It is republished here with explicit permission from the company (Copyright Permission #21953) and you should keep in mind that it is an intellectual property of International Business Machines Corp. that cannot be changed or reused without their permission and is not governed by the [[Attribution-Share Alike 3.0]] licence like the rest of the EDM/2 Wiki. |
|
| |
|
| === About This Book ===
| | The content of the documentation is unchanged apart from the following: |
| | * The original document was an INF file split into thousands of different small sections, these have been consolidated into chapters, and restructured to fit [[HTML]] formatting, mimicking the original [[GML]] format as much as possible. |
| | * Sales, technical help, download and contact information has been removed. The PDDR/2 and the related SDK's are no longer for sale, nor is support available from IBM. Some of the INF viewer related help has been removed as well as it is superfluous after the format change and might be misleading, and the Glossary and Notices section was merged with other DDK/SDK glossary sections as they are all identical. |
| | * Miniscule changes have been made to the text, spelling errors, formatting errors and possible copy and paste errors have been fixed and/or noted. |
| | |
| | Outside of formatting changes, adding Wikilinks and graphic improvements, the document shall be left as it is. It should be noted that the some of the driver models and data formats described in the documentation are have been replaced or extended by both IBM and third parties, but that does not mean that this document should be changed, but it is acceptable that a link is created to an internal or external article that explains the newer models and formats. |
| | |
| | ==About This Book== |
| The ''Printer Device Driver Reference for OS/2'' describes the printer and plotter presentation drivers as well as test tools that correspond to the source code that is supplied with the IBM Developer Connection Device Driver Kit for OS/2. | | The ''Printer Device Driver Reference for OS/2'' describes the printer and plotter presentation drivers as well as test tools that correspond to the source code that is supplied with the IBM Developer Connection Device Driver Kit for OS/2. |
|
| |
|
| This reference also provides a roadmap to the drivers and briefly describes their functions and modules. It is intended to be used in conjunction with the ''Presentation Driver Reference''. For additional information about graphics-engine functions and presentation drivers, see the ''Presentation Driver Reference''. | | This reference also provides a roadmap to the drivers and briefly describes their functions and modules. It is intended to be used in conjunction with the ''Presentation Driver Reference''. For additional information about graphics-engine functions and presentation drivers, see the ''Presentation Driver Reference''. |
|
| |
|
| Programmers can use the information found in this book to create printer drivers and tests as well as to test their drivers. Knowledge of C and Assembler programming languages is necessary. The programmer must be familiar with the the OS/2 operating system, the Presentation Manager interface, and 80X86 architecture. The programming concepts that should be understood before developing applications to run on the OS/2 system can be found in the ''Application Design Guide''. | | Programmers can use the information found in this book to create printer drivers and tests as well as to test their drivers. Knowledge of C and Assembler programming languages is necessary. The programmer must be familiar with the OS/2 operating system, the Presentation Manager interface, and 80X86 architecture. The programming concepts that should be understood before developing applications to run on the OS/2 system can be found in the ''Application Design Guide''. |
|
| |
|
| === How This Book is Organized === | | ===How This Book is Organized=== |
| *[[Generic Printer Library]], describes a set of subroutine packages that can be used in the development of 32-bit hardcopy presentation drivers. | | *[[Generic Printer Library]], describes a set of subroutine packages that can be used in the development of 32-bit hardcopy presentation drivers. |
|
| |
|
Line 22: |
Line 32: |
|
| |
|
| *[[Font Test 32-Bit Printing Utility]], describes Font Test. | | *[[Font Test 32-Bit Printing Utility]], describes Font Test. |
| | | :Font Test is a 32-bit Presentation Manager application that allows users to browse through and print text files as well as to query presentation drivers for device, font, and hardcopy information. Font Test is very useful for testing presentation drivers. All the functions used by Font Test are listed and described, and a description of how to add a test to Font Test is included. |
| Font Test is a 32-bit Presentation Manager application that allows users to browse through and print text files as well as to query presentation drivers for device, font, and hardcopy information. Font Test is very useful for testing presentation drivers. All the functions used by Font Test are listed and described, and a description of how to add a test to Font Test is included. | |
|
| |
|
| *[[Printer Test Tool (PTT)]], describes the Printer Test Tool (PTT) and how to run test cases. It also contains information about PTT commands and PTT command-line options. The PTT's tests are detailed, and the GPI functions called by the tests in the PTT are listed with any necessary configuration settings. | | *[[Printer Test Tool (PTT)]], describes the Printer Test Tool (PTT) and how to run test cases. It also contains information about PTT commands and PTT command-line options. The PTT's tests are detailed, and the GPI functions called by the tests in the PTT are listed with any necessary configuration settings. |
Line 29: |
Line 38: |
| *The ''[[IBM SDK/DDK Notices|Notices]]'' contain trademark and service-mark notices and information. | | *The ''[[IBM SDK/DDK Notices|Notices]]'' contain trademark and service-mark notices and information. |
| *The ''[[IBM SDK/DDK Glossary|Glossary]]'' defines terms commonly used in the IBM Device Driver Source Kit for OS/2. | | *The ''[[IBM SDK/DDK Glossary|Glossary]]'' defines terms commonly used in the IBM Device Driver Source Kit for OS/2. |
|
| |
| === What's New ===
| |
| The following update has been added to this release of the ''Printer Device Driver Reference for OS/2'':
| |
|
| |
| A new section, [[Sample Bidirectional Parallel Port Driver]] which describes the code/functions associated with the port driver.
| |
|
| |
| For information on items discussed in this reference that have been added to OS/2 (beginning with Warp) and their compatibility with different versions of OS/2, see [[OS/2 Version Compatibility Considerations]].
| |
|
| |
| === Assistance ===
| |
| Technical support for device driver development is provided by the IBM Driver Development Support Center (DDSC) through a bulletin board system (BBS). You are encouraged to use the DDSC to obtain support by sending in your questions and reviewing the question and answer database which can be downloaded for off-line review.
| |
|
| |
| To access the DDSC BBS, dial 512-838-9717 (using a modem) to register and access the support system. For voice support in the United States, call 512 -838-9493.
| |
|
| |
| Additional assistance is available through the IBM Solution Developer Program. For membership information:
| |
| :Internet: ibmsdp@vnet.ibm.com
| |
| :US/Canada: 800-627-8363
| |
| :International: 770-835-9902
| |
| :International Fax: 770-835-9444
| |
|
| |
| === Ordering Information ===
| |
| In addition to the actual tools and source code available on The IBM Developer Connection Device Driver Kit for OS/2, it CD-ROM also includes the following DDK reference books in online format.
| |
|
| |
| *The Physical Device Driver Reference
| |
| *The Storage Device Driver Reference
| |
| *The Input/Output Device Driver Reference
| |
| *The Pen for OS/2 Device Driver Reference
| |
| *The Virtual Device Driver Reference
| |
| *The Presentation Device Driver Reference
| |
| *The Display Device Driver Reference
| |
| *The Printer Device Driver Reference
| |
| *The Graphics Adapter Device Driver Reference
| |
| *The MMPM/2 Device Driver Reference (Multimedia)
| |
|
| |
| To order the DDK call:
| |
| <pre class="western">/----------------------------------------------------------------\
| |
| |U.S.A.: |1-800-633-8266 | |
| |
| |--------------------+---------------------+---------------------|
| |
| |Canada: |1-800-561-5293 | |
| |
| |--------------------+---------------------+---------------------|
| |
| |When calling from |* English |(+45) 48101500 |
| |
| |Europe, the Middle |* French |(+45) 48101200 |
| |
| |East, or Africa, the|* Italian |(+45) 48101600 |
| |
| |number depends on |* German |(+45) 48101000 |
| |
| |the language you use|* Spanish |(+45) 48101100 |
| |
| |to place the order: |* Dutch |(+45) 48101400 |
| |
| | |* Danish |(+45) 48101300 |
| |
| | |* Finish |(+45) 48101650 |
| |
| | |* Swedish |(+45) 48101150 |
| |
| | |* Norwegian |(+45) 48101250 |
| |
| | |* FAX |(+45) 48142207 |
| |
| |--------------------+---------------------+---------------------|
| |
| |When ordering from |* Bolivia | 02-35 1840 |
| |
| |Latin America or |* Columbia | 01-257-0111 |
| |
| |South America, the |* Dominican Republic | 566-5161 |
| |
| |number depends on |* El Salvador | 02-98 5011 |
| |
| |the country from |* Honduras | 32-2319 |
| |
| |which you are |* Paraguay | 021-444 094 |
| |
| |calling: |* Urugruay | 02-923 617 |
| |
| | |* Chile | 02-633-4400 |
| |
| | |* Costa Rica | 223-6222 |
| |
| | |* Ecuador | 02-56 5100 |
| |
| | |* Guatemala | 02-31 5859 |
| |
| | |* Panama | 02-639 977 |
| |
| | |* Peru | 014-36 6345 |
| |
| | |* Venezuela | 02-908-8901 |
| |
| | |* Argentina | 01-313-0014 |
| |
| |--------------------+---------------------+---------------------|
| |
| |To order from Asia/ |* All except Japan |(61) 2-354-7684 |
| |
| |Pacific: |* Japan |(81) 3-3495-2045(Fax)|
| |
| | | |Fax request to: |
| |
| | | |DAP-J, IBM Japan |
| |
| |--------------------+---------------------+---------------------|
| |
| |To order from SE |(021) 800-6120(Voice)| |
| |
| |Brazil: |(021) 800-6936(Fax) | |
| |
| |--------------------+---------------------+---------------------|
| |
| |To order from |* Mexico City |627-2444 |
| |
| |Mexico: |* Country |91-800-00639 |
| |
| \----------------------------------------------------------------/</pre>
| |
|
| |
| === Generic Printer Library ===
| |
| The Generic Printer Library (GenPLib) is a set of subroutine components that can be used in the development of 32-bit hardcopy presentation drivers.
| |
|
| |
| Presentation-driver developers often write similar sets of code to implement functions commonly required by hardcopy devices. Heap creation, output buffering, and banding raster data are examples. The GenPLib simplifies development and decreases the development time of 32-bit OS/2 printer presentation drivers because it provides these necessary functional components.
| |
|
| |
| The GenPLib consists of function packages that implement some of the more difficult code that is needed to create a printer driver. The library format is a way to realize software reuse so that other developers can benefit from code that can be made completely independent of any driver.
| |
|
| |
| GenPLib appears in the IBM Developer Connection Device Driver Kit for OS/2 (DDK) as a static library that is linked to OS/2 driver code. The GenPLib code is still in its early versions; updates to the functions and header files can occur with each release of the DDK. Eventually, the GenPLib may become a system DLL; but for now, you can use any static version of GenPLib . By convention, all functions exported from GenPLib begin with the ''Gpl'' prefix.
| |
|
| |
| Because of the design of the modules of the GenPLib, some functions can also be used for development in areas other than OS/2 printer drivers.
| |
|
| |
| Following are some reasons to use the GenPLib:
| |
|
| |
| *Allows developers to quickly, easily, and incrementally add function packages to their printer drivers.
| |
| *Written in portable C source code that can be recompiled for other processors.
| |
| *Provides 32-bit functions for new 32-bit operating-system environments, such as OS/2 2.0+SP and up-including OS/2 Warp.
| |
| *Available in Intel, PowerPC, debug, and non-debug versions. The current 16 -bit drivers cannot run in these environments.
| |
| *Provides a single, consistent source code for common functions.
| |
| *Packages are designed using data abstraction.
| |
| *Makes printer presentation-driver code more readable and maintainable.
| |
| *Produces extensive debugging and logging information for developers and service personnel.
| |
| *Implemented with the newest, most appropriate OS/2 system APIs, tailored to the underlying hardware and operating system version on which it is running (that is, system memory, paging behavior, CPU detection, etc.).
| |
|
| |
| '''Note:''' The GenPLib has no 16-bit routines.
| |
|
| |
| === GenPLib Functional Packages ===
| |
| The GenPLib currently contains the following function packages:
| |
|
| |
| [[Error Assertion]] Provides a consistent way of checking for errors in driver code and reporting and logging useful information for developers and field support.
| |
|
| |
| [[Banding]] Simplifies the use of journaling that assists in banding pages of raster output data to printers.
| |
|
| |
| [[Color Dithering]] Provides color-dithering support.
| |
|
| |
| [[Gamma Correction]]Provides gamma-correction support.
| |
|
| |
| [[Compression]]Provides commonly used compression routines recognized by printers.
| |
|
| |
| [[Exception Management]]Provides ways of setting errors with WinSetErrorInfo and logging appropriate warnings, exceptions, and error codes.
| |
|
| |
| [[Memory Management]]Provides a simple way of managing global and process memory needed by presentation drivers.
| |
|
| |
| [[Pattern Creation]]Provides functionality to create bitmap patterns.
| |
|
| |
| [[Output-Thread Management]]Provides multi-threaded output and buffer management to printer devices for improved performance.
| |
|
| |
| [[00077.htm|Semaphores]]Helps drivers protect their data in multitasking environments. The implementation detects the current CPU level and implements semaphores based on the smallest possible set of assembly instructions.
| |
|
| |
| [[00086.htm|String Management]]Provides a way to sort text strings that are being drawn to a printer output page so that they can be processed in many page orders when needed.
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === GenPLib Architecture ===
| |
|
| |
| The GenPLib is a 32-bit static linking library, GENPLIB.LIB. Developers use LINK386.EXE to link the GPL with their 32-bit printer drivers.
| |
|
| |
| Several C language include files (*.H) are associated with GENPLIB.LIB and define the function names and prototypes in the library. The main include file is GENPLIB.H.
| |
|
| |
| GENPLIB.H includes other relevant library H files based on symbolics (INCLs ) defined to the compiler. For example, the following symbolics have a special meaning to the operation of GENPLIB.H when included by a C program:
| |
|
| |
| <pre class="western">INCL_GENPLIB_ASSERT
| |
| INCL_GENPLIB_ERROR
| |
| INCL_GENPLIB_HANDLER
| |
| INCL_GENPLIB_JOURNAL
| |
| INCL_GENPLIB_MEMORY
| |
| INCL_GENPLIB_SEMAPHORES
| |
| INCL_GENPLIB_STRINGSORT
| |
| INCL_GENPLIB_THREAD
| |
| INCL_GENPLIB_UTIL
| |
| INCL_GENPLIB_PATTERNS</pre>
| |
|
| |
|
| |
| To include all functions, use:
| |
|
| |
| <pre class="western">INCL_GENPLIB_ALL</pre>
| |
|
| |
|
| |
| When a developer uses GenPLib memory-management routines, the C source file that requires GenPLib memory management would include a set of code resembling the following:
| |
|
| |
| <pre class="western">#define INCL_GENPLIB_MEMORY
| |
| #include <genplib.h></pre>
| |
|
| |
|
| |
| This code is included before any GenPLib memory-management functions or structures are referenced. The compiler automatically includes GPLMEM.H within GENPLIB.H.
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === Components of the Generic Print Library ===
| |
|
| |
| The following sections describe the components and functions of the GenPLib .
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === Error Assertion ===
| |
|
| |
| To use the GenPLib Error-Assertion package, you must include:
| |
|
| |
| <pre class="western">INCL_GENPLIB_ASSERT</pre>
| |
|
| |
|
| |
| The error-assertion package of the GenPLib consists of six APIs. Four are macros:
| |
|
| |
| *[[00010.htm|ASSERTT () and ASSERTF ()]]<br />*[[00011.htm|DBPRINTF (()) and DBPRINTIF (())]]
| |
|
| |
| The remaining two are functions:
| |
|
| |
| *[[00012.htm|PMAssert]]<br />*[[00013.htm|BaseAssert]]
| |
|
| |
| [[00012.htm|PMAssert]]Validates the return code from OS/2 Presentation Manager (PM) APIs that display the WinGetLastError() result and a supplied text string in a message box.
| |
|
| |
| [[00013.htm|BaseAssert]]Validates OS/2 APIs that use the APIRET return code.
| |
|
| |
| [[00010.htm|ASSERTT () and ASSERTF ()]]ASSERTT causes an error assertion if the supplied test evaluates to TRUE. ASSERTF causes an error assertion if the supplied test evaluates to FALSE. An assertion is an INT3 with kernel debug information displaying the failed test, file name, and line number of the location from which the assertion was called.
| |
|
| |
| [[00011.htm|DBPRINTF (()) and DBPRINTIF (())]]DBPRINTF outputs the supplied text string to the kernel debugger. DBPRINTIF outputs the supplied text string to the kernel debugger if the supplied condition is TRUE.
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === ASSERTT () and ASSERTF () ===
| |
|
| |
| The ASSERTT and ASSERTF macros are very useful to precisely locate errors in code. Each is simply a test. If the test fails, the system generates a sound, stops the program, and displays a message. The more often an ASSERTT or ASSERTF macro is used, the better the chance that the first point of failure will be captured for analysis.
| |
|
| |
| '''Use ASSERTT or ASSERTF prior to:'''
| |
|
| |
| Pointers Assert that pointers are nonzero. <br />Divisors Assert that divisors are nonzero. <br />Strings Assert that strings are valid. <br />Copying Assert that enough space is present before copying.
| |
|
| |
| '''Use ASSERTT or ASSERTF after:'''
| |
|
| |
| OS/2 APIs and internal functions Assert result codes of OS/2 APIs and your internal functions.
| |
|
| |
| Pointers Assert pointers after allocation.
| |
|
| |
| Switch statements Use ASSERTT (TRUE) in the default case of switch statements
| |
|
| |
| '''Do not use ASSERTT or ASSERTF in:'''
| |
|
| |
| Essential Code These macros are not included in the retail build of the product. For example, ASSERTT (0 != DosRequestMutexSem (hsem))
| |
|
| |
| The following is sample output on the kernel debugger:
| |
|
| |
| <pre class="western">Assertion failed on line 41 of file code.c
| |
| 'rc == 0'
| |
| eax=XXXXXXXX ebx=XXXXXXXX etc=XXXXXXXX edx=XXXXXXXX esi=XXXXXXXX edi=XXXXXXXX
| |
| eip=XXXXXXXX esp=XXXXXXXX ebp=XXXXXXXX iopl=2 -- -- -- xx xx xx xx xx xx xx xx
| |
| cs=XXXX ss=XXXX ds=XXXX es=XXXX fs=XXXX gs=XXXX cr2=XXXXXXXX cr3=XXXXXXXX
| |
| program:CODE32:BREAKPOINT
| |
| XXXX:XXXXXXXX cc int 3
| |
| ##</pre>
| |
| Use ASSERTT and ASSERTF under the following conditions:
| |
|
| |
| '''ASSERTT (z);'''where ''z''is a Boolean expression that should evaluate to zero or FALSE on success.
| |
|
| |
| '''ASSERTF (nz);'''where ''nz''is a Boolean expression that should evaluate to nonzero or TRUE on success.
| |
|
| |
| The following example shows how to use ASSERTT and ASSERTF:
| |
|
| |
| <pre class="western">pointer = NULL;
| |
| rc = DosAllocMem( &pointer, size, PAG_EXECUTE | PAG_READ | PAG_WRITE );
| |
| ASSERTT (rc); // Return code should be zero (success)
| |
| ASSERTF (pointer); // Pointer should be nonzero</pre>
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === DBPRINTF (()) and DBPRINTIF (()) ===
| |
|
| |
| DBPRINTF uses the printf functionally of ANSI C to write messages to the kernel debugger screen. DBPRINTF is a macro; but because it can have a variable number of parameters, it must have an extra set of parentheses.
| |
|
| |
| The following is the structure of DBPRINTF:
| |
|
| |
| <pre class="western">DBPRINTF( // Outputs a text string to debug terminal (like C printf command)
| |
| PSZ pszFormatString, // String with same format options as printf command
| |
| (...) ); // Parameter list of values to be placed in format string</pre>
| |
| The following is the structure of DBPRINTIF:
| |
|
| |
| <pre class="western">DBPRINTIF( // A conditional DBPRINTF command
| |
| BOOL bDoit, // Outputs format string if this parameter evaluates to TRUE
| |
| PSZ pszFormatString, // String with same format options as printf command
| |
| (...) ); // Parameter list of values to be placed in format string</pre>
| |
| '''ASSERTT, ASSERTF, DBPRINTF, and DBPRINTIF Notes:'''
| |
|
| |
| ASSERTT and ASSERTF as well as DBPRINTF and DBPRINTIF are macros. They are built for the debug-level build and disappear for the retail-level build.
| |
|
| |
| These macros rely on the PMDD device driver to be activated. To activate the PMDD device driver, add a /Cx parameter to the following statement (where x is the COM port number):
| |
|
| |
| <pre class="western">DEVICE=C:\OS2\PMDD.SYS /Cx</pre>
| |
|
| |
| === PMAssert ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is similar to ASSERTT and ASSERTF, but it displays a message box if an error condition occurs. In addition to displaying a user-provided error message, the message box also displays the results of WinGetLastError (), the Presentation Manager error code. Use this function to assert OS/2 Presentation Manager APIs.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">PMAssert( // Display a message box with pszString, and show WinGetLastError()
| |
| BOOL bDoit, // Display message box only if this expression evaluates to TRUE
| |
| HAB habErr, // Anchor block handle of thread checking for a PM error
| |
| PSZ pszString ); // Message to display on message box with PM error code</pre>
| |
| '''Parameters'''
| |
|
| |
| '''bDoit'''(''BOOL'') Boolean value. If TRUE, then a message box is displayed. <br />'''habErr'''(''HAB'') Anchor block of program. <br />'''pszString'''(''PSZ'') Message string.
| |
|
| |
| '''Returns'''
| |
|
| |
| TRUE Evaluated to TRUE <br />FALSE Evaluated to FALSE
| |
|
| |
| '''Example Code'''
| |
|
| |
| <pre class="western">BOOL rc;
| |
| rc = GpiDestroyPS( hps );
| |
| PMAssert( rc == FALSE,
| |
| hab,
| |
| "GpiDestroyPS failed!" );</pre>
| |
|
| |
| === BaseAssert ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is similar to ASSERTT and ASSERTF, but it displays a message box if an error condition occurs. Use this function to assert return codes from those OS/2 APIs that use DOS Error-type return codes.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">BaseAssert( // Display message box if a base error (DOS) is passed in (ulError)
| |
| ULONG ulError, // Value of base error as defined in BSEERR.H header file
| |
| PSZ pszString ); // String to print out with base error code</pre>
| |
| '''Parameters'''
| |
|
| |
| '''ulError'''(''ULONG'') Return code from OS/2 BaseAPI, either NO_ERROR (0) or one of the ERROR_xxx DOS Error codes. If ulError is not equal to NO_ERROR, a message box is displayed.
| |
|
| |
| '''pszString'''(''PSZ'') Message string.
| |
|
| |
| '''Returns'''
| |
|
| |
| TRUE Evaluated to TRUE <br />FALSE Evaluated to FALSE
| |
|
| |
| '''Example Code'''
| |
|
| |
| <pre class="western">APIRET apirc;
| |
| apirc = DosAllocMem( pbuf, 1024h, PAG_READ | PAG_WRITE );
| |
| BaseAssert( "DosAllocMem failed", apirc );</pre>
| |
|
| |
| === Banding ===
| |
| This component controls all aspects of managing a journal file and banding such as:
| |
|
| |
| *Calculating the band size-determines if banding is necessary based on the input parameters (resolution, bits/pel, page size, etc.).
| |
|
| |
| *Creating a journal file, and managing COM_DRAW flags.
| |
|
| |
| *Playing back either a full page or bands within a page, and managing the DC offset for each band.
| |
|
| |
| *Offering many different play options.
| |
|
| |
| *Handling destructive and non-destructive plays (if it is necessary to play more than once).
| |
|
| |
| *Handling portrait and landscape cases.
| |
|
| |
| *Playing bands from top-to-bottom or bottom-to-top.
| |
|
| |
| To use the GenPLib Banding package, you must include:
| |
|
| |
| <pre class="western">INCL_GENPLIB_JOURNAL</pre>
| |
|
| |
| === Journaling Overview ===
| |
| A journal file is a record of all the GreXXX function calls that a driver receives between the time that it starts recording a journal file and the time it stops recording a journal file. Typically, recording starts at the beginning of a page and stops at the end of a page. After the recording has stopped, you can replay the journal file as often as necessary.
| |
|
| |
| There are many reasons to record the GreXXX calls for a particular handle to a drawing context (HDC). Color sorting and banding are two examples.
| |
|
| |
| *For color sorting, printer commands are output for a particular color while the journal file is recorded. Then, the journal file is played back for the remaining colors. Printer commands are output only when the current color is the color with which you are working.
| |
|
| |
| *For banding, a portion of the page is defined as a bitmap and only that area is drawn in while the journal file is played back. Then, the DC origin is moved up the size of the band and the journal file is replayed. This must be done for every band on the page.
| |
|
| |
| The following functions are used for journaling:
| |
| *[[GplQueryPhysicalMem]]
| |
| *[[GplJournalCalcBandSize]]
| |
| *[[GplJournalCreateInstance]]
| |
| *[[GplJournalPlayInstance]]
| |
| *[[GplJournalDeleteInstance]]
| |
| *[[GplJournalAbortDoc]]
| |
| *[[GplJournalResetAbortDoc]]
| |
|
| |
| === Call Flow ===
| |
| [[GplQueryPhysicalMem]] is the first function that you can call. It tells you how much physical RAM you have available.
| |
|
| |
| [[00018.htm|GplJournalCalcBandSize]]is the second function that you can call. It is an optional helper function that tells you whether or not you need to band given your memory requirements and band size.
| |
|
| |
| The next function that you call is [[00019.htm|GplJournalCreateInstance]]. This function initializes an instance or reuses an instance.
| |
|
| |
| The next function that you call is [[00020.htm|GplJournalPlayInstance]]. This function replays the journal file either per-page or per-band; it can also preserve or change the attributes of the page.
| |
|
| |
| Finally, you call [[00021.htm|GplJournalDeleteInstance]]to clean up the instance data.
| |
|
| |
| === GplQueryPhysicalMem ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function tells you how much physical RAM is installed on your system.
| |
|
| |
| The function ulPhysMem can be used in determining the amount of memory that should be reserved for banding. For the Omni driver, for example:
| |
|
| |
| <pre class="western"> if( ulPhysMem <= 4 )
| |
| ulMaxBandMem = 256 * 1024; // 256K bands
| |
| elseif( ulPhysMem < 12 )
| |
| ulMaxBandMem = 512 * 1024; // 512K bands
| |
| elseif( ulPhysMem < 20 )
| |
| ulMaxBandMem = 1000 + 1024; // 1M bands
| |
| elseif( ulPhysMem >=20 )
| |
| ulMaxBandMem = 2000 + 1024; // 2M bands</pre>
| |
| '''Returns'''
| |
|
| |
| ulPhysMem Amount of physical RAM installed on system.
| |
|
| |
| === GplJournalCalcBandSize ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function helps you decide if you need to break the page up into bands. If you do need to journal, then it will set up the band size to be constrained by the memory limit and to be a multiple of the modulus.
| |
|
| |
| Based on the page size, number of bits per pel, number of color planes, etc ., the function calculates the number of bytes needed for the page bitmap. If the amount exceeds the memory limit, it calculates the number of bands into which to break the page.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplJournalCalcBandSize(
| |
| PIJOURNAL pIJournal, // Journal data structure
| |
| USHORT usBitsPerPel, // 1, 4, 8, or 24 bits per pel
| |
| USHORT usNumPlanes, // Number of color planes
| |
| USHORT usModulus, // Band size should be a multiple of this
| |
| USHORT usDotsPerColumn, // Resolution
| |
| ULONG ulMaxBandMem ); // Maximum memory available for banding</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pIJournal'''(''PIJOURNAL'') Journal data structure. The following input fields are used:
| |
|
| |
| '''usXLength'''Length of page in pels along x axis. <br />'''usYLength'''Length of page in pels along y axis. <br />'''bPortrait'''Orientation of page-portrait or landscape.
| |
|
| |
| '''usBitsPerPel'''(''USHORT'') Page bitmap, number of bits per pel.
| |
|
| |
| '''usNumPlanes'''(''USHORT'') Page bitmap, number of planes.
| |
|
| |
| '''usModulus'''(''USHORT'') The band size must be zero or a multiple of this number. This may be necessary to cause byte, word, or Dword alignment to align band size to match the width of a print head. This functionality may also be helpful if you need to send the bits in a certain column height.
| |
|
| |
| '''usDotsPerColumn'''(''USHORT'') Resolution.
| |
|
| |
| '''ulMaxBandMem'''(''ULONG'') Maximum memory available for banding.
| |
|
| |
| This parameter is the limit to the number of bytes that your band bitmap can exceed.
| |
|
| |
| '''Returns'''
| |
|
| |
| FALSE Journaling is '''not'''necessary. <br />TRUE Journaling '''is'''necessary. The following is filled in and valid: <br />'''pIJournal'''(''PIJOURNAL'') Journal data structure
| |
|
| |
| '''usBandLength'''Band length in pels
| |
|
| |
| ''pIJournal''is output with ''usBandLength''updated as follows:
| |
|
| |
| *x-band length indicates landscape orientation. <br />*y-band length indicates portrait orientation.
| |
|
| |
| '''Notes'''
| |
|
| |
| This function should be called at COMPLETE_OPEN_DC time; because at this time, job properties have been obtained that may affect how ''pIJournal''is filled in (for example, form size, mono/color selections).
| |
|
| |
| === GplJournalCreateInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function will create a reusable instance for a particular DC. The opposite of this function is [[00021.htm|GplJournalDeleteInstance]]. Following are the four cases in which this function may be called:
| |
|
| |
| Case 1 Ask for the number of bytes to allocate for the handle.
| |
|
| |
| Case 2 DEVESC_STARTDOC time is the first (real) time this function is called. hJournal has been allocated. Initialize hJournal's bytes to 0.
| |
|
| |
| Case 3 At DEVESC_NEWFRAME time, another page, more processing. After the call to [[00020.htm|GplJournalPlayInstance]]has completed, set it up for the next page.
| |
|
| |
| Case 4 At DEVESC_NEWFRAME time, another page, but this time we want the information about the page to change. The call to GplJournalPlayInstance has completed.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplJournalCreateInstance( HJOURNAL hJournal, // Journal handle
| |
| PIJOURNAL pIJournal, // Journal data structure
| |
| ULONG ulFlags ); // Creation flags (defaults)</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hJournal'''(''HJOURNAL'') Handle to the journal file instance.
| |
|
| |
| '''pIJournal'''(''PIJOURNAL'') A pointer to the input structure.
| |
|
| |
| '''ulFlags'''(''ULONG'') This function performs different actions based on the ulFlags. The ulFlags is a bit vector (individual bits have different meanings). The options are separated into mutually exclusive groups that must have one member set.
| |
|
| |
| '''CREATE_DRAW_WHILE_RECORDING'''Turn on drawing while the journal file is being recorded.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| '''Implementation'''
| |
|
| |
| This function will perform different actions based on the input parameters:
| |
|
| |
| ''Case 1''
| |
|
| |
| The function will return the size (in the number of bytes) of a handle. It is the responsibility of the of caller to allocate and free the memory for a journal handle.
| |
|
| |
| hJournal NULL. <br />pIJournal NULL.
| |
|
| |
| ''Case 2''
| |
|
| |
| This function creates an engine journal file and starts recording to it. It also starts the accumulation of bounds. Call [[00020.htm|GplJournalPlayInstance]]to stop recording and play the journal file.
| |
|
| |
| '''hJournal'''Address of newly allocated memory.
| |
|
| |
| '''pIJournal'''Address of the input structure. The structure has following format:
| |
|
| |
| '''ulSize'''Size of this structure.
| |
|
| |
| '''hModule'''Module handle of the calling program.
| |
|
| |
| '''hdc'''Current HDC.
| |
|
| |
| '''usXLength'''Page size in pels.
| |
|
| |
| '''usYLength'''Page size in pels.
| |
|
| |
| '''bPortrait'''Orientation of page. <br />'''TRUE'''-portrait <br />'''FALSE'''-landscape
| |
|
| |
| '''usBandLength'''Band height in pels.
| |
|
| |
| '''pfunBand'''Pointer to a callback function with the following prototype. This function is only called at the end of each band. (_System *)(PVOID, PRECTL)
| |
|
| |
| '''pfunArg'''Any pointer. This will be passed to the first parameter of the previous callback function.
| |
|
| |
| '''Flags'''Contains creation flags.
| |
|
| |
| ''Case 3''
| |
|
| |
| The function performs the same functionality as Case 2. However, you can change any of the parameters in the input structure from the previous call to GplJournalCreateInstance.
| |
|
| |
| '''hJournal'''Handle to a journal file instance.
| |
|
| |
| '''pIJournal'''Address of the input structure. The structure has following format:
| |
|
| |
| ulSize Size of this structure.
| |
|
| |
| hModule Module handle of the calling program.
| |
|
| |
| hdc Current HDC.
| |
|
| |
| usXLength Page size in pels.
| |
|
| |
| usYLength Page size in pels.
| |
|
| |
| bPortrait Orientation of page. <br />'''TRUE'''-portrait <br />'''FALSE'''-landscape
| |
|
| |
| ''Case 4''
| |
|
| |
| For this case, a new page has been sent and you will restart the entire process (Case 2). This function uses the same parameters that were given to the original call to GplJournalCreateInstance.
| |
|
| |
| '''hJournal'''Handle to a journal file instance. <br />'''pIJournal'''NULL.
| |
|
| |
| === GplJournalPlayInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function signifies the end of the recording. If you want to call this function multiple times for a page, then for calls 1..n-1 the flag PLAY_ NONDESTRUCTIVE should be used. On the last call, n, the flag PLAY_ DESTRUCTIVE should be used.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplJournalPlayInstance( HJOURNAL hJournal,
| |
| ULONG ulFlags );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hJournal'''(''HJOURNAL'') Handle to the journal file instance.
| |
|
| |
| '''ulFlags'''(''ULONG'') This function will perform different actions based on the ulFlags. The ulFlags is a bit vector (individual bits have different meanings). The options are separated into mutually exclusive groups that must have one member set.
| |
|
| |
| '''PLAY_JOURNAL_BAND'''Play all bands at this time. The callback function that was defined at [[00019.htm|GplJournalCreateInstance]]time will be called after each band has been played. <br />or <br />'''PLAY_JOURNAL_PAGE'''Plays the journal file once for this page. <br />'''PLAY_NONDESTRUCTIVE'''The DC state will not be altered after the call has been completed. <br />or <br />'''PLAY_DESTRUCTIVE'''The DC state will now have the final attributes of the page. <br />'''PLAY_TOP_TO_BOTTOM'''Bands are played from the maximum Y value to 0. <br />or <br />'''PLAY_BOTTOM_TO_TOP'''Bands are played from 0 to the maximum Y value.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === GplJournalDeleteInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is the opposite of [[00019.htm|GplJournalCreateInstance]]. It should be called at DEVESC_ENDDOC or enable subfunction 11 (begin close DC) time. It is responsible for cleaning up all of the resources that it used.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplJournalDeleteInstance( HJOURNAL hJournal );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''hJournal'''(''HJOURNAL'') Handle to the journal file instance.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === GplJournalAbortDoc ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is called when a DEVESC_ABORTDOC is received.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplJournalAbortDoc( HJOURNAL hJournal );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''hJournal'''(''HJOURNAL'') Handle to the journal file instance.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === GplJournalResetAbortDoc ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is called when a DEVESC_ENDDOC is received and the job has been aborted.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplJournalResetAbortDoc( HJOURNAL hJournal );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''hJournal'''(''HJOURNAL'') Handle to the journal file instance.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === Example Code ===
| |
|
| |
| '''[[GplQueryPhysicalMem]]Usage'''
| |
|
| |
| Following is an example of [[00017.htm|GplQueryPhysicalMem]]usage:
| |
|
| |
| <pre class="western">case COMPLETE_OPEN_DC: // Final driver enable subfunction
| |
| {
| |
| // If we are enabling for a DC where we may need to journal
| |
| if( OD_DIRECT == ulDCType || PM_Q_RAW == ulDataType )
| |
| {
| |
| // Fill in journal information structure
| |
| IJournal.ulSize = sizeof( pddc->IJournal );
| |
| IJournal.bPortrait = ( pddc->pJobProps->ulOrientation == PORTRAIT );
| |
| IJournal.hdc = pddc->hdc; // Handle to DC
| |
| IJournal.hModule = globals.hModule; // Driver's module handle
| |
| IJournal.pfunBand = (PJFUN)NewFrame; // Callback function
| |
| IJournal.pfunArg = (PVOID)pddc; // Arguments to callback function
| |
| IJournal.usXLength = pddc->pCurrentForm->hcInfo.xPels;
| |
| IJournal.usYLength = pddc->pCurrentForm->hcInfo.yPels;
| |
|
| |
| // Find out how much physical RAM is installed on the system
| |
| GplQueryPhysicalMem( &ulPhysMem );
| |
|
| |
| // Omni uses ulPhysMem to determine the maximum memory for banding
| |
| If( ulPhysMem <= 4 )
| |
| ulMaxBandMem = 256 * 1024; // 256K bands
| |
| elseif( ulPhysMem < 12 )
| |
| ulMaxBandMem = 512 * 1024; // 512K bands
| |
| elseif( ulPhysMem < 20 )
| |
| ulMaxBandMem = 1000 + 1024; // 1M bands
| |
| elseif( ulPhysMem >= 20 )
| |
| ulMaxBandMem = 2000 + 1024; // 2M bands
| |
|
| |
| } /* end if */
| |
| } /* end case */</pre>
| |
| '''[[00018.htm|GplJournalCalcBandSize]]Usage'''
| |
|
| |
| Following is an example of [[00018.htm|GplJournalCalcBandSize]]usage during OS2_PM_DRV_ ENABLE for a dot-matrix printer:
| |
|
| |
| <pre class="western">case COMPLETE_OPEN_DC: // Final driver enable subfunction
| |
| {
| |
| IJournal.ulSize = sizeof( pddc->IJournal );
| |
| IJournal.bPortrait = TRUE;
| |
| IJournal.hdc = hdc;
| |
| IJournal.hModule = globals.hModule;
| |
| IJournal.pfunBand = (PJFUN)NewFrame;
| |
| IJournal.pfunArg = (PVOID)pddc;
| |
| IJournal.usXLength = hcInfo.xPels;
| |
| IJournal.usYLength = hcInfo.yPels;
| |
|
| |
| // NOTE: Modulus should be should be '1' on full-page printers or print-head width
| |
| bBanding = GplJournalCalcBandSize(
| |
| &IJournal, // PIJournal
| |
| 1, // Bits per pel
| |
| 1, // Planes
| |
| 40, // Modulus
| |
| 64000 ); // Maximum memory available
| |
|
| |
| } /* end case */</pre>
| |
| '''[[GplJournalCreateInstance]]Usage'''
| |
|
| |
| Following is an example of [[00019.htm|GplJournalCreateInstance]]usage to allocate/ create a journal instance handle during processing of the start-document escape. At this point, the port is opened and the output thread is already created.
| |
|
| |
| <pre class="western">case DEVESC_STARTDOC:
| |
| {
| |
| if( ulDCType == OD_DIRECT || ulDataType == PM_Q_RAW )
| |
| {
| |
| // If we need to band (that implies journaling)
| |
| if( pddc->fBanding )
| |
| {
| |
| // First call to size of memory needed for journal handle
| |
| ulSize = GplJournalCreateInstance( NULL, NULL, 0 );
| |
|
| |
| // Allocate memory needed for journal handle (driver's responsibility)
| |
| hJournal = GplMemoryAlloc( hmcbHeap, ulSize ); // User per-DC heap
| |
|
| |
| // Allocate the memory for formal instance
| |
| lrc = GplJournalCreateInstance( hJournal, // Journal handle
| |
| &IJournal ), // Journal information structure
| |
| 0 ); // Creation flags (defaults)
| |
| } /* end if */
| |
| } /* end if */
| |
| /* end case */</pre>
| |
| '''[[00020.htm|GplJournalPlayInstance]]and [[00021.htm|GplJournalDeleteInstance]]Usage'''
| |
|
| |
| Following are examples of [[00020.htm|GplJournalPlayInstance]]and [[00021.htm|GplJournalDeleteInstance]]during the processing of the end-document escape:
| |
|
| |
| <pre class="western">case DEVESC_ENDDOC:
| |
| {
| |
| if( ulDCType == OD_DIRECT || ulDataType == PM_Q_RAW )
| |
| {
| |
| // If we need to band (that implies journaling)
| |
| if( pddc->fBanding )
| |
| {
| |
| apiret = GplJournalPlayInstance( hJournal,
| |
| PLAY_JOURNAL_BAND |
| |
| PLAY_DESTRUCTIVE |
| |
| PLAY_TOP_TO_BOTTOM );
| |
|
| |
| apiret = GplJournalDeleteInstance( hJournal );
| |
|
| |
| // Remember: Free memory allocated for journal instance handle (hjournal)
| |
|
| |
| } /* end if */
| |
| } /* end if */
| |
| } /* end case */</pre>
| |
| '''[[00022.htm|GplJournalAbortDoc]]Usage'''
| |
|
| |
| Following is an example of [[00022.htm|GplJournalAbortDoc]]usage:
| |
|
| |
| <pre class="western">case DEVESC_ABORTDOC:
| |
| {
| |
| if( ulDCType == OD_DIRECT && ulDataType == PM_Q_RAW )
| |
| {
| |
| // If we have a journal file (that is, we are banding)
| |
| if( pddc->hJournal )
| |
| {
| |
| // Inform journal code that abort condition is in effect
| |
| GplJournalAbortDoc( pddc->hJournal );
| |
|
| |
| } /* end if */
| |
| } /* end if */
| |
| } /* end case */</pre>
| |
| '''[[00023.htm|GplJournalResetAbortDoc]]Usage'''
| |
|
| |
| Following is an example of [[00023.htm|GplJournalResetAbortDoc]]usage:
| |
|
| |
| <pre class="western">case DEVESC_ENDDOC:
| |
| {
| |
| if( ulDCType == OD_DIRECT && ulDataType == PM_Q_RAW )
| |
| {
| |
| // If we have been called with an abort document
| |
| if( pddc->fAbortDocCalled )
| |
| {
| |
| // Inform journal code that abort condition is over
| |
| GplJournalResetAbortDoc( pddc->hJournal );
| |
|
| |
| } /* end if */
| |
| } /* end if */
| |
| } /* end case */</pre>
| |
|
| |
| === Color Dithering ===
| |
| Color dithering is technique of interleaving cyan, magenta, yellow, and optionally black so that the eye perceives another color-such as pink or orange. Color dithering converts picture pels in sizes 2, 4, 8, 16, 24, or 32 bits of RGB/K color to a 3 or 4 bitpel consisting of cyan, magenta, yellow, and optionally K(black). The best dither functions diffuse or spread out colors and also act as a low-pass filter to changes in color. The diffusion of color causes the printing of cyan, magenta, and yellow in the proper density so that from a distance, the eye perceives the correct color.
| |
|
| |
| Following are the dithering functions:
| |
|
| |
| *[[00026.htm|GplDitherCreateInstance]]<br />*[[00027.htm|GplDitherRGBtoCMYK]]<br />*[[00028.htm|GplDitherRGBtoRGB]]<br />*[[00029.htm|GplDitherDeleteInstance]]
| |
|
| |
| Gamma-correction functions are a part of the color-dithering package and are used internally by the dithering code, but they are also available separately. See [[00030.htm|Gamma Correction]].
| |
|
| |
| === GplDitherCreateInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| To optimize throughput, a dither handle is initialized when this function is invoked. This includes allocation and initialization of transform tables and parameters.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplDitherCreateInstance(
| |
| PPVOID ppdh, // Returned pointer to dither handle
| |
| // pointer
| |
| HMCB hmcb, // User-specified memory handle
| |
| PDITHEREQUEST pReq, // Pointer to dither-request structure
| |
| PDITHERESULT pReply ); // Pointer to dither-reply structure</pre>
| |
| '''Parameters'''
| |
|
| |
| '''ppdh'''(''PPVOID'') Pointer to the dither handle pointer that was created and returned by [[00026.htm|GplDitherCreateInstance]].
| |
|
| |
| '''hmcb'''(''HMCB'') If it is not zero, this parameter must be a handle (pointer to the API heap).
| |
|
| |
| '''pReq'''(''PDITHEREQUEST'')
| |
|
| |
| bReq (''BYTE'') Set to CMY_ALL or CMYK_ALL.
| |
|
| |
| lDitherType (''LONG'') From JobProperties.
| |
|
| |
| HT_LEVEL When selected, the following may be ORed with HT_LEVEL:
| |
|
| |
| <pre class="western">HT_PARAMETER
| |
| HT_MIN_COLOR
| |
| HT_PERCENT
| |
| HT_FUNCTION</pre>
| |
| HT_DITHER_4x4 Use a 4x4 halftone pattern for 16 levels of perceived intensity. Also "snap.pHalftone" must be a pointer to a 16x4x4 byte array of dither patterns.
| |
|
| |
| HT_DITHER_8x8 Use a 8x8 halftone pattern for 64 levels of perceived intensity. Also "snap.pHalftone" must be a pointer to a 16x8x8 byte array of dither patterns.
| |
|
| |
| HT_MAGIC_SQUARES A tessalated (tiled) dither that populates a dither matrix to guarantee a semi-random color mix yet controls average occurrence of colors (randomized pattern).
| |
|
| |
| HT_ORDERED_SQUARES Use recursive tesselated tiles of rectangular threshold arrays. Similar to HT_MAGIC_SQUARES, but uses a different method of populating dither matrix.
| |
|
| |
| HT_ERR_DIFFUSION Stucki Error Diffusion-a nice quality filter for photograph-quality images.
| |
|
| |
| HT_FAST_DIFFUSION Error diffusion with lower sampling rate, so error propagated less-essentially, a high-pass filter.
| |
|
| |
| HT_STEINBERG_DIFFUSION Steinberg Error Diffusion-slightly higher pass than Stucki.
| |
|
| |
| SrcOptions (''SRCMODS'') Flags that indicate the state of the buffer information.
| |
|
| |
| fStartOfPage (''BOOL'') Set in users NewFrame function; initialized by SYSTEM.
| |
|
| |
| fNewColors (''BOOL'') Set if pSrcInfo Color Table changes; initialized by SYSTEM.
| |
|
| |
| fModify (''BOOL'') Set if pSrc may be modified for K (Black) when CMY set.
| |
|
| |
| fResetErrBuf (''BOOL'') Set between pages or pictures when Err Buffers must be reset.
| |
|
| |
| ulResetErrBufs (''ULONG'') 0,1,2,or 3 for Diffusion ONLY.
| |
|
| |
| ulValue (''ULONG'') xxx << 20 value to be set as initialization value.
| |
|
| |
| snap (''SNAPIT'') SYSTEM initialized midpoint and function control parameters.
| |
|
| |
| pHalftone (''PRGB2'') Pointer to 4x4 8x8 or user-supplied table.
| |
|
| |
| ulParm (''ULONG'') User-supplied midpoint or function address.
| |
|
| |
| pArray (''PBYTE'') Pointer to 16x16 tables such as paintMixer or OrderSquares.
| |
|
| |
| ulResolution (''ULONG'') The larger of x or y resolution.
| |
|
| |
| iNumColors ( ''INT'') Set by user (2 ** number bits per pel).
| |
|
| |
| iSrcRowPels (''INT'') Number of pels in a source row.
| |
|
| |
| iNumDitherRows (''INT'') Number of rows in a band.
| |
|
| |
| pSrcInfo (''PBITMAPINFO2'') Pointer to user supplied BITMAPINFO2 structure; requires that cx and cy be set.
| |
|
| |
| pbSrc (''PBYTE'') Printer to RGB2 input bitmap (rows are 32bit aligned).
| |
|
| |
| iNumSrcRowBytes32 (''INT'') iDWordBytesInCMYKBandRow.
| |
|
| |
| iNumDestRowBytes (''INT'') iBytesInSinglePlaneBandRow.
| |
|
| |
| delta (''DELTACOLOR'') From JobProperties for tessalated-squares dithering only .
| |
|
| |
| lHue (''LONG'') 0..360 <br />lSaturation (''LONG'') 0..100 <br />lValue (''LONG'') 0..100
| |
|
| |
| fRemoveBlackColor (''BOOL'') Eliminate coincident black and color after dithering.
| |
|
| |
| ulRGamma (''ULONG'') 3 .. 255 true gamma value; actual value times 10.
| |
|
| |
| ulRBias (''ULONG'') 0 .. 255 gamma table minimum value.
| |
|
| |
| ulGGamma (''ULONG'') 3 .. 255 true gamma value.
| |
|
| |
| ulGBias (''ULONG'') 0 .. 255 gamma table minimum value.
| |
|
| |
| ulBGamma (''ULONG'') 3 .. 255 true gamma value.
| |
|
| |
| ulBBias (''ULONG'') 0 .. 255 gamma table minimum value.
| |
|
| |
| '''pReply'''(''PDITHERESULT'') Reply structure is allocated and initialized on return
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR 0 <br />Failure INVALID_PARAMETER
| |
|
| |
| '''Example Code'''
| |
|
| |
| Following is an example of filling the dither-request structure and using GplDitherCreateInstance from the Omni driver during start-document processing:
| |
|
| |
| <pre class="western"> pHandle->Req.iSrcRowPels = iBitsInArray;
| |
|
| |
| // Number of bytes in source, dword aligned
| |
| pHandle->Req.iNumSrcRowBytes32 = iDWordBitsInArray/8;
| |
|
| |
| // Number of bytes in destination, byte aligned
| |
| pHandle->Req.iNumDestRowBytes = iBitsInArray/8;
| |
|
| |
| // Fill in number of colors (derived from bitcount)
| |
| pHandle->Req.iNumColors = Power ( 2, pddc->bmp.cBitCount );
| |
| pHandle->Req.iNumDitherRows = 1;
| |
|
| |
| if( pddc->pdb->pResInfo->ulXRes >= pddc->pdb->pResInfo->ulYRes )
| |
| pHandle->Req.ulResolution = pddc->pdb->pResInfo->ulXRes;
| |
| else
| |
| pHandle->Req.ulResolution = pddc->pdb->pResInfo->ulYRes;</pre>
| |
|
| |
|
| |
| <pre class="western"> /*-------------------*/
| |
| /* Color Technology */
| |
| /*-------------------*/
| |
|
| |
| pHandle->Req.ulRGamma = (ULONG)( pddc->pdb->pDriver->pGammas->pSelect+i )->bRGamma;
| |
| pHandle->Req.ulGGamma = (ULONG)( pddc->pdb->pDriver->pGammas->pSelect+i )->bGGamma;
| |
| pHandle->Req.ulBGamma = (ULONG)( pddc->pdb->pDriver->pGammas->pSelect+i )->bBGamma;
| |
| pHandle->Req.ulRBias = (ULONG)( pddc->pdb->pDriver->pGammas->pSelect+i )->bBias;
| |
| pHandle->Req.ulGBias = (ULONG)( pddc->pdb->pDriver->pGammas->pSelect+i )->bBias;
| |
| pHandle->Req.ulBBias = (ULONG)( pddc->pdb->pDriver->pGammas->pSelect+i )->bBias;
| |
|
| |
| pHandle->Req.ulRGamma = (ULONG)( (LONG)pHandle->Req.ulRGamma + pddc->pdb->
| |
| pJobProperties->lRedGamma );
| |
| pHandle->Req.ulGGamma = (ULONG)( (LONG)pHandle->Req.ulGGamma + pddc->pdb->
| |
| pJobProperties->lGreenGamma );
| |
| pHandle->Req.ulBGamma = (ULONG)( (LONG)pHandle->Req.ulBGamma + pddc->pdb->
| |
| pJobProperties->lBlueGamma );
| |
| pHandle->Req.ulRBias = (ULONG)( (LONG)pHandle->Req.ulRBias + pddc->pdb->
| |
| pJobProperties->lRedBias );
| |
| pHandle->Req.ulGBias = (ULONG)( (LONG)pHandle->Req.ulGBias + pddc->pdb->
| |
| pJobProperties->lGreenBias );
| |
| pHandle->Req.ulBBias = (ULONG)( (LONG)pHandle->Req.ulBBias + pddc->pdb->
| |
| pJobProperties->lBlueBias );</pre>
| |
|
| |
|
| |
| <pre class="western"> /*-------------------*/
| |
| /* Color Algorithm */
| |
| /*-------------------*/
| |
|
| |
| switch ( pddc->pdb->pPrintMode->ulColorTech )
| |
| {
| |
| case COLOR_TECH_CMYK:
| |
| pHandle->Req.bReq = CMYK_ALL;
| |
| break;
| |
|
| |
| case COLOR_TECH_CMY:
| |
| pHandle->Req.bReq = CMY_ALL;
| |
| break;
| |
| }</pre>
| |
|
| |
|
| |
| <pre class="western"> /*-------------------*/
| |
| /* Color Algorithm */
| |
| /*-------------------*/
| |
|
| |
| // Need gamma buffers only if printing in color (CMY/CMYK)
| |
|
| |
| if( pddc->pdb->pPrintMode->ulColorTech != COLOR_TECH_K )
| |
| {
| |
| // Init modify flag telling Gamma/HSV that we may replace/change
| |
| // values in the source bitmap. 1,2,4,8 bit pel bitmaps; then
| |
| // if C,M,Y are to be printed, the RGB index will be set to white.
| |
| // If 16, 24 bit bitmaps, then the R,G,B value is replaced with white.
| |
| pHandle->Req.SrcOptions.fModify = TRUE;</pre>
| |
|
| |
|
| |
| <pre class="western"> /*-------------------*/
| |
| /* HSV */
| |
| /*-------------------*/
| |
|
| |
| pHandle->Req.delta.lHue = pddc->pdb->pJobProperties->lHue;
| |
| pHandle->Req.delta.lSaturation = pddc->pdb->pJobProperties->lSaturation;
| |
| pHandle->Req.delta.lValue = pddc->pdb->pJobProperties->lValue;</pre>
| |
|
| |
|
| |
| <pre class="western"> /*-------------------*/
| |
| /* Dither */
| |
| /*-------------------*/
| |
|
| |
| pHandle->Req.lDitherType = pddc->pdb->pJobProperties->ulAlgorithm;
| |
|
| |
| GPL_DITHER_SETUP_DEFAULTS( pHandle->Req, pddc->pdb->pJobProperties->ulLevel )
| |
| }
| |
|
| |
| // Set printer ' s physical head position in our ddc
| |
| pddc - > ptlPrintHead . x = 0 ;
| |
|
| |
| if ( ORIENTATION _ PORTRAIT = = pddc - > pdb - > pJobProperties - > ulOrientation )
| |
| pddc - > ptlPrintHead . y = pddc - > pdb - > pFormInfo - > hcInfo . yPels - 1 ;
| |
| else
| |
| pddc - > ptlPrintHead . y = pddc - > pdb - > pFormInfo - > hcInfo . xPels - 1 ;
| |
|
| |
|
| |
| GplDitherCreateInstance ( ( PPVOID ) & pHandle - > pdh ,
| |
| pddc - > pdb - > hmcbHeap ,
| |
| ( PDITHEREQUEST ) & pHandle - > Req ,
| |
| ( PDITHERESULT ) & pHandle - > Reply ) ; </pre>
| |
|
| |
|
| |
| <pre class="western"> /*--------------------------------*/
| |
| /* Init Dither Req struct */
| |
| /*--------------------------------*/
| |
|
| |
| pCMYReq->pSrcInfo = pbmi; // Passed to choose rasterize
| |
|
| |
| LOOP { // Each band
| |
|
| |
| // Copy raster bits into our buffer
| |
| pCMYReq->pbSrc = pbBitMap + iCurrentRow * pHandle->Req.iNumSrcRowBytes32;
| |
|
| |
| GplDitherRGBtoCMYK ( (PPVOID)&pHandle->pdh,
| |
| pCMYReq,
| |
| (PDITHERESULT)&pHandle->Reply );</pre>
| |
|
| |
| === GplDitherRGBtoCMYK ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function performs the dithering.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplDitherRGBtoCMYK( PHDITHER pdh,
| |
| PDITHEREQUEST pReq
| |
| PDITHERESULT pReply );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pdh'''(''PHDITHER'') Pointer to the dither handler that was created by [[00026.htm|GplDitherCreateInstance]].
| |
|
| |
| '''pReq'''(''PDITHEREQUEST'') If a diffusion dither algorithm is selected, use the macro GPL_SETUP_DITHER( req, ulLevel ) to set the SrcOptions structure.
| |
|
| |
| '''or'''
| |
|
| |
| If Magic Squares or Ordered Squares is selected, the following fields must be set:
| |
|
| |
| '''lHue'''<br />'''lSaturation'''<br />'''lValue'''Address of the API's pre-stuffed request structure. The following fields must be set by the API:
| |
|
| |
| fNewColors Must be set to TRUE at the beginning of the page. This element is set to FALSE on return.
| |
|
| |
| If fNewColors equals TRUE, the following two fields must be set:
| |
|
| |
| '''ulGamma'''<br />'''lBias'''
| |
|
| |
| pSrcInfo Must have the following two fields set:
| |
|
| |
| '''cx'''<br />'''cy'''
| |
|
| |
| If BitsPerPel is less than 16 and fNewColors equals TRUE, the pbmi array, argbColor[256] must be initialized.
| |
|
| |
| pbSrc Pointer to the surface bitmap.
| |
|
| |
| '''pReply'''(''PDITHERESULT'') Pointer to the reply structure.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR 0 <br />Failure INVALID_PARAMETER
| |
|
| |
| '''Example Code'''
| |
|
| |
| Following is an example of dithering RGB to CMYK data from the Omni driver' s "render" callback function:
| |
|
| |
| <pre class="western">// Change logical height of band bitmap to 1 (this device chooses to dither each scanline)
| |
| ulSavedcy = pddc->pbmi->cy;
| |
| pddc->pbmi->cy = 1;
| |
|
| |
| // For each row in the current band's bitmap (each scanline)
| |
| for( iCurrentRow=ulSavedcy; iCurrentRow > 0; iCurrentRow-- )
| |
| {
| |
| // Set pointer to current row in our band's bitmap
| |
| cmykReq.pbSrc = pbBits + iCurrentRow * iDWordBytesInCMYKBandRow;
| |
|
| |
| GplDitherRGBtoCMYK ( &pddc->pdh, &pddc->cmykReq, &pddc->pReply );
| |
|
| |
| // Now our consecutive KCMY buffers contain dithered data to send to printer
| |
|
| |
| } /* end for */
| |
|
| |
| // Restore bitmap height to TRUE value (no longer 1)
| |
| pddc->pbmi->cy = ulSavedcy;</pre>
| |
|
| |
| === GplDitherRGBtoRGB ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is a shell for [[00027.htm|GplDitherRGBtoCMYK]]. It simply inverts the CMY ''pDest''buffer to RGB for a printer that requires RGB.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplDitherRGBtoRGB( PHDITHER pdh,
| |
| PDITHEREQUEST pReq
| |
| PDITHERESULT pReply );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pdh'''(''PHDITHER'') Pointer to the dither handler that was created by [[00026.htm|GplDitherCreateInstance]].
| |
|
| |
| '''pReq'''(''PDITHEREQUEST'') Address of the API's pre-filled request structure.
| |
|
| |
| '''pReply'''(''PDITHERESULT'') Address of the reply structure.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR
| |
|
| |
| === GplDitherDeleteInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function must be called at the end of a document so that memory that was allocated in [[00026.htm|GplDitherCreateInstance]]can be freed.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplDitherDeleteInstance( PHDITHER pdh );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''pdh'''(''PHDITHER'') Pointer to the dither handler that was created by [[00026.htm|GplDitherCreateInstance]].
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR
| |
|
| |
| '''Example Code'''
| |
|
| |
| Following is an example of using GplDitherDeleteInstance:
| |
|
| |
| <pre class="western">// Tell the dither function to deallocate all it's buffers
| |
| GplDitherDeleteInstance( (HDITHER)pHandle->pdh );
| |
|
| |
| // Reminder:
| |
| // Free all buffers our driver allocated on behalf of GENPLIB's dithering code
| |
| // This includes error buffers for error-diffusion algorithms
| |
| // as well as the destination buffers used for rendering</pre>
| |
|
| |
| === Gamma Correction ===
| |
| Printer paper, ink, resolution, and other characteristics can cause the actual printed color to be different from the desired color. This "skew" is non-linear and occurs over the entire color spectrum. A gamma-compensation curve is used for each color to approximate the non-linear skew. Because the reflected frequencies of colors can cause them to appear different than expected, you can modify the gamma of each color. Increasing the gamma will lighten an image that might otherwise look too dark.
| |
|
| |
| Following are the gamma functions:
| |
| *[[00031.htm|GplGammaCreateTable]]
| |
| *[[00032.htm|GplGammaColorTableToGamma2]]
| |
|
| |
| === GplGammaCreateTable ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function creates an RGB (K) gamma table based on input gammas and bias .
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplGammaCreateTable( PBYTE pbGamma,
| |
| LONG lRgamma,
| |
| LONG lGgamma,
| |
| LONG lBgamma,
| |
| LONG lbias );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pbGamma'''(''PBYTE'') A byte pointer to a 768-byte buffer.
| |
|
| |
| pbGamma can be used as a PRGB2 instead of a PBYTE.
| |
|
| |
| '''lRgamma'''(''LONG'') Red. Gamma multiplied by 10, with a range of 1 to 99.
| |
|
| |
| '''lGgamma'''(''LONG'') Green. Gamma multiplied by 10, with a range of 1 to 99.
| |
|
| |
| '''lBgamma'''(''LONG'') Blue. Gamma multiplied by 10, with a range of 1 to 99.
| |
|
| |
| '''lbias'''(''LONG'') Offset, normally zero, generally for printers over 600 dpi.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success 0 <br />Failure INVALID_PARAMETER
| |
|
| |
| === GplGammaColorTableToGamma2 ===
| |
|
| |
| '''Description'''
| |
|
| |
| For 8-bit pels or less, replaces an RGB color value in the PBITMAPINFO2 argbColor[0..256] structure with a gamma-corrected color value.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplGammaColorTableToGamma2( PBYTE pbGamma,
| |
| PBITMAPINFO2 pbmi );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pbGamma'''(''PBYTE'') A byte pointer to a 768-byte buffer.
| |
|
| |
| pbGamma can be used as a PRGB2 instead of a PBYTE.
| |
|
| |
| '''pbmi'''(''PBITMAPINFO2'') PBITMAPINFO2 is assumed to have a valid RGB2 color table as input. The following PBITMAPINFO2 fields are used:
| |
|
| |
| cBitCount Bits per pel.
| |
|
| |
| argbColor When cBitCount is 8 or less, this parameter must include values for 2 to the power of cBitCount (2**cBitCount).
| |
|
| |
| '''Returns'''
| |
|
| |
| Success 0 <br />Failure INVALID_PARAMETER
| |
|
| |
| === Compression ===
| |
| The compression package contains routines that compress raster image data using common printer hardware-supported compression routines.
| |
|
| |
| Raster printer drivers render on a per-page basis into a raster representation of an output page. As soon as rendering is completed for a given page, that raster data can be compressed into a format that the printer hardware supports. Compressed data is typically smaller than the original uncompressed data and will therefore transmit faster across communication lines to the printer.
| |
|
| |
| '''Note:'''The caller of a compression routine should allocate a buffer to hold the compressed data whose size (in bytes) is as large as the the original uncompressed data.
| |
|
| |
| To use the GenPLib Compression package, you must include:
| |
|
| |
| <pre class="western">INCL_GENPLIB_COMPRESS</pre>
| |
|
| |
|
| |
| Following are the GenPLib compression routines:
| |
|
| |
| *[[00034.htm|GplCompressRLL]]<br />*[[00035.htm|GplCompressTIFF]]<br />*[[00036.htm|GplCompressDeltaRow]]<br />*[[00037.htm|GplCompressRLLDeltaRow]]<br />*[[00038.htm|GplCompressChooseMode]]<br />*[[00039.htm|GplCompressAscii85]]<br />*[[00040.htm|GplFaxG3EncodeBlock]]<br />*"GplFaxG3StartBlock" <br />*"GplFaxG3EndBlock" <br />*"GplFaxG3EndDoc" <br />*"GplFaxG3NewFrame" <br />*[[00041.htm|GplFaxG4EncodeBlock]]<br />*"GplFaxG4EndBlock" <br />*[[00042.htm|GplFaxTIFF2EncodeBlock]]<br />*"GplFaxTIFF2StartBlock" <br />*"GplFaxTIFF2EndBlock"
| |
|
| |
| === GplCompressRLL ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function performs run-length limited (RLL) encoding.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">LONG APIENTRY GplCompressRLL(
| |
| PBYTE pbDataIn, // Input raster data to compress (page/band)
| |
| LONG cbDataIn, // Length of input data buffer (pbDataIn)
| |
| PBYTE pbDataOut, // Output buffer to which compressed data is written
| |
| LONG cbDataOut ); // Length count of compressed data written</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pbDataIn'''(''PBYTE'') Pointer to input data.
| |
|
| |
| '''cbDataIn'''(''LONG'') Count of bytes in, pointed to by pbData.
| |
|
| |
| '''pbDataOut'''(''PBYTE'') Pointer to output data.
| |
|
| |
| '''cbDataOut'''(''LONG'') Size of buffer in bytes pointed to by pbDataOut.
| |
|
| |
| '''Returns'''
| |
|
| |
| Signed LONG, which is the length in bytes of the compressed data pointed to by cbDataOut.
| |
|
| |
| Success Number of bytes in compressed return string.
| |
|
| |
| Failure GPLCOMPRESS_ERROR (-1) <br />The output buffer length has been exceeded.
| |
|
| |
| '''Notes'''
| |
|
| |
| The input data is encoded with pairs of bytes. The first byte is the replacement count and the second byte is the data. A replacement count of 0 means that the data is not repeated.
| |
|
| |
| === GplCompressTIFF ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function performs tagged image file format (TIFF) encoding, PackBits encoding algorithm. This function compresses a scanline.
| |
|
| |
| Once in a repeated run, this function stops and emits a block if a different byte is encountered.
| |
|
| |
| Once in a literal run, this function stops and emits a block if at least four repeated bytes follow. The next block will be a repeat block. Repeats of two or more instances of a byte b are represented by -(n-1) b. Literal runs of different bytes b1 b2 b3 ... bn are represented by (n-1) b1 b2 b3 . .. bn.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">LONG APIENTRY GplCompressTIFF(
| |
| PBYTE pbDataIn, // Input raster data to compress (page/band)
| |
| LONG cbDataIn, // Length of input data buffer (pbDataIn)
| |
| PBYTE pbDataOut, // Output buffer to which compressed data is written
| |
| LONG cbDataOut ); // Length count of compressed data written</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pbDataIn'''(''PBYTE'') Pointer to input data.
| |
|
| |
| '''cbDataIn'''(''LONG'') Count of bytes in.
| |
|
| |
| '''pbDataOut'''(''PBYTE'') Pointer to output data.
| |
|
| |
| '''cbDataOut'''(''LONG'') Size of buffer in bytes pointed to by pbDataOut.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success Count of bytes put in destination. <br />Failure GPLCOMPRESS_ERROR (-1)
| |
|
| |
| === GplCompressDeltaRow ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function performs delta-row encoding. This method replaces only the bytes in a new row that are different from the preceding (seed) row. Unreplaced bytes are replicated from the seed row. The new row then becomes the seed row after it is printed.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">INT APIENTRY GplCompressDeltaRow(
| |
| INT usTotalBytes, // Bytes in the scan line
| |
| PBYTE pbData, // Input raster data to compress
| |
| PBYTE pbLastLine, // Previous scanline's raster data
| |
| INT usMaxReturn, // Length of output buffer
| |
| PBYTE pbReturn, // Output buffer with compressed data
| |
| PUSHORT pDeltas ); // Differences indexes-start/end pairs</pre>
| |
| '''Parameters'''
| |
|
| |
| '''usTotalBytes'''(''INT'') Count of bytes in, pointed to by pbData.
| |
|
| |
| '''pbData'''(''PBYTE'') Pointer to bytes of data to compress.
| |
|
| |
| '''pbLastLine'''(''PBYTE'') Pointer to previous scanline's raster data.
| |
|
| |
| '''usMaxReturn'''(''INT'') Size of output buffer.
| |
|
| |
| '''pbReturn'''(''PBYTE'') Pointer to compressed data will be written.
| |
|
| |
| '''pDeltas'''(''PUSHORT'') Differences indexes = array of start and end pairs.
| |
|
| |
| '''Note:'''This array is returned as the result of calling [[00038.htm|GplCompressChooseMode]]; therefore, you must call GplCompressChooseMode() before calling this function.
| |
|
| |
| '''Returns'''
| |
|
| |
| 0 Current and previous line are identical.
| |
|
| |
| >0 Length of data pointed to by pbReturn.
| |
|
| |
| -1 GPLCOMPRESS_ERROR <br />usMaxReturn is not large enough for the compressed output.
| |
|
| |
| === GplCompressRLLDeltaRow ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function performs RLL delta-row encoding. It compresses a string of bytes and returns the compressed string at pbReturn and the new string usLength as its return value. This method replaces only bytes in the current row that are different from the proceeding seed row. Unlike [[00036.htm|GplCompressDeltaRow]], however, the replacement or delta bytes themselves are encoded.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">INT APIENTRY GplCompressRLLDeltaRow(
| |
| INT usTotalBytes, // Bytes in the scan line
| |
| PBYTE pbData, // Input raster data to compress
| |
| PBYTE pbLastLine, // Previous scanline's raster data
| |
| INT usMaxReturn, // Length of output buffer
| |
| PBYTE pbReturn, // Output buffer with compressed data
| |
| PUSHORT pDeltas ); // Differences indexes-start/end pairs</pre>
| |
| '''Parameters'''
| |
|
| |
| '''usTotalBytes'''(''INT'') Count of bytes pointed to by pbData and pbLastLine.
| |
|
| |
| '''pbData'''(''PBYTE'') Pointer to bytes of data to compress.
| |
|
| |
| '''pbLastLine'''(''PBYTE'') Pointer to previous uncompressed data.
| |
|
| |
| '''usMaxReturn'''(''INT'') Size of output buffer.
| |
|
| |
| '''pbReturn'''(''PBYTE'') Pointer to compressed data will be written.
| |
|
| |
| '''pDeltas'''(''PUSHORT'') Differences indexes = array of start and end pairs.
| |
|
| |
| '''Returns'''
| |
|
| |
| 0 Current and previous line are identical.
| |
|
| |
| >0 Length of data pointed to by pbReturn.
| |
|
| |
| -1 GPLCOMPRESS_ERROR <br />usMaxOutput not large enough for the compressed output.
| |
|
| |
| === GplCompressChooseMode ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function uses a semi-intelligent algorithm to select the compression mode that will most likely give the best compression for the row of data.
| |
|
| |
| '''RLL Delta Row'''is currently chosen if this method best and if the printer supports this compression. '''Delta Row'''is chosen if most of the bytes are the same as the corresponding bytes in the previous row. '''TIFF'''is chosen if most of the bytes are repeated within this row. RLL is chosen if most of the bytes are repeated within this row and the printer does not support TIFF PackBits. '''No compression (value of 0)'''is chosen of most bytes are neither repeats within the row nor duplicates of the previous row.
| |
|
| |
| '''Note:'''The function GplCompressChooseMode() must be run before either of the delta-compression functions [[00036.htm|GplCompressDeltaRow]]() or [[00037.htm|GplCompressRLLDeltaRow]](). This function must be run first because pDelta is filled in by GplCompressChooseMode() while it is reading pbRow and pbLast_ Row. Performance is increased by combining GplCompressChooseMode() with either [[00036.htm|GplCompressDeltaRow]]() or [[00037.htm|GplCompressRLLDeltaRow]]().
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">INT APIENTRY GplCompressChooseMode( PBYTE pbRow,
| |
| PBYTE pbLast_Row,
| |
| INT usRow_Length,
| |
| ULONG CompressModes,
| |
| PUSHORT pDelta );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pbRow'''(''PBYTE'') Pointer to the current row's data.
| |
|
| |
| '''pbLast_Row'''(''PBYTE'') Pointer to the last row's data.
| |
|
| |
| '''usRow_Length'''(''INT'') The number of bytes in the row. Note that both the previous row and the current row are equal in size.
| |
|
| |
| '''CompressModes'''(''ULONG'') Compression modes supported.
| |
|
| |
| This is a ULONG with the follow bit positions used to represent compress modes that this printer supports:
| |
|
| |
| GPLCOMPRESS_NONE <br />GPLCOMPRESS_RLL <br />GPLCOMPRESS_TIFF <br />GPLCOMPRESS_DELTAROW <br />GPLCOMPRESS_RLLDELTAROW
| |
|
| |
| These values may be logically ORed together to create a bitfield of all compression methods to consider. For example,
| |
|
| |
| <pre class="western"> CompressModes = GPLCOMPRESS_RLL | GPLCOMPRESS_TIFF</pre>
| |
| This tells the routine to only choose between the RLL and TIFF compression routines and GPLCOMPRESS_NONE.
| |
|
| |
| '''pDelta'''(''PUSHORT'') Array of unsigned shorts to hold the offsets from the beginning of pbRow that differ from pbLast_Row. This data will be used by [[00036.htm|GplCompressDeltaRow]]and [[00037.htm|GplCompressRLLDeltaRow]]. Note that pDelta must have a length equal to two times usRow_Length plus one to hold the pDelta output . There is no check on the size of pDelta. You must supply a size of a minimum of two times usRow_Length plus one. This is because the maximum number of differences occur when every other byte differs from the preceding row.
| |
|
| |
| '''Returns'''
| |
|
| |
| The mode that will probably compress the best:
| |
|
| |
| 0 No compression <br />1 RLL (run-length limited) compression <br />2 TIFF (tagged image file format) compression <br />3 Delta-row compression <br />9 RLL delta-row compression
| |
|
| |
| '''Notes'''
| |
|
| |
| For [[00036.htm|GplCompressDeltaRow]]and [[00037.htm|GplCompressRLLDeltaRow]], pDelta is filled with the start and end of the difference fragments. Note that a difference fragment is defined as a contiguous group of bytes in the current row that differ from those in the previous row. For example:
| |
|
| |
| <pre class="western">/-----------------------------------------------------------------------\
| |
| |Column Number |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |
| |
| |---------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---|
| |
| |Current Row |7 |8 |1 |0 |4 |5 |6 |7 |23 |128|257|1 |7 |8 |
| |
| |Byte Value | | | | | | | | | | | | | | |
| |
| |---------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---|
| |
| |Previous Row |7 |1 |3 |1 |4 |5 |9 |7 |23 |128|7 |9 |7 |8 |
| |
| |Byte Value | | | | | | | | | | | | | | |
| |
| \-----------------------------------------------------------------------/</pre>
| |
| There are three difference fragments:
| |
|
| |
| *Fragment one begins at column 2 and ends at column 4. <br />*Fragment two begins at column 7 and ends at column 7. <br />*Fragment three begins at column 11 and ends at column 12.
| |
|
| |
| The output in pDelta will be 2 4 7 7 11 12 0. Note that these are unsigned shorts and the difference array is null-terminated. If no difference fragments are found (the previous and current buffers are the same) the first unsigned short in pDelta will be 0.
| |
|
| |
| ''pDelta''above will point to a array of the indexes stored to used by GplCompressDeltaRow() and GplCompressRLLDeltaRow().
| |
|
| |
| '''Example Code'''
| |
|
| |
| Following is an example of GplCompressChooseMode usage from the Omni driver for a typical inkjet device:
| |
|
| |
| <pre class="western">iNewMode = GplCompressChooseMode(
| |
| pbBuffer, // Contains current row of data
| |
| pbLastLine, // Contains previous row of data
| |
| iBytesInRow, // Number of bytes in output row (pbBuffer)
| |
| GPLCOMPRESS_RLL | // All compression modes supported
| |
| GPLCOMPRESS_TIFF,
| |
| pDelta ); // Offsets into pbBuffer ((2 x pbBuffer) + 1)
| |
|
| |
| if( iNewMode != iCurrentMode )
| |
| {
| |
| // Send command to printer to set new mode
| |
| iCurrentMode = iNewMode;
| |
|
| |
| } /* end if */
| |
|
| |
| switch( iNewMode )
| |
| {
| |
| case 0: // No Compression
| |
| break;
| |
| case 1: iCompressed = GplCompressRLL();
| |
| break;
| |
| case 2: iCompressed = GplCompressTIFF();
| |
| break;
| |
| case 3: iCompressed = GplCompressDeltaRow();
| |
| break;
| |
| case 9: iCompressed = GplCompressRLLDeltaRow();
| |
| break;
| |
|
| |
| } /* end switch */
| |
|
| |
| // Write raster data transfer command and compressed data</pre>
| |
|
| |
| === GplCompressAscii85 ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function performs ASCII encoding. It encodes 4 bytes in to 5 bytes out , and it converts data from a base 256 on input to a base-85 representation on output. The output is then output in ASCII with base 85.
| |
|
| |
| Buffer allocation is the responsibility of the driver.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">INT APIENTRY GplCompressAscii85(
| |
| PBYTE pSource, // Source input data buffer (normal Hex 256)
| |
| PBYTE pDest, // Destination output data buffer (ASCII 85)
| |
| INT usSourceLen ); // Source buffer input length</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pSource'''(''PBYTE'') Pointer to input data buffer.
| |
|
| |
| '''pDest'''(''PBYTE'') Pointer to output data buffer. It must be at least 5/4 size of pSource.
| |
|
| |
| '''usSourceLen'''(''LONG'') Length of source buffer in bytes.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success Count of bytes put in destination. <br />Failure GPLCOMPRESS_ERROR (-1)
| |
|
| |
| === GplFaxG3EncodeBlock ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function performs G3 "Fax"-type compression.
| |
|
| |
| It provides a run-length type compression with table-lookup replacement encodings for certain bit sequences. This type of compression is also know as "Modified Huffman."
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">GplFaxG3EncodeBlock( HTHREAD hThread,
| |
| PBYTE pbOutput,
| |
| ULONG ulOutputSize,
| |
| PULONG pulBitposition,
| |
| PBYTE pbInput,
| |
| ULONG ulBitwide,
| |
| ULONG ulBitheight,
| |
| PFN pfnFlushBuffer );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hThread'''(''HTHREAD'') Handle.
| |
|
| |
| '''pbOutput'''(''PBYTE'') Pointer to output buffer to fill.
| |
|
| |
| '''ulOutputSize'''(''ULONG'') Number of output bytes; must be divisible by 4.
| |
|
| |
| '''pulBitposition'''(''PULONG'') Pointer to bit position in output buffer; gets updated and must be stored off the pddc.
| |
|
| |
| '''pbInput'''(''PBYTE'') Input pointer to upper left corner of raster image to compress.
| |
|
| |
| '''ulBitwide'''(''ULONG'') Width of raster image to compress in bits; must be less than or equal to 2560 + 63 = 2623.
| |
|
| |
| '''ulBitheight'''(''ULONG'') Height of raster image to compress in bits.
| |
|
| |
| '''pfnFlushBuffer'''(''PFN'') The prototype for this function must be:
| |
|
| |
| <pre class="western">void pfnFlushBuffer ( PVOID,
| |
| PBYTE,
| |
| ULONG );</pre>
| |
| PVOID Use is the same as G4.
| |
|
| |
| PBYTE Unsigned char * to output buffer; same as pbOutput.
| |
|
| |
| ULONG Unsigned long; size of pbOutput buffer; same as ulOutputSize.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success Count of data written out (compressed data count). <br />Failure GPLCOMPRESS_ERROR (-1)
| |
|
| |
| '''Related Functions'''The following G3 "Fax"-compression related functions provide help in sending down special G3 commands.
| |
|
| |
| GplFaxG3StartBlock() Modified Huffman (MH) Group 3 end of line (EOL) sent at the beginning of the first page. This function outputs the EOL to pbOutput and initializes pulBitposition to 12. It simply sends out the EOL bit sequence to signal the start of raster data (for example, '000000000001 ' binary, eleven 0's and a single 1).
| |
|
| |
| Inputs
| |
|
| |
| pbOutput Output buffer to fill <br />pulBitposition Bit-position count in the output buffer
| |
|
| |
| Returns Void
| |
|
| |
| GplFaxG3EndBlock() End of block flushed.
| |
|
| |
| <pre class="western">GplFaxG3EndBlock( PVOID hThread,
| |
| PBYTE pbOutput,
| |
| ULONG ulOutputSize,
| |
| PULONG pulBitposition
| |
| PFN pfnFlushBuffer );</pre>
| |
| Inputs
| |
|
| |
| hThread PVOID.
| |
|
| |
| pbOutput Output buffer to fill.
| |
|
| |
| ulOutputSize Size in bytes of output buffer; must be a multiple of 32 bits; must be divisible by 4.
| |
|
| |
| pulBitposition Bit-position count in the output buffer; *pulBitposition gets updated and must be stored off the pddc.
| |
|
| |
| pfnFlushBuffer Flush buffer function; prototype for this function must be:
| |
|
| |
| <pre class="western">void pfnFlushBuffer( PVOID,
| |
| PBYTE,
| |
| ULONG );</pre>
| |
| PVOID Use is the same as above.
| |
|
| |
| PBYTE Unsigned char to output buffer; same as pbOutput.
| |
|
| |
| ULONG Unsigned long; size of pbOutput buffer; same as ulOutputSize.
| |
|
| |
| Returns
| |
|
| |
| Success Count of data written out (compressed data count).
| |
|
| |
| Failure GPLCOMPRESS_ERROR (-1).
| |
|
| |
| GplFaxG3EndDoc() Modified Huffman (MH) Group 3 return to control (RTC) sent at the end of document.
| |
|
| |
| <pre class="western">GplFaxG3EndDoc( PVOID hThread,
| |
| PBYTE pbOutput,
| |
| ULONG ulOutputSize,
| |
| PULONG pulBitposition
| |
| PFN pfnFlushBuffer );</pre>
| |
| Inputs
| |
|
| |
| hThread PVOID.
| |
|
| |
| pbOutput Output buffer to fill.
| |
|
| |
| ulOutputSize Size in bytes of output buffer; must be a multiple of 32 bits; must be divisible by 4.
| |
|
| |
| pulBitposition Bit-position count in the output buffer; gets updated and must be stored off the pddc.
| |
|
| |
| pfnFlushBuffer Flush buffer function; prototype for this function must be:
| |
|
| |
| <pre class="western">void pfnFlushBuffer( PVOID,
| |
| PBYTE,
| |
| ULONG );</pre>
| |
| PVOID Use is the same as above.
| |
|
| |
| PBYTE Unsigned char to output buffer; same as pbOutput.
| |
|
| |
| ULONG Unsigned long; size of pbOutput buffer; same as ulOutputSize.
| |
|
| |
| Returns
| |
|
| |
| Success Count of data written out (compressed data count).
| |
|
| |
| Failure GPLCOMPRESS_ERROR (-1).
| |
|
| |
| GplFaxG3NewFrame() Modified Huffman (MH) Group 3 end of line (EOL) sent at the beginning of each new page. This function is the same as GplFaxG3EncodeBlock() except that it flushes data at this point to cause the current page to be completely sent. This call sends compressed data followed by the EOL bit sequence (see GplFaxG3StartBlock).
| |
|
| |
| Instead of GplFaxG3NewFrame() you can use pfnFlushBuffer() = NULL to see whether or not the buffer for GplFaxG3EncodeBlock() is large enough. You output the bytes after GplFaxG3EncodeBlock() returns OK. You can then call GplFaxG3StartBlock(). This function places an EOL in the output buffer and sets the pulBitposition to 12.
| |
|
| |
| <pre class="western">GplFaxG3NewFrame( HTHREAD hThread,
| |
| PBYTE pbOutput,
| |
| ULONG ulOutputSize,
| |
| PULONG pulBitposition
| |
| PFN pfnFlushBuffer );</pre>
| |
| Inputs
| |
|
| |
| hThread HTHREAD
| |
|
| |
| pbOutput Output buffer to fill.
| |
|
| |
| ulOutputSize Size in bytes of output buffer; must be a multiple of 32 bits.
| |
|
| |
| pulBitposition Bit-position count in the output buffer.
| |
|
| |
| pfnFlushBuffer Flush buffer function; prototype for this function must be:
| |
|
| |
| <pre class="western">void pfnFlushBuffer( PVOID,
| |
| PBYTE,
| |
| ULONG );</pre>
| |
| PVOID Use is the same as above.
| |
|
| |
| PBYTE Unsigned char to output buffer; same as pbOutput.
| |
|
| |
| ULONG Unsigned long; size of pbOutput buffer; same as ulOutputSize.
| |
|
| |
| Returns
| |
|
| |
| Success Count of data written out (compressed data count).
| |
|
| |
| Failure GPLCOMPRESS_ERROR (-1)
| |
|
| |
| === GplFaxG4EncodeBlock ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function performs G4 "Fax"-type compression.
| |
|
| |
| It is similar to [[00040.htm|GplFaxG3EncodeBlock]](), but it has five extra parameters. These extra parameters are used to keep track of on/off bit runs between calls.
| |
|
| |
| The driver is again responsible for all memory allocations.
| |
|
| |
| Make sure all buffers for on/off bit tracking are equal to scanline DWORD aligned.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">GplFaxG4EncodeBlock( PVOID pddc,
| |
| PBYTE pbOutput,
| |
| ULONG ulOutputSize,
| |
| PULONG pulBitposition,
| |
| PBYTE pbInput,
| |
| ULONG ulBitwide,
| |
| ULONG ulBitheight,
| |
| PFN pfnFlushBuffer,
| |
| PULONG pulwstartc,
| |
| PULONG pulbstartc,
| |
| PULONG pulwstartp,
| |
| PULONG pulbstartp,
| |
| ULONG ulSkipCount );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pddc'''(''PVOID'') First parameter to pfnFlushBuffer; generally pddc or hThread.
| |
|
| |
| '''pbOutput'''(''PBYTE'') Pointer to output buffer to fill.
| |
|
| |
| '''ulOutputSize'''(''ULONG'') Size in bytes of output buffer; must be a multiple of 32 bits; must be divisible by 4.
| |
|
| |
| '''pulBitposition'''(''PULONG'') Pointer to position in the output buffer; gets updated and must be unique to each print job; *pulBitposition must be zero on the first invocation of this function for a block.
| |
|
| |
| '''pbInput'''(''PBYTE'') Input pointer to upper left corner of raster image to compress.
| |
|
| |
| '''ulBitwide'''(''ULONG'') Width of raster image to compress in bits; must be less than or equal to 2560 + 63 = 2623.
| |
|
| |
| '''ulBitheight'''(''ULONG'') Height of raster image to compress in bits.
| |
|
| |
| '''pfnFlushBuffer'''(''PFN'') The prototype for this function must be:
| |
|
| |
| <pre class="western">void pfnFlushBuffer ( PVOID,
| |
| PBYTE,
| |
| ULONG );</pre>
| |
| PVOID Use is the same as G3; necessary parameter for separating printout; generally pddc or hThread.
| |
|
| |
| PBYTE Unsigned char * to output buffer; same as pbOutput.
| |
|
| |
| ULONG Unsigned long; size of pbOutput buffer; same as ulOutputSize.
| |
|
| |
| pfnFlushBuffer can be either NULL or point to a function that you supply that will write the compressed bytes out. If pfnFlushBuffer is not NULL, this function will be called when output buffer is full. If pfnFlushBuffer is NULL, you must write the bytes out yourself.
| |
|
| |
| If pfnFlushBuffer() = NULL this function will compress the data and place it into pbOutput. If the output buffer size is not large enough for all the compressed data, the function will return with -1 = error. If pfnFlushBuffer() is not NULL, every time pbOutput is full, pfnFlushBuffer( ) is called to write the compressed bytes out. Note that the return value will the total number of bytes written even though the buffer was filled multiple times.
| |
|
| |
| '''pulwstartc'''(''PULONG'') Pointer to array of ULONGs. Its length must be ( ulBitwide + 31 ) / 32 + 2. The 2 extra ULONGs are needed. So for an image of 371 bits width, the length of this array is ( 371 + 31 ) / 32 = 12 plus 2 more-which is 14 unsigned longs. This array is used to store the start bits of the beginning of consecutive 0 bits for the current scan line.
| |
|
| |
| '''pulbstartc'''(''PULONG'') Size is the same calculation as above. This array is used to store the start bits of the beginning of consecutive 1 bits for the current scan line.
| |
|
| |
| '''pulwstartp'''(''PULONG'') Size is the same calculation as above. This array is used to store the start bits of the beginning of consecutive 0 bits for the previous scan line. This must be zero filled on the first invocation of this function.
| |
|
| |
| '''pulbstartp'''(''PULONG'') Size is the same calculation as above. This array is used to store the start bits of the beginning of consecutive 1 bits for the previous scan line. This must be zero filled on the first invocation of this function.
| |
|
| |
| '''ulSkipCount'''(''ULONG'') Number of bytes to skip to the next row of input data to compress.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success Count of data written out (compressed data count). <br />Failure GPLCOMPRESS_ERROR (-1)
| |
|
| |
| '''Related Function'''The following is a G4-compression related function automatically sends the "End Block" data sequence (24 bits represented by Hex 001001).
| |
|
| |
| GplFaxG4EndBlock() Modified Read ( MRR) Group 4 compression with K = infinity for sending end-of-facsimile block (EOFB). This function has the same first eight parameters as GplFaxG4EncodeBlock().
| |
|
| |
| <pre class="western">GplFaxG4EndBlock( PVOID pHandle,
| |
| PBYTE pbOutput,
| |
| ULONG ulOutputSize,
| |
| PULONG pulBitposition,
| |
| PBYTE pbInput,
| |
| ULONG ulBitwide,
| |
| ULONG ulBitheight,
| |
| PFN pfnFlushBuffer );</pre>
| |
| Inputs
| |
|
| |
| pddc PVOID; used as first parameter to the pfnFlushBuffer function; generally the pddc or HTHREAD.
| |
|
| |
| pbOutput Output buffer to fill.
| |
|
| |
| ulOutputSize Size in bytes of output buffer; must be a multiple of 32 bits; must be divisible by 4.
| |
|
| |
| pulBitposition Bit-position count in the output buffer; gets updated and must be unique to each print job.
| |
|
| |
| ulBitwide Width of the raster image in bits.
| |
|
| |
| ulBitheight Height of the raster image in bits.
| |
|
| |
| pfnFlushBuffer Flush buffer function; prototype for this function must be:
| |
|
| |
| <pre class="western">void pfnFlushBuffer( PVOID,
| |
| PBYTE,
| |
| ULONG );</pre>
| |
| PVOID Necessary parameter for separating printout; generally pddc or hThread.
| |
|
| |
| PBYTE Unsigned char * to output buffer; same as pbOutput.
| |
|
| |
| ULONG Unsigned long; size of pbOutput buffer; same as ulOutputSize.
| |
|
| |
| pfnFlushBuffer can be either NULL or point to the function you supply that will write the compressed bytes out. If pfnFlushBuffer is not NULL, this function will be called when the output buffer is full. If pfnFlushBuffer is NULL, you must write the bytes out yourself.
| |
|
| |
| Returns
| |
|
| |
| Success Count of data written out (compressed data count). <br />Failure GPLCOMPRESS_ERROR (-1)
| |
|
| |
| === GplFaxTIFF2EncodeBlock ===
| |
|
| |
| '''Description'''
| |
|
| |
| TIFF algorithm 2 compression. This function essentially provides a " Modified Huffman" G3 compression with no size limits. It is limited only by the byte representation of ULONG (4 Gigabytes).
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">GplFaxTIFF2EncodeBlock( PVOID pHandle,
| |
| PBYTE pbOutput,
| |
| ULONG ulOutputSize,
| |
| PULONG pulBitposition,
| |
| PBYTE pbInput,
| |
| ULONG ulBitwide,
| |
| ULONG ulBitheight,
| |
| PFN pfnFlushBuffer );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pHandle'''(''PVOID'') Pointer to a handle.
| |
|
| |
| '''pbOutput'''(''PBYTE'') Pointer to output buffer to fill.
| |
|
| |
| '''ulOutputSize'''(''ULONG'') Size in bytes of output buffer; must be a multiple of 32 bits; must be divisible by 4.
| |
|
| |
| '''pulBitposition'''(''PULONG'') Pointer to position in output buffer.
| |
|
| |
| '''pbInput'''(''PBYTE'') Input pointer to upper left corner of raster image to compress.
| |
|
| |
| '''ulBitwide'''(''ULONG'') Width of raster image to compress in bits.
| |
|
| |
| '''ulBitheight'''(''ULONG'') Height of raster image to compress in bits.
| |
|
| |
| '''pfnFlushBuffer'''(''PFN'') Flush buffer function; prototype for this function must be:
| |
|
| |
| <pre class="western">void pfnFlushBuffer( PVOID,
| |
| PBYTE,
| |
| ULONG );</pre>
| |
| PVOID Necessary parameter for separating printout; generally pddc or hThread.
| |
|
| |
| PBYTE Unsigned char * to output buffer; same as pbOutput.
| |
|
| |
| ULONG Unsigned long; size of pbOutput buffer; same as ulOutputSize.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success Count of data written out (compressed data count). <br />Failure GPLCOMPRESS_ERROR (-1)
| |
|
| |
| '''Related Functions'''The following are TIFF2-compression related functions.
| |
|
| |
| GplFaxTIFF2StartBlock() TIFF algorithm 2 compression start-of-document function.
| |
|
| |
| Inputs
| |
|
| |
| pulBitposition Bit-position count in the output buffer; *pulBitposition gets updated and must be stored off the pddc; function just sets pulBitposition to 0 (you can do this yourself).
| |
|
| |
| Returns Void
| |
|
| |
| GplFaxTIFF2EndBlock() TIFF algorithm 2 compression to flush output buffer.
| |
|
| |
| <pre class="western">GplFaxTIFF2EndBlock( PVOID pHandle,
| |
| PBYTE pbOutput,
| |
| ULONG ulOutputSize,
| |
| PULONG pulBitposition,
| |
| PBYTE pbInput,
| |
| ULONG ulBitwide,
| |
| ULONG ulBitheight,
| |
| PFN pfnFlushBuffer );</pre>
| |
| Inputs
| |
|
| |
| hThread HTHREAD.
| |
|
| |
| pbOutput Output buffer to fill.
| |
|
| |
| ulOutputSize Size in bytes of output buffer; must be divisible by 4.
| |
|
| |
| pulBitposition Bit-position count in the output buffer; must be a multiple of 32 bits; gets updated and must be stored off the pddc.
| |
|
| |
| pbInput Input pointer to upper left corner of raster image to compress.
| |
|
| |
| ulBitwide Width of the raster image in bits.
| |
|
| |
| ulBitheight Height of the raster image in bits.
| |
|
| |
| pfnFlushBuffer Flush buffer function; prototype for this function must be:
| |
|
| |
| <pre class="western">int pfnFlushBuffer( HTHREAD,
| |
| PBYTE,
| |
| ULONG );</pre>
| |
| HTHREAD Gotten from GplThreadCreateInstance().
| |
|
| |
| PBYTE Unsigned char to output buffer; same as pbOutput.
| |
|
| |
| ULONG Unsigned long; size of pbOutput buffer; same as ulOutputSize.
| |
|
| |
| Returns
| |
|
| |
| TRUE If OK <br />FALSE If error
| |
|
| |
| === Exception Management ===
| |
| This package contains functions for setting errors with WinSetErrorInfo and logging appropriate warnings, exceptions, and error codes.
| |
|
| |
| Four ascending severity levels are defined for error messages:
| |
|
| |
| Warning The function detected a problem, took corrective action, and was able to complete processing successfully.
| |
|
| |
| Error The function detected a problem for which no sensible corrective action is possible. The function is not executed and the system remains at the same state as when the function was requested.
| |
|
| |
| Severe Error The function detected a problem from which the system cannot reestablish its state. The function has partially executed and the application must now make some corrective action to restore the system to a known state.
| |
|
| |
| Unrecoverable Error The function detected an error from which it is impossible for the system to reestablish the state that it held at the time that the function was called. It is also impossible for the application to restore the system to a known state.
| |
|
| |
| To use the GenPLib Exception-Management package, you must include:
| |
|
| |
| <pre class="western">INCL_GENPLIB_ERROR</pre>
| |
|
| |
| The following functions are included in the package:
| |
|
| |
| [[00044.htm|GplErrSetDosError]]<br />[[00045.htm|GplErrSetError]]<br />[[00046.htm|GplErrSetSevereError]]<br />[[00047.htm|GplErrSetWarning]]<br />[[00048.htm|GplErrSetUnrecoverableError]]
| |
|
| |
| === GplErrSetDosError ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function saves DOS error.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">ERRORID APIENTRY GplErrSetDosError( USHORT usDosError );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''usDosError'''(''USHORT'') Any error code defined in BSEERR.H that best identifies the failing event.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success ERRORID <br />Failure None
| |
|
| |
| === GplErrSetError ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function saves an error.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">ERRORID APIENTRY GplErrSetError( USHORT usError );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''usError'''(''USHORT'') Any error code defined in PMERR.H that best identifies the failing event.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success ERRORID <br />Failure None
| |
|
| |
| === GplErrSetSevereError ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function saves a severe error.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">ERRORID APIENTRY GplErrSetSevereError( USHORT usError );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''usError'''(''USHORT'') Any error code defined in PMERR.H that best identifies the failing event.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success ERRORID <br />Failure None
| |
|
| |
| === GplErrSetWarning ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function saves the error warning.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">ERRORID APIENTRY GplErrSetWarning( USHORT usError );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''usError'''(''USHORT'') Any error code defined in PMERR.H that best identifies the failing event.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success ERRORID <br />Failure None
| |
|
| |
| === GplErrSetUnrecoverableError ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function saves an unrecoverable error.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">ERRORID APIENTRY GplErrSetUnrecoverableError( USHORT usError );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''usError'''(''USHORT'') Any error code defined in PMERR.H that best identifies the failing event.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success ERRORID <br />Failure None
| |
|
| |
| === Memory Management ===
| |
| This package manages global and process (shared and non-shared) memory areas (heaps) using a single handle to a memory control block (HMCB) for all allocations. Therefore, you do not need to manage different heap or memory handles within your code.
| |
|
| |
| This package calls appropriate OS/2 system APIs for memory creation and allocation. Dosxxx, SSxxx, and other API decisions are optimized for current OS/2 version performance. Examples include the underlying file system paging architecture and the number of processes in system.
| |
|
| |
| Memory areas (heaps) are automatically grown when the initial memory size runs out. Committing more memory than needed is not required. Your code can use a single HMCB and underlying code will manage multiple memory areas ( heaps) if necessary.
| |
|
| |
| Sets of debug trace information are displayed whenever memory is overwritten by other processes or writes to memory exceed the allocation size. Memory that has been allocated and not freed (memory leaks) is also shown as debug information.
| |
|
| |
| To use the GenPLib Memory-Management package, you must include:
| |
|
| |
| <pre class="western">INCL_GENPLIB_MEMORY</pre>
| |
|
| |
|
| |
| The following APIs comprise the GenPLib Memory-Management package:
| |
|
| |
| *[[00051.htm|GplMemoryCreateInstance]]<br />*[[00052.htm|GplMemoryDeleteInstance]]<br />*[[00053.htm|GplMemoryAlloc]]<br />*[[00054.htm|GplMemoryFree]]<br />*[[00055.htm|GplMemoryGetObjectSize]]<br />*[[00056.htm|GplMemorySetUserID]]
| |
|
| |
| === Call Flow ===
| |
| The [[00051.htm|GplMemoryCreateInstance]]() function should be the first memory API called in order to get a handle to a memory control block (HMCB). The HMCB handles all memory allocations. Using an HMCB, any number of memory allocations can be made using [[00053.htm|GplMemoryAlloc]](). These allocations should be freed using [[00054.htm|GplMemoryFree]].
| |
|
| |
| [[00052.htm|GplMemoryDeleteInstance]]() is used when the HMCB is no longer needed for memory allocations.
| |
|
| |
| '''Note:'''Any memory that was allocated using [[00053.htm|GplMemoryAlloc]]() using an HMCB being deleted by [[00052.htm|GplMemoryDeleteInstance]]and not freed by a corresponding [[00054.htm|GplMemoryFree]]() call will be shown as debug output (with location of function where allocation was done) for developers to correct memory leaks within their code.
| |
|
| |
| === GplMemoryCreateInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function creates an MCB and a user heap.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">HMCB APIENTRY GplMemoryCreateInstance( ULONG ulPrimarySize,
| |
| ULONG ulExtSize,
| |
| ULONG ulThreshold,
| |
| ULONG ulType );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''ulPrimarySize'''(''ULONG'') Initial Heap size in bytes.
| |
|
| |
| '''ulExtSize'''(''ULONG'') Heap growth size fills in bytes.
| |
|
| |
| '''ulThreshold'''(''ULONG'') Threshold for heap allocation. Requests larger than this will be converted to DosAllocMem.
| |
|
| |
| '''ulType'''(''ULONG'') Heap type (process, shared). See the following notes for a description of process and shared heaps.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success Valid handle to memory control block. Failure NULL. <br />WinGetLastError() will return one of the following: <br />PMERR_MEMORY_ALLOCATION_ERROR <br />PMERR_INV_OR_INCOMPAT_OPTIONS
| |
|
| |
| '''Notes'''
| |
|
| |
| Treat creating a memory instance like creating a memory heap. The ulSize parameter should be a reasonable amount of memory for most of your processing. It is not necessary to set ulSize to a high number so that you do not run out of memory, because the memory area will automatically grow if your processing allocates more than the amount originally set by ulSize.
| |
|
| |
| When the memory area is automatically grown, the ulExtSize value is used to determine how large an additional memory area should be created. A default value of 0 (zero) may be used, and the growth size will be tailored to a reasonable amount for the OS/2 version.
| |
|
| |
| The [[00053.htm|GplMemoryAlloc]]() API will allocate memory blocks differently based on the ulThreshold value. Typically, allocations of memory of sizes less than the threshold are allocated in a fast access memory area, and sizes larger than the threshold are allocated from a different memory pool. A default value of 0 (zero) may be used and the threshold will be automatically set to perform most efficiently on the current OS/2 version.
| |
|
| |
| The ulType parameter allows you to specify the type of memory that you want to allocate. This defines the scope of accessibility to the memory within your driver or program and is one of the following:
| |
|
| |
| '''SHARED_MEMORY'''Used to create a global memory area (heap). For example, it is used for allocating global data like string tables in a printer driver.
| |
|
| |
| '''PROCESS_MEMORY'''Used to create a per process memory area (heap). For example , it is used for allocating a per device context (DC) memory in a printer driver.
| |
|
| |
| === GplMemoryDeleteInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function frees memory heap(s) for the user.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplMemoryDeleteInstance( HMCB hMCB );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''hMCB'''(''HMCB'') Pointer to memory allocated.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR. <br />Returns valid handle to memory control block. Failure ERROR_INVALID_PARA <br />or return values from: <br />SSFreeMem <br />DosFreeMem <br />DosSubUnsetMem <br />WinGetLastError() returns one of the following: <br />PM_INV_OR_INCOMPAT_OPTIONS <br />PMERR_MEMORY_DEALLOCATION_ERR
| |
|
| |
| === GplMemoryAlloc ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function allocates memory for the user.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">PVOID APIENTRY GplMemoryAlloc( HMCB hMCB,
| |
| ULONG ulSize );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hMCB'''(''HMCB'') Handle to memory control block.
| |
|
| |
| '''ulSize'''(''ULONG'') Amount to allocate.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success Valid pointer to memory allocated. Failure NULL. <br />WinGetLastError() returns one of the following: <br />PMERR_INV_OR_INCOMPAT_OPTIONS <br />PMERR_INSUFFICIENT_MEMORY
| |
|
| |
| === GplMemoryFree ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function frees memory for a user.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplMemoryFree( PVOID pData );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''pData'''(''PVOID'') Pointer to memory allocated.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR. Failure ERROR_INVALID_PARA <br />or return values from: <br />SSFreeMem <br />DosFreeMem <br />DosSubFreeMem <br />WinGetLastError() returns one of the following: <br />PM_INV_OR_INCOMPAT_OPTIONS <br />PMERR_MEMORY_DEALLOCATION_ERR
| |
|
| |
| === GplMemoryGetObjectSize ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function returns the size of a memory object allocated by [[00053.htm|GplMemoryAlloc]].
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">LONG APIENTRY GplMemoryGetObjectSize( PVOID pData );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''pData'''(''PVOID'') Pointer to object.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success Size of memory object.
| |
|
| |
| (LONG) lsize
| |
|
| |
| Failure 0, no size found for memory object. WinGetLastError will return PMERR_INVALID_PARAMETERS (meaning pData was invalid or NULL).
| |
|
| |
|
| |
| === GplMemorySetUserID ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is optional, and it is helpful in debugging. You attach a pointer to the heap instance (like your pddc or pdb)-this extra pointer can then be viewed under the kernel debugger.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">VOID APIENTRY GplMemorySetUserID( HMCB hMCB,
| |
| ULONG ulUserID );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hMCB'''(''HMCB'') Handle to memory control block.
| |
|
| |
| '''ulUserID'''(''ULONG'') Pointer to something helpful.
| |
|
| |
| === Implementation ===
| |
| The GenPLib Memory-Management package was created to provide consistency and to simplify the growth and management of heaps.
| |
|
| |
| This package was one of the first developed for driver use. When writing a driver "from scratch" or modifying a driver to use GenPLib, begin with this package because many of the other GenPLib packages require memory allocated in the unique format of the memory-management package.
| |
|
| |
| Previously, all drivers had to manage their own memory heaps, often using memory allocation packages exported from other parts of the OS/2 system-for example, the INCL_WINHEAP functions from PM WIN or the Subsystem Allocation routines in the PM Graphics Rendering Engine (GRE). It was never clear what routines should be used in a presentation driver or where they should be used (especially for portability). Many of these packages did not allow the caller to grow their heaps, provided no controls for memory leakage, and had no validation or recovery when a driver terminated unexpectedly.
| |
|
| |
| A typical raster printer driver creates two types of heaps: a shared heap during Dynamic Link Library (DLL) initialization processing, and a per-DC heap when the PM GRE enables the driver during the FILL_PHYSICAL (02 Hex) subfunction. These heaps are freed during corresponding DLL termination and DISABLE_PHYSICAL calls to the driver.
| |
|
| |
| In addition, a per-process heap is also created for the OS2_PM_DRV_DEVMODE entry point in a printer presentation driver. This entry point causes the driver to display its printer and job properties dialogs to the user or to retrieve printer and job property information for a specific output device/ destination.
| |
|
| |
| A typical driver initially allocates a 256KB shared global heap and a 100KB per-DC heap and elects to use the memory package's default heap growth size and threshold for larger allocations (achieved by passing in 0L for parameters 2 and 3 for [[00052.htm|GplMemoryDeleteInstance]]).
| |
|
| |
| In case of unexpected driver termination, a driver should register a per- process exception handler for each of the major presentation driver entry points. This exception handler can contain cleanup code that frees any per- process heaps created using [[00051.htm|GplMemoryCreateInstance]]in case any code problems cause an exception to occur.
| |
|
| |
| One major benefit of the GenPLib memory code is the ability to detect memory leaks (memory a driver allocates but never frees). Whenever a call to [[00052.htm|GplMemoryDeleteInstance]]is made, all memory allocated from the heap is freed so that no leaks can occur. If the debug version of the GenPLib library is used, while [[00052.htm|GplMemoryDeleteInstance]]is cleaning up memory areas that a developer forgot to free, it will inform the developer on a debugging terminal which line of code allocated the memory that was not freed. This is possible because the memory-management package records the function address (and other information) from where [[00053.htm|GplMemoryAlloc]]is called.
| |
|
| |
| An OS/2 presentation driver must consider the memory constraints of the user and other programs in the system. In the past, drivers allocated large heaps, hoping the memory an application needed would never overrun the amount initially allocated and cause an exception. Under the paging architecture of OS/2 Warp, however, all the heap memory is often committed during heap creation.
| |
|
| |
| All this memory could be forced in and never used by an application (for example, an application queries the driver for the devices it supports and performs no output). In this case, the driver's memory pages would not be touched, so OS/2 would slowly page it out and give it back to the applications that had it in the first place. As a result, a good deal of swapping could occur for active addressable memory, especially on low-RAM systems. The alternative was to force the driver to manage its own heap growth and consolidate multiple heaps.
| |
|
| |
| Using the GenPLib Memory-Management package, the heap is identified to the driver as a generic handle to a memory control block (HMCB), not as an address into memory. This handle is supplied by [[00051.htm|GplMemoryCreateInstance]]and is used to identify the heap for all subsequent memory allocations and frees.
| |
|
| |
| Therefore, a reasonable initial heap can be created that is just large enough to allow the driver to enable and respond to basic queries. As applications use the driver to render graphics (or other memory-intensive operations), the memory package detects when a given [[00053.htm|GplMemoryAlloc]]call will overflow the current heap and grows it by a default or specified size. The caller does not ever need to know that the heap has grown because it continues to use the same HMCB, while the memory package chains these heaps together.
| |
|
| |
| === Example Code ===
| |
|
| |
| '''Creating and Allocating From a Per-DC Heap'''
| |
|
| |
| Following is an example of creating and allocating from a per-DC heap during a printer-driver enable via the OS2_PM_DRV_ENABLE entry point:
| |
|
| |
| <pre class="western">ULONG APIENTRY OS2_PM_DRV_ENABLE( ULONG ulSubFunc, ULONG p1, ULONG p2 )
| |
| {
| |
| switch( ulSubFunc ) // Determine which enable/disable subfunction
| |
| {
| |
| case FILL_PHYSICAL: // Enable subfunction
| |
| {
| |
| // Create a per-DC memory area (heap)
| |
| hmcbHeap = GplMemoryCreateInstance(
| |
| LEN_DCHEAP, // Size of DC Heap (80K)
| |
| 0L, // Default extent
| |
| 0L, // Default threshold
| |
| PROCESS_MEMORY ); // Type of heap (define in GPLMEM.H)
| |
|
| |
| // If GplMemoryCreateInstance succeeded
| |
| if(hmcbHeap != NULL);
| |
| {
| |
| // Allocate PDEVICEBLOCK
| |
| pddc->pdb = ( PDEVICEBLOCK ) GplMemoryAlloc( hmcbHeap, sizeof( DEVICEBLOCK ) );
| |
|
| |
| } /* end if */
| |
| } /* end case */
| |
| break;
| |
| } /* end switch */
| |
| } /* end OS2_PM_DRV_ENABLE */</pre>
| |
| '''Note:'''System memory must be used when passing data buffers to PrtWrite() calls.
| |
|
| |
| '''Creating a Global Heap'''
| |
|
| |
| Following is an example of creating a global heap:
| |
|
| |
| <pre class="western">ULONG APIENTRY _DLL_InitTerm( ULONG hThisModule, ULONG ulFlag )
| |
| {
| |
| switch( ulFlag ) // Flag to determine which load/unload module subfunction
| |
| {
| |
| case 0: // Load module
| |
| {
| |
| // Create a global heap
| |
| globals.pvHeap = GplMemoryCreateInstance(
| |
| LEN_SHAREDHEAP, // Initial size (256K)
| |
| 0, // Default extent
| |
| 0, // Default threshold
| |
| SHARED_MEMORY); // Type of heap (defined in GPLMEM.H)
| |
| } /* end case */
| |
| break;
| |
| } /* end switch */
| |
| } /* end _DLL_InitTerm */</pre>
| |
| '''Allocating From a Global Heap'''
| |
|
| |
| Following is an example of allocating from a global heap:
| |
|
| |
| <pre class="western">switch( ulSubFunc ) // Determine which enable/disable subfunction
| |
| {
| |
| case FILL_LOGICAL: // Enable subfunction
| |
| {
| |
| // For every string in our driver's string resource table
| |
| for( i=0; i < STRING_TABLE_SIZE; i++ )
| |
| {
| |
| // Load each string from resource table (returns length)
| |
| sLen = WinLoadString (szTemp);
| |
|
| |
| // Allocate memory to hold string just loaded from global heap
| |
| globals.pbStringTable[i] = GplMemoryAlloc( globals.pvSharedHeap, sLen+1 );
| |
|
| |
| // Copy string from temporary buffer to our driver's global string table
| |
| strcpy( globals.pbStringTable[i], szTemp );
| |
|
| |
| } /* end for */
| |
| break;
| |
| } /* end case */
| |
| } /* end switch */</pre>
| |
| '''Deleting a Per-DC Heap'''
| |
|
| |
| Following is an example of deleting a per-DC heap:
| |
|
| |
| <pre class="western">ULONG APIENTRY OS2_PM_DRV_ENABLE( ULONG ulSubFunc, ULONG p1, ULONG p2 )
| |
| {
| |
| switch( ulSubFunc )
| |
| {
| |
| case DISABLE_PHYSICAL:
| |
| {
| |
| // Free per-DC heap after freeing per-DC memory objects
| |
| GplMemoryDeleteInstance( hmcbHeap );
| |
|
| |
| } /* end case */
| |
| break;
| |
| } /* end switch */
| |
| } /* end OS2_PM_DRV_ENABLE */</pre>
| |
| '''Deleting a Global Heap'''
| |
|
| |
| Following is an example of deleting a global heap:
| |
|
| |
| <pre class="western">ULONG APIENTRY _DLL_InitTerm( ULONG hThisModule, ULONG ulFlag )
| |
| {
| |
| switch( ulFlag )
| |
| {
| |
| case 1:
| |
| {
| |
| // Free global heap after freeing global memory objects
| |
| GplMemoryDeleteInstance( globals.pvSharedHeap );
| |
|
| |
| } /* end case */
| |
| break;
| |
| } /* end switch */
| |
| } /* end _DLL_InitTerm */</pre>
| |
|
| |
| === Output-Thread Management ===
| |
| The output-thread management module provides a way to create multiple output threads that will manage the sending of data buffers to the printer. This functionality has also been called ''second-thread code''; however, the implementation allows a separate thread per physical output address (for example, LPT, COM, and file).
| |
|
| |
| This package seamlessly manages multiple buffer allocations and chains them together. It adjusts the internal data buffering to always try to keep the printer busy processing data. The functions assure that buffer sizes and their reuse align for the best performance with the system-memory memory model (for example, the OS/2 paging architecture).
| |
|
| |
| '''Note:''' You may override the default buffer size and the maximum number of buffers to create.
| |
|
| |
| Other benefits of using the separate output-thread code in your driver include:
| |
|
| |
| *Ability to pass off data buffers as fast as you can fill them without waiting for a device with slower transfer speeds
| |
|
| |
| *Unknowingly, the OS/2 PM graphics engine (and other system components) might have locked down system resources, such as fonts, while calling your driver. Therefore, implementing the thread code allows you to return to the graphics engine and free up the resource for other parts of the system, such as the display. This makes the system and applications more responsive to the user.
| |
|
| |
| *The package uses the GenPLib Exception-Management package for simple debug tracing.
| |
|
| |
| *The package uses the GenPLib Memory-Management package for allocation of instance data.
| |
|
| |
| To use the GenPLib Output-Thread Management package, you must include:
| |
|
| |
| <pre class="western">INCL_GENPLIB_THREAD</pre>
| |
|
| |
|
| |
| Following are the Output-Thread Management APIs:
| |
|
| |
| *[[00061.htm|GplThreadCreateInstance]]
| |
| *[[00062.htm|GplThreadStart]]
| |
| *[[00063.htm|GplThreadOutput]]
| |
| *[[00064.htm|GplThreadEnd]]
| |
| *[[00065.htm|GplThreadDeleteInstance]]
| |
| *[[00066.htm|GplThreadAbortDoc]]
| |
| *[[00067.htm|GplThreadResetAbortDoc]]
| |
| *[[00068.htm|GplThreadFlushBuffer]]
| |
| *[[00069.htm|GplThreadHookDeviceWrites]]
| |
|
| |
| === Call Flow ===
| |
| The thread instance (data and semaphores) is initialized; but a real thread is not spun off until you are certain that the application is really sending data to be printed. Therefore, you can systematically use [[00061.htm|GplThreadCreateInstance]]() at enable and [[00062.htm|GplThreadStart]]() at the first data write. This keeps the code straightforward.
| |
|
| |
| === GplThreadCreateInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is used to allocate and initialize thread instance data. This function must be called before making any other thread calls in order to get a thread instance handle (HTHREAD). Semaphores and buffers are not created or allocated by this call.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">BOOL APIENTRY GplThreadCreateInstance( HMCB hMcb
| |
| HMODULE hMod,
| |
| HTHREAD *phThread,
| |
| PVOID pvUserData );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hMcb'''(''HMCB'') Handle to the memory control block (See [[00049.htm|Memory Management]]).
| |
|
| |
| '''hMod'''(''HMODULE'') Handle of calling module. Used for exception management and error logging.
| |
|
| |
| '''*phThread'''(''HTHREAD'')-output Thread instance handle.
| |
|
| |
| '''pvUserData'''(''PVOID'')-output This is used in debugging and is optional. It is recommended that you place a helpful pointer, such as your pddc or pdb pointer.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === GplThreadStart ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function starts or updates thread parameters. It creates semaphores and buffers, committing system resources.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">BOOL APIENTRY GplThreadStart( HTHREAD hThread,
| |
| LHANDLE hSpooler,
| |
| HFILE hDev,
| |
| ULONG ulBufferSize,
| |
| USHORT usMaxBuffers,
| |
| UCHAR ucAbortChar,
| |
| ULONG ulAbortCharCount,
| |
| ULONG ulAbortBufferSize,
| |
| PBYTE pbAbortBuffer,
| |
| PSZ pszAbortString,
| |
| PSZ pszLogAddress,
| |
| PSZ pszWriteError,
| |
| PSZ pszDeviceDescription,
| |
| LONG lDCType );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hThread'''(''HTHREAD'') Instance handle of thread to start. Returned by [[00061.htm|GplThreadCreateInstance]].
| |
|
| |
| '''hSpooler'''(''LHANDLE'') Handle to Spooler (OD_QUEUED). Returned from SplQmOpen. May be zero (0) if hDev is supplied.
| |
|
| |
| '''hDev'''(''HFILE'') Handle to Device (OD_DIRECT). Returned from PrtOpen. May be zero (0) if hSpooler is supplied.
| |
|
| |
| '''ulBufferSize'''(''ULONG'') Size of buffer allocations. May be 0 to use default size.
| |
|
| |
| '''usMaxBuffers'''(''USHORT'') Maximum number of buffers to create. May be 0 to use default # of buffers.
| |
|
| |
| '''ucAbortChar'''(''UCHAR'') Character to send before the abort string. ucAbortChar can be used for devices that need to be sent a number of bytes before the abort string can be sent. ulAbortChar is sent first during the abort sequence.
| |
|
| |
| '''ulAbortCharCount'''(''ULONG'') Number of ucAbortChars to send to the device.
| |
|
| |
| '''ulAbortBufferSize'''(''ULONG'') Abort buffer size in bytes.
| |
|
| |
| '''pbAbortBuffer'''(''PBYTE'') Pointer to buffer to send when aborting a job. Buffer must not be deleted until after [[00064.htm|GplThreadEnd]]. ulAbortBuffer is sent after ulAbortChar.
| |
|
| |
| '''pszAbortString'''(''PSZ'') Abort job reset command for your specific printer language. May be NULL and no string will be sent. pszAbortString is sent last in the abort sequence.
| |
|
| |
| '''pszLogAddress'''(''PSZ'') File or port name (for example, LPT1). Used for error reporting. May be NULL.
| |
|
| |
| '''pszWriteError'''(''PSZ'') Error prompt string to display in a SplMsgBox (for example, "Unable to write to printer"). May be NULL.
| |
|
| |
| '''pszDeviceDescription'''(''PSZ'') Device description to display in a SplMsgBox ( for example, "Laserprinter"). May be NULL.
| |
|
| |
| '''lDCType'''(''LONG'') DC type (OD_QUEUED, OD_DIRECT).
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| '''Notes'''
| |
|
| |
| ulAbortChar is sent first during the abort sequence. <br />ulAbortBuffer is sent after ulAbortChar. <br />pszAbortString is sent last in the abort sequence.
| |
|
| |
| === GplThreadOutput ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is used to pass data to a thread instance (referenced by the thread instance handle passed in) for output. [[00062.htm|GplThreadStart]]must be called prior to calling GplThreadOutput.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">BOOL APIENTRY GplThreadOutput( HTHREAD hThread,
| |
| PBYTE pBytes,
| |
| ULONG ulCount,
| |
| ULONG fulDataType );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hThread'''(''HTHREAD'') Thread instance handle.
| |
|
| |
| '''pBytes'''(''PBYTE'') Pointer to data to buffer.
| |
|
| |
| '''ulCount'''(''ULONG'') Size of data (byte size) pointed to by pBytes parameter
| |
|
| |
| '''fulDataType'''(''ULONG'') Data type flag.
| |
|
| |
| THREAD_DT_PRINTERLANGUAGE Data is printer language commands and only requires an abort string to be sent when aborting during this buffer. See pszAbortString in [[00062.htm|GplThreadStart]].
| |
|
| |
| THREAD_DT_BINARY Data is binary (raster) data and requires a series of bytes to be sent to ensure the printer is not in binary transfer mode before the abort string can be sent. See ucAbortChar in [[00062.htm|GplThreadStart]].
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === GplThreadEnd ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function frees up any resources allocated by the thread instance ( semaphores and data buffers). A call to this function implies that any remaining data buffers are flushed before the return of this call. This call is the logical pair to GplThreadCreate, which allocates system resources.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">BOOL APIENTRY GplThreadEnd( HTHREAD hThread );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''hThread'''(''HTHREAD'') Handle to thread instance.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === GplThreadDeleteInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is used to free thread instance data allocated by a corresponding call to [[00061.htm|GplThreadCreateInstance]]().
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">BOOL APIENTRY GplThreadDeleteInstance( HTHREAD *phThread );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''phThread'''(''HTHREAD'') Pointer to the thread instance handle to be freed.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === GplThreadAbortDoc ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is called to abort output from the thread that is referenced by the thread instance handle that was passed in. After output is stopped, the function will attempt to restore the printer to a known state where it can process data from another print job.
| |
|
| |
| The first issue to consider when using this function is that the device may be executing a command that has a large amount of data that it is expecting to receive as a block. Therefore the parameter ulAbortChar passed in on [[00062.htm|GplThreadStart]]is sent ulAbortCharCount times.
| |
|
| |
| The second issue to consider is that the abort string 'pszAbortString' provided in [[00062.htm|GplThreadStart]]() is sent last.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">BOOL APIENTRY GplThreadAbortDoc( HTHREAD hThread );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''hThread'''(''HTHREAD'') Handle to thread instance.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === GplThreadResetAbortDoc ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is used to resolve any previous calls to [[00066.htm|GplThreadAbortDoc]]() so that another job can start printing using the same thread instance handle.
| |
|
| |
| This function will wait, if necessary, for the abort processing started by [[00066.htm|GplThreadAbortDoc]]to be completed before returning so that the thread instance can be put into a state to receive data from a new print job.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">BOOL APIENTRY GplThreadResetAbortDoc( HTHREAD hThread );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''hThread'''(''HTHREAD'') Handle to thread instance.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === GplThreadFlushBuffer ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function causes all data buffers currently being managed by the thread instance to be flushed (written) to their final output destination (for example, parallel port and spool file).
| |
|
| |
| This call allows a flag to be set so that all the data buffers are sent ( flushed) before this call returns (fwait == TRUE) or synchronously (fwait = = FALSE).
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">BOOL APIENTRY GplThreadFlushBuffer( HTHREAD hThread,
| |
| BOOL fWait );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hThread'''(''HTHREAD'') Handle to thread instance.
| |
|
| |
| '''fWait'''(''BOOL'') Flag indicating flush asynchronously or synchronously.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === GplThreadHookDeviceWrites ===
| |
|
| |
| '''Description'''
| |
|
| |
| This is an optional function. This call was created because a class of devices added to the Omni driver did not set status lines according to known standard protocols. Calling this function allows the Omni driver to interpret the status lines because it knows about the devices' special protocols.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">BOOL APIENTRY GplThreadHookDeviceWrites( HTHREAD hThread,
| |
| PFN PfnPrtWrite,
| |
| pddc );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hThread'''(''HTHREAD'') Handle to thread instance.
| |
|
| |
| '''pfnPrtWrite'''(''PFN'') Our function.
| |
|
| |
| '''pddc'''Parameter to our function.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success TRUE <br />Failure FALSE
| |
|
| |
| === Implementation ===
| |
| After the memory-management package is implemented, the next logical package that can be added to a driver is the GenPLib Output-Thread Management package.
| |
|
| |
| The best place to implement threads in a driver is when sending and buffering data to what is more than likely a slower output device (or file) . This allows the driver to return back to the application and PM GRE for rendering the next page immediately to improve system response.
| |
|
| |
| The benefits of adding multiple threads are proven in tests performed on OS /2 printer drivers that have added the GenPLib thread-management package. Results have shown a 7%-12% performance increase.
| |
|
| |
| A printer driver retrieves a thread handle (HTHREAD) from GenPLib by calling [[00061.htm|GplThreadCreateInstance]]during the FILL_PHYSICAL enable subfunction . This call is made only if the DC type is OD_QUEUED or OD_DIRECT (the DC types that request output). This call does not start a thread at this time but causes the GenPLib thread code to initialize its internal structures with information you supply. Once again, a corresponding call to [[00065.htm|GplThreadDeleteInstance]]is made during the driver's disable subfunction DISABLE_PHYSICAL to free the thread handle.
| |
|
| |
| The actual thread is started in the driver when the start-document escape code is received from the application (DEVESC_STARTDOC from the DevEscape() device call) using [[00062.htm|GplThreadStart]]. The [[00064.htm|GplThreadEnd]]call that stops the thread is placed in disable subfunction BEGIN_CLOSE_DC by the driver. It is not placed in end-document (DEVESC_ENDDOC) code because some applications choose to call many DEVESC_STARTDOC/DEVESC_ENDDOC pairs for the same DC. Placing the call in a disable subfunction assures that a thread will not start and stop many times in a row. The side effect of this is that the GenPLib thread code will receive multiple [[00062.htm|GplThreadStart]]calls for the same thread. In this case, subsequent [[00062.htm|GplThreadStart]]calls cause an implied flush of all data received at that time for the thread.
| |
|
| |
| If you call [[00062.htm|GplThreadStart]]multiple times, the thread code accepts any changed information for input parameters to this call. This allows the driver to dynamically change the buffer size and the maximum number of buffers used by the thread code.
| |
|
| |
| The [[00066.htm|GplThreadAbortDoc]]call is also added to the driver's escape code processing routine for the abort-document call (DEVESC_ABORTDOC). This call the thread code to clear data out of all its buffers and to ignore any other data received by the thread until a [[00067.htm|GplThreadResetAbortDoc]]call is made to the thread. As soon as all data is flushed by [[00066.htm|GplThreadAbortDoc]], the abort sequences supplied during [[00062.htm|GplThreadStart]]will place the printer in a known state for the next print job.
| |
|
| |
| [[00067.htm|GplThreadResetAbortDoc]]tells the thread code that the job has ended, that no more data will be sent for this print job, and to resume sending data. This call is added during the end-document escape processing (DEVESC_ENDDOC ) in the driver. This allows applications that perform multiple DEVESC_ STARTDOC/DEVESC_ENDDOC calls for a single DC (that is, submitting multiple print jobs using one DC) to function normally.
| |
|
| |
| [[00063.htm|GplThreadOutput]]is used to add any data to the thread's output buffers. The call has been added for the DEVESC_RAWDATA escape code. This escape code is sent to a driver to pass through raw data received from DOS or Windows applications along with a data buffer and data count. The call is also implemented wherever the driver needs to send out its own escape codes for graphical or text generating output. This data includes printer/job initialization commands, raster image data (compressed or uncompressed), font/text data, and job/printer termination commands.
| |
|
| |
| The last function in the thread-management package is [[00068.htm|GplThreadFlushBuffer]], which tells the thread code to send all data currently held in the thread's buffers before the call returns. This call appears just after [[00067.htm|GplThreadResetAbortDoc]]in a driver's DEVESC_ENDDOC processing code.
| |
|
| |
| === Example Code ===
| |
|
| |
| '''Starting a Thread With Output to a Printer'''
| |
|
| |
| Following is an example of starting a thread with output to a printer:
| |
|
| |
| <pre class="western"> case DEVESC_STARTDOC: // Escape code signals start of document
| |
| {
| |
| // If going to a file or direct to a printer
| |
| if( OD_DIRECT == ulDCType )
| |
| {
| |
| // Open output port (printer-driver version of DosOpen)
| |
| rc = PrtOpen( hFile, pszLogAddress );
| |
|
| |
| // Create/Update the second print thread
| |
| rc = GplThreadStart( hThread, // Instance handle
| |
| 0, // Handle to spooler
| |
| hFile, // Handle to device
| |
| 0, // Default buffer size
| |
| 0, // Default number of buffers
| |
| '\0', // Abort character
| |
| 1024, // Abort character repeat count
| |
| sizeof( pszCmdAbort ); // Length of abort command
| |
| pszCmdAbort, // Our abort command
| |
| pszLogAddress, // For example, LPT1
| |
| "Error", // Error string if write fails
| |
| pszDeviceName, // For example, "Epson LQ2550"
| |
| ulDCType ); // DC type
| |
| } /* end if */
| |
| } /* end case */</pre>
| |
| '''Starting a Thread With Output Queuing "Raw" Data'''
| |
|
| |
| Following is an example of starting a thread with output queuing "raw" printer escapes:
| |
|
| |
| <pre class="western"> case DEVESC_STARTDOC: // Escape code signals start of document
| |
| {
| |
| // Else DC type is queued, not direct to a printer
| |
| elseif( OD_QUEUED == ulDCType )
| |
| {
| |
| if( ulDataType == PM_Q_RAW )
| |
| {
| |
| if( !hspl )
| |
| {
| |
| // Open appropriate queue (from DevOpenData) for output
| |
| hspl = SplQmOpen( "*", 9, (PQMOPENDATA)&DevOpenData );
| |
| SplQmStartDoc( hspl, szDocumentName );
| |
|
| |
| } /* end if */
| |
|
| |
| // Create/Update the second print thread
| |
| rc = GplThreadStart( hThread, // Instance handle
| |
| hspl, // Handle to spooler
| |
| 0, // Handle to device
| |
| 0, // Default buffer size
| |
| 0, // Default number of buffers
| |
| '\0', // Abort character
| |
| 1024, // Abort character repeat count
| |
| sizeof( pszCmdAbort ); // Length of abort command
| |
| pszCmdAbort, // Our abort command
| |
| pszLogAddress, // For example, LPT1
| |
| "Error", // Error string if write fails
| |
| pszDeviceName, // For example, "Epson LQ2550"
| |
| ulDCType ); // DC Type
| |
| } /* end if */
| |
| } /* end if */
| |
| } /* end case */</pre>
| |
| '''Starting a Thread With Output Queuing "Standard" Data'''
| |
|
| |
| Following is an example of starting a thread with output queuing "standard" data:
| |
|
| |
| <pre class="western"> case DEVESC_STARTDOC: // Escape code signals start of document
| |
| {
| |
| // Else DC type is queued, not direct to a printer
| |
| elseif( OD_QUEUED == ulDCType )
| |
| {
| |
| if( ulDataType == PM_Q_STD )
| |
| {
| |
| SplStdStart( pddc->pdb->hdc );
| |
|
| |
| // Open appropriate queue (from DevOpenData) for output
| |
| hspl = SplQmOpen( "*", 9, (PQMOPENDATA)&DevOpenData );
| |
|
| |
| // Signal start of document (no thread is started by Omni driver)
| |
| SplQmStartDoc( hspl, szDocumentName );
| |
|
| |
| } /* end if */
| |
| } /* end if */
| |
| } /* end case */</pre>
| |
| '''GplThreadCreateInstance and GplThreadDeleteInstance Usage'''
| |
|
| |
| The enable and disable subfunctions FILL_PHYSICAL and DISABLE_PHYSICAL are ideal points at which to create and delete a thread instance. Following is an example of [[00061.htm|GplThreadCreateInstance]]() and [[00065.htm|GplThreadDeleteInstance]]() usage :
| |
|
| |
| <pre class="western">ULONG APIENTRY OS2_PM_DRV_ENABLE( ULONG ulSubFunc, ULONG p1, ULONG p2 )
| |
| {
| |
| switch( ulSubFunc ) // Determine enable subfunction
| |
| {
| |
| case FILL_PHYSICAL: // An enable subfunction
| |
| {
| |
| // Only create a thread if we expect to output data
| |
| if( (OD_QUEUED == pdb->ulType ) || (OD_DIRECT == pdb->ulType ) )
| |
| {
| |
| // Create an output thread instance (do not start thread yet)
| |
| bRC = GplThreadCreateInstance( hmcbHeap, globals.hmod, &hThread, pddc );
| |
|
| |
| } /* end if */
| |
| } /* end case */
| |
| break;
| |
|
| |
| case DISABLE_PHYSICAL: // A disable subfunction
| |
| {
| |
| // Delete the output thread instance if allocated
| |
| if( hThread )
| |
| {
| |
| bRC = GplThreadDeleteInstance( &hThread );
| |
|
| |
| } /* end if */
| |
| } /* end case */
| |
| break;
| |
|
| |
| } /* end switch */
| |
| } /* end OS2_PM_DRV_ENABLE */</pre>
| |
| '''GplThreadOutput Usage'''
| |
|
| |
| Following is an example of [[00063.htm|GplThreadOutput]]() usage:
| |
|
| |
| <pre class="western"> case DEVESC_NEWFRAME: // Page eject requested
| |
| {
| |
| CHAR achRasterCmd[] = "*Esc*r1Q";
| |
|
| |
| // When getting a DEVESC_NEWFRAME or DEVESC_ENDDOC,
| |
| // The current page's raster image can be retrieved from the
| |
| // device surface and transferred to the printer
| |
|
| |
| // Enter raster mode by sending down escape code for current device
| |
| bRC = GplThreadOutput( hThread, // Thread instance handle
| |
| achRasterCmd, // Pointer to data buffer
| |
| strlen(achRasterCmd), // Size of data buffer
| |
| THREAD_DT_BINARY ); // Data type
| |
|
| |
| // Dither and/or compress raster data and send to output thread
| |
| bRC = GplThreadOutput( hThread,
| |
| pbRasterData,
| |
| ulRasterDataLength,
| |
| THREAD_DT_BINARY );
| |
|
| |
| } /* end case */</pre>
| |
| '''[[00064.htm|GplThreadEnd]]Usage'''
| |
|
| |
| Following is an example of [[00064.htm|GplThreadEnd]]usage during OS2_PM_DRV_ENABLE:
| |
|
| |
| <pre class="western">ULONG APIENTRY OS2_PM_DRV_ENABLE( ULONG ulSubFunc, ULONG p1, ULONG p2 )
| |
| {
| |
| switch( ulSubFunc ) // Determine enable subfunction
| |
| {
| |
| case BEGIN_CLOSE_DC:
| |
| {
| |
| // If we created an output thread
| |
| if( hThread )
| |
| {
| |
| // End the second thread implied flush with wait
| |
| bRC = GplThreadEnd ( hThread ) ;
| |
|
| |
| } / * end if * /
| |
| } / * end case * /
| |
| } / * end switch * /
| |
| } / * end OS2 _ PM _ DRV _ ENABLE * / </pre>
| |
| '''[[00066.htm|GplThreadAbortDoc]]Usage'''
| |
|
| |
| Following is an example of [[00066.htm|GplThreadAbortDoc]]usage for handling an abort- document escape:
| |
|
| |
| <pre class="western"> case DEVESC_ABORTDOC:
| |
| {
| |
| // Tell second thread that an abort doc occurred
| |
| GplThreadAbortDoc( hThread );
| |
|
| |
| // Store a state flag in our pddc to indicate abort is in effect
| |
| pddc->fAbortDocCalled = TRUE;
| |
|
| |
| } /* end case */</pre>
| |
| '''[[00067.htm|GplThreadResetAbortDoc]]Usage'''
| |
|
| |
| Following is an example of using [[00067.htm|GplThreadResetAbortDoc]]:
| |
|
| |
| <pre class="western">case DEVESC_ENDDOC:
| |
| {
| |
| // If we received a DEVESC_ABORTDOC
| |
| if( pddc->fAbortDocCalled )
| |
| {
| |
| // Notify the output thread that the abort condition is over
| |
| GplThreadResetAbortDoc( hThread );
| |
|
| |
| // Reset the abort state so thread will begin processing data again
| |
| pddc->fAbortDocCalled = FALSE;
| |
|
| |
| } /* end if */
| |
| } /* end case */</pre>
| |
| '''[[00068.htm|GplThreadFlushBuffer]]Usage'''
| |
|
| |
| Following is an example of using [[00068.htm|GplThreadFlushBuffer]]:
| |
|
| |
| <pre class="western">case DEVESC_ENDDOC:
| |
| {
| |
| // If going to a file or direct to a printer
| |
| if( OD_DIRECT == ulDCType )
| |
| {
| |
| // Flush all data in second thread; we are done
| |
| GplThreadFlushBuffer( hThread, TRUE );
| |
|
| |
| } /* end if */
| |
|
| |
| elseif( OD_QUEUED == ulDCType && PM_Q_RAW == ulDataType )
| |
| {
| |
| // Flush all data in second thread; we are done
| |
| GplThreadFlushBuffer( hThread, TRUE );
| |
|
| |
| } /* end if */
| |
| } /* end case */</pre>
| |
| '''[[00069.htm|GplThreadHookDeviceWrites]]Usage'''
| |
|
| |
| Following is an example of using [[00069.htm|GplThreadHookDeviceWrites]]:
| |
|
| |
| <pre class="western">case DEVESC_STARTDOC:
| |
| {
| |
| // We have just called thread Start
| |
| GplThreadStart();
| |
|
| |
| // We inform the thread that we want to subclass the write of data
| |
| // to the output destination, replacing it with our callback function
| |
| GplThreadHookDeviceWrites( hThread, // Thread handle
| |
| pfnPrtWrite, // Our "write" function
| |
| pddc ); // Parameter to our "write" function
| |
| } /* end case */</pre>
| |
|
| |
| === Pattern Creation ===
| |
|
| |
| This module contains functions to create bitmap patterns.
| |
|
| |
| To use the GenPLib Pattern-Creation package, you must include:
| |
|
| |
| <pre class="western">INCL_GENPLIB_MEMORY
| |
| INCL_GENPLIB_PATTERNS</pre>
| |
|
| |
|
| |
| The following functions are used to create bitmap patterns.
| |
|
| |
| [[00073.htm|GplPatternCreateBitmaps]]<br />[[00074.htm|GplPatternDeleteBitmaps]]<br />[[00075.htm|GplPatternCreate]]
| |
|
| |
| === GplPatternCreateBitmaps ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function fills in an array of BMAPINFO structures with the PATSYM patterns. This function is designed to be used to fill in the DEVICESURFACE structure with patterns that match the resolution of the target device. GplPattern functions use the GenPLib Memory-Management package and require that a HMCB had been created with [[00051.htm|GplMemoryCreateInstance]].
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">LONG APIENTRY GplPatternCreateBitmaps(
| |
| HMCB hMcb, // Memory instance handle
| |
| ULONG ulXResolution, // X device resolution
| |
| ULONG ulYResolution, // Y device resolution
| |
| ULONG ulWidth, // Desired pattern width
| |
| ULONG ulHeight, // Desired pattern height
| |
| PBMAPINFO paBmapInfo, // Array of pattern bitmaps (output)
| |
| LONG lCount, // Number of bitmaps to create
| |
| ULONG ulFlip ); // Flip bitmaps horiz/vertically</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hMcb'''(''HMCB'') Handle to initialized memory control block.
| |
|
| |
| '''ulXResolution'''(''ULONG'') Target device x resolution.
| |
|
| |
| '''ulYResolution'''(''ULONG'') Target device y resolution.
| |
|
| |
| '''ulWidth'''(''ULONG'') Size of bitmap X.
| |
|
| |
| '''ulHeigh'''(''ULONG'') Size of bitmap Y.
| |
|
| |
| '''paBmapInfo'''(''PBMAPINFO'') Pointer to an array of BMAPINFO.
| |
|
| |
| '''lCount'''(''LONG'') Number of bitmap information structures.
| |
|
| |
| '''ulFlip'''(''ULONG'') Bit vector. If GPLPAT_INVERT_BITS is set, the bitmaps are inverted.
| |
|
| |
| '''Returns'''
| |
|
| |
| TRUE Success <br />FALSE Failure
| |
|
| |
| === GplPatternDeleteBitmaps ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function deletes the bits and clears the array of BMAPINFO.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">LONG APIENTRY GplPatternDeleteBitmaps(
| |
| HMCB hMcb, // Memory instance handle
| |
| PBMAPINFO paBmapInfo, // Pointer to bitmaps to be freed
| |
| LONG lCount ); // Count of bitmaps to be freed</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hMcb'''(''HMCB'') Handle to initialized memory control block.
| |
|
| |
| '''paBmapInfo'''(''PBMAPINFO'') Pointer to an array of BMAPINFO.
| |
|
| |
| '''lCount'''(''LONG'') Number of bitmap information structures.
| |
|
| |
| '''Returns'''
| |
|
| |
| TRUE Success <br />FALSE Failure
| |
|
| |
| === GplPatternCreate ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function can be used by a presentation driver to create a bitmap representation of any one of the predefined OS/2 patterns. Typically, it is called to create all or a subset of patterns a device driver will support at the start of a print job.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">LONG APIENTRY GplPatternCreate( HMCB hMcb, // Memory instance handle
| |
| ULONG ulXResolution, // X device resolution
| |
| ULONG ulYResolution, // Y device resolution
| |
| ULONG ulPatSym, // OS/2 pattern define
| |
| PBMAPINFO pBmapInfo ); // A pattern bitmap (output)</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hMcb'''(''HMCB'') Handle to initialized Memory control block.
| |
|
| |
| '''ulXResolution'''(''ULONG'') Target device x resolution.
| |
|
| |
| '''ulYResolution'''(''ULONG'') Target device y resolution.
| |
|
| |
| '''ulPatSym'''(''ULONG'') Pattern number as defined for OS/2 in PMDDI.H:
| |
|
| |
| <pre class="western"> PATSYM_DEFAULT
| |
| PATSYM_DENSE1
| |
| PATSYM_DENSE2
| |
| PATSYM_DENSE3
| |
| PATSYM_DENSE4
| |
| PATSYM_DENSE5
| |
| PATSYM_DENSE6
| |
| PATSYM_DENSE7
| |
| PATSYM_DENSE8
| |
| PATSYM_VERT
| |
| PATSYM_HORIZ
| |
| PATSYM_DIAG1
| |
| PATSYM_DIAG2
| |
| PATSYM_DIAG3
| |
| PATSYM_DIAG4
| |
| PATSYM_NOSHADE
| |
| PATSYM_SOLID
| |
| PATSYM_BLANK
| |
| PATSYM_HALFTONE
| |
| PATSYM_HATCH
| |
| PATSYM_DIAGHATCH</pre>
| |
| '''pBmapInfo'''(''PBMAPINFO'') Number of bitmap information structures.
| |
|
| |
| '''Returns'''
| |
|
| |
| TRUE Success <br />FALSE Failure
| |
|
| |
| === Example Code ===
| |
|
| |
| '''GplPatternCreateBitmaps Usage'''
| |
|
| |
| Following is an example of using [[00073.htm|GplPatternCreateBitmaps]]:
| |
|
| |
| <pre class="western">// PM Graphics Rendering Engine v2.2 Device Surface Function from the Omni driver
| |
|
| |
| LONG APIENTRY QueryDeviceSurface( PDDC pddc, PVOID pv )
| |
| {
| |
| // Initialize all fields of the device surface structure, then...
| |
| if( !pddc->pdb->bAllocatedPatterns )
| |
| {
| |
| if( ORIENTATION_PORTRAIT == pdb->pJobProperties->ulOrientation )
| |
| {
| |
| if( GplPatternCreateBitmaps ( pddc->hmcbHeap,
| |
| pddc->pResInfo->ulXRes,
| |
| pddc->pResInfo->ulYRes,
| |
| 64L,
| |
| 64L,
| |
| (PBMAPINFO)&pds->abmapinfoDefPattern,
| |
| DEFAULT_PATTERNS_NUMBER,
| |
| 0L ) )
| |
| {
| |
| pddc->pdb->bAllocatedPatterns = TRUE;
| |
|
| |
| } /* end if */
| |
| } /* end if */
| |
| } /* end if */
| |
| } /* end QueryDeviceSurface */</pre>
| |
| '''GplPatternDeleteBitmaps Usage'''
| |
|
| |
| Following is an example of using [[00074.htm|GplPatternDeleteBitmaps]]:
| |
|
| |
| <pre class="western">case BEGIN_CLOSE_DC:
| |
|
| |
| // Perform other disable processing, then near end of case...
| |
| if( GRE_22 <= globals.ulGreVersion ) // PM Graphics Rendering Engine v2.2 or higher
| |
| {
| |
| PDEVICESURFACE pds;
| |
|
| |
| // Note: We only allocate patterns in QueryDeviceSurface for GRE v2.2 and higher
| |
| pds = (PDEVICESURFACE)pddc->pdb->pDeviceSurface;
| |
| if( GplPatternDeleteBitmaps( pddc->pdb->hmcbHeap,
| |
| (PBMAPINFO)&pds->abmapinfoDefPattern,
| |
| DEFAULT_PATTERNS_NUMBER ) )
| |
| {
| |
| pddc->pdb->bAllocatedPatterns = FALSE;
| |
|
| |
| } /* end if */
| |
| } /* end if */</pre>
| |
|
| |
| === Semaphores ===
| |
| Printer drivers are responsible for serializing threads' access to any of their device contexts (DCs). OS/2 mutual exclusion (MUTEX) semaphores are a possible choice to implement this serialization. When two threads attempt to use the same printer DC at the same time, the second thread should receive a failing result code and PMERR_HDC_BUSY from WinGetLastError.
| |
|
| |
| Given this behavior of OS/2 and its presentation drivers, most OS/2 applications use just one thread when printing. Whenever there is just one thread, there is little contention for the DC; but presentation drivers must safely manage this contention.
| |
|
| |
| There is some performance overhead to consider whenever a thread calls into the OS/2 kernel, as is the case for calls to DosRequest/ReleaseMutexSem. The overhead occurs because the kernel reloads code and data selectors on kernel entry and exit. OS/2 MUTEX semaphores are always safe semaphores, however, because of this transition to the kernel.
| |
|
| |
| === Semaphores in the GenPLib ===
| |
| The semaphore package in the GenPLib implements a Ring-3 RAM semaphore when running on the 486 processor. The 486 has the CMPXCHG instruction that is not present on the 386. This single instruction implements a fast, safe, RAM semaphore at Ring 3.
| |
|
| |
| On a 486, a thread requesting an unowned semaphore will remain at Ring 3 and not enter the kernel. If the semaphore is owned and the thread intends to wait, however, then it will enter the kernel to block on an event semaphore.
| |
|
| |
| On a 386, the GenPLib simply uses OS/2 MUTEX semaphores. Implementing a semaphore on the 386 requires multiple instructions; thus, a switch to the kernel is required to disable interrupts while these multiple instructions execute.
| |
|
| |
| For either processor, a thread may repeatedly request the same semaphore without an intervening release (nested requests). Use [[00084.htm|GplSemQueryMutexSem]]to query the nested use count.
| |
|
| |
| The GenPLib detects the processor type at runtime.
| |
|
| |
| All GenPLib semaphore APIs return 0 on success. When not zero, they return the same result codes documented for their OS/2 MUTEX semaphore counterparts.
| |
|
| |
| The GenPLib semaphore APIs require a pointer to a MTXSEM data structure instead of a semaphore handle like OS/2 MUTEX semaphores. It is the responsibility of the client to allocate one of these structures per semaphore and supply its pointer to the GenPLib semaphore API.
| |
|
| |
| When the MTXSEM semaphore structure resides on shared memory, it may be created with the DC_SEM_SHARED flag. Additional processes may obtain access to this shared memory and open the semaphore.
| |
|
| |
| All GenPLib semaphores are created in the unowned state.
| |
|
| |
| To use the GenPLib Semaphores package, you must include:
| |
|
| |
| <pre class="western">INCL_GENPLIB_SEMAPHORES</pre>
| |
| The following APIs are included in the semaphore package of GenPLib:
| |
|
| |
| *[[00079.htm|GplSemCreateMutexSem]]
| |
| *[[00080.htm|GplSemOpenMutexSem]]
| |
| *[[00081.htm|GplSemRequestMutexSem]]
| |
| *[[00082.htm|GplSemReleaseMutexSem]]
| |
| *[[00083.htm|GplSemCloseMutexSem]]
| |
| *[[00084.htm|GplSemQueryMutexSem]]
| |
|
| |
| With the exception of the first parameter, PMTXSEM, the parameters to the GenPLib semaphore APIs are as documented for OS/2 MUTEX semaphores.
| |
|
| |
| === GplSemCreateMutexSem ===
| |
|
| |
| '''Description'''
| |
|
| |
| This call creates a MUTEX semaphore.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplSemCreateMutexSem( PMTXSEM pmtxsem,
| |
| ULONG flAttr );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pmtxsem'''(''PMTXSEM'') Address of MTXSEM structure.
| |
|
| |
| '''flAttr'''(''ULONG'') Creation flags. DC_SEM_SHARED is the only flag.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR Failure ERROR_INVALID_PARAMETER <br />or return code from: <br />DosQueryMem <br />DosCreateEventSem <br />DosCreateMutexSem
| |
|
| |
| '''Notes'''
| |
|
| |
| The caller must first allocate memory for the MTXSEM structure. See GPLSEM. H, where this structure is defined. If the memory is allocated from shared memory, the caller may specify the DC_SEM_SHARED flag for flAttr parameter.
| |
|
| |
| === GplSemOpenMutexSem ===
| |
|
| |
| '''Description'''
| |
|
| |
| This call opens a shared GPL Mutex semaphore.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplSemOpenMutexSem( PMTXSEM pmtxsem );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''pmtxsem'''(''PMTXSEM'') Address of MTXSEM structure.
| |
|
| |
| '''Notes'''
| |
|
| |
| When multiple processes are using a shared semaphore, then subsequent processes must open the semaphore. It is not necessary for the creating process to perform an open.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR Failure ERROR_INVALID_PARAMETER <br />or return code from: <br />DosOpenEventSem <br />DosOpenMutexSem
| |
|
| |
| === GplSemRequestMutexSem ===
| |
|
| |
| '''Description'''
| |
|
| |
| This call is used to request an OS/2 PM MUTEX semaphore.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplSemRequestMutexSem( PMTXSEM pmtxsem,
| |
| LONG lTime );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pmtxsem'''(''PMTXSEM'') Address of MTXSEM structure.
| |
|
| |
| '''lTime'''(''LONG'') Time out value in milliseconds.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR
| |
|
| |
| Failure Typical error returns for this function include ERROR_INVALID_ PARAMETER or return codes from DosRequestMutexSem.
| |
|
| |
| ERROR_TIMEOUT (RC 640d) means that the semaphore is owned.
| |
|
| |
| '''Notes'''
| |
|
| |
| The caller can specify the timeout value for the request. When timeout is 0 , the call returns immediately. When timeout is -1, the call is an indefinite wait. Otherwise the call will block up to the timeout specified.
| |
|
| |
| === GplSemReleaseMutexSem ===
| |
|
| |
| '''Description'''
| |
|
| |
| This call will release an owned MUTEX semaphore.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplSemReleaseMutexSem( PMTXSEM pmtxsem );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''pmtxsem'''(''PMTXSEM'') Address of MTXSEM structure.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR Failure ERROR_INVALID_PARAMETER <br />ERROR_NOT_OWNER (not the owner of the MUTEX semaphore) <br />DosReleaseMutexSem
| |
|
| |
| '''Notes'''
| |
|
| |
| This call decrements the nested use count for the semaphore. When the nested use count goes to zero, the semaphore is truly released.
| |
|
| |
| === GplSemCloseMutexSem ===
| |
|
| |
| '''Description'''
| |
|
| |
| This call closes a GPL MUTEX semaphore for the process.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplSemCloseMutexSem( PMTXSEM pmtxsem );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''pmtxsem'''(''PMTXSEM'') Address of MTXSEM structure.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR Failure ERROR_INVALID_PARAMETER <br />DosCloseEventSem <br />DosCloseMutexSem
| |
|
| |
| '''Notes'''
| |
|
| |
| Every process using GPL semaphores should close each one with this API.
| |
|
| |
| === GplSemQueryMutexSem ===
| |
|
| |
| '''Description'''
| |
|
| |
| This call returns information about the semaphore.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplSemQueryMutexSem( PMTXSEM pmtxsem,
| |
| PID *ppid,
| |
| TID *ptid,
| |
| PULONG pulCount );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''pmtxsem'''(''PMTXSEM'') Address of MTXSEM structure.
| |
|
| |
| '''*ppid'''(''PPID'') Address where process ID is returned.
| |
|
| |
| '''*ptid'''(''PTID'') Address where thread ID is returned.
| |
|
| |
| '''pulCount'''(''PULONG'') Request count.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR Failure ERROR_INVALID_PARAMETER <br />or the return codes from: <br />DosQueryMutexSem
| |
|
| |
| '''Notes'''
| |
|
| |
| This API will return information about the semaphore, such as what process and thread currently owns it, and if owned, what is the nested use count.
| |
|
| |
| It is important for asynchronously killed threads to make this call to determine if they own the DC semaphore. If they own the semaphore, they should release it the appropriate number of times before exiting.
| |
|
| |
| === Differences Between GenPLib Semaphores and Kernel Semaphores ===
| |
|
| |
| If a nonzero request time times out, it will timeout to within 30 milliseconds of the supplied time out.
| |
|
| |
| DosQueryMutexSem returns a process and thread ID even if the MUTEX sem is unowned; that is, the count returned is zero. This semaphore package returns process and thread ID of zero when the semaphore is unowned regardless of 386 or 486.
| |
|
| |
| === String Management ===
| |
| The string-management package provides string-sorting functionality for printer output devices.
| |
|
| |
| Certain printer output devices can output data only in small bands, yet they are expected to keep track of strings that might be positioned anywhere on a physical output page. These devices need an independent mechanism for keeping those strings in sorted "page" order until the device is actually processing the band of that string.
| |
|
| |
| This is true for raster printers that utilize a print head and must only send text strings that are drawn using device (printer) fonts within a certain range of the print head when printing graphics data. The following diagrams represent this concept:
| |
|
| |
| <pre class="western"> Output Page
| |
| /----------\
| |
| | |
| |
| | |
| |
| |xxxxxxxxxx|
| |
| |xxxxxxxxxx| <--- Current band of raster output
| |
| | | that can be processed by the
| |
| | | output device.
| |
| | Hello |
| |
| | |
| |
| | | <--- Text is below current band so
| |
| | ABCD | we can't output it yet
| |
| | |
| |
| | |
| |
| | |
| |
| \----------/</pre>
| |
|
| |
|
| |
| <pre class="western"> Output Page (later)
| |
| /----------\
| |
| | |
| |
| | |
| |
| | |
| |
| | |
| |
| | |
| |
| |xHelloxxxx| <--- Current band of raster output
| |
| |xxxxxxxxxx| that can be processed by the
| |
| | | output device.
| |
| Lower string still --> | ABCD | This time the text string is in
| |
| not in range | | the band region and it should be
| |
| | | processed at this time
| |
| | |
| |
| | |
| |
| \----------/</pre>
| |
|
| |
|
| |
| <pre class="western"> Output Page (later)
| |
| /----------\
| |
| | |
| |
| | |
| |
| | |
| |
| | |
| |
| | |
| |
| String already --> | Hello |
| |
| processed | |
| |
| | |
| |
| | |
| |
| |xxxxABCDxx| <--- Current band of raster output
| |
| |xxxxxxxxxx| that can be processed by the
| |
| | | output device.
| |
| | | This time the second string is in
| |
| \----------/ the band region and it should be
| |
| processed at this time.</pre>
| |
| The package sorts text strings passed in page order. Top-to-bottom and left -to-right is the current default page order.
| |
|
| |
| Once strings are inserted, you can extract strings in respect to a rectangular area (typically the current graphics band rectangle) that you pass in.
| |
|
| |
| The string-sorting package utilizes the GenPLib Memory-Management and Exception-Management packages, thereby providing very efficient system resource usage and consistent error reporting and logging.
| |
|
| |
| To use the GenPLib String-Management package, you must include:
| |
|
| |
| <pre class="western">INCL_GENPLIB_STRING</pre>
| |
|
| |
| The following functions comprise the string-management package:
| |
| *[[00087.htm|GplStringSorterCreateInstance]]
| |
| *[[00088.htm|GplStringSorterInsertString]]
| |
| *[[00089.htm|GplStringSorterQueryNumStrings]]
| |
| *[[00090.htm|GplStringSorterGetFirstString]]
| |
| *[[00091.htm|GplStringSorterGetNextString]]
| |
| *[[00092.htm|GplStringSorterRemoveStrings]]
| |
| *[[00093.htm|GplStringSorterReset]]
| |
| *[[00094.htm|GplStringSorterDeleteInstance]]
| |
|
| |
| === GplStringSorterCreateInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function creates a string sorter instance (memory resource allocated) and returns a handle that must be used by all other string sorter package functions.
| |
|
| |
| The default heap size that is created is based on current printer driver media sizes and application text usage. A parameter is supplied so that the user can increase the initial memory area that is created to hold text strings. Otherwise a default value, based on test averages, will be used.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplStringSorterCreateInstance( HDC hdc,
| |
| PHSORTER phStrSort,
| |
| ULONG ulHeapSize,
| |
| ULONG ulOptions );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hdc'''(''HDC'') Handle to current DC.
| |
|
| |
| '''phStrSort'''(''PHSORTER'') Pointer to the location where string-sorter handle will be placed.
| |
|
| |
| '''ulHeapSize'''(''ULONG'') Initial size of heap to allocate for strings. This can be zero. A default memory area will be created.
| |
|
| |
| '''ulOptions'''(''ULONG'') Creation options (for example, DBCS and TTY). This parameter is reserved for future use. This parameter must be zero.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR <br />Failure ERROR_xxx
| |
|
| |
| === GplStringSorterInsertString ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function adds a text string to a string instance. Information, including the bounding rectangle passed in and a pointer to the data, is stored with the string. You can store with the string (for example, a pointer to a structure containing font name, font ID, and color).
| |
|
| |
| Currently, the sort order is determined by the top-left corner of the text box passed in. The strings are sorted in page order. Page order is the order the text would be printed by a banding device on a hardcopy page.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplStringSorterInsertString( HSORTER hStrSort,
| |
| PSZ pszStr,
| |
| RECTL rectlStr,
| |
| PVOID pUserDef,
| |
| PVOID pUnused );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hStrSort'''(''HSORTER'') Handle of the string sorter to be used for insert operation.
| |
|
| |
| '''pszStr'''(''PSZ'') Pointer to text string to insert.
| |
|
| |
| '''rectlStr'''(''RECTL'') Bounding rectangle of string being inserted.
| |
|
| |
| '''pUserDef'''(''PVOID'') Pointer to user-defined data to be stored with this string .
| |
|
| |
| '''pUnused'''(''PVOID'') NULL. Reserved for future use.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR <br />Failure ERROR_INVALID_PARAMETER <br />ERROR_xxx
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === GplStringSorterQueryNumStrings ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function returns the current number of strings in the string sorter instance (HSORTER) referenced on the call.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplStringSorterQueryNumStrings( HSORTER hStrSort,
| |
| PULONG pulNumStr );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hStrSort'''(''HSORTER'') Handle of string sorter instance to be queried.
| |
|
| |
| '''pulNumStr'''(''PULONG'') Pointer to the location where number is to be returned.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR <br />Failure ERROR_xxx
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === GplStringSorterGetFirstString ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is used to get a linked list of strings from the string sorter in relation to a band rectangle passed in.
| |
|
| |
| The strings are not deleted from the linked list on this call because we allocated the information and will de-allocate on a [[00093.htm|GplStringSorterReset]]() call or a [[00092.htm|GplStringSorterRemoveStrings]]() call.
| |
|
| |
| Currently, the defined relationships that can be selected are:
| |
|
| |
| Option Description
| |
|
| |
| STR_INCL_PART_IN_BAND Return any string whose text box intersects any part of the band passed in.
| |
|
| |
| STR_INCL_ALL_IN_BAND Return any string whose text box is entirely inside the band passed in.
| |
|
| |
| STR_INCL_TOPLEFT_IN_BAND Return any string whose top-left coordinate is inside the band passed in.
| |
|
| |
| '''Notes:'''
| |
|
| |
| 1.All retrievals are inclusive on all boundaries of the ''rectlBand''passed in.
| |
|
| |
| 2.GplStringSorterGetFirstString retrievals are non-destructive. (the string remains in the string-sorter instance and are only removed by [[00092.htm|GplStringSorterRemoveStrings]]or [[00093.htm|GplStringSorterReset]]calls).
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplStringSorterGetFirstString( HSORTER hStrSort,
| |
| ULONG ulOption,
| |
| RECTL rectlBand,
| |
| PSZ *ppszStr,
| |
| PRECTL prectlStr,
| |
| PPVOID ppUserDef );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hStrSort'''(''HSORTER'') Handle of string-sorter instance to be used for string retrieval.
| |
|
| |
| '''ulOption'''(''ULONG'') Option passed in to indicate the relationship to test for on the "Get" operation. See options above.
| |
|
| |
| '''rectlBand'''(''RECTL'') The band rectangle passed in that will be used to test all text-string rectangles against.
| |
|
| |
| '''*ppszStr'''(''PSZ'')-output Pointer to first text string meeting retrieve criteria (ulOption).
| |
|
| |
| '''prectlStr'''(''PRECTL'')-output Pointer to the bounding rectangle of first string retrieved (passed in during [[00088.htm|GplStringSorterInsertString]]).
| |
|
| |
| '''ppUserDef'''(''PPVOID'')-output Pointer to the user-defined data that was associated with text string retrieved (passed in during [[00088.htm|GplStringSorterInsertString]]).
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR <br />Failure ERROR_xxx
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === GplStringSorterGetNextString ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is used to retrieve the next string matching the retrieve criteria passed in on the last call to [[00090.htm|GplStringSorterGetFirstString]](). The criteria is based on the ''ulOption''and ''rectlBand''parameters from that function). This function can be called multiple times until an ERROR_NO_ MORE_ITEMS return code is detected. Each successful call (NO_ERROR) returns another string from the string sorter instance meeting the criteria until no more strings meet the criteria.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplStringSorterGetNextString( HSORTER hStrSort
| |
| PSZ *ppszStr,
| |
| PRECTL prectlStr
| |
| PPVOID ppUserDef );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hStrSort'''(''HSORTER'') Handle of the string-sorter instance to be used for the retrieve operation.
| |
|
| |
| '''*ppszStr'''(''PSZ'') - output Pointer to the location that the text string will be retrieved to.
| |
|
| |
| '''prectlStr'''(''PRECTL'') - output Bounding rectangle of the string being retrieved.
| |
|
| |
| '''ppUserDef'''(''PPVOID'') - output Pointer to user-defined data stored with string during the insert operation.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR <br />Failure ERROR_xxx
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === GplStringSorterRemoveStrings ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function is used to delete all strings from the string sorter instance , based on a relationship (ulOption) to a rectangle (rectlBand) both passed .
| |
|
| |
| See StringGetFirstStringFromSorter() and StringGetNextStringFromSorter() calls for non-destructive string retrievals.
| |
|
| |
| Remove options include:
| |
|
| |
| Option Description
| |
|
| |
| STR_INCL_PART_IN_BAND Return any string whose text box intersects any part of the band passed in.
| |
|
| |
| STR_INCL_ALL_IN_BAND Return any string whose text box is entirely inside the band passed in.
| |
|
| |
| STR_INCL_TOPLEFT_IN_BAND Return any string whose top-left coordinate is inside the band passed in.
| |
|
| |
| Removes are inclusive on all sides of ''rectlBand''passed in.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplStringSorterRemoveStrings( HSORTER hStrSort,
| |
| ULONG ulOption,
| |
| RECTL rectlBand );</pre>
| |
| '''Parameters'''
| |
|
| |
| '''hStrSort'''(''HSORTER'') Handle of the string sorter to be used for remove operation.
| |
|
| |
| '''ulOption'''(''ULONG'') Remove options.
| |
|
| |
| '''rectlBand'''(''RECTL'') Rectangle that is used for comparison by the remove option.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR <br />Failure ERROR_xxx
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === GplStringSorterReset ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function resets the string sorter instance by removing all text strings inserted into the sorter.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplStringSorterReset( HSORTER hStrSort );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''hStrSort'''(''HSORTER'') Handle of the string sorter to be reset.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR <br />Failure ERROR_xxx
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === GplStringSorterDeleteInstance ===
| |
|
| |
| '''Description'''
| |
|
| |
| This function destroys a string sorter instance by freeing any system resources allocated on the corresponding call to [[00087.htm|GplStringSorterCreateInstance]](). This function implies a [[00093.htm|GplStringSorterReset]]() call.
| |
|
| |
| '''Format'''
| |
|
| |
| <pre class="western">APIRET APIENTRY GplStringSorterDeleteInstance( HSORTER hStrSort );</pre>
| |
| '''Parameter'''
| |
|
| |
| '''hStrSort'''(''HSORTER'') Handle of string sorter to be destroyed. The handle is no longer valid after the call.
| |
|
| |
| '''Returns'''
| |
|
| |
| Success NO_ERROR <br />Failure ERROR_INVALID_PARAMETER
| |
|
| |
|
| |
|
| |
|
| |
|
| |
| === Example Code ===
| |
|
| |
| '''Retrieving Strings From String Sorter During Band Processing'''
| |
|
| |
| Following is an example of retrieving strings from string sorter during band processing in a raster printer driver:
| |
|
| |
| <pre class="western"> HSORTER hSorter;
| |
| CharString( PDDC pddc, ..., LONG cChars, PCH pchString, ... )
| |
| {
| |
| if( bDeviceFont ) // If we have a device font to manage
| |
| {
| |
| if( ! hSorter ) // If we have not yet created a sorter
| |
| {
| |
| // Create a string sorter to handle our device fonts
| |
| apiret = GplStringSorterCreateInstance( pddc,&hSorter, 0L, 0L );
| |
|
| |
| } /* end if */
| |
|
| |
| // Calculate text box of string from our character-width tables
| |
| // Insert character string into sorter
| |
| apiret = GplStringSorterInsertString( hSorter,
| |
| (PSZ)pchString,
| |
| rectlTextBox,
| |
| (PVOID)NULL,
| |
| (PVOID)NULL );
| |
|
| |
| // Example: check number of strings currently in sorter
| |
| apiret = GplStringSorterQueryNumStrings( hSorter,&ulNumStr );
| |
|
| |
| } /* end if */
| |
| } /* end CharString */
| |
|
| |
| Usage Notes:
| |
|
| |
| Used default values for heap size and options during 'StringCreate' API (LTR, TTB).
| |
|
| |
| Used default value for during 'StringInsert' API.
| |
|
| |
| For 'StringInsert' API, we could have allocated and filled in our own
| |
| structure that helps us process this string (for example, font name, identifier,
| |
| color, etc.).</pre>
| |
| '''Removing Strings From a String Sorter During Processing of a Graphics Band'''
| |
|
| |
| Following is an example of removing strings from a string sorter during processing of a graphics band (banding):
| |
|
| |
| <pre class="western"> ProcessBand( PDDC pddc, ...)
| |
| {
| |
| APIRET apiret;
| |
| RECTL rectlString, rectlBand;
| |
| PSZ pszString;
| |
|
| |
| // Retrieve first sting in the raster band we are processing
| |
| apiret = GplStringSorterGetFirstString(
| |
| hSorter,
| |
| STR_INCL_TOP_LEFT_IN_BAND,
| |
| // Retrieve strings whose Top-Left corner are in band
| |
| rectlBand,
| |
| // Rectangle of the graphic band we are processing
| |
| &pszString,
| |
| // Pointer that first string will be returned in
| |
| &rectlString,
| |
| // Text box of the string
| |
| (PVOID)NULL );
| |
| // We had no user-defined data to retrieve
| |
|
| |
| // if we have a string meeting retrieval criteria
| |
| while( apiret != ERROR_NO_MORE_ITEMS )
| |
| {
| |
| // Get next string (uses same retrieve option as "GetFirst")
| |
| apiret = GplStringSorterGetNextString( hSorter,
| |
| &pszString,
| |
| &rectlString,
| |
| (PVOID)NULL );
| |
| } /* end while */
| |
|
| |
| } /* end ProcessBand */</pre>
| |
| '''Removing Strings From a String Sorter After Retrieving Them'''
| |
|
| |
| Following is an example of removing strings from a string sorter after retrieving them (during graphics band processing):
| |
|
| |
| <pre class="western"> ProcessBand( PDDC pddc, ... )
| |
| {
| |
| // After retrieving all strings from band and sending them to printer
| |
| // See the previous example
| |
|
| |
| // We can remove these strings from the sorter
| |
| // since we do not need to process them again
| |
| apiret = GplStringSorterRemoveStrings( hSorter,
| |
| STR_INCL_TOP_LEFT_IN_BAND,
| |
| rectlBand );
| |
| } /* end ProcessBand */</pre>
| |
| '''Resetting and Destroying the String Sorter During Escape Processing'''
| |
|
| |
| Following is an example of resetting and destroying the string sorter during escape processing in a printer driver:
| |
|
| |
| <pre class="western"> Escape( PDDC pddc, ... )
| |
| {
| |
| APIRET apiret;
| |
|
| |
| case DEVESC_NEWFRAME:
| |
| {
| |
| // Process all graphics bands on page
| |
|
| |
| // Reset sorter for next page
| |
| apiret = GplStringSorterReset( hSorter );
| |
|
| |
| } /* end case */
| |
| break;
| |
|
| |
| case DEVESC_ENDDOC:
| |
| {
| |
| // Process the last page (implied NewFrame)
| |
|
| |
| // Sorter no longer needed for this print job
| |
| apiret = GplStringSorterDeleteInstance( hSorter );
| |
|
| |
| } /* end case */
| |
| break;
| |
| } /* end Escape */</pre>
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| ==OS/2 Version Compatibility Considerations== | | ==OS/2 Version Compatibility Considerations== |
Line 3,651: |
Line 57: |
| |} | | |} |
|
| |
|
| | | [[Category:Device Driver Reference]] |
| | |
| [[Category:Driver Articles]] | |