VOID PsSelectManualFeed( PDEVDATA pdev, BOOL bManual ) /*++ Routine Description: Enable or disable manual feed feature on the printer. Arguments: bManual TRUE to enable manual feed and FALSE to disable it Return Value: NONE --*/ { PSTR pstr; // Check if the manual feed feature is already // in the requested state. if (bManual != ((pdev->dwFlags & PDEV_MANUALFEED) != 0)) { // Generate PostScript to send to the printer // and enclosed within a stopped context. DscBeginFeature(pdev, "ManualFeed "); psprintf(pdev, "%s\n", bManual ? "True" : "False"); if ((pstr = PpdFindManualFeedCode(pdev->hppd, bManual)) != NULL) { psputs(pdev, pstr); } DscEndFeature(pdev); // Set or clear the manual feed flag in DEVDATA if (bManual) pdev->dwFlags |= PDEV_MANUALFEED; else pdev->dwFlags &= ~PDEV_MANUALFEED; } }
VOID SetTimeoutValues( PDEVDATA pdev ) /*++ Routine Description: Output code to printer to set job and wait timeout values Arguments: pdev Pointer to DEVDATA structure Return Value: NONE --*/ { psprintf(pdev, "[{%d\n", pdev->pPrinterData->dwJobTimeout); psputs(pdev, "/languagelevel where{pop languagelevel 2 ge}{false}ifelse\n" "{1 dict dup/JobTimeout 4 -1 roll put setuserparams}\n" "{statusdict/setjobtimeout get exec}ifelse\n" "}stopped cleartomark\n"); psprintf(pdev, "[{%d\n", pdev->pPrinterData->dwWaitTimeout); psputs(pdev, "/languagelevel where{pop languagelevel 2 ge}{false}ifelse\n" "{1 dict dup/WaitTimeout 4 -1 roll put setuserparams}\n" "{statusdict/waittimeout 3 -1 roll put}ifelse\n" "}stopped cleartomark\n"); }
VOID SetResolution( PDEVDATA pdev, DWORD res, WORD restype) /*++ Routine Description: Generate commands to set printer resolution. Arguments: pdev pointer to device data res desired resolution bPJL TRUE this is called at the beginning of a job FALSE if this called during the setup section Return Value: NONE --*/ { HPPD hppd = pdev->hppd; PRESOPTION pResOption; // We only need to do something when the requested // resolution type matches what the printer can do if (restype != hppd->wResType) return; // Check if the desired resolution is supported pResOption = PpdFindResolution(hppd, res); // Ignore if the desired resolution is not found if (pResOption == NULL) { DBGMSG1(DBG_LEVEL_TERSE, "No invocation string for resolution option: %d.\n", res); return; } switch (restype) { case RESTYPE_NORMAL: // Use normal PS code if (pResOption->pInvocation == NULL) { DBGMSG(DBG_LEVEL_ERROR, "Failed to set resolution."); } else { DscBeginFeature(pdev, "Resolution "); psprintf(pdev, "%d\n", res); psputs(pdev, pResOption->pInvocation); DscEndFeature(pdev); } break; case RESTYPE_JCL: // Use JCL code if (! PpdSupportsProtocol(hppd,PROTOCOL_PJL) || pResOption->pJclCode == NULL) { DBGMSG(DBG_LEVEL_ERROR, "Cannot set resolution using PJL commands.\n"); } else { psputs(pdev, pResOption->pJclCode); } break; case RESTYPE_EXITSERVER: // Use exitserver code if (pResOption->pSetResCode == NULL) { DBGMSG(DBG_LEVEL_ERROR, "Failed to set resolution."); } else { PSTR password = hppd->pPassword ? hppd->pPassword : "******"; psputs(pdev, "%%BeginExitServer: "); psputs(pdev, password); psprintf(pdev, "\n%%%%Resolution: %d\n", res); psputs(pdev, password); psputs(pdev, "\n"); psputs(pdev, pResOption->pSetResCode); psputs(pdev, "\n%%EndExitServer\n"); } break; } }
VOID PsSelectCustomPageSize( PDEVDATA pdev ) /*++ Routine Description: Generate PostScript code to select custom page size on the printer. Arguments: pdev Pointer to DEVDATA structure Return Value: NONE --*/ { PSREAL params[MAXPCP]; INT index; HPPD hppd = pdev->hppd; PSREAL xlen, ylen; // Sanity check: if no custom page size invocation is provided, // simply return with emitting anything. if (hppd->pCustomSizeCode == NULL) { DBGMSG(DBG_LEVEL_WARNING, "No invocation string for custom page size.\n"); return; } // Generate parameters for custom page size invocation // Sort them according to the order specified in PPD file for (index=0; index < MAXPCP; index++) params[index] = 0; // Figure out size of the physical page along x- and y-axis // // Undo the effect of AdjustForLandscape here: // in landscape mode, CurForm.PaperSize.width and // and CurForm.PaperSize.height were swapped. if (pdev->CurForm.bLandscape) { xlen = pdev->CurForm.PaperSize.height; ylen = pdev->CurForm.PaperSize.width; } else { xlen = pdev->CurForm.PaperSize.width; ylen = pdev->CurForm.PaperSize.height; } if (! hppd->bCutSheet) { PSREAL maxWidth, maxHeight, tmpPsreal; // For roll-fed devices, choose orientation 0 or 1 // depending on whether width is bigger than height maxWidth = hppd->maxMediaWidth - hppd->customParam[PCP_WIDTHOFFSET].minVal; maxHeight = hppd->maxMediaHeight - hppd->customParam[PCP_HEIGHTOFFSET].minVal; if (xlen <= ylen && ylen <= maxWidth && xlen <= maxHeight) { // Use orientation 0: ylen is used as width parameter // and xlen is used as height parameter if (hppd->customParam[PCP_ORIENTATION].minVal > 0) { DBGMSG(DBG_LEVEL_ERROR, "Device does not support orientation 0.\n"); } tmpPsreal = xlen; xlen = ylen; ylen = tmpPsreal; } else { // Use orientation 1 if (hppd->customParam[PCP_ORIENTATION].maxVal < 1) { DBGMSG(DBG_LEVEL_ERROR, "Device does not support orientation 1.\n"); } params[hppd->customParam[PCP_ORIENTATION].dwOrder - 1] = 1; } } params[hppd->customParam[PCP_WIDTH].dwOrder - 1] = xlen; params[hppd->customParam[PCP_HEIGHT].dwOrder - 1] = ylen; // Use minimum width and height offsets params[hppd->customParam[PCP_WIDTHOFFSET].dwOrder - 1] = hppd->customParam[PCP_WIDTHOFFSET].minVal; params[hppd->customParam[PCP_HEIGHTOFFSET].dwOrder - 1] = hppd->customParam[PCP_HEIGHTOFFSET].minVal; // Emit custom page size parameters and invocation string for (index=0; index < MAXPCP; index++) psprintf(pdev, "%f ", params[index]); psputs(pdev, hppd->pCustomSizeCode); psputs(pdev, "\n"); }
BOOL bOutputHeader( PDEVDATA pdev ) /*++ Routine Description: Send PostScript output header to the printer Arguments: pdev - Pointer to our DEVDATA Return Value: TRUE if successful, FALSE otherwise --*/ { CHAR *pstr; HPPD hppd = pdev->hppd; ENG_TIME_FIELDS localtime; // // Process information in the public devmode fields and map it to printer // feature selections. This must be called before PsSelectPrinterFeatures. // HandlePublicDevmodeOptions(pdev); // // Spit out job control stuff at the beginning of a job if necessary // if (! bPageIndependence(pdev) && ! (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_NO_JOB_CONTROL)) { if (PpdSupportsProtocol(hppd, PROTOCOL_PJL)) { // Universal exit language if (hppd->pJclBegin != NULL) { psputs(pdev, hppd->pJclBegin); } else { DBGMSG(DBG_LEVEL_TERSE, "No JCLBegin code.\n"); psputs(pdev, "\033%-12345X"); } // If the printer uses PJL commands to set resolution, // then do it before the job. SetResolution(pdev, pdev->dm.dmPublic.dmPrintQuality, RESTYPE_JCL); // Select printer specific features - JCLSetup PsSelectPrinterFeatures(pdev, ODS_JCLSETUP); // if the printer supports job switching, put the printer into // postscript mode now. if (hppd->pJclToPs != NULL) { psputs(pdev, hppd->pJclToPs); } else { DBGMSG(DBG_LEVEL_TERSE, "No JCLToPSInterpreter code.\n"); psputs(pdev, "@PJL ENTER LANGUAGE=POSTSCRIPT\n"); } } else if (PpdSupportsProtocol(hppd, PROTOCOL_SIC)) { // directly call pswrite to output the necessary escape commands. // psputs will NOT output '\000'. pswrite(pdev, "\033\133\113\030\000\006\061\010\000\000\000\000\000", 13); pswrite(pdev, "\000\000\000\000\000\000\000\000\004\033\133\113\003", 13); pswrite(pdev, "\000\006\061\010\004", 5); } else if (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_CTRLD_BEFORE) { // send a ^D before the job pswrite(pdev, "\004", 1); } } psputs(pdev, "%!PS-Adobe-3.0\n"); // output the title of the document. if (pdev->pwstrDocName) { CHAR buf[128]; CopyUnicode2Str(buf, pdev->pwstrDocName, 128); psprintf(pdev, "%%%%Title: %s\n", buf); } else psputs(pdev, "%%Title: Untitled Document\n"); // let the world know who we are. psputs(pdev, "%%Creator: Windows NT 4.0\n"); // print the date and time of creation. EngQueryLocalTime(&localtime); psprintf(pdev, "%%%%CreationDate: %d:%d %d/%d/%d\n", localtime.usHour, localtime.usMinute, localtime.usMonth, localtime.usDay, localtime.usYear); if (! (pdev->dwFlags & PDEV_EPSPRINTING_ESCAPE)) psputs(pdev, "%%Pages: (atend)\n"); // mark the bounding box of the document. psputs(pdev, "%%BoundingBox: "); psprintf(pdev, "%d %d %d %d\n", PSREAL2INT(pdev->CurForm.ImageArea.left), PSREAL2INT(pdev->CurForm.ImageArea.bottom), PSREAL2INT(pdev->CurForm.ImageArea.right), PSREAL2INT(pdev->CurForm.ImageArea.top)); if (pdev->cCopies > 1) psprintf(pdev, "%%%%Requirements: numcopies(%d) collate\n", pdev->cCopies); DscLanguageLevel(pdev, pdev->hppd->dwLangLevel); DscOutputFontComments(pdev, FALSE); // we are done with the comments portion of the document. psputs(pdev, "%%EndComments\n"); // If the printer uses exitserver commands to set // resolution, then do it before any other PS code. SetResolution(pdev, pdev->dm.dmPublic.dmPrintQuality, RESTYPE_EXITSERVER); // define our procedure set. if (!(pdev->dwFlags & PDEV_EPSPRINTING_ESCAPE)) { psputs(pdev, "%%BeginProlog\n"); DownloadNTProcSet(pdev, TRUE); psputs(pdev, "%%EndProlog\n"); } // do the device setup. psputs(pdev, "%%BeginSetup\n"); // set job and wait timeout values SetTimeoutValues(pdev); // Set number of copies psprintf(pdev, "/#copies %d def\n", pdev->cCopies); // Select printer specific features - DocumentSetup and AnySetup PsSelectPrinterFeatures(pdev, ODS_DOCSETUP|ODS_ANYSETUP); // The implemention of EPSPRINTING escape here just follows Win31 if ((pdev->dwFlags & PDEV_EPSPRINTING_ESCAPE) && (pdev->dm.dmPublic.dmOrientation == DMORIENT_LANDSCAPE)) { SetLandscape(pdev, TRUE, pdev->CurForm.PaperSize.height, pdev->CurForm.PaperSize.width); } // // Invert the default transfer function if Negative Output option is selected // if (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_NEG) { psputs(pdev, "[currenttransfer /exec load {1 exch sub} /exec load] cvx settransfer\n"); } psputs(pdev, "%%EndSetup\n"); // the form-tray information has already been sent for the first page. pdev->dwFlags &= ~PDEV_RESETPDEV; return(TRUE); }
VOID PsSelectFormAndTray( PDEVDATA pdev ) /*++ Routine Description: This function pick the tray for a particular form selected, depends on the user request in the UI Arguments: pdev - Pointer to our PDEVDATA Return Value: NONE --*/ { BOOL IsManual; PINPUTSLOT pInputSlot; HPPD hppd = pdev->hppd; PSTR pstr; // If a valid input slot is specified, then we'll instruct // the printer to draw paper from that slot. Otherwise, // we'll tell printer to select input slot based on paper size. IsManual = FALSE; pInputSlot = NULL; if ((pdev->dm.dmPublic.dmFields & DM_DEFAULTSOURCE) && (pdev->dm.dmPublic.dmDefaultSource != DMBIN_FORMSOURCE)) { DWORD SlotNum, cInputSlots; SlotNum = pdev->dm.dmPublic.dmDefaultSource; cInputSlots = UIGROUP_CountOptions(hppd->pInputSlots); if (SlotNum == DMBIN_MANUAL || SlotNum == DMBIN_ENVMANUAL) { // Manual feed is requested IsManual = TRUE; } else if (SlotNum >= DMBIN_USER && SlotNum < DMBIN_USER+cInputSlots) { // A valid input slot is requested pInputSlot = (PINPUTSLOT) LISTOBJ_FindIndexed( (PLISTOBJ) hppd->pInputSlots->pUiOptions, SlotNum - DMBIN_USER); } } else if (pdev->CurForm.FormName[0] != NUL) { // No input slot is specifically requested. Go through // the form to tray assignment table and find the input // slot matching the requested form. pInputSlot = MatchFormToTray(pdev, &IsManual); } if (IsManual) { // If manual feed feature is requested, then // generate PostScript code to enable it. PsSelectManualFeed(pdev, TRUE); } else { // Disable manual feed if it's currently enabled PsSelectManualFeed(pdev, FALSE); if (pInputSlot != NULL) { // If an input slot is designated, then generate // PostScript code to select it. DscBeginFeature(pdev, "InputSlot "); psprintf(pdev, "%s\n", pInputSlot->pName); if (pInputSlot->pInvocation != NULL) psputs(pdev, pInputSlot->pInvocation); DscEndFeature(pdev); } } if (IsCustomPrinterForm(& pdev->CurForm)) { // If the custom page size is requested, then generate // appropriate PostScript code to send to the printer. DscBeginFeature(pdev, "CustomPageSize\n"); PsSelectCustomPageSize(pdev); DscEndFeature(pdev); } else if (pInputSlot == NULL || pInputSlot->bReqPageRgn) { BOOL bRegion; PMEDIAOPTION pMediaOption; // If an input slot was selected and it doesn't require // PageRegion, then we are done. Otherwise, we need to // generate either PageRegion or PageSize code (depending // on whether a tray was selected). bRegion = IsManual || (pInputSlot != NULL); DscBeginFeature(pdev, bRegion ? "PageRegion" : "PageSize"); psprintf(pdev, " %s\n", pdev->CurForm.PaperName); // Find the invocation string to send to the printer pMediaOption = (PMEDIAOPTION) LISTOBJ_FindIndexed( (PLISTOBJ) hppd->pPageSizes->pUiOptions, pdev->CurForm.featureIndex); if (pMediaOption != NULL) { pstr = bRegion ? pMediaOption->pPageRgnCode : pMediaOption->pPageSizeCode; if (pstr != NULL) { psputs(pdev, pstr); } } DscEndFeature(pdev); } }
BOOL bSendDeviceSetup( PDEVDATA pdev ) /*++ Routine Description: Send page setup code to the printer. This is called at the beginning of every page. Arguments: pdev - Pointer to our DEVDATA structure Return Value: TRUE if successful, FALSE if error --*/ { PSTR pstr; HPPD hppd = pdev->hppd; // // Clear the current page if Negative Output option is selected // if (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_NEG) { psputs(pdev, "gsave clippath 1 setgray fill grestore\n"); } // Rotate 90 degrees counterclockwise for normal landscape // or 90 degrees clockwise for rotated landscape if (pdev->dm.dmPublic.dmOrientation == DMORIENT_LANDSCAPE) { SetLandscape(pdev, (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_LSROTATE) != 0, pdev->CurForm.PaperSize.height, pdev->CurForm.PaperSize.width); } if (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_MIRROR) { psprintf(pdev, "%f %f translate -1 1 scale\n", pdev->CurForm.ImageArea.right - pdev->CurForm.ImageArea.left, 0); } /* Translate origin to upper left corner a la GDI */ psprintf(pdev, "%f %f translate ", pdev->CurForm.ImageArea.left, pdev->CurForm.ImageArea.top); /* Flip y-axis to point downwards and scale from points to dpi */ psprintf(pdev, "%d %d div dup neg scale\n", 72, pdev->dm.dmPublic.dmPrintQuality); /* Snap to pixel */ psputs(pdev, "0 0 transform .25 add round .25 sub exch .25 add " "round .25 sub exch itransform translate\n"); return TRUE; }
VOID PsSelectPrinterFeatures( PDEVDATA pdev, WORD section ) /*++ Routine Description: Select printer specific feature to appear in a given section. Arguments: pdev - Pointer to our DEVDATA structure section - DSC section we're currently in Return Value: NONE --*/ { WORD index; PFEATUREDATA pFeatureData; PUIGROUP pUiGroup; PUIOPTION pUiOption; // // Prepare data for handling printer specific feature if it's not done already. // if (!pdev->pFeatureData && !PrepareFeatureData(pdev)) { DBGERRMSG("PrepareFeatureData"); return; } // // For each requested feature, check if it should be sent to // the printer in the current DSC section. // for (index = 0, pFeatureData = pdev->pFeatureData; index < pdev->cSelectedFeature; index ++, pFeatureData++) { // // Find the UIOPTION object corresponding to the requested feature/selection. // // HACK: PageSize feature is handled differently here because it involves // lots of legacy stuff which we don't want to touch at this point. // if (! (pFeatureData->section & section)) continue; if (pdev->hppd->pPageSizes && pdev->hppd->pPageSizes->featureIndex == pFeatureData->feature) { PsSelectFormAndTray(pdev); } else if (PpdFindFeatureSelection( pdev->hppd, pFeatureData->feature, pFeatureData->option, &pUiGroup, &pUiOption)) { DBGMSG1(DBG_LEVEL_VERBOSE, "Feature: %s\n", pUiGroup->pName); DBGMSG1(DBG_LEVEL_VERBOSE, "Selection: %s\n", pUiOption->pName); // // If we're not in JCLSetup section, then enclose the feature // invocation in a mark/cleartomark pair. // if (section != ODS_JCLSETUP) { DscBeginFeature(pdev, pUiGroup->pName); psprintf(pdev, " %s\n", pUiOption->pName); } if (pUiOption->pInvocation) psputs(pdev, pUiOption->pInvocation); if (section != ODS_JCLSETUP) DscEndFeature(pdev); } } }
BOOL bOutput24bppBitmapAsMask( PDEVDATA pdev, SURFOBJ *psoSrc, PPOINTL pptlSrc, PRECTL prclDst) { RGBTRIPLE *prgbAlt = NULL; PBYTE pjStart,pjBits; int x,y; LONG cx,cy,xLeft,yTop; // compute the area to actualy draw, the smaller of the src or dest xLeft = max(0,pptlSrc->x); yTop = max(0,pptlSrc->y); cx = min(prclDst->right - prclDst->left,psoSrc->sizlBitmap.cx - xLeft); cy = min(prclDst->bottom - prclDst->top,psoSrc->sizlBitmap.cy - yTop); // first go over the bitmap to find the first non white pixel pjStart = (PBYTE)psoSrc->pvScan0 + xLeft * sizeof(RGBTRIPLE) + yTop * psoSrc->lDelta; pjBits = pjStart; for (y = yTop; (prgbAlt == NULL) && (y < (yTop + cy)); ++y, pjBits += psoSrc->lDelta) { RGBTRIPLE *prgb = (RGBTRIPLE*)pjBits; for (x = xLeft; x < (xLeft + cx); ++x, ++prgb) { if ((prgb->rgbtBlue & prgb->rgbtGreen & prgb->rgbtRed) != 0xff) { // found a non white pixel prgbAlt = prgb; break; } } } if (prgbAlt == NULL) return(TRUE); // prgbAlt now points to an RGB value for the alternate color. If we didn't // find an alternate color we use white. In the future for performance we could // replace the ROP by SRCCOPY. Not much reason to optimize for this case now // since it shouldn't happen // output the header information psputs(pdev, "gsave\n"); psprintf(pdev, "%d %d translate\n", prclDst->left, prclDst->top); psprintf(pdev, "%d %d scale\n", cx, cy); // r g b setrgbcolor psprintf(pdev, "%d 256 div ", prgbAlt->rgbtRed); psprintf(pdev, "%d 256 div ", prgbAlt->rgbtGreen); psprintf(pdev, "%d 256 div setrgbcolor\n", prgbAlt->rgbtBlue); psprintf(pdev, "/str2 %d string def\n", (cx+7) / 8); // size of mask psprintf(pdev, "%d %d", cx, cy); // paint the 0's, leave the 1's alone psputs(pdev, "\nfalse\n"); // [cx 0 0 cy 0 0] psprintf(pdev, "[%d 0 0 %d 0 0]\n", cx, cy); // get ready for the data psputs (pdev, "{currentfile str2 readhexstring pop}bind imagemask\n"); // Now go through the bitmap output ascii hex values for each byte of the mask. // 1's should be left alone, 0's should be set to the alternate color. pjBits = pjStart; for (y = yTop; y < (yTop + cy); ++y, pjBits += psoSrc->lDelta) { RGBTRIPLE *prgb = (RGBTRIPLE*)pjBits; int c = 0; for (x = xLeft; x < (xLeft + cx);) { BYTE jMask; int i; for (i = 0; (i < 8) && (x < (xLeft + cx)); ++i, ++x, ++prgb) { jMask <<= 1; if ((prgb->rgbtBlue & prgb->rgbtGreen & prgb->rgbtRed) == 0xff) { // non white pixel jMask |= 1; } } // if we got to the end without filling up the last byte, fill it with 1's jMask = (jMask << (8 - i)) | ajOrBits[i]; psputhex(pdev, 1, &jMask); // add a line feed every 80 bytes of data if ((c++ == 80) && (x < (xLeft + cx))) { c = 0; psputs(pdev,"\n"); } } psputs(pdev,"\n"); } // restore the state psputs(pdev,"grestore\n"); return(TRUE); }
VOID ps_setrgbcolor( PDEVDATA pdev, PSRGB *prgb ) /*++ Routine Description: Select a new color into the current graphics state Arguments: pdev - Points to our DEVDATA structure prgb - Specifies the new color to be selected Return Value: NONE --*/ { if (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_BLACK) { // If monochrome flag is set, map all non-white colors to black if (*((ULONG *) prgb) == RGB_WHITE) psputs(pdev, "1 g\n"); else psputs(pdev, "0 g\n"); } else if (pdev->cgs.ulColor != *((ULONG *) prgb)) { PS_FIX psfxRed, psfxGreen, psfxBlue; // Save the new color in the current graphics state structure. pdev->cgs.ulColor = *((ULONG *) prgb); // Convert RGB values from integers in the range of 0-255 // to 24.8 fixed-point values: // fixValue = (rgbValue << 8) / 255 // // Here, we use a simpler formula here to achieve similar results. psfxRed = prgb->red; if (psfxRed > 128) psfxRed++; psfxGreen = prgb->green; if (psfxGreen > 128) psfxGreen++; psfxBlue = prgb->blue; if (psfxBlue > 128) psfxBlue++; if (pdev->dm.dmPublic.dmColor == DMCOLOR_COLOR) { // If all color components have equal value, just output a // gray scale value. Otherwise, output the RGB value. if (psfxRed == psfxGreen && psfxRed == psfxBlue) { psprintf(pdev, "%f g\n", psfxRed); } else { psprintf(pdev, "%f %f %f r\n", psfxRed, psfxGreen, psfxBlue); } } else { // Convert RGB color to grayscale using NTSC formula // and output the grayscale value to the printer. psprintf(pdev, "%f g\n", RgbToGray(psfxRed, psfxGreen, psfxBlue)); } } }