1 /*****************************************************************************\
\r
2 quickconnect.cpp : Implementation for the QuickConnect class
\r
4 Copyright (c) 2008, Hewlett-Packard Co.
\r
7 Redistribution and use in source and binary forms, with or without
\r
8 modification, are permitted provided that the following conditions
\r
10 1. Redistributions of source code must retain the above copyright
\r
11 notice, this list of conditions and the following disclaimer.
\r
12 2. Redistributions in binary form must reproduce the above copyright
\r
13 notice, this list of conditions and the following disclaimer in the
\r
14 documentation and/or other materials provided with the distribution.
\r
15 3. Neither the name of Hewlett-Packard nor the names of its
\r
16 contributors may be used to endorse or promote products derived
\r
17 from this software without specific prior written permission.
\r
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
\r
20 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
21 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
\r
22 NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
\r
23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
\r
24 TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
\r
25 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
\r
26 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
\r
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
\r
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
29 \*****************************************************************************/
\r
32 #ifdef APDK_QUICKCONNECT
\r
35 #include "io_defs.h"
\r
36 #include "quickconnect.h"
\r
37 #include "printerproxy.h"
\r
38 #include "resources.h"
\r
41 APDK_BEGIN_NAMESPACE
\r
43 #define MAX_JPEG_FILE_SIZE 2097152
\r
45 QuickConnect::QuickConnect (SystemServices* pSS, BOOL proto)
\r
46 : Printer (pSS, proto)
\r
49 if ((!proto) && (IOMode.bDevID))
\r
51 constructor_error = VerifyPenInfo ();
\r
55 ePen = BOTH_PENS; // matches default mode
\r
58 pMode[ModeCount++] = new QCAutomatic ();
\r
59 pMode[ModeCount++] = new QCFastNormal ();
\r
60 pMode[ModeCount++] = new QCNormal ();
\r
61 pMode[ModeCount++] = new QCBest ();
\r
65 m_iJpegBufferPos = 0;
\r
66 m_iMaxFileSize = MAX_JPEG_FILE_SIZE;
\r
67 m_iInputBufferSize = 0;
\r
68 m_pbyJpegBuffer = NULL;
\r
69 m_pbyInputBuffer = NULL;
\r
72 m_iRemoveRedEye = 1;
\r
73 m_iJobId = pSS->GetSystemTickCount ();
\r
76 QuickConnect::~QuickConnect ()
\r
78 if (m_pbyJpegBuffer)
\r
80 pSS->FreeMemory (m_pbyJpegBuffer);
\r
82 if (m_pbyInputBuffer)
\r
84 pSS->FreeMemory (m_pbyInputBuffer);
\r
88 QCAutomatic::QCAutomatic ()
\r
91 ResolutionX[0] = 300;
\r
92 ResolutionY[0] = 300;
\r
93 BaseResX = BaseResY = 300;
\r
95 bFontCapable = FALSE;
\r
97 theQuality = qualityAuto;
\r
100 pmQuality = QUALITY_AUTO;
\r
101 pmMediaType = MEDIA_PLAIN;
\r
102 Config.bColorImage = FALSE;
\r
103 Config.bCompress = FALSE;
\r
104 #ifdef APDK_AUTODUPLEX
\r
105 bDuplexCapable = FALSE;
\r
109 QCFastNormal::QCFastNormal ()
\r
112 ResolutionX[0] = 300;
\r
113 ResolutionY[0] = 300;
\r
114 BaseResX = BaseResY = 300;
\r
116 bFontCapable = FALSE;
\r
118 theQuality = qualityFastNormal;
\r
119 medium = mediaAuto;
\r
121 pmQuality = QUALITY_FASTNORMAL;
\r
122 pmMediaType = MEDIA_PLAIN;
\r
123 Config.bColorImage = FALSE;
\r
124 Config.bCompress = FALSE;
\r
125 #ifdef APDK_AUTODUPLEX
\r
126 bDuplexCapable = FALSE;
\r
130 QCNormal::QCNormal ()
\r
133 ResolutionX[0] = 300;
\r
134 ResolutionY[0] = 300;
\r
135 BaseResX = BaseResY = 300;
\r
137 bFontCapable = FALSE;
\r
139 theQuality = qualityNormal;
\r
140 medium = mediaAuto;
\r
142 pmQuality = QUALITY_NORMAL;
\r
143 pmMediaType = MEDIA_PLAIN;
\r
144 Config.bColorImage = FALSE;
\r
145 Config.bCompress = FALSE;
\r
146 #ifdef APDK_AUTODUPLEX
\r
147 bDuplexCapable = FALSE;
\r
154 ResolutionX[0] = 300;
\r
155 ResolutionY[0] = 300;
\r
156 BaseResX = BaseResY = 300;
\r
158 bFontCapable = FALSE;
\r
160 theQuality = qualityPresentation;
\r
161 medium = mediaAuto;
\r
163 pmQuality = QUALITY_BEST;
\r
164 pmMediaType = MEDIA_PLAIN;
\r
165 Config.bColorImage = FALSE;
\r
166 Config.bCompress = FALSE;
\r
167 #ifdef APDK_AUTODUPLEX
\r
168 bDuplexCapable = FALSE;
\r
172 Header *QuickConnect::SelectHeader (PrintContext *pc)
\r
176 m_iRowWidth = pc->OutputPixelsPerRow () * 3;
\r
178 m_iInputBufferSize = m_iRowWidth * (int) (pc->PhysicalPageSizeY () * pc->EffectiveResolutionY ());
\r
179 m_pbyInputBuffer = (BYTE *) pSS->AllocMem (m_iInputBufferSize);
\r
180 m_pbyJpegBuffer = (BYTE *) pSS->AllocMem (m_iMaxFileSize);
\r
181 if (m_pbyInputBuffer == NULL || m_pbyJpegBuffer == NULL)
\r
183 constructor_error = ALLOCMEM_ERROR;
\r
186 memset (m_pbyInputBuffer, 0xFF, m_iInputBufferSize);
\r
187 return new HeaderQuickConnect (this, pc);
\r
190 DRIVER_ERROR QuickConnect::Encapsulate (const RASTERDATA* InputRaster, BOOL bLastPlane)
\r
192 memcpy (m_pbyInputBuffer + (m_iRowNumber * m_iRowWidth), InputRaster->rasterdata[COLORTYPE_COLOR],
\r
193 InputRaster->rastersize[COLORTYPE_COLOR]);
\r
198 DRIVER_ERROR QuickConnect::ParsePenInfo (PEN_TYPE& ePen, BOOL QueryPrinter)
\r
204 DRIVER_ERROR err = SetPenInfo (str, QueryPrinter);
\r
205 if (err != NO_ERROR)
\r
210 num_pens = str[0] - '0';
\r
217 if ((int) strlen (str) < (num_pens * 8))
\r
219 return BAD_DEVICE_ID;
\r
225 DRIVER_ERROR QuickConnect::VerifyPenInfo ()
\r
228 DRIVER_ERROR err = NO_ERROR;
\r
230 if (IOMode.bDevID == FALSE)
\r
235 err = ParsePenInfo (ePen);
\r
237 if(err == UNSUPPORTED_PEN) // probably Power Off - pens couldn't be read
\r
240 // have to delay or the POWER ON will be ignored
\r
241 if (pSS->BusyWait ((DWORD) 2000) == JOB_CANCELED)
\r
243 return JOB_CANCELED;
\r
246 DWORD length = sizeof (DJ895_Power_On);
\r
247 err = pSS->ToDevice (DJ895_Power_On, &length);
\r
250 err = pSS->FlushIO ();
\r
253 // give the printer some time to power up
\r
254 if (pSS->BusyWait ((DWORD) 2500) == JOB_CANCELED)
\r
256 return JOB_CANCELED;
\r
259 err = ParsePenInfo (ePen);
\r
263 while (ePen == NO_PEN)
\r
265 pSS->DisplayPrinterStatus (DISPLAY_NO_PENS);
\r
267 if (pSS->BusyWait (500) == JOB_CANCELED)
\r
269 return JOB_CANCELED;
\r
271 err = ParsePenInfo (ePen);
\r
275 pSS->DisplayPrinterStatus (DISPLAY_PRINTING);
\r
280 int QuickConnect::MapPaperSize (PAPER_SIZE ePaperSize)
\r
282 switch (ePaperSize)
\r
301 int QuickConnect::MapMediaType (MEDIATYPE eMediaType)
\r
303 switch (eMediaType)
\r
305 case MEDIA_HIGHRES_PHOTO:
\r
307 case MEDIA_PREMIUM:
\r
319 int QuickConnect::MapQualityMode (QUALITY_MODE eQualityMode)
\r
321 switch (eQualityMode)
\r
323 case QUALITY_NORMAL:
\r
325 case QUALITY_FASTNORMAL:
\r
335 DRIVER_ERROR QuickConnect::SetHint (PRINTER_HINT eHint, int iValue)
\r
339 case PHOTO_FIX_HINT:
\r
341 m_iPhotoFix = iValue & 0x1;
\r
344 case RED_EYE_REMOVAL_HINT:
\r
346 m_iRemoveRedEye = iValue & 0x1;
\r
349 case MAX_FILE_SIZE_HINT:
\r
351 m_iMaxFileSize = iValue;
\r
361 DRIVER_ERROR QuickConnect::Flush (int iBufferSize)
\r
363 DRIVER_ERROR err = NO_ERROR;
\r
364 if (iBufferSize == -1 && m_iRowNumber > 0)
\r
367 int iPaperSize, iMediaType, iPrintQuality;
\r
368 char szCopiesStr[64];
\r
369 char szNullBytes[632];
\r
370 static const char szPJLHeader[] = "\x1B\x45\x1B%-12345X@PJL ENTER LANGUAGE=PHOTOJPEG\012";
\r
371 static const char szPJLEndJob[] = "\x1B\x45\x1B%-12345X";
\r
376 memset (szNullBytes, 0, sizeof (szNullBytes));
\r
377 sprintf (szCopiesStr, "@PJL SET COPIES=%d\012@PJL SET JOBID=%d\012", m_pPC->GetCopyCount (), m_iJobId);
\r
379 Send ((const BYTE *) szNullBytes, 600);
\r
380 Send ((const BYTE *) szPJLHeader, sizeof(szPJLHeader) - 1);
\r
381 Send ((const BYTE *) szCopiesStr, strlen (szCopiesStr));
\r
383 COLORMODE eColorMode = COLOR;
\r
384 MEDIATYPE eMediaType;
\r
385 QUALITY_MODE eQualityMode;
\r
388 m_pPC->GetPrintModeSettings (eQualityMode, eMediaType, eColorMode, bDeviceText);
\r
389 iMediaType = MapMediaType (eMediaType);
\r
390 iPrintQuality = MapQualityMode (eQualityMode);
\r
391 iPaperSize = MapPaperSize (m_pPC->GetPaperSize ());
\r
394 "@PJL SET PAPER=%d\012@PJL SET MEDIATYPE=%d\012@PJL SET PRINTQUALITY=%d\012@PJL SET BORDERLESS=%d\012",
\r
395 iPaperSize, iMediaType, iPrintQuality, m_pPC->IsBorderless ());
\r
396 err = Send ((const BYTE *) szStr, strlen (szStr));
\r
398 err = AddExifHeader ();
\r
401 memset (m_pbyInputBuffer, 0xFF, m_iInputBufferSize);
\r
403 // Send the END JOB PJL command
\r
405 Send ((const BYTE *) szPJLEndJob, sizeof(szPJLEndJob) - 1);
\r
412 HeaderQuickConnect::HeaderQuickConnect (Printer *p, PrintContext *pc)
\r
417 DRIVER_ERROR HeaderQuickConnect::Send ()
\r
422 DRIVER_ERROR HeaderQuickConnect::EndJob ()
\r
424 DRIVER_ERROR err = NO_ERROR;
\r
429 DRIVER_ERROR HeaderQuickConnect::FormFeed ()
\r
431 DRIVER_ERROR err = NO_ERROR;
\r
432 thePrinter->Flush (-1);
\r
436 DRIVER_ERROR HeaderQuickConnect::SendCAPy (unsigned int iAbsY)
\r
441 void HPFlush_output_buffer_callback (JOCTET *outbuf, BYTE *buffer, int size)
\r
443 QuickConnect *pQC = (QuickConnect *) outbuf;
\r
444 pQC->JpegData (buffer, size);
\r
447 void QuickConnect::JpegData (BYTE *buffer, int iSize)
\r
449 m_iJpegBufferPos += iSize;
\r
450 if (m_iJpegBufferPos < m_iMaxFileSize)
\r
452 memcpy (m_pbyJpegBuffer + m_iJpegBufferPos - iSize, buffer, iSize);
\r
456 m_iJpegBufferPos = m_iMaxFileSize + 1;
\r
460 //----------------------------------------------------------------
\r
461 // These are "overrides" to the JPEG library error routines
\r
462 //----------------------------------------------------------------
\r
464 void HPJpeg_error (j_common_ptr cinfo)
\r
471 void jpeg_buffer_dest (j_compress_ptr cinfo, JOCTET* outbuff, void* flush_output_buffer_callback);
\r
472 void hp_rgb_ycc_setup (int iFlag);
\r
475 DRIVER_ERROR QuickConnect::Compress ()
\r
479 int volatile iQuality = 100;
\r
482 * Convert the byte buffer to jpg, if converted size is greater than 2MB, delete it and
\r
483 * convert with a higher compression factor.
\r
486 struct jpeg_compress_struct cinfo;
\r
487 struct jpeg_error_mgr jerr;
\r
488 jmp_buf setjmp_buffer;
\r
492 // Use the standard RGB to YCC table rather than the modified one for JetReady
\r
494 hp_rgb_ycc_setup (0);
\r
499 m_iJpegBufferPos = 0;
\r
500 memset (m_pbyJpegBuffer, 0xFF, m_iMaxFileSize);
\r
502 cinfo.err = jpeg_std_error (&jerr);
\r
503 jerr.error_exit = HPJpeg_error;
\r
504 if (setjmp (setjmp_buffer))
\r
506 jpeg_destroy_compress (&cinfo);
\r
507 return SYSTEM_ERROR;
\r
510 jpeg_create_compress (&cinfo);
\r
511 cinfo.in_color_space = JCS_RGB;
\r
512 jpeg_set_defaults (&cinfo);
\r
513 cinfo.image_width = m_iRowWidth / 3;
\r
514 cinfo.image_height = m_iRowNumber;
\r
515 cinfo.input_components = 3;
\r
516 cinfo.data_precision = 8;
\r
517 jpeg_set_quality (&cinfo, iQuality, TRUE);
\r
518 jpeg_buffer_dest (&cinfo, (JOCTET *) this, (void *) (HPFlush_output_buffer_callback));
\r
519 jpeg_start_compress (&cinfo, TRUE);
\r
520 JSAMPROW pRowArray[1];
\r
521 p = m_pbyInputBuffer;
\r
522 for (int i = 0; i < m_iRowNumber; i++)
\r
524 pRowArray[0] = (JSAMPROW) p;
\r
525 jpeg_write_scanlines (&cinfo, pRowArray, 1);
\r
526 p += (m_iRowWidth);
\r
527 if (m_iJpegBufferPos > m_iMaxFileSize)
\r
529 m_iJpegBufferPos = 0;
\r
533 jpeg_finish_compress (&cinfo);
\r
534 jpeg_destroy_compress (&cinfo);
\r
538 m_iJpegBufferPos = 0;
\r
539 return SYSTEM_ERROR;
\r
544 char szFileName[64];
\r
545 sprintf (szFileName, "C:\\temp\\HPJpeg.jpg");
\r
546 FILE *fp = fopen (szFileName, "wb");
\r
549 fwrite (m_pbyJpegBuffer, 1, m_iJpegBufferPos, fp);
\r
557 DRIVER_ERROR QuickConnect::AddExifHeader ()
\r
561 BYTE *pBuffer = m_pbyJpegBuffer;
\r
565 * APP2 Header| Length | Identifier | Version |Number of Tags
\r
566 * -------------------------------------------------------------------------
\r
567 * 0xFF|0xE2 |0x00 | 0x23|0x48|0x50|0x51|0x43|0x00|0x00|0x01|0x00|0x02
\r
568 * Length = No. of Tags * length of tag + length of APP2 marker
\r
569 * -------------------------------------------------------------------------
\r
570 * Tag ID |field Type| Count |Value Offset
\r
571 * -------------------------------------------------------------
\r
572 * 0x00|0x01|0x00|0x03 |0x00|0x00|0x00|0x01|0x00|0x00|0x00|0x01
\r
573 * -------------------------------------------------------------
\r
574 * Field Type 0x0003 stands for short
\r
575 * Count and Value Offset are 4 bytes in TIFF convention.
\r
576 * If the count <=4, Value Offset satisfies. If the count is bigger than 4 bytes,
\r
577 * it will be offset to where data is located.
\r
580 unsigned char App2[] = {"\xFF\xE2\x00\x23\x48\x50\x51\x43\x00\x00\x01\x00\x02"};
\r
581 unsigned char szApp2Markers[2][12];
\r
585 // Things to set are: PhotoFix, RedEyeRemoval
\r
587 iOpts[0] = m_iRemoveRedEye;
\r
588 iOpts[1] = m_iBorderless;
\r
591 unsigned char szTag[] = {"\x00\x01\x00\x03\x00\x00\x00\x01\x00\x00\x00\x01"};
\r
594 for (skey = 1; skey <= 2; skey++)
\r
596 szTag[0] = (BYTE) ((skey & 0xFF) >> 8);
\r
597 szTag[1] = (BYTE) (skey & 0xFF);
\r
599 iVal = iOpts[skey];
\r
600 szTag[8] = (BYTE) ((iVal >> 24) & 0xFF);
\r
601 szTag[9] = (BYTE) ((iVal >> 16) & 0xFF);
\r
602 szTag[10] = (BYTE) ((iVal >> 8) & 0xFF);
\r
603 szTag[11] = (BYTE) (iVal & 0xFF);
\r
604 memcpy (szApp2Markers[iNumTags], szTag, 12);
\r
607 skey = (short) iNumTags * 12 + 11;
\r
608 App2[2] = (BYTE) ((skey >> 8) & 0xFF);
\r
609 App2[3] = (BYTE) (skey & 0xFF);
\r
610 App2[11] = (BYTE) ((iNumTags >> 8) & 0xFF);
\r
611 App2[12] = (BYTE) (iNumTags & 0xFF);
\r
615 * First write the SOI and JFIF header
\r
616 * File structure is:
\r
618 * BYTE SOI[2]; // 00h Start of Image Marker
\r
619 * BYTE APP0[2]; // 02h Application Use Marker
\r
620 * BYTE Length[2]; // 04h Length of APP0 Field
\r
621 * BYTE Identifier[5]; // 06h "JFIF" (zero terminated) Id String
\r
622 * BYTE Version[2]; // 07h JFIF Format Revision
\r
623 * BYTE Units; // 09h Units used for Resolution
\r
624 * BYTE Xdensity[2]; // 0Ah Horizontal Resolution
\r
625 * BYTE Ydensity[2]; // 0Ch Vertical Resolution
\r
626 * BYTE XThumbnail; // 0Eh Horizontal Pixel Count
\r
627 * BYTE YThumbnail; // 0Fh Vertical Pixel Count
\r
630 short sJFIFHeaderSize = ((((short) pBuffer[4]) << 8) | pBuffer[5]) + 4;
\r
631 err = Send ((const BYTE *) pBuffer, sJFIFHeaderSize);
\r
634 m_iJpegBufferPos -= sJFIFHeaderSize;
\r
635 pBuffer += sJFIFHeaderSize;
\r
639 err = Send ((const BYTE *) App2, 13);
\r
640 for (int i = 0; i < iNumTags; i++)
\r
642 err = Send ((const BYTE *) szApp2Markers[i], 12);
\r
646 err = Send ((const BYTE *) pBuffer, m_iJpegBufferPos);
\r
652 #endif // defined APDK_QUICKCONNECT
\r