Code sync
[external/hplip.git] / prnt / hpijs / job.cpp
1 /*****************************************************************************\
2   job.cpp : Implimentation for the Job class
3
4   Copyright (c) 1996 - 2001, Hewlett-Packard Co.
5   All rights reserved.
6
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
10   1. Redistributions of source code must retain the above copyright
11      notice, this list of conditions and the following disclaimer.
12   2. Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15   3. Neither the name of Hewlett-Packard nor the names of its
16      contributors may be used to endorse or promote products derived
17      from this software without specific prior written permission.
18
19   THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
22   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24   TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25   OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \*****************************************************************************/
30
31 #include "header.h"
32 #include "halftoner.h"
33 #include "colormatch.h"
34 #include "scaler_open.h"
35 #include "scaler_prop.h"
36
37 APDK_BEGIN_NAMESPACE
38 extern Halftoner* Create_Halftoner( SystemServices* pSys, PrintMode* pPM,
39                 unsigned int iInputWidth, unsigned int iNumRows[], unsigned int HiResFactor,
40                 BOOL usematrix);
41 extern Scaler* Create_Scaler(SystemServices* pSys,int inputwidth,
42                              int numerator,int denominator,BOOL vip,unsigned int BytesPerPixel);
43 extern ColorMatcher* Create_ColorMatcher( SystemServices* pSys,
44                                    ColorMap cm,unsigned int DyeCount,
45                                    unsigned int iInputWidth);
46 extern BOOL ProprietaryImaging();
47 extern BOOL ProprietaryScaling();
48 APDK_END_NAMESPACE
49
50 APDK_BEGIN_NAMESPACE
51
52 extern float frac(float f);
53
54 #define InitialPixelSize 3  // means first data into pipeline is RGB24
55 #define Bytes(x) ((x/8)+(x%8))
56
57 //////////////////////////////////////////////////////////////////////////
58 // The Job object receives data for a contiguous set of pages targeted at
59 // a single printer, with a single group of settings encapsulated in the
60 // PrintContext.
61 // At least one page will be ejected for a job, if any data at all
62 // is printed (no half-page jobs). If settings are to be changed, this
63 // must be done between jobs.
64 //
65
66 /*!
67 constructor - must pass a valid PrintContext to create the job.
68 Check constructor_error for NO_ERROR before continuing.
69 */
70 Job::Job
71 (
72     PrintContext* pPC
73 ) :
74     thePrintContext(pPC),
75     pSS(pPC->pSS),
76     thePrinter(NULL),
77     thePipeline(NULL),
78     pText(NULL),
79     pSender(NULL),
80     pHalftoner(NULL),
81     pColorMatcher(NULL),
82     pResSynth(NULL),
83         pBlackPlaneReplicator(NULL),
84     pReplicator(NULL),
85     theCompressor(NULL),
86         pBlackPlaneCompressor(NULL),
87     pHead(NULL),
88 #if defined(APDK_VIP_COLORFILTERING)
89     pErnie(NULL),
90 #endif
91 #if defined(APDK_FONTS_NEEDED)
92     theTextManager(NULL),
93 #endif
94     CurrentMode(pPC->CurrentMode),
95     fcount(0),
96     skipcount(0),
97     RowsInput(0),
98     BlankRaster(NULL),
99         BlackRaster(NULL),
100     DataSent(FALSE)
101 #ifdef APDK_USAGE_LOG
102     , UText(0),
103     UTextCount(0)
104 #endif
105 {
106 #ifdef APDK_CAPTURE
107     Capture_Job(pPC);
108 #endif
109     unsigned int i;
110     constructor_error = NO_ERROR;
111
112     if (!thePrintContext->PrinterSelected())
113       {
114         constructor_error = NO_PRINTER_SELECTED;
115         return;
116       }
117     thePrinter = thePrintContext->thePrinter;
118
119
120     for (i=0; i<(unsigned)MAXCOLORPLANES; i++)
121         if (CurrentMode->MixedRes)      // means res(K) !+ res(C,M,Y)
122             numrows[i] =  CurrentMode->ResolutionX[i] / CurrentMode->BaseResX;
123         else numrows[i]=1;
124
125     ResBoost = CurrentMode->BaseResX / CurrentMode->BaseResY;
126     if (ResBoost==0) ResBoost=1;                    // safety
127
128
129     pHead = thePrinter->SelectHeader(thePrintContext);
130     CNEWCHECK(pHead);
131
132
133     // set up blank raster used by SendRasters
134     constructor_error=setblankraster();
135     CERRCHECK;
136
137      // flush any garbage out of the printer's buffer
138     constructor_error=thePrinter->Flush();
139     CERRCHECK;
140     // send the PCL header
141     constructor_error=pHead->Send();
142     CERRCHECK;
143     // set CAPy after sending header in case header used it
144     CAPy=pHead->CAPy;
145
146
147     constructor_error=Configure();
148     CERRCHECK;
149
150
151 #if defined(APDK_FONTS_NEEDED)
152
153     pText = new TextTranslator(thePrinter, pHead->QualityCode(),
154                                thePrintContext->CurrentMode->dyeCount);
155     CNEWCHECK(pText);
156
157     theTextManager = NULL;
158     if (CurrentMode->bFontCapable)
159     {
160         unsigned int pixelsX = (unsigned int) (int) (thePrintContext->printablewidth() *
161                                 CurrentMode->BaseResX);
162         unsigned int pixelsY = (unsigned int) (int) (thePrintContext->printableheight() *
163                                 CurrentMode->BaseResY);
164
165         theTextManager=new TextManager( pText, pixelsX,pixelsY );
166         CNEWCHECK(theTextManager);
167         constructor_error = theTextManager->constructor_error;
168         CERRCHECK;
169     }
170 #endif
171
172     if (!thePrintContext->ModeAgreesWithHardware(TRUE))
173         constructor_error = WARN_MODE_MISMATCH;
174
175 #ifdef APDK_USAGE_LOG
176     UHeader[0]='\0';
177 #endif
178 } //Job
179
180 DRIVER_ERROR Job::SetupHalftoning(HALFTONING_ALGORITHM eHT)
181 // Subroutine of Job constructor to handle ColorMatcher/Halftoner initialization.
182 // OutputWidth set in InitScaler (it is not the ultimate width if horizontal doubling is needed)
183 // Has to decide whether to use matrix or fast-error-diffusion, open or proprietary.
184 {
185 // first level of decision on matrix-vs.FED is the printmode setting itself
186     BOOL usematrix = (eHT == MATRIX);
187 // but this is overridden in speed-optimized builds
188 // we also can simulate the build-switch at runtime in the test harness
189 #ifdef APDK_OPTIMIZE_FOR_SPEED
190         usematrix = TRUE;
191 #endif
192
193     pHalftoner = Create_Halftoner(thePrintContext->pSS, CurrentMode,
194                                   OutputWidth, numrows,ResBoost,usematrix);
195     NEWCHECK(pHalftoner);
196     return pHalftoner->constructor_error;
197 } //SetupHalftoning
198
199 DRIVER_ERROR Job::SetupColorMatching()
200 {
201
202     unsigned int cmWidth=InputWidth;
203     if (pResSynth)      // if 2X scaling happens before ColorMatching
204         cmWidth *= 2;
205
206     pColorMatcher = Create_ColorMatcher(thePrintContext->pSS, CurrentMode->cmap,
207                                         CurrentMode->dyeCount, cmWidth);
208     NEWCHECK(pColorMatcher);
209     return pColorMatcher->constructor_error;
210 } //SetupColorMatching
211
212
213 Job::~Job()
214 {
215 #ifdef APDK_CAPTURE
216     Capture_dJob();
217 #endif
218
219     // Client isn't required to call NewPage at end of last page, so
220     // we may need to eject a page now.
221     if (DataSent)
222     {
223         MediaSource     mSource = thePrintContext->GetMediaSource ();
224         if (mSource == sourceBanner)
225         {
226             thePrintContext->SetMediaSource (sourceTrayAuto);
227         }
228         newpage();
229         thePrintContext->SetMediaSource (mSource);
230     }
231
232
233     // Tell printer that job is over.
234     if(pHead)
235     {
236         pHead->EndJob();
237     }//end if
238
239 // Delete the 4 components created in Job constructor.
240 #if defined(APDK_FONTS_NEEDED)
241 DBG1("deleting TextManager\n");
242     if (theTextManager)
243     {
244         delete theTextManager;
245     }
246 #endif
247
248 DBG1("deleting RasterSender\n");
249     if (pSender)
250     {
251         delete pSender;
252     }
253
254     if (pHalftoner)
255     {
256         delete pHalftoner;
257     }
258
259     if (pColorMatcher)
260     {
261         delete pColorMatcher;
262     }
263
264     if (BlankRaster)
265     {
266         pSS->FreeMemory(BlankRaster);
267     }
268
269     if (BlackRaster)
270     {
271         pSS->FreeMemory(BlackRaster);
272     }
273
274     if (pBlackPlaneReplicator)
275     {
276         delete pBlackPlaneReplicator;
277     }
278
279     if (pReplicator)
280     {
281         delete pReplicator;
282     }
283
284     if (pResSynth)
285     {
286         delete pResSynth;
287     }
288
289     if (thePipeline)
290     {
291         delete thePipeline;
292     }
293
294     if (pHead)
295     {
296         delete pHead;
297     }
298
299 #if defined(APDK_VIP_COLORFILTERING)
300     if (pErnie)
301     {
302         delete pErnie;
303     }
304 #endif
305
306     if (theCompressor)
307     {
308         delete theCompressor;
309     }
310
311     if (pBlackPlaneCompressor)
312     {
313         delete pBlackPlaneCompressor;
314     }
315
316 #if defined(APDK_FONTS_NEEDED)
317     if (pText)
318     {
319         delete pText;
320     }
321 #endif // defined(APDK_FONTS_NEEDED)
322
323     if(thePrinter)
324     {
325         BYTE temp = 0;
326         thePrinter->EndJob = TRUE;  // the Job is done -
327         thePrinter->Send(&temp,0);  // call Send to dump any buffered data
328     }//end if
329
330 DBG1("done with ~Job\n");
331 } //~Job
332
333
334 DRIVER_ERROR Job::SendCAPy()
335 {
336     return pHead->SendCAPy(CAPy++);
337 } //SendCAPy
338
339 ///////////////////////////////////////////////////////////////////////////////////
340 //
341 /*!
342 This is the fundamental method for the driver, by means of which graphics data
343 is sent to the printer.
344 */
345 DRIVER_ERROR Job::SendRasters(BYTE* ImageData)      // RGB24 data for one raster
346 // This is how graphical data is sent to the driver.
347
348 // We do not check for rasters where data is supplied but happens
349 // to be all blank (white); caller should have used NULL in this case.
350 {
351 #ifdef APDK_CAPTURE
352     Capture_SendRasters(NULL, ImageData);
353 #endif
354
355  return sendrasters(NULL, ImageData);
356 } //SendRasters
357
358
359 ///////////////////////////////////////////////////////////////////////////////////
360 //
361 /*!
362 This is the fundamental method for the driver, by means of which graphics data
363 is sent to the printer.
364 */
365 DRIVER_ERROR Job::SendRasters(BYTE* BlackImageData, BYTE* ColorImageData)      // 1bit K data and RGB24 data for one raster
366 // This is how graphical data is sent to the driver.
367
368 // We do not check for rasters where data is supplied but happens
369 // to be all blank (white); caller should have used NULL in this case.
370 {
371 #ifdef APDK_CAPTURE
372         Capture_SendRasters(BlackImageData, ColorImageData);
373 #endif
374         return sendrasters(BlackImageData, ColorImageData);
375 } //SendRasters
376
377 /*!
378 This is the method for use to check if they can send a separate 1 bit black channel
379 */
380 DRIVER_ERROR Job::SupportSeparateBlack(BOOL* bSeparateBlack)
381 {
382         *bSeparateBlack = thePrinter->SupportSeparateBlack(CurrentMode);
383         return NO_ERROR;
384 }
385
386 // internal entry point, used by newpage
387 DRIVER_ERROR Job::sendrasters(BYTE* BlackImageData, BYTE* ColorImageData)
388 {
389     DRIVER_ERROR err = NO_ERROR;
390
391     if (thePipeline == NULL)
392     {
393         return SYSTEM_ERROR;
394     }
395
396     // need to put out some data occasionally in case of all-text page,
397     // so printer will go ahead and start printing the text before end of page
398     if (BlackImageData == NULL && ColorImageData == NULL)
399     {
400                 if (thePrinter->GetDataFormat() == RASTER_STRIP)
401                 {
402                         skipcount=0;
403                         ColorImageData=BlankRaster;
404                 }
405                 else
406                 {
407                         skipcount++;
408                         if (skipcount >= 200)
409                         {
410                                 skipcount=0;
411                                 ColorImageData=BlankRaster;
412                         }
413                         else
414                         {
415                            fcount += ScaleFactor;
416                         }
417
418                         err = thePipeline->Flush();
419                         ERRCHECK;
420                 }
421     }
422     else
423     {
424         skipcount=0;
425         DataSent=TRUE;      // so we know we need a formfeed when job ends
426     }
427
428     RowsInput++;        // needed in case res > 300
429
430         if (BlackImageData || ColorImageData)
431         {
432                 if (fcount > 1000)
433                 {
434                    CAPy += fcount/1000;
435
436                         err = thePrinter->SkipRasters ((fcount / 1000)); // needed for DJ3320
437                         ERRCHECK;
438                     fcount =fcount % 1000;
439                 }
440
441                 if (BlackImageData && CurrentMode->dyeCount != 3 && CurrentMode->dyeCount != 6)
442                 {
443                         err = setblackraster();
444                         ERRCHECK;
445
446                         for (unsigned int i = 0; i < thePrintContext->InputWidth / 8; i++)
447                         {
448                                 unsigned char  bitflag = 0x80;
449                                 for (unsigned int j = 0; j < 8; j++)
450                                 {
451                                         if (BlackImageData[i] & bitflag)
452                                                 BlackRaster[i*8+j] = 1;
453                                         bitflag = bitflag >> 1;
454                                 }
455                         }
456                         if (thePrintContext->InputWidth % 8 > 0)
457                         {
458                                 unsigned int i = thePrintContext->InputWidth / 8;
459                                 unsigned char bitflag = 0x80;
460                                 for (unsigned int j = 0; j < thePrintContext->InputWidth % 8; j++)
461                                 {
462                                         if (BlackImageData[i] & bitflag)
463                                                 BlackRaster[i*8+j] = 1;
464                                         bitflag = bitflag >> 1;
465                                 }
466                         }
467                         thePipeline->Exec->raster.rastersize[COLORTYPE_BLACK] = thePrintContext->InputWidth;
468                         thePipeline->Exec->raster.rasterdata[COLORTYPE_BLACK] = BlackRaster;
469                 }
470                 else
471                 {
472                     thePipeline->Exec->raster.rastersize[COLORTYPE_BLACK] = 0;
473                         thePipeline->Exec->raster.rasterdata[COLORTYPE_BLACK] = NULL;
474                 }
475                 if (ColorImageData)
476                 {
477                         thePipeline->Exec->raster.rastersize[COLORTYPE_COLOR] = thePrintContext->InputWidth*3;
478                         thePipeline->Exec->raster.rasterdata[COLORTYPE_COLOR] = ColorImageData;
479                 }
480                 else
481                 {
482                     thePipeline->Exec->raster.rastersize[COLORTYPE_COLOR] = 0;
483                         thePipeline->Exec->raster.rasterdata[COLORTYPE_COLOR] = NULL;
484                 }
485             err = thePipeline->Execute(&(thePipeline->Exec->raster));
486         }
487
488         return err;
489 } //sendrasters
490
491
492 DRIVER_ERROR Job::newpage()
493 // (for internal use, called by external NewPage)
494 {
495         DRIVER_ERROR err;
496
497         if (thePrinter->GetDataFormat() == RASTER_STRIP)
498         {
499                 pHead->SetLastBand(TRUE);
500         }
501
502     sendrasters();     // flush pipeline
503
504     if ((thePrintContext->GetMediaSource ()) == sourceBanner)
505     {
506         CAPy = 0;
507     }
508     else
509     {
510         err = pHead->FormFeed();
511         ERRCHECK;
512
513         // reset vertical cursor counter
514         if (thePrinter->UseGUIMode(thePrintContext->CurrentMode) &&
515             ((int) (thePrintContext->PrintableStartY () * 100)) != 0)
516         // DJ895 in GUImode doesn't accept top-margin setting, so we use CAP for topmargin
517         // Start at the top for full-bleed printing - PhotoSmart 100 for now
518         {
519             CAPy = thePrintContext->GUITopMargin();
520         }
521         else
522         {
523             CAPy = 0;
524         }
525     }
526
527     skipcount = RowsInput = 0;
528     fcount = 0;
529
530 // reset flag used to see if formfeed needed
531     DataSent = FALSE;
532
533     if (!thePrintContext->ModeAgreesWithHardware(TRUE))
534     {
535         return WARN_MODE_MISMATCH;
536     }
537
538 #ifdef APDK_USAGE_LOG
539     theTranslator->PrintDotCount(UHeader);
540     theTranslator->NextPage();
541     UTextCount=UText=0;
542 #endif
543
544     return NO_ERROR;
545 } //newpage
546
547 /*!\r
548 This method forces the associated printer to flush the remaining buffered\r
549 data and tells it that the job is ended.\r
550 \r
551 Calling this method is not mandatory, since the object destructor already\r
552 performs this action. It may be required, however, if the destructor is not\r
553 called for some reason (for instance, when the call depends on the execution\r
554 of a "finalize" method of a Java wrapper.\r
555 */\r
556 \r
557 DRIVER_ERROR Job::Flush()\r
558 {\r
559     if(thePrinter)\r
560     {\r
561         BYTE temp = 0;\r
562         thePrinter->EndJob = TRUE;  // the Job is done -\r
563         return thePrinter->Send(&temp,0);  // call Send to dump any buffered data\r
564     }//end if\r
565     return NO_PRINTER_SELECTED;\r
566 }\r
567
568 /*!
569 Resets counters, flushes buffers, and sends a form feed to the printer.
570 */
571 DRIVER_ERROR Job::NewPage()
572 // External entry point
573 {
574 #ifdef APDK_CAPTURE
575     Capture_NewPage();
576 #endif
577     return newpage();
578 } //NewPage
579
580
581 void Job::SetOutputWidth()
582 // set OutputWidth -- this is local and may not agree with PrintContext
583 // in cases where horizontal doubling is needed
584 {
585     OutputWidth = thePrintContext->OutputWidth;
586     InputWidth = thePrintContext->InputWidth;
587
588     if (CurrentMode->BaseResX != CurrentMode->BaseResY) // if horizontal expansion needed
589     {
590         int mixedfactor = CurrentMode->BaseResX / CurrentMode->BaseResY;
591         int widthfactor = OutputWidth / InputWidth;
592         if (widthfactor >= mixedfactor)
593         {
594             OutputWidth = OutputWidth / mixedfactor;
595         }
596     }
597 } //SetOutputWidth
598
599
600 DRIVER_ERROR Job::InitScaler()
601 // sets pResSynth & pReplicator
602 {
603     unsigned int numerator, denominator;
604     // set OutputWidth -- this is local and may not agree with PrintContext
605     // in cases where horizontal doubling is needed (see next if clause)
606     SetOutputWidth();
607
608     if ((OutputWidth % InputWidth) == 0)
609     {
610         numerator = OutputWidth / InputWidth;
611         denominator = 1;
612     }
613     else
614     {
615         numerator = OutputWidth;
616         denominator = InputWidth;
617     }
618
619
620      float tempfactor = (float)numerator / (float)denominator;
621      tempfactor *= 1000.0f;
622      ScaleFactor = (unsigned int) (int) tempfactor;
623
624         // Two paths: if ResSynth included (proprietary path), then use it for the first doubling;
625         //            otherwise do it all in PixelReplication phase
626         //  but don't use ResSynth anyway if printer-res=600 and scale<4 (i.e. original-res<150),
627         //  or printer-res=300 and scale<2.33 (i.e. original-res<133)
628     BOOL RSok;
629     BOOL speedy=FALSE;
630 #ifdef APDK_OPTIMIZE_FOR_SPEED
631     speedy = TRUE;
632 #endif  // APDK_OPTIMIZE_FOR_SPEED
633     if (speedy)
634     {
635         RSok = FALSE;
636     }
637     else
638     {
639         if (thePrintContext->EffectiveResolutionX()>300)
640         {
641             // I don't know about 1200dpi, so I'm doing it this way
642             RSok = ScaleFactor >= 4000;
643         }
644         else
645         {
646             RSok = ScaleFactor >= 2333;
647         }
648     }
649
650
651     unsigned int ReplFormat;                    // how many bytes per pixel
652     if (CurrentMode->Config.bColorImage)
653     {
654         ReplFormat = CurrentMode->dyeCount;      // dealing with colormatching output
655     }
656     else
657     {
658         ReplFormat = 3;                        // RGB only
659     }
660
661     BOOL vip = !CurrentMode->Config.bColorImage;
662
663     if ((!ProprietaryScaling())  || !RSok )
664     // everything happens at Replication phase; input may be KCMY (or K, CMY, etc.) or RGB
665     {
666         pResSynth=NULL;
667         pReplicator = new Scaler_Open(pSS,InputWidth,numerator,denominator,vip,ReplFormat);
668         NEWCHECK(pReplicator);
669         return pReplicator->constructor_error;
670     }
671
672         // Proprietary path and scalefactor>=2, so break it up into 2 parts
673         // first give ResSynth a factor of 2, which is all it really does anyway.
674
675         // Scaler_Prop only operates on RGB, so it doesn't need the last two parameters
676     pResSynth = Create_Scaler(pSS,InputWidth,2,1,
677                               TRUE,     // as if VIP since it is working on RGB only at this phase
678                               3);       // 3 bytes per pixel
679     NEWCHECK(pResSynth);
680         pResSynth->myplane = COLORTYPE_COLOR;
681     if (pResSynth->constructor_error != NO_ERROR)
682     {
683         return pResSynth->constructor_error;
684     }
685
686         pBlackPlaneReplicator = new Scaler_Open(pSS,InputWidth,2,1,FALSE,1);
687     NEWCHECK(pBlackPlaneReplicator);
688         pBlackPlaneReplicator->myplane = COLORTYPE_BLACK;
689     if (pBlackPlaneReplicator->constructor_error != NO_ERROR)
690     {
691         return pBlackPlaneReplicator->constructor_error;
692     }
693
694         // now replicate the rest of the way -- only half as much left
695     pReplicator = new Scaler_Open(pSS,2*InputWidth,numerator,2*denominator,vip,ReplFormat);
696     NEWCHECK(pReplicator);
697     return pReplicator->constructor_error;
698
699 } //InitScaler
700
701
702 DRIVER_ERROR Job::Configure()
703 // mode has been set -- now set up rasterwidths and pipeline
704 {
705    DRIVER_ERROR err;
706    Pipeline* p=NULL;
707    unsigned int width;
708    BOOL useRS=FALSE;
709
710    err = InitScaler();      // create pReplicator and maybe pResSynth
711    ERRCHECK;
712
713    if ((CurrentMode->Config.bResSynth) && ProprietaryScaling()
714        && pResSynth)        // pResSynth==NULL if no scaling required
715    {
716        p = new Pipeline(pBlackPlaneReplicator);
717        NEWCHECK(p);
718        if (thePipeline)
719           thePipeline->AddPhase(p);
720        else thePipeline=p;
721
722        p = new Pipeline(pResSynth);
723        NEWCHECK(p);
724        if (thePipeline)
725           thePipeline->AddPhase(p);
726        else thePipeline=p;
727        useRS=TRUE;
728    }
729
730 #if (defined(APDK_DJ9xxVIP) || defined(APDK_LJJETREADY)) && defined(APDK_VIP_COLORFILTERING)
731    if (CurrentMode->Config.bErnie)
732    {
733        // create Ernie (need pixelwidth for constructor)
734        if (p)
735        {
736            width = p->GetMaxOutputWidth(COLORTYPE_COLOR) / 3;     // GetOutputWidth returns # of bytes
737        }
738        else
739        {
740            width = thePrintContext->InputWidth;
741        }
742
743                 // calculate Ernie threshold value
744                 //Normal: threshold = (resolution) * (0.0876) - 2
745                 // roughly: image at original 300 implies threshold=24; 600=>48, 150=>12, 75=>6
746                 // to get resolution of "original" image, divide target resolution by scalefactor
747        float scale = (float)thePrintContext->OutputWidth / (float)thePrintContext->InputWidth;
748        float original_res = ((float)thePrintContext->EffectiveResolutionX()) / scale;
749        if (useRS && (scale >= 2.0f))
750        {
751            // image already doubled by ResSynth so consider the resolution as of now
752             original_res *= 2.0f;
753        }
754        float fthreshold = original_res * 0.0876f;
755        int threshold = (int)fthreshold - 2;
756
757        pErnie = new TErnieFilter(width, eBGRPixelData, threshold);
758        p = new Pipeline(pErnie);
759        NEWCHECK(p);
760        if (thePipeline)
761        {
762           thePipeline->AddPhase(p);
763        }
764        else
765        {
766            thePipeline = p;
767        }
768         }
769 #endif //APDK_DJ9xxVIP && APDK_VIP_COLORFILTERING
770
771    if (CurrentMode->Config.bColorImage)
772    {
773        err = SetupColorMatching();      // create pColorMatcher
774        ERRCHECK;
775        p = new Pipeline(pColorMatcher);
776        NEWCHECK(p);
777        if (thePipeline)
778        {
779           thePipeline->AddPhase(p);
780       }
781        else
782        {
783            thePipeline = p;
784        }
785    }
786
787    if (CurrentMode->Config.bPixelReplicate)
788    {
789        // create Replicator
790        p = new Pipeline(pReplicator);
791        NEWCHECK(p);
792        if (thePipeline)
793        {
794           thePipeline->AddPhase(p);
795       }
796        else
797        {
798            thePipeline = p;
799        }
800    }
801
802    if (CurrentMode->Config.bColorImage)
803    {
804        err = SetupHalftoning(CurrentMode->Config.eHT);     // create pHalftoner
805        ERRCHECK;
806        p = new Pipeline(pHalftoner);
807        NEWCHECK(p);
808        if (thePipeline)
809        {
810           thePipeline->AddPhase(p);
811       }
812        else
813        {
814            thePipeline = p;
815        }
816    }
817
818    if (CurrentMode->Config.bCompress)
819    {
820        if (p)
821        {
822             width = p->GetMaxOutputWidth(COLORTYPE_COLOR);
823        }
824        else
825        {
826            width = thePrintContext->InputWidth;
827        }
828        unsigned int SeedBufferSize;
829        if (pHalftoner)      // if data is halftoned-output
830        {
831                         // format is 1 bit-per-pixel for each ink,drop,pass
832            SeedBufferSize = MAXCOLORPLANES * MAXCOLORDEPTH * MAXCOLORROWS * width;
833        }
834        else              // VIP data is just RGB24 here
835        {
836            SeedBufferSize = width;
837        }
838
839        theCompressor = thePrinter->CreateCompressor(SeedBufferSize);
840        NEWCHECK(theCompressor);
841        err = theCompressor->constructor_error;
842        ERRCHECK;
843            theCompressor->myplane = COLORTYPE_COLOR;
844
845        p = new Pipeline(theCompressor);
846        NEWCHECK(p);
847        if (thePipeline)
848        {
849            thePipeline->AddPhase(p);
850        }
851        else
852        {
853            thePipeline = p;
854        }
855            if (thePrinter->VIPPrinter())
856            {
857                         width = (width/3+7)/8;
858                     if (width > 0)
859                         {
860                            // VIP black data is 1 bit here
861                            unsigned int SeedBufferSize;
862                            SeedBufferSize = width;
863                            pBlackPlaneCompressor = thePrinter->CreateBlackPlaneCompressor(SeedBufferSize, TRUE);
864                            NEWCHECK(pBlackPlaneCompressor);
865                            err = pBlackPlaneCompressor->constructor_error;
866                            ERRCHECK;
867                            pBlackPlaneCompressor->myplane = COLORTYPE_BLACK;
868
869                            p = new Pipeline(pBlackPlaneCompressor);
870                            NEWCHECK(p);
871                            if (thePipeline)
872                            {
873                                   thePipeline->AddPhase(p);
874                            }
875                            else
876                            {
877                                    thePipeline = p;
878                            }
879                    }
880            }
881
882    }
883
884    // always end pipeline with RasterSender
885    // create RasterSender object
886    pSender = new RasterSender(thePrinter,thePrintContext,this,pHalftoner);
887    NEWCHECK(pSender);
888    err = pSender->constructor_error;
889    ERRCHECK;
890
891    p = new Pipeline(pSender);
892
893    if (thePipeline)
894    {
895       thePipeline->AddPhase(p);
896   }
897    else
898    {
899        thePipeline = p;
900    }
901
902   return NO_ERROR;
903 } //Configure
904
905
906 DRIVER_ERROR Job::setblankraster()
907 {
908     if (BlankRaster)
909     {
910         pSS->FreeMemory(BlankRaster);
911     }
912
913     size_t    BlankRasterSize = thePrintContext->OutputWidth * 3;          // Raghu
914     BlankRaster = (BYTE*)pSS->AllocMem (BlankRasterSize);
915     NEWCHECK(BlankRaster);
916
917     memset (BlankRaster, 0xFF, BlankRasterSize);    // Raghu
918
919     return NO_ERROR;
920 } //setblankraster
921
922 DRIVER_ERROR Job::setblackraster()
923 {
924         size_t    BlackRasterSize = thePrintContext->InputWidth;  
925     if (!BlackRaster)
926     {
927                 BlackRaster = (BYTE*)pSS->AllocMem (BlackRasterSize);
928                 NEWCHECK(BlackRaster);
929         }
930     memset (BlackRaster, 0, BlackRasterSize);
931
932     return NO_ERROR;
933 } //setblankraster
934
935
936 //////////////////////////////////////////////////////////////////////
937 #if defined(APDK_FONTS_NEEDED)
938
939 /*!
940 This method is used to send ASCII data to the printer, which it will render
941 as determined by the Font object.
942 */
943 DRIVER_ERROR Job::TextOut
944 (
945     const char* pTextString,
946     unsigned int iLenString,
947     const Font& font,
948     int iAbsX,
949     int iAbsY
950 )
951 // This is how ASCII data is sent to the driver.
952 // Everything is really handled by the TextManager, including error checking.
953 {
954 #ifdef APDK_CAPTURE
955     Capture_TextOut(pTextString, iLenString, font, iAbsX, iAbsY);
956 #endif
957
958     // Map coordinates (assumed to be in the graphical space) to the text-placement grid,
959     // which may be of lower resolution, indicated by TextRes
960     //
961     // using floats to cover the unusual case where graphical res is lower than text
962     float xfactor = ((float)CurrentMode->BaseResX) / ((float)CurrentMode->TextRes);
963     float yfactor = ((float)CurrentMode->BaseResY) / ((float)CurrentMode->TextRes);
964
965     float x = (float)iAbsX / xfactor;
966     float y = (float)iAbsY / yfactor;
967
968     iAbsX = (unsigned int)(int)x;   // double cast for webtv compiler
969     iAbsY = (unsigned int)(int)y;
970
971     DRIVER_ERROR err = theTextManager->TextOut(pTextString,iLenString,font,iAbsX,iAbsY);
972     ERRCHECK;
973
974     DataSent=TRUE;
975
976 #ifdef APDK_USAGE_LOG
977     if (iLenString > UTextSize)
978     {
979         iLenString = UTextSize-1;
980         UHeader[iLenString] = '\0';
981     }
982     if (UTextCount<2)
983     {
984         strcpy(UHeader,pTextString);
985         UText += iLenString;
986     }
987     if (UTextCount==1)
988     {
989         UHeader[UText] = '\0';
990     }
991     UTextCount++;
992
993 #endif
994
995     return err;
996 } //TextOut
997
998 #endif
999
1000
1001 ///////////////////////////////////////////////////////////
1002 // Pipeline management
1003 Pipeline::Pipeline
1004 (
1005     Processor* E
1006 ) :
1007     next(NULL),
1008     prev(NULL)
1009 {
1010     Exec = E;
1011     Exec->myphase = this;
1012 } //Pipeline
1013
1014
1015 void Pipeline::AddPhase(Pipeline* newp)
1016 {
1017     Pipeline* p = this;
1018     while (p->next)
1019     {
1020         p = p->next;
1021     }
1022     p->next = newp;
1023     newp->prev = p;
1024 } //AddPhase
1025
1026
1027 Pipeline::~Pipeline()
1028 {
1029     if (next)
1030     {
1031         delete next;
1032     }
1033 } //~Pipeline
1034
1035
1036 BOOL Pipeline::Process(RASTERDATA* raster)
1037 {
1038     return Exec->Process(raster);
1039 } //Process
1040
1041
1042 DRIVER_ERROR Pipeline::Execute(RASTERDATA* InputRaster)
1043 {
1044     err=NO_ERROR;
1045
1046     if (Process(InputRaster)        // true if output ready; may set err
1047         && (err==NO_ERROR))
1048     {
1049         if (next)
1050         {
1051                         next->Exec->raster.rasterdata[COLORTYPE_BLACK] = NextOutputRaster(COLORTYPE_BLACK);
1052                         next->Exec->raster.rasterdata[COLORTYPE_COLOR] = NextOutputRaster(COLORTYPE_COLOR);
1053             while (next->Exec->raster.rasterdata[COLORTYPE_COLOR] || 
1054                                    next->Exec->raster.rasterdata[COLORTYPE_BLACK])
1055             {
1056                                 next->Exec->raster.rastersize[COLORTYPE_COLOR] = GetOutputWidth(COLORTYPE_COLOR);
1057                                 next->Exec->raster.rastersize[COLORTYPE_BLACK] = GetOutputWidth(COLORTYPE_BLACK);
1058                 err = next->Execute(&(next->Exec->raster));
1059                 ERRCHECK;
1060                                 next->Exec->raster.rasterdata[COLORTYPE_BLACK] = NextOutputRaster(COLORTYPE_BLACK);
1061                                 next->Exec->raster.rasterdata[COLORTYPE_COLOR] = NextOutputRaster(COLORTYPE_COLOR);
1062             }
1063         }
1064     }
1065     return err;
1066 } //Execute
1067
1068
1069 DRIVER_ERROR Pipeline::Flush()
1070 {
1071     err=NO_ERROR;
1072
1073     Exec->Flush();
1074
1075     if (next && (err == NO_ERROR))
1076     {
1077                 next->Exec->raster.rasterdata[COLORTYPE_BLACK] = NextOutputRaster(COLORTYPE_BLACK);
1078                 next->Exec->raster.rasterdata[COLORTYPE_COLOR] = NextOutputRaster(COLORTYPE_COLOR);
1079         while (next->Exec->raster.rasterdata[COLORTYPE_COLOR] || next->Exec->raster.rasterdata[COLORTYPE_BLACK])
1080         {
1081                         next->Exec->raster.rastersize[COLORTYPE_BLACK] = GetOutputWidth(COLORTYPE_BLACK);
1082                         next->Exec->raster.rastersize[COLORTYPE_COLOR] = GetOutputWidth(COLORTYPE_COLOR);
1083             err = next->Execute(&(next->Exec->raster));
1084                         next->Exec->raster.rasterdata[COLORTYPE_BLACK] = NextOutputRaster(COLORTYPE_BLACK);
1085                         next->Exec->raster.rasterdata[COLORTYPE_COLOR] = NextOutputRaster(COLORTYPE_COLOR);
1086             ERRCHECK;
1087         }
1088                 // one more to continue flushing downstream
1089                 err = next->Flush();
1090     }
1091
1092     return err;
1093 } //Flush
1094
1095
1096 Processor::Processor() :
1097     iRastersReady(0),
1098     iRastersDelivered(0),
1099     myphase(NULL),
1100         myplane(COLORTYPE_BOTH)
1101 {
1102         for (int i = COLORTYPE_COLOR; i < MAX_COLORTYPE; i++)
1103         {
1104                 raster.rasterdata[i] = NULL;
1105                 raster.rastersize[i] = 0;
1106         }
1107 } //Processor
1108
1109
1110 Processor::~Processor()
1111 {
1112 } //~Processor
1113
1114 APDK_END_NAMESPACE