|
|
/*++
Copyright (c) 1990-2003 Microsoft Corporation
Module Name:
htbmp1.c
Abstract:
This module contains functions used to output halftoned 1BPP bitmaps to the target device. Rotation is also handled here.
Author:
21-Dec-1993 Tue 21:35:56 created
[Environment:]
GDI Device Driver - Plotter.
[Notes:]
Revision History:
10-Feb-1994 Thu 16:52:55 updated Remove pDrvHTInfo->PalXlate[] reference, all monochrome bitmap will be sent as index 0/1 color pal set before hand (in OutputHTBitmap)
--*/
#include "precomp.h"
#pragma hdrstop
#define DBG_PLOTFILENAME DbgHTBmp1
#define DBG_OUTPUT1BPP 0x00000001
#define DBG_OUTPUT1BPP_ROT 0x00000002
#define DBG_JOBCANCEL 0x00000004
#define DBG_SHOWSCAN 0x80000000
DEFINE_DBGVAR(0);
#define HTBIF_MONO_BA (HTBIF_FLIP_MONOBITS | HTBIF_BA_PAD_1)
//
// Very useful macro for outputing scan line in a text representation to
// the debug output stream.
//
#define SHOW_SCAN \
{ \ if (DBG_PLOTFILENAME & DBG_SHOWSCAN) { \ \ LPBYTE pbCur; \ UINT cx; \ UINT x; \ UINT Size; \ BYTE bData; \ BYTE Mask; \ BYTE Buf[128]; \ \ pbCur = pbScanSrc; \ Mask = 0; \ \ if ((cx = RTLScans.cxBytes << 3) >= sizeof(Buf)) { \ \ cx = sizeof(Buf) - 1; \ } \ \ for (Size = x = 0; x < cx; x++) { \ \ if (!(Mask >>= 1)) { \ \ Mask = 0x80; \ bData = *pbCur++; \ } \ \ Buf[Size++] = (BYTE)((bData & Mask) ? 178 : 176); \ } \ \ Buf[Size] = '\0'; \ DBGP((Buf)); \ } \ }
//
// To Use OUT_ONE_1BPP_SCAN, the following variables must be set ahead of time
//
// HTBmpInfo - The whole structure with bitmap info set
// cxDestBytes - Total size of destination scan line buffer per plane
//
// This macro will directly return a FALSE if a CANCEL JOB is detected in
// the PDEV
//
// This function will only allowe the pbScanSrc passed = HTBmpInfo.pScanBuf
//
// 21-Mar-1994 Mon 17:00:21 updated
// If we shift to to the left then we will only load last source if
// we have a valid last source line.
//
#define OUT_ONE_1BPP_SCAN \
{ \ LPBYTE pbTempS; \ \ if (LShift) { \ \ BYTE b0; \ INT SL; \ INT SR; \ \ pbTempS = HTBmpInfo.pScanBuf; \ Loop = RTLScans.cxBytes; \ \ if ((SL = LShift) > 0) { \ \ b0 = *pbScanSrc++; \ SR = 8 - SL; \ \ while (Loop--) { \ \ *pbTempS = (b0 << SL); \ \ if ((Loop) || (FullSrc)) { \ \ *pbTempS++ |= ((b0 = *pbScanSrc++) >> SR); \ } \ } \ \ } else { \ \ SR = -SL; \ SL = 8 - SR; \ b0 = 0; \ \ while (Loop--) { \ \ *pbTempS = (b0 << SL); \ *pbTempS++ |= ((b0 = *pbScanSrc++) >> SR); \ } \ } \ \ pbScanSrc = HTBmpInfo.pScanBuf; \ } \ \ if (HTBmpInfo.Flags & HTBIF_FLIP_MONOBITS) { \ \ pbTempS = (LPBYTE)pbScanSrc; \ Loop = RTLScans.cxBytes; \ \ while (Loop--) { \ \ *pbTempS++ ^= 0xFF; \ } \ } \ \ if (HTBmpInfo.Flags & HTBIF_BA_PAD_1) { \ \ *(pbScanSrc ) |= MaskBA[0]; \ *(pbScanSrc + MaskIdx) |= MaskBA[1]; \ \ } else { \ \ *(pbScanSrc ) &= MaskBA[0]; \ *(pbScanSrc + MaskIdx) &= MaskBA[1]; \ } \ \ OutputRTLScans(HTBmpInfo.pPDev, \ pbScanSrc, \ NULL, \ NULL, \ &RTLScans); \ }
BOOL FillRect1bppBmp( PHTBMPINFO pHTBmpInfo, BYTE FillByte, BOOL Pad1, BOOL Rotate )
/*++
Routine Description:
This function fills a 1BPP bitmap with the passed mode.
Arguments:
pHTBmpInfo - Pointer to the HTBMPINFO data structure set up for this fuction to output the bitmap
FillByte - Byte to be filled
Pad1 - TRUE if need to pad 1 bit else 0 bit
Rotate - TRUE if bitmap should be rotated
Return Value:
TRUE if sucessful otherwise a FALSE is returned
Author:
06-Apr-1994 Wed 14:34:28 created For Fill the area 0,1 or inversion, so we will get away of some device 600 byte alignment problem
Revision History:
--*/
{ LPBYTE pbScanSrc; HTBMPINFO HTBmpInfo; RTLSCANS RTLScans; DWORD FullSrc; DWORD Loop; INT LShift; UINT MaskIdx; BYTE MaskBA[2];
HTBmpInfo = *pHTBmpInfo; LShift = 0;
//
// Mode <0: Invert Bits (Pad 0 : XOR)
// =0: Fill All ZERO (Pad 1 : AND)
// >0: Fill All Ones (Pad 0 : OR)
//
if (Rotate) {
HTBmpInfo.szlBmp.cx = pHTBmpInfo->szlBmp.cy; HTBmpInfo.szlBmp.cy = pHTBmpInfo->szlBmp.cx; FullSrc = (DWORD)(HTBmpInfo.rclBmp.top & 0x07);
} else {
FullSrc = (DWORD)(HTBmpInfo.rclBmp.left & 0x07); }
HTBmpInfo.Flags = (BYTE)((Pad1) ? HTBIF_BA_PAD_1 : 0);
//
// Some devices require that the scanlines produced be byte aligned,
// not allowing us to simply position to the correct coordinate, and
// output the scan line. Instead we must determine the nearest byte
// aligned starting coordinate, and shift the resulting scan line
// accordingly. Finally we must output the shifted scan line, in such
// a way as to not affect the padding area (if possible).
//
if (NEED_BYTEALIGN(HTBmpInfo.pPDev)) {
//
// Now we must shift either left or right, depending on the rclBmp.left
// location.
//
HTBmpInfo.szlBmp.cx += FullSrc;
//
// Determine the correct mask byte to use, so we only affect bits
// in the original position (not ones we are forced to shift
// to in order to overcome device positioning limitations.
//
MaskIdx = (UINT)FullSrc; MaskBA[0] = (BYTE)((MaskIdx) ? ((0xFF >> MaskIdx) ^ 0xFF) : 0);
if (MaskIdx = (INT)(HTBmpInfo.szlBmp.cx & 0x07)) {
//
// Increase cx so that it covers the last full byte, this way the
// compression will not try to clear it
//
MaskBA[1] = (BYTE)(0xFF >> MaskIdx); HTBmpInfo.szlBmp.cx += (8 - MaskIdx);
} else {
MaskBA[1] = 0; }
if (HTBmpInfo.Flags & HTBIF_BA_PAD_1) {
PLOTDBG(DBG_OUTPUT1BPP, ("Output1bppHTBmp: BYTE ALIGN: MaskBA=1: OR %02lx:%02lx", MaskBA[0], MaskBA[1]));
} else {
MaskBA[0] ^= 0xFF; MaskBA[1] ^= 0xFF;
PLOTDBG(DBG_OUTPUT1BPP, ("Output1bppHTBmp: BYTE ALIGN: MaskBA=0: AND %02lx:%02lx", MaskBA[0], MaskBA[1])); }
} else {
HTBmpInfo.Flags &= ~(HTBIF_MONO_BA); MaskBA[0] = MaskBA[1] = 0xFF; }
//
// If we are shifting to the left then we might have SRC BYTES <= DST BYTES
// so we need to make sure we do not read the extra byte.
// This guarantees we will never OVERREAD the source.
//
EnterRTLScans(HTBmpInfo.pPDev, &RTLScans, HTBmpInfo.szlBmp.cx, HTBmpInfo.szlBmp.cy, TRUE);
FullSrc = 0; MaskIdx = RTLScans.cxBytes - 1;
#if DBG
if (DBG_PLOTFILENAME & DBG_SHOWSCAN) {
DBGP(("\n\n")); } #endif
//
// Stay in a loop processing the source till we are done.
//
while (RTLScans.Flags & RTLSF_MORE_SCAN) {
FillMemory(pbScanSrc = HTBmpInfo.pScanBuf, RTLScans.cxBytes, FillByte);
OUT_ONE_1BPP_SCAN; #if DBG
SHOW_SCAN; #endif
}
ExitRTLScans(HTBmpInfo.pPDev, &RTLScans);
return(TRUE); }
BOOL Output1bppHTBmp( PHTBMPINFO pHTBmpInfo )
/*++
Routine Description:
This function outputs a 1 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 JB
21-Dec-1993 Tue 16:05:08 Updated Re-write to make it take HTBMPINFO
23-Dec-1993 Thu 22:47:45 updated We must check if the source bit 1 is BLACK, if not then we need to flip it
25-Jan-1994 Tue 17:32:36 updated Fixed dwFlipCount mis-computation from DW_ALIGN(cxDestBytes) to (DWORD)(DW_ALIGN(7cxDestBytes) >> 2);
22-Feb-1994 Tue 14:54:42 updated Using RTLScans data structure
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; HTBMPINFO HTBmpInfo; RTLSCANS RTLScans; DWORD FullSrc; DWORD Loop; INT LShift; UINT MaskIdx; BYTE MaskBA[2];
HTBmpInfo = *pHTBmpInfo; HTBmpInfo.pScan0 += (HTBmpInfo.OffBmp.x >> 3); LShift = (INT)(HTBmpInfo.OffBmp.x & 0x07); Loop = (DWORD)((HTBmpInfo.szlBmp.cx + (LONG)LShift + 7) >> 3);
if (NEED_BYTEALIGN(HTBmpInfo.pPDev)) {
//
// Based on some devices requiring byte aligned coordinates for
// outputing graphics, we have to handle that situation now.
// We do this by finding the closest byte aligned position,
// then shifting, masking and padding to effect the corect pixels
// on the target device.
//
FullSrc = (INT)(HTBmpInfo.rclBmp.left & 0x07); HTBmpInfo.szlBmp.cx += FullSrc; LShift -= FullSrc;
//
// Check and compute masking since we are handling the byte align
// requirement of the target device.
//
MaskIdx = (UINT)FullSrc; MaskBA[0] = (BYTE)((MaskIdx) ? ((0xFF >> MaskIdx) ^ 0xFF) : 0);
if (MaskIdx = (INT)(HTBmpInfo.szlBmp.cx & 0x07)) {
//
// Increase cx so that it covers the last byte, this way the
// compression will not try to clear it
//
MaskBA[1] = (BYTE)(0xFF >> MaskIdx); HTBmpInfo.szlBmp.cx += (8 - MaskIdx);
} else {
MaskBA[1] = 0; }
if (HTBmpInfo.Flags & HTBIF_BA_PAD_1) {
PLOTDBG(DBG_OUTPUT1BPP, ("Output1bppHTBmp: BYTE ALIGN: MaskBA=1: OR %02lx:%02lx", MaskBA[0], MaskBA[1]));
} else {
MaskBA[0] ^= 0xFF; MaskBA[1] ^= 0xFF;
PLOTDBG(DBG_OUTPUT1BPP, ("Output1bppHTBmp: BYTE ALIGN: MaskBA=0: AND %02lx:%02lx", MaskBA[0], MaskBA[1])); }
} else {
HTBmpInfo.Flags &= ~(HTBIF_MONO_BA); MaskBA[0] = MaskBA[1] = 0xFF; }
PLOTDBG(DBG_OUTPUT1BPP, ("Output1bppHTBmp: LShift=%d", LShift));
//
// If we are shifting to the left then we might have SRC BYTES <= DST BYTES
// so we need to make sure we do not read the extra byte.
// This guarantees we will never OVERREAD the source.
//
EnterRTLScans(HTBmpInfo.pPDev, &RTLScans, HTBmpInfo.szlBmp.cx, HTBmpInfo.szlBmp.cy, TRUE);
FullSrc = ((LShift > 0) && (Loop >= RTLScans.cxBytes)) ? 1 : 0; MaskIdx = RTLScans.cxBytes - 1;
#if DBG
if (DBG_PLOTFILENAME & DBG_SHOWSCAN) {
DBGP(("\n\n")); } #endif
while (RTLScans.Flags & RTLSF_MORE_SCAN) {
if (LShift) {
pbScanSrc = HTBmpInfo.pScan0;
} else {
//
// Make copy if we do not shift it to temp buffer, so we always
// output from temp buffer
//
CopyMemory(pbScanSrc = HTBmpInfo.pScanBuf, HTBmpInfo.pScan0, RTLScans.cxBytes); }
HTBmpInfo.pScan0 += HTBmpInfo.Delta;
OUT_ONE_1BPP_SCAN; #if DBG
SHOW_SCAN; #endif
}
ExitRTLScans(HTBmpInfo.pPDev, &RTLScans);
return(TRUE); }
BOOL Output1bppRotateHTBmp( PHTBMPINFO pHTBmpInfo )
/*++
Routine Description:
This function outputs a 1 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 function to output the bitmap
Return Value:
TRUE if sucessful otherwise a FALSE is returned
Author:
Created JB
21-Dec-1993 Tue 16:05:08 Updated Re-write to make it take HTBMPINFO
23-Dec-1993 Thu 22:47:45 updated We must check if the source bit 1 is BLACK, if not then we need to flip it, we will flip using DWORD mode and only do it at time we have transpos the buffer.
25-Jan-1994 Tue 17:32:36 updated Fixed dwFlipCount mis-computation from (TPInfo.cbDestScan << 1) to (TPInfo.cbDestScan >> 2)
22-Feb-1994 Tue 14:54:42 updated Using RTLScans data structure
Revision History:
--*/
{ LPBYTE pbCurScan; LPBYTE pbScanSrc; HTBMPINFO HTBmpInfo; RTLSCANS RTLScans; TPINFO TPInfo; DWORD FullSrc; DWORD EndX; DWORD Loop; INT LShift; UINT MaskIdx; BYTE MaskBA[2];
//
// EndX is the pixel we will start reading from in the X direction. We must
// setup the varialbe before we call OUT_1BMP_SETUP, also set LShift to 0
// because we will never left shift in this mode.
//
HTBmpInfo = *pHTBmpInfo; EndX = (DWORD)(HTBmpInfo.OffBmp.x + HTBmpInfo.szlBmp.cx - 1); HTBmpInfo.pScan0 += (EndX >> 3); LShift = 0; FullSrc = TPInfo.DestXStart = 0; TPInfo.cySrc = HTBmpInfo.szlBmp.cy;
//
// Since we are having to rotate anyway, in this model, we will correctly
// identify the x coordinate to be bytealigned, and have the correct
// LShift amount after the rotation (taking into account). This way, we
// don't have to addionally shift.
//
if (NEED_BYTEALIGN(HTBmpInfo.pPDev)) {
//
// In order for us to start at the correct offset, the TPInfo.DestXStart
// will be set to the correct location. When we rotate to the right,
// the original rclBmp.top is the left offset for the RTL coordinate in
// the target device.
//
TPInfo.DestXStart = (DWORD)(HTBmpInfo.rclBmp.top & 0x07); HTBmpInfo.szlBmp.cy += TPInfo.DestXStart;
//
// Create the correct mask for the byte aligned mode. This way,
// we don't affect pixels that fall into the area we send data
// to in order to take into account the byte aligned position change.
//
MaskIdx = (UINT)TPInfo.DestXStart; MaskBA[0] = (BYTE)((MaskIdx) ? ((0xFF >> MaskIdx) ^ 0xFF) : 0);
if (MaskIdx = (INT)(HTBmpInfo.szlBmp.cy & 0x07)) {
//
// Increase cx so that it cover the last full byte, this way the
// compression in effect will not try to clear it
//
MaskBA[1] = (BYTE)(0xFF >> MaskIdx); HTBmpInfo.szlBmp.cy += (8 - MaskIdx);
} else {
MaskBA[1] = 0; }
if (HTBmpInfo.Flags & HTBIF_BA_PAD_1) {
PLOTDBG(DBG_OUTPUT1BPP, ("Output1bppHTBmp: BYTE ALIGN: MaskBA=1: OR %02lx:%02lx", MaskBA[0], MaskBA[1]));
} else {
MaskBA[0] ^= 0xFF; MaskBA[1] ^= 0xFF;
PLOTDBG(DBG_OUTPUT1BPP, ("Output1bppHTBmp: BYTE ALIGN: MaskBA=0: AND %02lx:%02lx", MaskBA[0], MaskBA[1])); }
} else {
HTBmpInfo.Flags &= ~(HTBIF_MONO_BA); MaskBA[0] = MaskBA[1] = 0xFF; }
EnterRTLScans(HTBmpInfo.pPDev, &RTLScans, HTBmpInfo.szlBmp.cy, HTBmpInfo.szlBmp.cx, TRUE);
MaskIdx = RTLScans.cxBytes - 1; TPInfo.pPDev = HTBmpInfo.pPDev; TPInfo.pSrc = HTBmpInfo.pScan0; TPInfo.pDest = HTBmpInfo.pRotBuf; TPInfo.cbSrcScan = HTBmpInfo.Delta; TPInfo.cbDestScan = DW_ALIGN(RTLScans.cxBytes);
PLOTASSERT(1, "The RotBuf size is too small (%ld)", (DWORD)(TPInfo.cbDestScan << 3) <= HTBmpInfo.cRotBuf, HTBmpInfo.cRotBuf);
//
// We will always do the first transpose and set the correct pbCurScan
// first. We will make EndX the loop counter and increment it by one
// first. We do this because we increment pbCurScan in the inner loop.
// We use (6 - EndX++) based on the fact we are rotating 90 degrees to the
// right. The first scan line is EndX == 7 , the second is at EndX == 6 and
// so forth. We use 6, in order to go back one extra scan line so that the
// inner loop will do pbCurScan += TPInfo.cbNextScan will cancel the effect
// the first time around (since we incremented to accomodate). The EndX++
// is needed for the same reason, since we do an EndX-- in the inner loop.
//
//
// Win64 fix: Increase a pointer with a INT_PTR quantity.
//
EndX &= 0x07; pbCurScan = TPInfo.pDest + (INT_PTR)((6 - (INT_PTR)EndX++) * TPInfo.cbDestScan);
TransPos1BPP(&TPInfo);
#if DBG
if (DBG_PLOTFILENAME & DBG_SHOWSCAN) {
DBGP(("\n\n")); } #endif
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 now points
// to the first scan line and TPInfo.pDest + TPInfo.cbDestScan has the
// 2nd scan line and so forth.
//
if (EndX--) {
//
// Still not finished the rotated buffer's scan line yet so
// increment the pbScanSrc to the next scan line
//
pbCurScan += TPInfo.cbDestScan;
} else {
TransPos1BPP(&TPInfo);
//
// Point to the first scan line in the rotated direction by
// computing correctly by the TRANSPOS function, even if we
// rotated left.
//
EndX = 7; pbCurScan = TPInfo.pDest; }
//
// Output one 1bpp scan line and handle shift control
//
pbScanSrc = pbCurScan;
OUT_ONE_1BPP_SCAN; #if DBG
SHOW_SCAN; #endif
}
ExitRTLScans(HTBmpInfo.pPDev, &RTLScans);
return(TRUE); }
|