You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
438 lines
12 KiB
438 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1990-2003 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
htbmp4.c
|
|
|
|
|
|
Abstract:
|
|
|
|
This module contains functions to output halftoned 4 bit per pel (4 BPP)
|
|
bitmaps to the target device.
|
|
|
|
|
|
Author:
|
|
|
|
21-Dec-1993 Tue 21:32:26 created
|
|
|
|
|
|
[Environment:]
|
|
|
|
GDI Device Driver - Plotter.
|
|
|
|
|
|
[Notes:]
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define DBG_PLOTFILENAME DbgHTBmp4
|
|
|
|
#define DBG_OUTPUT4BPP 0x00000001
|
|
#define DBG_OUTPUT4BPP_ROT 0x00000002
|
|
#define DBG_JOBCANCEL 0x00000004
|
|
|
|
DEFINE_DBGVAR(0);
|
|
|
|
|
|
|
|
//
|
|
// To Use OUT_ONE_4BPP_SCAN, the following variables must be set before hand:
|
|
//
|
|
// HTBmpInfo - The whole structure copied down
|
|
// pbScanSrc - LPBYTE for getting the source scan line buffer
|
|
// pbScanR0 - Red destination scan line buffer pointer
|
|
// pbScanG0 - Green destination scan line buffer pointer
|
|
// pbScanB0 - Blue destination scan line buffer pointer
|
|
// RTLScans.cxBytes- Total size of destination scan line buffer per plane
|
|
// pHTXB - Computed HTXB xlate table in pPDev
|
|
//
|
|
// This macro will always assume the pbScanSrc is DWORD aligned. This
|
|
// makes the inner loop go faster since we only need to move the source once
|
|
// for all raster planes.
|
|
//
|
|
// This macro will directly return a FALSE if a CANCEL JOB is detected during
|
|
// procesing.
|
|
//
|
|
// This will output directly to RTL.
|
|
//
|
|
//
|
|
|
|
#define OUT_ONE_4BPP_SCAN \
|
|
{ \
|
|
LPBYTE pbScanR = pbScanR0; \
|
|
LPBYTE pbScanG = pbScanG0; \
|
|
LPBYTE pbScanB = pbScanB0; \
|
|
DWORD LoopHTXB = RTLScans.cxBytes; \
|
|
HTXB htXB; \
|
|
\
|
|
while (LoopHTXB--) { \
|
|
\
|
|
P4B_TO_3P_DW(htXB.dw, pHTXB, pbScanSrc); \
|
|
\
|
|
*pbScanR++ = HTXB_R(htXB); \
|
|
*pbScanG++ = HTXB_G(htXB); \
|
|
*pbScanB++ = HTXB_B(htXB); \
|
|
} \
|
|
\
|
|
OutputRTLScans(HTBmpInfo.pPDev, \
|
|
pbScanR0, \
|
|
pbScanG0, \
|
|
pbScanB0, \
|
|
&RTLScans); \
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
Output4bppHTBmp(
|
|
PHTBMPINFO pHTBmpInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function outputs a 4 bpp halftoned bitmap
|
|
|
|
Arguments:
|
|
|
|
pHTBmpInfo - Pointer to the HTBMPINFO data structure set up for this
|
|
fuction to output the bitmap
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessful otherwise a FALSE is returned
|
|
|
|
|
|
Author:
|
|
|
|
Created
|
|
|
|
18-Jan-1994 Tue 16:05:08 Updated
|
|
Changed ASSERT to look at pHTBmpInfo instead of HTBmpInfo
|
|
|
|
21-Dec-1993 Tue 16:05:08 Updated
|
|
Re-write to make it take HTBMPINFO
|
|
|
|
16-Mar-1994 Wed 16:54:59 updated
|
|
Updated so we do not copy to the temp. buffer anymore, the masking
|
|
of last source byte problem in OutputRTLScans() will be smart enough
|
|
to put the original byte back after the masking
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
LPBYTE pbScanSrc;
|
|
PHTXB pHTXB;
|
|
LPBYTE pbScanR0;
|
|
LPBYTE pbScanG0;
|
|
LPBYTE pbScanB0;
|
|
HTBMPINFO HTBmpInfo;
|
|
RTLSCANS RTLScans;
|
|
DWORD LShiftCount;
|
|
|
|
|
|
PLOTASSERT(1, "Output4bppHTBmp: No DWORD align buffer (pRotBuf)",
|
|
pHTBmpInfo->pRotBuf, 0);
|
|
HTBmpInfo = *pHTBmpInfo;
|
|
|
|
EnterRTLScans(HTBmpInfo.pPDev,
|
|
&RTLScans,
|
|
HTBmpInfo.szlBmp.cx,
|
|
HTBmpInfo.szlBmp.cy,
|
|
FALSE);
|
|
|
|
pHTXB = ((PDRVHTINFO)HTBmpInfo.pPDev->pvDrvHTData)->pHTXB;
|
|
HTBmpInfo.pScan0 += (HTBmpInfo.OffBmp.x >> 1);
|
|
pbScanR0 = HTBmpInfo.pScanBuf;
|
|
pbScanG0 = pbScanR0 + RTLScans.cxBytes;
|
|
pbScanB0 = pbScanG0 + RTLScans.cxBytes;
|
|
|
|
PLOTASSERT(1, "The ScanBuf size is too small (%ld)",
|
|
(RTLScans.cxBytes * 3) <= HTBmpInfo.cScanBuf, HTBmpInfo.cScanBuf);
|
|
|
|
PLOTASSERT(1, "The RotBuf size is too small (%ld)",
|
|
(DWORD)((HTBmpInfo.szlBmp.cx + 1) >> 1) <= HTBmpInfo.cRotBuf,
|
|
HTBmpInfo.cRotBuf);
|
|
|
|
if (HTBmpInfo.OffBmp.x & 0x01) {
|
|
|
|
//
|
|
// We must shift one nibble to the left now
|
|
//
|
|
|
|
LShiftCount = (DWORD)HTBmpInfo.szlBmp.cx;
|
|
|
|
PLOTDBG(DBG_OUTPUT4BPP,
|
|
("Output4bppHTBmp: Must SHIFT LEFT 1 NIBBLE To align"));
|
|
|
|
} else {
|
|
|
|
LShiftCount = 0;
|
|
}
|
|
|
|
//
|
|
// We must be very careful not to read past the end of the source buffer.
|
|
// This could happen if we pbScanSrc is not DWORD aligned, since this
|
|
// will cause the last conversion macro to load all 4 bytes. To resolve
|
|
// this we can either copy the source buffer to a DWORD aligned temporary
|
|
// location, or handle the last incomplete DWORD differently. This only
|
|
// occurs when the bitmap is NOT rotated, and (pbScanSrc & 0x03).
|
|
//
|
|
|
|
while (RTLScans.Flags & RTLSF_MORE_SCAN) {
|
|
|
|
//
|
|
// This is the final source for this scan line
|
|
//
|
|
|
|
if (LShiftCount) {
|
|
|
|
LPBYTE pbTmp;
|
|
DWORD PairCount;
|
|
BYTE b0;
|
|
BYTE b1;
|
|
|
|
|
|
pbTmp = HTBmpInfo.pScan0;
|
|
b1 = *pbTmp;
|
|
pbScanSrc = HTBmpInfo.pRotBuf;
|
|
PairCount = LShiftCount;
|
|
|
|
while (PairCount > 1) {
|
|
|
|
b0 = b1;
|
|
b1 = *pbTmp++;
|
|
*pbScanSrc++ = (BYTE)((b0 << 4) | (b1 >> 4));
|
|
PairCount -= 2;
|
|
}
|
|
|
|
if (PairCount) {
|
|
|
|
//
|
|
// If we have the last nibble to do then make it 0xF0 nibble,
|
|
// so we only look at the bits of interest.
|
|
//
|
|
|
|
*pbScanSrc = (BYTE)(b1 << 4);
|
|
}
|
|
|
|
//
|
|
// Reset this pointer back to the final shifted source buffer
|
|
//
|
|
|
|
pbScanSrc = HTBmpInfo.pRotBuf;
|
|
|
|
} else {
|
|
|
|
pbScanSrc = HTBmpInfo.pScan0;
|
|
}
|
|
|
|
//
|
|
// Output one 4 bpp scan line (3 planes)
|
|
//
|
|
|
|
OUT_ONE_4BPP_SCAN;
|
|
|
|
//
|
|
// advance source bitmap buffer pointer to next scan line
|
|
//
|
|
|
|
HTBmpInfo.pScan0 += HTBmpInfo.Delta;
|
|
}
|
|
|
|
//
|
|
// The caller will send END GRAPHIC command if we return TRUE, thus
|
|
// completing the RTL graphic command.
|
|
//
|
|
|
|
ExitRTLScans(HTBmpInfo.pPDev, &RTLScans);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
Output4bppRotateHTBmp(
|
|
PHTBMPINFO pHTBmpInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function outputs a 4 bpp halftoned bitmap and rotates it to the left
|
|
as illustrated
|
|
|
|
cx Org ---- +X -->
|
|
+-------+ | @------------+
|
|
| | | | |
|
|
| ***** | | | * |
|
|
c| * | | * c|
|
|
y| * | +Y | ******* y|
|
|
| * | | * |
|
|
| * | | | * |
|
|
| * | V | |
|
|
| * | +------------+
|
|
+-------+
|
|
|
|
|
|
Arguments:
|
|
|
|
pHTBmpInfo - Pointer to the HTBMPINFO data structure set up for this
|
|
fuction to output the bitmap
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessful otherwise a FALSE is returned
|
|
|
|
|
|
Author:
|
|
|
|
21-Dec-1993 Tue 16:05:08 Updated
|
|
Re-write to make it take an HTBMPINFO structure.
|
|
|
|
Created
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
LPBYTE pbScanSrc;
|
|
LPBYTE pb2ndScan;
|
|
PHTXB pHTXB;
|
|
LPBYTE pbScanR0;
|
|
LPBYTE pbScanG0;
|
|
LPBYTE pbScanB0;
|
|
HTBMPINFO HTBmpInfo;
|
|
RTLSCANS RTLScans;
|
|
TPINFO TPInfo;
|
|
DWORD EndX;
|
|
|
|
|
|
//
|
|
// The EndX is the pixel we will start reading in the X direction, we must
|
|
// setup the variable correctly before we call OUT_4BPP_SETUP.
|
|
//
|
|
|
|
HTBmpInfo = *pHTBmpInfo;
|
|
|
|
EnterRTLScans(HTBmpInfo.pPDev,
|
|
&RTLScans,
|
|
HTBmpInfo.szlBmp.cy,
|
|
HTBmpInfo.szlBmp.cx,
|
|
FALSE);
|
|
|
|
pHTXB = ((PDRVHTINFO)HTBmpInfo.pPDev->pvDrvHTData)->pHTXB;
|
|
EndX = (DWORD)(HTBmpInfo.OffBmp.x + HTBmpInfo.szlBmp.cx - 1);
|
|
HTBmpInfo.pScan0 += (EndX >> 1);
|
|
pbScanR0 = HTBmpInfo.pScanBuf;
|
|
pbScanG0 = pbScanR0 + RTLScans.cxBytes;
|
|
pbScanB0 = pbScanG0 + RTLScans.cxBytes;
|
|
|
|
PLOTASSERT(1, "The ScanBuf size is too small (%ld)",
|
|
(RTLScans.cxBytes * 3) <= HTBmpInfo.cScanBuf, HTBmpInfo.cScanBuf);
|
|
|
|
//
|
|
// after the transpose of the source bitmap into two scanlines the rotated
|
|
// buffer will always start from the high nibble, we will never have
|
|
// an odd src X position.
|
|
// We assume rotation is always to the right 90 degree
|
|
//
|
|
|
|
TPInfo.pPDev = HTBmpInfo.pPDev;
|
|
TPInfo.pSrc = HTBmpInfo.pScan0;
|
|
TPInfo.pDest = HTBmpInfo.pRotBuf;
|
|
TPInfo.cbSrcScan = HTBmpInfo.Delta;
|
|
TPInfo.cbDestScan = (LONG)((HTBmpInfo.szlBmp.cy + 1) >> 1);
|
|
TPInfo.cbDestScan = (LONG)DW_ALIGN(TPInfo.cbDestScan);
|
|
TPInfo.cySrc = HTBmpInfo.szlBmp.cy;
|
|
TPInfo.DestXStart = 0;
|
|
|
|
PLOTASSERT(1, "The RotBuf size is too small (%ld)",
|
|
(DWORD)(TPInfo.cbDestScan << 1) <= HTBmpInfo.cRotBuf,
|
|
HTBmpInfo.cRotBuf);
|
|
|
|
//
|
|
// Compute the 2nd scan pointer once, rather than every time in the
|
|
// loop.
|
|
//
|
|
|
|
pb2ndScan = TPInfo.pDest + TPInfo.cbDestScan;
|
|
|
|
|
|
//
|
|
// If we are in an even position do the first transpose once, outside the
|
|
// loop, so we don't have to check this state for ever pass through the
|
|
// loop. If we do the transpose, TPInfo.pSrc, will be decremented by one,
|
|
// and pointing to the correct position.
|
|
//
|
|
|
|
if (!(EndX &= 0x01)) {
|
|
|
|
TransPos4BPP(&TPInfo);
|
|
}
|
|
|
|
|
|
while (RTLScans.Flags & RTLSF_MORE_SCAN) {
|
|
|
|
//
|
|
// Do the transpose, only if the source goes into the new byte position.
|
|
// After the transpose (right 90 degrees) the TPInfo.pDest will point
|
|
// to the first scan line and TPInfo.pDest + TPInfo.cbDestScan will be
|
|
// the second scan line.
|
|
//
|
|
|
|
|
|
if (EndX ^= 0x01) {
|
|
|
|
pbScanSrc = pb2ndScan;
|
|
|
|
} else {
|
|
|
|
TransPos4BPP(&TPInfo);
|
|
|
|
//
|
|
// Point to the first scan line in the rotated direction. This
|
|
// will be computed correctly by the TRANSPOSE function, even
|
|
// if we rotated left.
|
|
//
|
|
|
|
pbScanSrc = TPInfo.pDest;
|
|
}
|
|
|
|
//
|
|
// Output one 4bpp scan line (in 3 plane format)
|
|
//
|
|
|
|
OUT_ONE_4BPP_SCAN;
|
|
}
|
|
|
|
//
|
|
// The caller will send the END GRAPHIC command if we return TRUE, thus
|
|
// completing the RTL graphic command.
|
|
//
|
|
|
|
ExitRTLScans(HTBmpInfo.pPDev, &RTLScans);
|
|
|
|
return(TRUE);
|
|
}
|