Aurelon Open API 8.1.1
Loading...
Searching...
No Matches
AOI_TIFFRenderer.cpp
1#include "./AOI_TIFFRenderer.h"
2#include "../GDocument.h"
3#include "../GInstance.h"
4#include "../GProfile.h"
5#include <ACPL/Utilities.h>
6#include "../TIFF/CTiff.h"
7#include "../JPEG/CJPeg.h"
8
9#if ACPL_MAC
10# define Sleep( x ) usleep( x * 1000 )
11#endif
12
13using namespace aur;
14using namespace aur::PDF;
15using namespace aur::ACPL;
16
17#define kDataUnitsLimit ( 64 * 1024 * 1024 )
18#define kSleepTime 125
19
20AOI_TIFFRenderer::AOI_TIFFRenderer( AOI_Document& doc ) :
21 mContinue( false ),
22 mReaderEnded( true ),
23 mCMMEnded( true ),
24 mDocument( doc.mDocument ),
25 mColorConvertor( NULL ),
26 mImageSpec( doc.mImageSpec ),
27 mInputCMM( NULL ),
28 mOutputCMM( NULL ),
29 mInputCS( NULL ),
30 mOutputCS( NULL ),
31 mLABLine( NULL ),
32 mColorConvertCallBack( NULL )
33{
34}
35
36AOI_TIFFRenderer::~AOI_TIFFRenderer()
37{
38 Cleanup();
39}
40
41void AOI_TIFFRenderer::SetColorConvertCallBack( ::ColorConvertCB cb, void* ref )
42{
43 mColorConvertCallBack = cb;
44 mColorConvertRef = ref;
45}
46
47void AOI_TIFFRenderer::Cleanup()
48{
49 mContinue = false;
50 while( mReaderEnded == false )
51 Sleep( 250 );
52 while( mCMMEnded == false )
53 Sleep( 250 );
54
55 mReaderQueue.DestroyBuffers();
56 mCMMQueue.DestroyBuffers();
57 mWriterQueue.DestroyBuffers();
58
59 delete mColorConvertor;
60 mColorConvertor = NULL;
61
62 mOutputCMM->Dispose();
63 mOutputCS->Dispose();
64 mInputCMM->Dispose();
65 mInputCS->Dispose();
66
67 delete[] mLABLine;
68 mLABLine = NULL;
69}
70
71aur::ExceptionCode AOI_TIFFRenderer::Setup( const FileSpec& profSpec, const StringList& extraChannels, void* banddata, int32_t w, int32_t h, bool alpha )
72{
73 Cleanup();
74
75 if( w <= 0 || h <= 0 )
76 throw ErrAssertFailed;
77
78 try
79 {
80 Document::Info info;
81 Document::GetInfo( *mImageSpec, info );
82
83 mImageMapping.Reset();
84 mImageMapping.Scale( 0, 0, 18/info.xResolution, 18/info.yResolution );
85
86 if( info.reference )
87 {
88 mInputCMM = new CMM();
89 mInputCMM->Open( info.reference->GetFileSpec(), CMM::eInput, eRelativeColorimetric );
90 mInputCS = new ICCColorSpace( mDocument, info.reference->GetFileSpec() );
91 }
92 else
93 {
94 switch( NONINDEXED( info.space ) )
95 {
96 case GraySpace :
97 mInputCS = mDocument->GetDeviceGrayColorSpace();
98 break;
99 case RGBSpace :
100 mInputCS = mDocument->GetDeviceRGBColorSpace();
101 break;
102 case CMYKSpace :
103 mInputCS = mDocument->GetDeviceCMYKColorSpace();
104 break;
105 case LABSpace :
106 mInputCS = mDocument->GetLabColorSpace();
107 break;
108 default :
109 mInputCS = NULL;
110 }
111 if( NONINDEXED( info.space ) == info.space )
112 mInputCS->Clone();
113 else
114 mInputCS = new IndexColorSpace( mDocument, mInputCS );
115 }
116
117 mOutputCMM = new CMM();
118 mOutputCMM->Open( profSpec, CMM::eOutput, eRelativeColorimetric );
119 mOutputCS = new ICCColorSpace( mDocument, profSpec );
120 mWhite = mOutputCS->Space() == RGBSpace || mOutputCS->Space() == GraySpace ? 255 : 0;
121
122 mInputOriginal.channelCount = mInputCS->NrOfComponents();
123 mInputOriginal.width = info.pixelWidth;
124 mInputOriginal.height = info.pixelHeight;
125 mInputOriginal.rowBytes = mInputOriginal.channelCount * mInputOriginal.width;
126
127 mOutputOriginal.channelCount = mOutputCMM->GetSpaceComponents() + (uint32_t)extraChannels.size();
128 mOutputOriginal.width = w;
129 mOutputOriginal.height = h;
130 mOutputOriginal.rowBytes = mOutputOriginal.channelCount * mOutputOriginal.width;
131
132 uint32_t pixelSize;
133 if( mInputOriginal.width < mOutputOriginal.width )
134 pixelSize = mOutputOriginal.width;
135 else
136 pixelSize = mInputOriginal.width;
137 mLABLine = new uint16_t[ pixelSize * 3 ];
138
139 mColorConvertor = new PDF::Renderer();
140 mDocument->SetRenderer( mColorConvertor );
141 mColorConvertor->Setup( profSpec, extraChannels, w, h, alpha, false, false );
142
143 mOutputBand = (uint8_t*)banddata;
144
145 uint32_t bufferSize;
146 if( mInputOriginal.rowBytes < mOutputOriginal.rowBytes )
147 bufferSize = mOutputOriginal.rowBytes;
148 else
149 bufferSize = mInputOriginal.rowBytes;
150 uint32_t bufferCnt = kDataUnitsLimit / (bufferSize + bufferSize );
151 if( bufferCnt > 512 )
152 bufferCnt = 512;
153 while( bufferCnt-- )
154 {
155 Unit* unit = new Unit;
156 ::memset( unit, 0, sizeof(Unit) );
157 unit->mInputData = new uint8_t[ bufferSize ];
158 unit->mOutputData = new uint8_t[ bufferSize ];
159 mReaderQueue.AddBuffer( unit );
160 }
161
162 mY_Input_Start = 0;
163 mPreviousMapY = 0;
164
165 mDocument->GetPage()->GetDimensions( mPageWidth, mPageHeight );
166 }
167 catch( aur::ExceptionCode err )
168 {
169 Cleanup();
170 return err;
171 }
172
173 return NoError;
174}
175
176void AOI_TIFFRenderer::SetMapping( const AOI_Mapping& docToBandMap )
177{
178 mRenderMapping = (const Mapping&)docToBandMap;
179}
180
181void AOI_TIFFRenderer::Render()
182{
183 // Set scales
184 Mapping map( mImageMapping );
185 map.Map( mRenderMapping );
186 if( mContinue )
187 {
188 // Restart all threads from start when offset is changed in opposite direction
189 if( ( map.map[1][1] > 0 && map.map[2][1] >= mPreviousMapY ) ||
190 ( map.map[1][1] < 0 && map.map[2][1] <= mPreviousMapY ) )
191 {
192 mContinue = false;
193 while( mReaderEnded == false )
194 Sleep( 250 );
195 while( mCMMEnded == false )
196 Sleep( 250 );
197 Unit* unit;
198 while( ( unit = mWriterQueue.AquireBuffer() ) != NULL )
199 mReaderQueue.AddBuffer( unit );
200 while( ( unit = mCMMQueue.AquireBuffer() ) != NULL )
201 mReaderQueue.AddBuffer( unit );
202 }
203 }
204 if( mContinue == false )
205 {
206 mPreviousMapY = map.map[2][1];
207 mYScale = fabsf( map.map[1][1] );
208 //
209 // How much can be skipped when the start of 1st band is in the middle of the image
210 //
211 Mapping invmap( map );
212 invmap.Invert();
213 PDF::Point topLeft( 0, 0 );
214 PDF::Point bottomRight( (float)mOutputOriginal.width, (float)mOutputOriginal.height );
215 topLeft.Map( invmap );
216 bottomRight.Map( invmap );
217 if( bottomRight.y < topLeft.y )
218 {
219 float h = bottomRight.y;
220 bottomRight.y = topLeft.y;
221 topLeft.y = h;
222 h = bottomRight.x;
223 bottomRight.x = topLeft.x;
224 topLeft.x = h;
225 }
226 // Vertical skip
227 if( topLeft.y > 0 )
228 mY_Input_Start = uint32_t( topLeft.y );
229 else
230 mY_Input_Start = 0;
231 // Horizontal skip
232 uint32_t offsetInPixels;
233 if( topLeft.x > 0 )
234 {
235 offsetInPixels = uint32_t( topLeft.x );
236 if( offsetInPixels > mInputOriginal.width )
237 offsetInPixels = mInputOriginal.width;
238 }
239 else
240 offsetInPixels = 0;
241 mInputClipped = mInputOriginal;
242 mInput_X_OffsetBytes = offsetInPixels * mInputOriginal.channelCount;
243 if( uint32_t( bottomRight.x ) < mInputOriginal.width )
244 mInputClipped.width = uint32_t( bottomRight.x );
245 mInputClipped.width -= offsetInPixels;
246 mInputClipped.rowBytes = mInputClipped.width * mInputClipped.channelCount;
247 // Adjust output size if the image is smaller than the renderer
248 // of when the image if only partial on the renderer
249 topLeft.x = topLeft.y = 0;
250 bottomRight.x = (float)mInputOriginal.width;
251 bottomRight.y = (float)mInputOriginal.height;
252 topLeft.Map( map );
253 bottomRight.Map( map );
254 if( bottomRight.y < topLeft.y )
255 {
256 float h = bottomRight.y;
257 bottomRight.y = topLeft.y;
258 topLeft.y = h;
259 h = bottomRight.x;
260 bottomRight.x = topLeft.x;
261 topLeft.x = h;
262
263 if( bottomRight.y < 0 )
264 mY_Output_Start = 0;
265 else
266 mY_Output_Start = uint32_t( bottomRight.y );
267 }
268 else
269 {
270 if( topLeft.y > 0 )
271 mY_Output_Start = uint32_t( topLeft.y );
272 else
273 mY_Output_Start = 0;
274 }
275 if( topLeft.x > 0 )
276 {
277 offsetInPixels = uint32_t( topLeft.x );
278 if( offsetInPixels > mOutputOriginal.width )
279 offsetInPixels = mOutputOriginal.width;
280 }
281 else
282 offsetInPixels = 0;
283 mOutputClipped = mOutputOriginal;
284 mOutput_X_OffsetBytes = offsetInPixels * mOutputClipped.channelCount;
285 if( uint32_t( bottomRight.x ) < mOutputClipped.width )
286 mOutputClipped.width = uint32_t( bottomRight.x );
287 mOutputClipped.width -= offsetInPixels;
288 mOutputClipped.rowBytes = mOutputClipped.width * mOutputClipped.channelCount;
289
290 mY_Input_Threshold = 0;
291 mY_Output_Threshold = 0;
292 mY_Input = 0;
293
294 // Start threads
295 mContinue = true;
296 mImageExhausted = false;
297
298 mCMMEnded = false;
299#if ACPL_WIN
300 mCMMThreadH = ::_beginthread( CMMCreate, 0, this );
301#else
302 ::pthread_create( &mCMMThreadH, NULL, CMMCreate, this );
303 ::pthread_detach( mCMMThreadH );
304#endif
305
306 mReaderEnded = false;
307#if ACPL_WIN
308 mReaderThreadH = ::_beginthread( ReaderCreate, 0, this );
309#else
310 ::pthread_create( &mReaderThreadH, NULL, ReaderCreate, this );
311 ::pthread_detach( mReaderThreadH );
312#endif
313 }
314 // Fill band with lines received in mWriterQueue
315 bool quitThis = false;
316 Unit* unit;
317 uint32_t rightSide_X_Bytes = mOutputOriginal.rowBytes - mOutputClipped.rowBytes - mOutput_X_OffsetBytes;
318 if( mRenderMapping.map[1][1] > 0 )
319 {
320 // Upright
321 uint32_t bandY = 0;
322 uint8_t* outputLinePtr = mOutputBand;
323 uint32_t outputY = 0;
324 while( outputY < mY_Output_Start && bandY != mOutputOriginal.height )
325 {
326 ::memset( outputLinePtr, mWhite, mOutputOriginal.rowBytes );
327 ++outputY;
328 ++bandY;
329 outputLinePtr += mOutputOriginal.rowBytes;
330 }
331 mY_Output_Start -= outputY;
332 if( bandY == mOutputOriginal.height )
333 return;
334 if( mImageExhausted == false )
335 {
336 if( mYScale > 1 )
337 {
338 // Write upright + upsampling
339 do
340 {
341 while( ( unit = mWriterQueue.AquireBuffer() ) == NULL && mContinue )
342 Sleep( kSleepTime );
343
344 if( unit )
345 {
346 if( unit->mIsLast )
347 {
348 mImageExhausted = true;
349 mReaderQueue.AddBuffer( unit );
350 break;
351 }
352
353 // Write to band
354 while( mY_Output_Threshold <= mYScale && bandY != mOutputOriginal.height )
355 {
356 if( mOutput_X_OffsetBytes )
357 ::memset( outputLinePtr, mWhite, mOutput_X_OffsetBytes );
358 ::memcpy( outputLinePtr + mOutput_X_OffsetBytes, unit->mOutputData, mOutputClipped.rowBytes );
359 if( rightSide_X_Bytes )
360 ::memset( outputLinePtr + mOutput_X_OffsetBytes + mOutputClipped.rowBytes, mWhite, rightSide_X_Bytes );
361 ++bandY;
362 outputLinePtr += mOutputOriginal.rowBytes;
363 mY_Output_Threshold += 1;
364 }
365 mY_Output_Threshold -= mYScale;
366
367 // Release unit
368 mReaderQueue.AddBuffer( unit );
369 }
370 }
371 while( mContinue && bandY != mOutputOriginal.height );
372 }
373 else
374 {
375 // Write upright
376 do
377 {
378 while( ( unit = mWriterQueue.AquireBuffer() ) == NULL && mContinue )
379 Sleep( kSleepTime );
380
381 if( unit )
382 {
383 if( unit->mIsLast )
384 {
385 mImageExhausted = true;
386 mReaderQueue.AddBuffer( unit );
387 break;
388 }
389
390 // Write to band
391 if( mOutput_X_OffsetBytes )
392 ::memset( outputLinePtr, mWhite, mOutput_X_OffsetBytes );
393 ::memcpy( outputLinePtr + mOutput_X_OffsetBytes, unit->mOutputData, mOutputClipped.rowBytes );
394 if( rightSide_X_Bytes )
395 ::memset( outputLinePtr + mOutput_X_OffsetBytes + mOutputClipped.rowBytes, mWhite, rightSide_X_Bytes );
396 ++bandY;
397 outputLinePtr += mOutputOriginal.rowBytes;
398
399 // Release unit
400 quitThis = unit->mIsLast;
401 mReaderQueue.AddBuffer( unit );
402 }
403 }
404 while( mContinue && bandY != mOutputOriginal.height );
405 }
406 }
407 while( bandY != mOutputOriginal.height )
408 {
409 ::memset( outputLinePtr, mWhite, mOutputOriginal.rowBytes );
410 ++bandY;
411 outputLinePtr += mOutputOriginal.rowBytes;
412 }
413 }
414 else
415 {
416 // Upside down
417 //
418 // ATTENTION: Y is line below target, thus out of band
419 //
420 uint32_t bandY = mOutputOriginal.height;
421 uint8_t* outputLinePtr = mOutputBand + bandY * mOutputOriginal.rowBytes;
422 uint32_t outputY = bandY;
423 while( outputY > mY_Output_Start && bandY != 0 )
424 {
425 --outputY;
426 --bandY;
427 outputLinePtr -= mOutputOriginal.rowBytes;
428 ::memset( outputLinePtr, mWhite, mOutputOriginal.rowBytes );
429 }
430 mY_Output_Start -= outputY;
431 if( bandY == 0 )
432 return;
433 if( mImageExhausted == false )
434 {
435 if( mYScale > 1 )
436 {
437 // Write upside down + upsampling
438 do
439 {
440 while( ( unit = mWriterQueue.AquireBuffer() ) == NULL && mContinue )
441 Sleep( kSleepTime );
442
443 if( unit )
444 {
445 if( unit->mIsLast )
446 {
447 mImageExhausted = true;
448 mReaderQueue.AddBuffer( unit );
449 break;
450 }
451
452 // Write to band
453 while( mY_Output_Threshold <= mYScale && bandY != 0 )
454 {
455 --bandY;
456 outputLinePtr -= mOutputOriginal.rowBytes;
457 mY_Output_Threshold += 1;
458 if( mOutput_X_OffsetBytes )
459 ::memset( outputLinePtr, mWhite, mOutput_X_OffsetBytes );
460
461 const uint8_t* in = unit->mOutputData;
462 uint8_t* out = outputLinePtr + mOutput_X_OffsetBytes + mOutputClipped.rowBytes - mOutputClipped.channelCount;
463 uint32_t twoPixels = mOutputClipped.channelCount * 2;
464 for( uint32_t i = 0 ; i != mOutputClipped.width; ++i )
465 {
466 for( uint32_t c = 0 ;c != mOutputClipped.channelCount; ++c )
467 *out++ = *in++;
468 out -= twoPixels;
469 }
470
471 if( rightSide_X_Bytes )
472 ::memset( outputLinePtr + mOutput_X_OffsetBytes + mOutputClipped.rowBytes, mWhite, rightSide_X_Bytes );
473 }
474 mY_Output_Threshold -= mYScale;
475
476 // Release unit
477 quitThis = unit->mIsLast;
478 mReaderQueue.AddBuffer( unit );
479 }
480 }
481 while( mContinue && bandY != 0 );
482 }
483 else
484 {
485 // Write upside down
486 do
487 {
488 while( ( unit = mWriterQueue.AquireBuffer() ) == NULL && mContinue )
489 Sleep( kSleepTime );
490
491 if( unit )
492 {
493 if( unit->mIsLast )
494 {
495 mImageExhausted = true;
496 mReaderQueue.AddBuffer( unit );
497 break;
498 }
499
500 --bandY;
501 outputLinePtr -= mOutputOriginal.rowBytes;
502 // Write to band
503 if( mOutput_X_OffsetBytes )
504 ::memset( outputLinePtr, mWhite, mOutput_X_OffsetBytes );
505
506 const uint8_t* in = unit->mOutputData;
507 uint8_t* out = outputLinePtr + mOutput_X_OffsetBytes + mOutputClipped.rowBytes - mOutputClipped.channelCount;
508 uint32_t twoPixels = mOutputClipped.channelCount * 2;
509 for( uint32_t i = 0 ; i != mOutputClipped.width; ++i )
510 {
511 for( uint32_t c = 0 ;c != mOutputClipped.channelCount; ++c )
512 *out++ = *in++;
513 out -= twoPixels;
514 }
515
516 if( rightSide_X_Bytes )
517 ::memset( outputLinePtr + mOutput_X_OffsetBytes + mOutputClipped.rowBytes, mWhite, rightSide_X_Bytes );
518
519 // Release unit
520 quitThis = unit->mIsLast;
521 mReaderQueue.AddBuffer( unit );
522 }
523 }
524 while( mContinue && bandY != 0 );
525 }
526 }
527 while( bandY != 0 )
528 {
529 --bandY;
530 outputLinePtr -= mOutputOriginal.rowBytes;
531 ::memset( outputLinePtr, mWhite, mOutputOriginal.rowBytes );
532 }
533 }
534}
535
536ACPL_RES AOI_TIFFRenderer::ReaderCreate( void* param )
537{
538 AOI_TIFFRenderer* obj = (AOI_TIFFRenderer*)param;
539 obj->Reader();
540 return ACPL_RETURN;
541}
542
543void AOI_TIFFRenderer::Reader()
544{
545 Import* plug = NULL;
546 try
547 {
548 mY_Input = 0;
549 String fileType;
550 Document::DetermineFileType( *mImageSpec, fileType );
551 if( fileType == "tif" )
552 {
553 CTiff* tif = new CTiff( mDocument );
554 plug = tif->GetImport();
555 plug->SetCB( this, ReaderPlugSetup, ReaderPlugSaveLine );
556 aur::ExceptionCode err = tif->Open( mImageSpec );
557 if( err )
558 throw err;
559 }
560 else if( fileType == "jpg" )
561 {
562 CJPeg* jpg = new CJPeg( mDocument );
563 plug = jpg;
564 plug->SetCB( this, ReaderPlugSetup, ReaderPlugSaveLine );
565 aur::ExceptionCode err = jpg->Open( mImageSpec );
566 if( err )
567 throw err;
568 }
569 // Restore original dimensions, RasterClose modifies the dimensions
570 // due to the patch to gracefully exit Import
571 mDocument->GetPage()->SetDimensions( mPageWidth, mPageHeight );
572 }
573 catch( ... )
574 {
575 mContinue = false;
576 }
577 delete plug;
578
579 mReaderEnded = true;
580}
581
582aur::ExceptionCode AOI_TIFFRenderer::ReaderPlugSetup(void* ref, const aur::PDF::BitmapT& inBitmap)
583{
584 AOI_TIFFRenderer* obj = (AOI_TIFFRenderer*)ref;
585 inBitmap.space->Clone();
586 obj->mInputCS->Dispose();
587 obj->mInputCS = inBitmap.space;
588 obj->mInputOriginal.width = inBitmap.width;
589 obj->mInputOriginal.height = inBitmap.height;
590 obj->mInputOriginal.rowBytes = obj->mInputOriginal.channelCount * obj->mInputOriginal.width;
591 if( obj->mInputClipped.height > obj->mInputOriginal.height )
592 obj->mInputClipped.height = obj->mInputOriginal.height;
593
594 return NoError;
595}
596
597aur::ExceptionCode AOI_TIFFRenderer::ReaderPlugSaveLine( void* ref, const uint8_t* inImageLine )
598{
599 AOI_TIFFRenderer* obj = (AOI_TIFFRenderer*)ref;
600 bool postResult = true;
601
602 if( obj->mYScale < 1 )
603 {
604 postResult = obj->mY_Input_Threshold >= 0;
605 if( postResult )
606 obj->mY_Input_Threshold -= 1;
607 obj->mY_Input_Threshold += obj->mYScale;
608 }
609 if( obj->mY_Input < obj->mY_Input_Start )
610 postResult = false;
611 ++obj->mY_Input;
612 if( postResult )
613 {
614 Unit* unit;
615 while( ( unit = obj->mReaderQueue.AquireBuffer() ) == NULL && obj->mContinue )
616 Sleep( kSleepTime );
617
618 if( unit )
619 {
620 ::memcpy( unit->mInputData, inImageLine + obj->mInput_X_OffsetBytes, obj->mInputClipped.rowBytes );
621 unit->mIsLast = false;
622 obj->mCMMQueue.AddBuffer( unit );
623 }
624 }
625 if( obj->mY_Input == obj->mInputClipped.height )
626 {
627 Unit* unit;
628 while( ( unit = obj->mReaderQueue.AquireBuffer() ) == NULL && obj->mContinue )
629 Sleep( kSleepTime );
630 if( unit )
631 {
632 unit->mIsLast = true;
633 obj->mCMMQueue.AddBuffer( unit );
634 }
635 }
636 return obj->mContinue ? NoError : ErrUserCanceled;
637}
638
639ACPL_RES AOI_TIFFRenderer::CMMCreate( void* param )
640{
641 AOI_TIFFRenderer* obj = (AOI_TIFFRenderer*)param;
642 obj->ScaleCMM();
643 return ACPL_RETURN;
644}
645
646void AOI_TIFFRenderer::ScaleCMM()
647{
648 bool quitThis = false;
649 Unit* unit;
650 if( mColorConvertCallBack )
651 {
652 bool set[ MAX_CHANNELS ];
654 ccd.inObject = NULL;
655 ccd.inIsVector = false;
656 ccd.inIsShading = false;
657 ccd.inChannels16 = NULL;
658 ccd.outChannels16 = NULL;
659 ccd.outChannelsUsed = set;
660 ClearStruct( set );
661
662 uint32_t sz;
663 if( mInputClipped.width > mOutputClipped.width ) // Down sample
664 sz = mInputClipped.channelCount * mOutputClipped.width;
665 else // Up sample
666 sz = mInputClipped.width * mOutputClipped.channelCount;
667 do
668 {
669 while( ( unit = mCMMQueue.AquireBuffer() ) == NULL && mContinue )
670 Sleep( kSleepTime );
671 if( unit == NULL )
672 break;
673 if( unit->mIsLast == false )
674 {
675 ccd.inSourceSpace = AOI_ColorSpacePtr(mInputCS);
676 ccd.inDestinationSpace = NULL;
677
678 if( mInputClipped.width > mOutputClipped.width ) // Down sample
679 {
680 DownscaleFree( mInputClipped.channelCount, unit->mInputData, mInputClipped.width, unit->mOutputData, mOutputClipped.width );
681 ::memcpy( unit->mInputData, unit->mOutputData, sz );
682
683 ccd.inChannels8 = unit->mInputData;
684 ccd.inPixelCount = mOutputClipped.width;
685 ccd.outChannels8 = unit->mOutputData;
686
687 if( mColorConvertCallBack( ccd, mColorConvertRef ) == false )
688 {
689 if( mInputCMM )
690 {
691 mInputCMM->Image2Lab( unit->mInputData, mLABLine, mOutputClipped.width );
692 mOutputCMM->Lab2Image( mLABLine, unit->mOutputData, mOutputClipped.width );
693 }
694 else
695 SimpleConvert( mOutputClipped.width, unit->mInputData, unit->mOutputData );
696 }
697 }
698 else if( mInputClipped.width == mOutputClipped.width ) // No scale needed
699 {
700 ccd.inChannels8 = unit->mInputData;
701 ccd.inPixelCount = mInputClipped.width;
702 ccd.outChannels8 = unit->mOutputData;
703
704 if( mColorConvertCallBack( ccd, mColorConvertRef ) == false )
705 {
706 if( mInputCMM )
707 {
708 mInputCMM->Image2Lab( unit->mInputData, mLABLine, mInputClipped.width );
709 mOutputCMM->Lab2Image( mLABLine, unit->mOutputData, mOutputClipped.width );
710 }
711 else
712 SimpleConvert( mOutputClipped.width, unit->mInputData, unit->mOutputData );
713 }
714 }
715 else // Up sample
716 {
717 ccd.inChannels8 = unit->mInputData;
718 ccd.inPixelCount = mInputClipped.width;
719 ccd.outChannels8 = unit->mOutputData;
720
721 if( mColorConvertCallBack( ccd, mColorConvertRef ) == false )
722 {
723 if( mInputCMM )
724 {
725 mInputCMM->Image2Lab( unit->mInputData, mLABLine, mInputClipped.width );
726 mOutputCMM->Lab2Image( mLABLine, unit->mInputData, mInputClipped.width );
727 }
728 else
729 {
730 SimpleConvert( mInputClipped.width, unit->mInputData, unit->mOutputData );
731 ::memcpy( unit->mInputData, unit->mOutputData, sz );
732 }
733 }
734 else
735 ::memcpy( unit->mInputData, unit->mOutputData, sz );
736
737 UpscaleFree( mOutputClipped.channelCount, unit->mInputData, mInputClipped.width, unit->mOutputData, mOutputClipped.width );
738 }
739 }
740 else
741 quitThis = true;
742 mWriterQueue.AddBuffer( unit );
743 }
744 while( mContinue && !quitThis );
745 }
746 else if( mInputCMM )
747 {
748 do
749 {
750 while( ( unit = mCMMQueue.AquireBuffer() ) == NULL && mContinue )
751 Sleep( kSleepTime );
752 if( unit == NULL )
753 break;
754
755 if( unit->mIsLast == false )
756 {
757 if( mInputClipped.width > mOutputClipped.width ) // Down sample
758 {
759 DownscaleFree( mInputClipped.channelCount, unit->mInputData, mInputClipped.width, unit->mOutputData, mOutputClipped.width );
760 mInputCMM->Image2Lab( unit->mOutputData, mLABLine, mOutputClipped.width );
761 mOutputCMM->Lab2Image( mLABLine, unit->mOutputData, mOutputClipped.width );
762 }
763 else if( mInputClipped.width == mOutputClipped.width ) // No scale needed
764 {
765 mInputCMM->Image2Lab( unit->mInputData, mLABLine, mInputClipped.width );
766 mOutputCMM->Lab2Image( mLABLine, unit->mOutputData, mOutputClipped.width );
767 }
768 else // Up sample
769 {
770 mInputCMM->Image2Lab( unit->mInputData, mLABLine, mInputClipped.width );
771 mOutputCMM->Lab2Image( mLABLine, unit->mInputData, mInputClipped.width );
772 UpscaleFree( mOutputClipped.channelCount, unit->mInputData, mInputClipped.width, unit->mOutputData, mOutputClipped.width );
773 }
774 }
775 else
776 quitThis = true;
777 mWriterQueue.AddBuffer( unit );
778 }
779 while( mContinue && !quitThis );
780 }
781 else
782 {
783 do
784 {
785 while( ( unit = mCMMQueue.AquireBuffer() ) == NULL && mContinue )
786 Sleep( kSleepTime );
787 if( unit == NULL )
788 break;
789
790 if( unit->mIsLast == false )
791 {
792 if( mInputClipped.width > mOutputClipped.width ) // Down sample
793 {
794 DownscaleFree( mInputClipped.channelCount, unit->mInputData, mInputClipped.width, unit->mOutputData, mOutputClipped.width );
795 SimpleConvert( mOutputClipped.width, unit->mOutputData, unit->mInputData );
796 ::memcpy( unit->mOutputData, unit->mInputData, mOutputClipped.rowBytes );
797 }
798 else if( mInputClipped.width == mOutputClipped.width ) // No scale needed
799 {
800 SimpleConvert( mInputClipped.width, unit->mInputData, unit->mOutputData );
801 }
802 else // Up sample
803 {
804 SimpleConvert( mInputClipped.width, unit->mInputData, unit->mOutputData );
805 ::memcpy( unit->mInputData, unit->mOutputData, mInputClipped.width * mOutputClipped.channelCount );
806 UpscaleFree( mOutputClipped.channelCount, unit->mInputData, mInputClipped.width, unit->mOutputData, mOutputClipped.width );
807 }
808 }
809 else
810 quitThis = true;
811 mWriterQueue.AddBuffer( unit );
812 }
813 while( mContinue && !quitThis );
814 }
815
816 mCMMEnded = true;
817}
818
819void AOI_TIFFRenderer::SimpleConvert( uint32_t width, const uint8_t* src, uint8_t* dest )
820{
821 ChannelColor cc;
822 uint16_t inChannels[4];
823 uint32_t inChannelCount = mInputCS->NrOfComponents();
824 uint32_t outChannelCount = mOutputOriginal.channelCount;
825 uint32_t p;
826
827 if( mInputCS->ResourceType() == IndexColorSpace::eResourceType )
828 {
829 for( uint32_t x = 0; x != width; ++x )
830 {
831 inChannels[0] = uint16_t(*src++);
832 mInputCS->SetRenderChannels( mColorConvertor, inChannels, cc );
833 for( p = 0; p != outChannelCount; ++p )
834 *dest++ = uint8_t( cc.value[p] >> 8 );
835 }
836 }
837 else
838 {
839 for( uint32_t x = 0; x != width; ++x )
840 {
841 for( p = 0; p != inChannelCount; ++p )
842 inChannels[p] = uint16_t(*src++) << 8;
843 mInputCS->SetRenderChannels( mColorConvertor, inChannels, cc );
844 for( p = 0; p != outChannelCount; ++p )
845 *dest++ = uint8_t( cc.value[p] >> 8 );
846 }
847 }
848}
849
850void AOI_TIFFRenderer::DownscaleFree( uint32_t channels, const uint8_t* inImage, int32_t inWidth, uint8_t* outImage, int32_t outWidth )
851{
852 double x = 0;
853 double step = double( inWidth ) / outWidth;
854 const uint8_t* src;
855 uint8_t* dest = outImage;
856 const uint8_t* end = outImage + outWidth * channels;
857 uint32_t p;
858 while( dest != end )
859 {
860 src = inImage + uint32_t( x ) * channels;
861 x += step;
862 for( p = 0; p != channels; ++p )
863 *dest++ = *src++;
864 }
865}
866
867void AOI_TIFFRenderer::UpscaleFree( uint32_t channels, const uint8_t* inImage, int32_t inWidth, uint8_t* outImage, int32_t outWidth )
868{
869 double pixelsNeeded = 0;
870 double step = double( outWidth ) / inWidth;
871 const uint8_t* src = inImage;
872 uint8_t* dest = outImage;
873 const uint8_t* end = outImage + outWidth * channels;
874 const uint8_t* inEnd = inImage + inWidth * channels;
875 uint32_t p;
876 while( dest != end )
877 {
878 pixelsNeeded += step;
879 while( dest != end && pixelsNeeded >= 1 )
880 {
881 for( p = 0; p != channels; ++p )
882 *dest++ = *src++;
883 src -= channels;
884 --pixelsNeeded;
885 }
886 src += channels;
887 if( src == inEnd )
888 src -= channels;
889 }
890}
891
892AOI_TIFFRenderer::UnitQueue::UnitQueue()
893{
894 mUnits = NULL;
895}
896
897AOI_TIFFRenderer::UnitQueue::~UnitQueue()
898{
899 DestroyBuffers();
900}
901
902void AOI_TIFFRenderer::UnitQueue::AddBuffer( Unit* unit )
903{
904 mSemaphore.Enter();
905 Unit** prev = &mUnits;
906 while( *prev )
907 prev = &(*prev)->mNext;
908 *prev = unit;
909 unit->mNext = NULL;
910 mSemaphore.Leave();
911}
912
913AOI_TIFFRenderer::Unit* AOI_TIFFRenderer::UnitQueue::AquireBuffer()
914{
915 mSemaphore.Enter();
916 Unit* unit = mUnits;
917 if( mUnits )
918 mUnits = mUnits->mNext;
919 mSemaphore.Leave();
920 return unit;
921}
922
923void AOI_TIFFRenderer::UnitQueue::DestroyBuffers()
924{
925 mSemaphore.Enter();
926 Unit* unit;
927 while( mUnits )
928 {
929 unit = mUnits;
930 mUnits = unit->mNext;
931 delete[] unit->mInputData;
932 delete[] unit->mOutputData;
933 delete unit;
934 }
935 mUnits = NULL;
936 mSemaphore.Leave();
937}
PDF Document.
3x3 matrix
Definition AOI_Types.h:113
bool(* ColorConvertCB)(ColorConvert_Data &, void *)
CMM callback routine.
Color information for CMM callback.
aur::PDF::ColorSpaceObject * inSourceSpace
const aur::PDF::Object * inObject
const uint16_t * inChannels16
const uint8_t * inChannels8
aur::PDF::ColorSpaceObject * inDestinationSpace