1#include "./AOI_SoftProofRenderer.h"
2#include "../GDocument.h"
3#include "../GRenderer.h"
6#include "../GProfile.h"
7#include <PNG Library/png.h>
9#include <JPEG Library/jpeglib.h>
12#include "../GInstance.h"
13#include <ACPL/Utilities.h>
14#include <ACPL/FileStream.h>
16#include "../GVector.h"
17#include "../ColorSpace.h"
18#include "../GPlaceHolder.h"
19#include "../GRectangle.h"
20#include "../FindSpotcolorInLibraries.h"
23using namespace aur::PDF;
24using namespace aur::ACPL;
26class ThumbnailRenderer :
public aur::PDF::Renderer
30 virtual ~ThumbnailRenderer();
31 void SetProfile( aur::PDF::Document* doc, aur::PDF::ProfilePtr refProf, aur::PDF::Intent intent, aur::PDF::CMM* deviceCMMs );
32 void CopyBits( uint8_t* dest,
const aur::PDF::LRectangle& updateBounds, int32_t rowBytes,
bool bImageAlphaBlending =
false );
33 bool Update( int32_t, int32_t );
34 const aur::PDF::CMM* GetDeviceCMM()
const;
35 void SetVisiblePlates( uint64_t mask );
38 typedef struct RGBValues
42 aur::PDF::ProfilePtr mProofProfile;
43 aur::PDF::CMM* mDeviceCMM;
44 aur::PDF::Intent mProofIntent;
45 bool mProofProfileOpen;
46 std::vector<RGBValues> mChannelRGB;
47 double mChannelSolidity[MAX_CHANNELS];
48 std::vector<aur::ACPL::String> mExtraPlates;
49 uint64_t mVisiblePlates;
50 bool mTransparencyGrid;
58 void CopyBitsDeviceN( uint8_t*,
const aur::PDF::LRectangle&, int32_t,
bool bImageAlphaBlending );
59 void CopyBitsICC( uint8_t*,
const aur::PDF::LRectangle&, int32_t,
bool bImageAlphaBlending );
60 void CopyBitsNoMatch( uint8_t*,
const aur::PDF::LRectangle&, int32_t,
bool bImageAlphaBlending );
61 void CopyBitsSingleChannel( uint8_t*,
const aur::PDF::LRectangle&, int32_t,
bool bImageAlphaBlending );
63 void AddDocumentColorants( aur::PDF::Document* doc );
64 void DeterminePlates( PDF::Document* doc );
67inline const aur::PDF::CMM* ThumbnailRenderer::GetDeviceCMM()
const
72static void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
74 fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
85static bool SaveAsPNG(
const FileSpec& filePath,
const uint8_t* buf, int32_t width, int32_t height )
87 uint8_t * * buffer =
new uint8_t*[height];
88 int32_t lineLen = 4 * width;
89 for ( int32_t nCount = 0; nCount < height; nCount++ )
91 buffer[nCount] =
new unsigned char[lineLen];
92 memcpy( buffer[nCount], buf + (nCount * lineLen) , lineLen );
100 fp = _wfopen( filePath.GetPOSIXPath().w_str(), L
"wb" );
102 fp = fopen( filePath.GetPOSIXPath().ToUTF8(),
"wb" );
107 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
109 info_ptr = png_create_info_struct(png_ptr);
110 png_ptr->io_ptr = (png_voidp)fp;
112 png_set_compression_level(png_ptr, 6);
114 png_set_IHDR(png_ptr, info_ptr, width, height,
115 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
116 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
118 double filegamma_ = 0.5;
120 png_set_gAMA(png_ptr, info_ptr, filegamma_);
121 png_set_gAMA(png_ptr, info_ptr, 0.5 );
125 png_text text_ptr[5];
127 png_convert_from_time_t(&mod_time, gmt);
128 png_set_tIME(png_ptr, info_ptr, &mod_time);
129 text_ptr[0].key =
"Title";
130 text_ptr[0].text =
"Preview";
131 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
132 text_ptr[1].key =
"Author";
133 text_ptr[1].text =
"Aurelon";
134 text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
135 text_ptr[2].key =
"Description";
136 text_ptr[2].text =
"";
137 text_ptr[2].compression = PNG_TEXT_COMPRESSION_NONE;
138 text_ptr[3].key =
"Creation Time";
139#if defined(PNG_TIME_RFC1123_SUPPORTED)
140 text_ptr[3].text = png_convert_to_rfc1123(png_ptr, &mod_time);
142 static const char short_months[12][4] =
143 {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"};
145 text_ptr[3].text =
new char[128];
146 sprintf(text_ptr[3].text,
"%d %s %d %02d:%02d:%02d +0000",
147 mod_time.day % 32, short_months[(mod_time.month - 1) % 12],
148 mod_time.year, mod_time.hour % 24, mod_time.minute % 60,
149 mod_time.second % 61);
151 text_ptr[3].compression = PNG_TEXT_COMPRESSION_NONE;
152 text_ptr[4].key =
"Software";
153 text_ptr[4].text =
"";
154 text_ptr[4].compression = PNG_TEXT_COMPRESSION_NONE;
155 png_set_text(png_ptr, info_ptr, text_ptr, 5);
156 png_ptr->write_data_fn = png_write_data;
157 png_write_info(png_ptr, info_ptr);
159 png_write_image(png_ptr, buffer);
160 png_write_end(png_ptr, info_ptr);
161 png_destroy_write_struct(&png_ptr, &info_ptr);
164 for (
int i = 0; i < height; i++)
180static bool SaveAsJPG(
const ACPL::FileSpec& filePath,
const uint8_t* buf, int32_t width, int32_t height, int32_t quality )
188 struct jpeg_compress_struct cinfo;
197 struct jpeg_error_mgr jerr;
200 JSAMPROW row_pointer[1];
210 cinfo.err = jpeg_std_error(&jerr);
212 jpeg_create_compress(&cinfo);
223 fp = _wfopen( filePath.GetPOSIXPath().w_str(), L
"wb" );
225 fp = fopen( filePath.GetPOSIXPath().ToUTF8(),
"wb" );
230 jpeg_stdio_dest(&cinfo, fp);
237 cinfo.image_width = width;
238 cinfo.image_height = height;
239 cinfo.input_components = 3;
240 cinfo.in_color_space = JCS_RGB;
245 jpeg_set_defaults(&cinfo);
249 jpeg_set_quality(&cinfo, quality, TRUE );
256 jpeg_start_compress(&cinfo, TRUE);
266 row_stride = width * 3;
268 while (cinfo.next_scanline < cinfo.image_height) {
273 row_pointer[0] = (JSAMPROW)&buf[cinfo.next_scanline * row_stride];
274 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
279 jpeg_finish_compress(&cinfo);
286 jpeg_destroy_compress(&cinfo);
310 mDocument = document->mDocument;
325 if( !referenceProfile.Exists() )
328 if( !outputProfile.Exists() )
331 mCMM =
new PDF::CMM();
332 mCMM->Open( outputProfile, PDF::CMM::eOutput, PDF::eRelativeColorimetric );
334 PDF::ColorSpaceObject* cs = NULL;
336 if( mDocument->GetPage()->GetPageColorSpace() )
337 cs = mDocument->GetPage()->GetPageColorSpace();
338 else if( mDocument->GetDocumentColorSpace() )
339 cs = mDocument->GetDocumentColorSpace();
341 if( cs && cs->ResourceType() == PDF::ICCColorSpace::eResourceType )
342 mProfile =
new PDF::Profile(
static_cast<PDF::ICCColorSpace*
>( cs ) );
344 mProfile =
new PDF::Profile( referenceProfile );
346 ThumbnailRenderer* renderer =
new ThumbnailRenderer();
347 renderer->SetProfile( mDocument, mProfile, PDF::eRelativeColorimetric, mCMM );
348 mDocument->SetRenderer( renderer );
358 PDF::ColorSpaceObject* cs = NULL;
359 PDF::ProfilePtr profile = NULL;
361 if( mDocument->GetPage()->GetPageColorSpace() )
362 cs = mDocument->GetPage()->GetPageColorSpace();
364 if( cs && cs->ResourceType() == PDF::ICCColorSpace::eResourceType )
366 profile =
new PDF::Profile(
static_cast<PDF::ICCColorSpace*
>( cs ) );
369 if( profile != NULL )
371 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->SetProfile( mDocument, profile, PDF::eRelativeColorimetric, mCMM );
377 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->SetProfile( mDocument, mProfile, PDF::eRelativeColorimetric, mCMM );
396bool AOI_SoftProofRenderer::Render(
const FileSpec& outputPath,
const char* thumbnailType, int32_t x, int32_t y, int32_t width, int32_t height, uint32_t quality, uint64_t visiblePlates )
398 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->SetVisiblePlates( visiblePlates );
401 float srcPageWidth, srcPageHeight;
402 mDocument->GetPage()->GetDimensions( srcPageWidth, srcPageHeight );
404 if( srcPageWidth > srcPageHeight )
406 mDPU = width / srcPageWidth;
410 mDPU = height / srcPageHeight;
416 map.map[0][0] = mDPU;
417 map.map[1][1] = mDPU;
418 map.map[2][0] = float( -1 * x * width );
419 map.map[2][1] = float( -1 * y * height );
421 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->SetMapping( map );
423 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->RenderDocument( mDocument,
true,
true, NULL );
426 int32_t destLineBytes;
427 if(::strcmp( thumbnailType,
"png" ) == 0)
429 destLineBytes = width * (( (ThumbnailRenderer*)mDocument->GetRenderer() )->GetDeviceCMM()->GetSpaceComponents() + 1 );
431 else if(::strcmp( thumbnailType,
"jpg" ) == 0)
433 destLineBytes = width * ( (ThumbnailRenderer*)mDocument->GetRenderer() )->GetDeviceCMM()->GetSpaceComponents();
440 uint32_t dataLen = destLineBytes * height;
441 uint8_t* data =
new uint8_t[dataLen];
442 ::memset( data, 0, dataLen );
443 PDF::LRectangle ubounds;
446 ubounds.right = x + width;
447 ubounds.bottom = y + height;
449 if( ::strcmp( thumbnailType,
"png" ) == 0 )
451 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->CopyBits( data, ubounds, destLineBytes );
452 SaveAsPNG( outputPath, data, width, height );
454 else if( ::strcmp( thumbnailType,
"jpg" ) == 0 )
456 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->CopyBits( data, ubounds, destLineBytes,
true );
457 SaveAsJPG( outputPath, data, width, height, quality );
474 if( ( (ThumbnailRenderer*)mDocument->GetRenderer() )->Update( width, height ) )
476 mDocument->Invalidate();
489 return mDocument->GetRenderer()->mChannelNames[index];
499 return (uint32_t)mDocument->GetRenderer()->mChannelNames.size();
502typedef enum EProfileSelector
514static bool IsDeviceSpace(
const PDF::ColorSpaceObject* inSpace )
516 if( inSpace->ResourceType() == PDF::IndexColorSpace::eResourceType )
517 return IsDeviceSpace(
static_cast<const PDF::IndexColorSpace*
>( inSpace )->GetBase() );
518 return dynamic_cast<const PDF::DeviceColorSpace*
>( inSpace ) != NULL;
521static int GetIndex(
const char* name )
523 static const char *
const kChannelNames[] =
525 "Cyan",
"Magenta",
"Yellow",
"Black"
527 for(
int i = 0; i != 4; ++i )
528 if( !::stricmp( name, kChannelNames[ i ] ) )
533static bool IsSubsetOfCMYK( PDF::ColorSpaceObject* cs, uint32_t mappingArray[4] )
535 if( cs->ResourceType() != PDF::DeviceN::eResourceType || cs->NrOfComponents() > 4 )
538 PDF::DeviceN* devN = (PDF::DeviceN*)cs;
540 for( uint32_t i = 0 ; i != devN->NrOfComponents(); ++i )
542 if( ( index = GetIndex( devN->ChannelName( i ) ) ) == -1 )
544 mappingArray[ i ] = uint32_t( index );
549static PDF::Intent ConvertIntent(
bool vector, PDF::Intent intents[4], PDF::ColorSpaceObject* inSpace,
bool wasDeviceSpace )
551 PDF::Intent changedIntent = PDF::eMaxEnumIntent;
553 switch( NONINDEXED( inSpace->Space() ) )
556 changedIntent = intents[ vector ? eRGB_Vector : eRGB_Image ];
558 case PDF::CMYKSpace :
559 changedIntent = intents[ vector ? eCMYK_Vector : eCMYK_Image ];
561 case PDF::GraySpace :
562 changedIntent = intents[ vector ? eGray_Vector : eGray_Image ];
565 changedIntent = intents[ vector ? eCIELab_Vector : eCIELab_Image ];
570 return changedIntent;
573static PDF::ColorSpace ConvertColorSpace( PDF::Document* doc, PDF::ColorSpaceObject*& inSpace, PDF::ColorSpaceObject* inRGB, PDF::ColorSpaceObject* inCMYK, PDF::ColorSpaceObject* inGray )
575 PDF::ColorSpace changedSpace = PDF::NoSpace;
578 switch( inSpace->Space() )
581 inSpace = doc->GetDeviceRGBColorSpace();
582 changedSpace = PDF::RGBSpace;
584 case PDF::CMYKSpace :
585 inSpace = doc->GetDeviceCMYKColorSpace();
586 changedSpace = PDF::CMYKSpace;
588 case PDF::GraySpace :
589 inSpace = doc->GetDeviceGrayColorSpace();
590 changedSpace = PDF::GraySpace;
596 switch( inSpace->ResourceType() )
598 case PDF::DeviceRGB::eResourceType :
602 changedSpace = PDF::RGBSpace;
605 case PDF::DeviceCMYK::eResourceType :
606 case PDF::IllustratorCMYK::eResourceType :
610 changedSpace = PDF::CMYKSpace;
613 case PDF::DeviceGray::eResourceType :
617 changedSpace = PDF::GraySpace;
620 case PDF::IndexColorSpace::eResourceType :
622 PDF::IndexColorSpace* idxCS =
static_cast<PDF::IndexColorSpace*
>( inSpace );
623 PDF::ColorSpaceObject* baseCS = idxCS->GetBase();
624 if( baseCS->ResourceType() != PDF::DeviceN::eResourceType )
626 changedSpace = ConvertColorSpace( doc, baseCS, inRGB, inCMYK, inGray );
627 if( baseCS != idxCS->GetBase() )
628 idxCS->SetBase( baseCS );
632 case PDF::DeviceN::eResourceType :
635 uint32_t cmykLink[4];
636 if( IsSubsetOfCMYK( inSpace, cmykLink ) )
639 changedSpace = PDF::CMYKSpace;
647static bool ConvertRasterToDeviceCMYK( PDF::RasterPtr ras, PDF::DocumentPtr doc, PDF::RasterPtr& newRaster )
649 uint32_t cmykLink[4];
650 if( !IsSubsetOfCMYK( ras->GetColorSpace(), cmykLink ) )
652 uint32_t comps = ras->GetColorSpace()->NrOfComponents();
654 PDF::BitmapPtr bitmapPtr = ras->GetBitmap();
655 PDF::BitmapT bitmap = *bitmapPtr->GetBitmap();
656 bitmap.space = doc->GetDeviceCMYKColorSpace();
658 bitmap.rowBytes = bitmap.width * 4;
660 PDF::Import
import( doc );
661 import.OpenRaster( bitmap );
663 uint8_t* buffer =
new uint8_t[ bitmap.rowBytes ];
664 ::memset( buffer, 0, bitmap.rowBytes );
666 bitmapPtr->Open( NULL );
668 for( int32_t y = 0; y != bitmap.height; ++y )
670 uint8_t* out = buffer;
671 for( int32_t x = 0; x != bitmap.width; ++x )
673 data = bitmapPtr->GetPixelPtr( x, y );
674 for( uint32_t i = 0; i != comps; ++i )
675 out[ cmykLink[i] ] = data[i];
678 import.SaveLine( buffer );
684 newRaster =
import.CloseRaster(
true );
686 newRaster->Map( ras->mapping() );
688 newRaster->SetBlendMode( ras->GetBlendMode() );
689 newRaster->SetBlendValue( ras->GetBlendValue() );
690 newRaster->SetIntent( ras->GetIntent() );
691 newRaster->SetVisible( ras->Visible() );
692 newRaster->SetLock( ras->Locked() );
697static void AssignDefaultProfiles( PDF::ObjectPtr obj, PDF::ICCColorSpace* cs[3], PDF::Intent intents[4], PDF::DocumentPtr doc )
699 PDF::ColorSpaceObject* ioCS;
700 PDF::ColorSpace changedSpace;
701 PDF::Intent changedIntent;
703 uint32_t i, cmykLink[4];
707 while( doc->TraverseNext( obj ) )
709 PDF::VectorPtr vec =
dynamic_cast<PDF::VectorPtr
>( obj );
712 if( vec->GetStrokeStyle() )
714 if( vec->GetStrokeStyle()->ResourceType() == PDF::Solid::eResourceType )
716 PDF::SolidPtr col =
static_cast<PDF::SolidPtr
>( vec->GetStrokeStyle() );
717 ioCS = col->GetSpace();
718 isDeviceSpace = IsDeviceSpace( ioCS );
719 if( ( changedSpace = ConvertColorSpace( doc, ioCS, cs[eRGB_Vector], cs[eCMYK_Vector], cs[eGray_Vector] ) ) != PDF::NoSpace )
722 if( changedSpace == PDF::CMYKSpace )
724 if( IsSubsetOfCMYK( c.space, cmykLink ) )
727 ::memset( c.channel, 0, 4*
sizeof(uint16_t) );
728 for( i = 0 ; i != c.space->NrOfComponents(); ++i )
729 c.channel[ cmykLink[i] ] = org.channel[i];
730 if( vec->GetBlendMode() == PDF::eBMOverprint1 && vec->GetBlendValue() == 1 )
731 vec->SetBlendMode( PDF::eBMMultiply );
733 else if( c.space->ResourceType() == PDF::IllustratorCMYK::eResourceType &&
734 vec->GetBlendMode() == PDF::eBMOverprint1 && vec->GetBlendValue() == 1 )
736 for( i = 0 ; i != 4; ++i )
737 if( c.channel[i] == 0 )
739 vec->SetBlendMode( PDF::eBMMultiply );
745 col =
new PDF::Solid( doc, c );
746 vec->SetStrokeStyle( col );
748 col =
static_cast<PDF::SolidPtr
>( vec->GetStrokeStyle() );
750 if( ( changedIntent = ConvertIntent(
true, intents, ioCS, isDeviceSpace && changedSpace != PDF::NoSpace ) ) != PDF::eMaxEnumIntent )
751 vec->SetIntent( changedIntent );
755 PDF::ShadingSpacePtr shad =
dynamic_cast<PDF::ShadingSpacePtr
>( vec->GetStrokeStyle() );
758 ioCS = shad->GetColorSpace();
759 isDeviceSpace = IsDeviceSpace( ioCS );
760 if( ( changedSpace = ConvertColorSpace( doc, ioCS, cs[eRGB_Vector], cs[eCMYK_Vector], cs[eGray_Vector] ) ) != PDF::NoSpace )
762 if( changedSpace == PDF::CMYKSpace && IsSubsetOfCMYK( shad->GetColorSpace(), cmykLink ) )
764 shad->ConvertToDeviceCMYK( cmykLink );
765 if( vec->GetBlendMode() == PDF::eBMOverprint1 && vec->GetBlendValue() == 1 )
766 vec->SetBlendMode( PDF::eBMMultiply );
768 shad->SetColorSpace( ioCS );
770 if( ( changedIntent = ConvertIntent(
true, intents, ioCS, isDeviceSpace && changedSpace != PDF::NoSpace ) ) != PDF::eMaxEnumIntent )
771 vec->SetIntent( changedIntent );
775 if( vec->GetFillStyle() )
777 if( vec->GetFillStyle()->ResourceType() == PDF::Solid::eResourceType )
779 PDF::SolidPtr col =
static_cast<PDF::SolidPtr
>( vec->GetFillStyle() );
780 ioCS = col->GetSpace();
781 isDeviceSpace = IsDeviceSpace( ioCS );
782 if( ( changedSpace = ConvertColorSpace( doc, ioCS, cs[eRGB_Vector], cs[eCMYK_Vector], cs[eGray_Vector] ) ) != PDF::NoSpace )
785 if( changedSpace == PDF::CMYKSpace )
787 if( IsSubsetOfCMYK( c.space, cmykLink ) )
790 ::memset( c.channel, 0, 4*
sizeof(uint16_t) );
791 for( i = 0 ; i != c.space->NrOfComponents(); ++i )
792 c.channel[ cmykLink[i] ] = org.channel[i];
793 if( vec->GetBlendMode() == PDF::eBMOverprint1 && vec->GetBlendValue() == 1 )
794 vec->SetBlendMode( PDF::eBMMultiply );
796 else if( c.space->ResourceType() == PDF::IllustratorCMYK::eResourceType &&
797 vec->GetBlendMode() == PDF::eBMOverprint1 && vec->GetBlendValue() == 1 )
799 for( i = 0 ; i != 4; ++i )
800 if( c.channel[i] == 0 )
802 vec->SetBlendMode( PDF::eBMMultiply );
808 col =
new PDF::Solid( doc, c );
809 vec->SetFillStyle( col );
811 col =
static_cast<PDF::SolidPtr
>( vec->GetFillStyle() );
813 if( ( changedIntent = ConvertIntent(
true, intents, ioCS, isDeviceSpace && changedSpace != PDF::NoSpace ) ) != PDF::eMaxEnumIntent )
814 vec->SetIntent( changedIntent );
818 PDF::ShadingSpacePtr shad =
dynamic_cast<PDF::ShadingSpacePtr
>( vec->GetFillStyle() );
821 ioCS = shad->GetColorSpace();
822 isDeviceSpace = IsDeviceSpace( ioCS );
823 if( ( changedSpace = ConvertColorSpace( doc, ioCS, cs[eRGB_Vector], cs[eCMYK_Vector], cs[eGray_Vector] ) ) != PDF::NoSpace )
825 if( changedSpace == PDF::CMYKSpace && IsSubsetOfCMYK( shad->GetColorSpace(), cmykLink ) )
827 shad->ConvertToDeviceCMYK( cmykLink );
828 if( vec->GetBlendMode() == PDF::eBMOverprint1 && vec->GetBlendValue() == 1 )
829 vec->SetBlendMode( PDF::eBMMultiply );
831 shad->SetColorSpace( ioCS );
833 if( ( changedIntent = ConvertIntent(
true, intents, ioCS, isDeviceSpace && changedSpace != PDF::NoSpace ) ) != PDF::eMaxEnumIntent )
834 vec->SetIntent( changedIntent );
838 if(
auto pattern =
dynamic_cast<PDF::PatternSpacePtr
>( vec->GetFillStyle() ) )
839 if( pattern->GetTile() && pattern->GetTile()->GetObject() )
840 AssignDefaultProfiles( pattern->GetTile()->GetObject(), cs, intents, doc );
845 else if( obj->GetType() == PDF::gRasterType )
847 PDF::RasterPtr raster = NULL;
849 raster = PDF::RasterPtr(obj);
851 ioCS = raster->GetColorSpace();
852 isDeviceSpace = IsDeviceSpace( ioCS );
853 if( ( changedSpace = ConvertColorSpace( doc, ioCS, cs[eRGB_Image], cs[eCMYK_Image], cs[eGray_Image] ) ) != PDF::NoSpace )
855 if( changedSpace == PDF::CMYKSpace && ConvertRasterToDeviceCMYK( raster, doc, raster ) )
857 if( obj->GetBlendMode() == PDF::eBMOverprint1 && obj->GetBlendValue() == 1 )
858 raster->SetBlendMode( PDF::eBMMultiply );
859 obj->Replace( raster );
863 raster->SetColorSpace( ioCS );
864 ioCS = raster->GetColorSpace();
866 if( ( changedIntent = ConvertIntent(
false, intents, ioCS, isDeviceSpace && changedSpace != PDF::NoSpace ) ) != PDF::eMaxEnumIntent )
867 raster->SetIntent( changedIntent );
871 PDF::SymbolPtr sym =
dynamic_cast<PDF::SymbolPtr
>( obj );
872 if( sym && sym->GetObject() )
873 AssignDefaultProfiles( sym->GetObject(), cs, intents, doc );
890 PDF::ICCColorSpace* cs[3];
891 ACPL::FileSpec sp[3];
895 for( int16_t i = 0; i < 3; i++ )
902 PDF::ICCColorSpace* newCS =
new PDF::ICCColorSpace( mDocument, sp[i] );
903 cs[i] = (PDF::ICCColorSpace*)mDocument->FindEqualResource( newCS );
913 PDF::Intent intents[4];
917 intents[0] = PDF::eRelativeColorimetric;
920 intents[0] = PDF::ePerceptual;
923 intents[0] = PDF::eAbsoluteColorimetric;
926 intents[0] = PDF::eRelativeColorimetric;
930 intents[3] = intents[1] = intents[2] = intents[0];
931 AssignDefaultProfiles( NULL, cs, intents, mDocument );
932 for( int16_t i = 0; i < 3; i++ )
950 TileGenerator tg( tileSettings );
952 float srcPageWidth, srcPageHeight;
953 mDocument->GetPage()->GetDimensions( srcPageWidth, srcPageHeight );
954 tg.InitPage( srcPageWidth, srcPageHeight );
956 if( srcPageWidth > srcPageHeight )
958 mDPU = tg.GetPageWidth() * 2 / srcPageWidth;
962 mDPU = tg.GetPageHeight() * 2 / srcPageHeight;
964 ACPL::FileStream* multiStream = NULL;
966 if( !multichannelRender.IsEmpty() )
968 ACPL::FileSpec multiSpec;
969 multiSpec.Make( multichannelRender );
970 if( !multiSpec.Exists() )
972 multiStream =
new ACPL::FileStream( multiSpec );
976 int32_t multiPixelBytes, multiLineBytes;
979 if( channelIndex == -1 )
981 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->SetVisiblePlates( tileSettings.mVisiblePlates );
983 else if( multiStream )
986 *multiStream >> multiPixelBytes;
987 *multiStream >> multiLineBytes;
988 *multiStream >> hasAlpha;
992 struct jpeg_compress_struct cinfo;
993 struct jpeg_error_mgr jerr;
996 JSAMPROW row_pointer[1];
998 cinfo.err = jpeg_std_error(&jerr);
999 jpeg_create_compress(&cinfo);
1001 ACPL::UString filePath;
1003 if( !outputPath.DirectoryExists() )
1004 outputPath.CreateDirectory();
1006 f2.Make( outputPath, L
"Converted.jpg" );
1007 filePath = f2.GetPOSIXPath();
1010 fp = _wfopen( filePath.w_str(), L
"wb" );
1012 fp = fopen( filePath.ToUTF8(),
"wb" );
1016 jpeg_stdio_dest(&cinfo, fp);
1019 ACPL::FileSpec inputSpec, outputSpec;
1021 int32_t currentZoomLevel = tg.GetNrZoomLevels() - 1;
1022 int32_t remainingNrOfTiles = tg.GetTotalNrOfTiles();
1023 uint32_t positionInZoomLevel;
1024 while( currentZoomLevel >= 0 )
1026 tg.SetZoomLevel( currentZoomLevel );
1028 positionInZoomLevel = 1;
1030 uint32_t tilesVertical = 0;
1032 outputSpec.CreateTemporary();
1034 ACPL::FileStream outputStream( outputSpec );
1035 ACPL::FileStream* inputFileStream = NULL;
1037 if( currentZoomLevel != tg.GetNrZoomLevels() - 1 )
1039 inputFileStream =
new ACPL::FileStream( inputSpec );
1044 cinfo.image_width = tg.GetScaledWidth();
1045 cinfo.image_height = tg.GetScaledHeight();
1046 cinfo.input_components = 3;
1047 cinfo.in_color_space = JCS_RGB;
1048 jpeg_set_defaults(&cinfo);
1049 jpeg_set_quality(&cinfo, tileSettings.mJpgQuality, TRUE );
1050 jpeg_start_compress(&cinfo, TRUE);
1051 row_stride = tg.GetScaledWidth() * 3;
1054 for( uint32_t band = 0; band != tg.GetNrBands(); ++band )
1056 uint32_t bandSize = tg.GetBandHeight() * tg.GetScaledWidth() * 3;
1057 uint8_t* bandData =
new uint8_t[ bandSize ];
1059 if( currentZoomLevel == tg.GetNrZoomLevels() - 1 )
1061 uint8_t* doubleBandData = NULL;
1062 if( channelIndex == -1 )
1064 doubleBandData =
new uint8_t[ 4 * tg.GetBandHeight() * tg.GetScaledWidth() * 4 ];
1066 RenderBand( doubleBandData, band * tg.GetBandHeight() * 2, 2 * tg.GetScaledHeight(), tg.GetScaledWidth() * 2, tg.GetBandHeight() * 2 );
1068 SaveMultichannelRender( *multiStream, tg.GetScaledWidth() * 2, 2 * tg.GetBandHeight() );
1069 DownsampleRGBBy2( doubleBandData, bandData, 4 * 2 * tg.GetScaledWidth(), 2 * tg.GetBandHeight(), 2 * tg.GetScaledWidth(), 3 * tg.GetScaledWidth(), 4 );
1073 doubleBandData =
new uint8_t[ 4 * tg.GetBandHeight() * tg.GetScaledWidth() * 3 ];
1075 LoadMultiChannelRender(doubleBandData, channelIndex, *multiStream, tg.GetScaledWidth() * 2, 2 * tg.GetBandHeight(), multiPixelBytes, multiLineBytes, hasAlpha );
1076 DownsampleRGBBy2( doubleBandData, bandData, 3 * 2 * tg.GetScaledWidth(), 2 * tg.GetBandHeight(), 2 * tg.GetScaledWidth(), 3 * tg.GetScaledWidth(), 3 );
1080 uint32_t previewY = 0;
1081 while( previewY < tg.GetBandHeight() && jpegY < tg.GetScaledHeight() )
1083 row_pointer[0] = (JSAMPROW)&bandData[previewY * row_stride];
1084 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
1088 delete[] doubleBandData;
1092 LoadBand( bandData, *inputFileStream, bandSize );
1095 for( uint32_t j = 0; j < tg.GetTilesVerticalInBand() && tilesVertical != tg.GetTilesVertical(); j++ )
1097 for( uint32_t i = 0; i < tg.GetTilesHorizontal(); i++ )
1099 tg.WriteTile( i, tilesVertical, remainingNrOfTiles, j, bandData, 3 * tg.GetScaledWidth(), outputPath, positionInZoomLevel );
1100 positionInZoomLevel++;
1104 if( currentZoomLevel > 0 )
1106 uint32_t newBandSize = ( tg.GetBandHeight() / 2 ) * ( tg.GetScaledWidth() / 2 ) * 3;
1107 uint8_t* newBand =
new uint8_t[ newBandSize ];
1109 DownsampleRGBBy2( bandData, newBand, 3 * tg.GetScaledWidth(), tg.GetBandHeight(), tg.GetScaledWidth(), 3 * ( tg.GetScaledWidth() / 2 ), 3 );
1110 SaveBand( newBand, outputStream, newBandSize );
1116 delete inputFileStream;
1119 inputSpec = outputSpec;
1120 if( currentZoomLevel == tg.GetNrZoomLevels() - 1 )
1122 jpeg_finish_compress(&cinfo);
1124 jpeg_destroy_compress(&cinfo);
1129 remainingNrOfTiles -= tg.GetTilesHorizontal() * tg.GetTilesVertical();
1132 if( outputSpec.Exists() )
1133 outputSpec.Delete();
1135 tg.CreateTilesXML( outputPath );
1142void AOI_SoftProofRenderer::DownsampleRGBBy2( uint8_t* inBandData, uint8_t* outBandData, uint32_t inRowbytes, uint32_t inHeight, uint32_t inWidth, uint32_t outRowBytes, uint32_t inComponents )
1144 uint8_t* dest8 = outBandData;
1146 bool evenLine =
false;
1148 uint32_t height = inHeight / 2;
1149 uint32_t width = inWidth / 2;
1153 uint16_t* extLine =
new uint16_t[ width * inComponents ];
1156 while( y != height )
1161 memset( extLine, 0, 2 * width * inComponents );
1168 *dest16++ += *line++;
1169 *dest16++ += *line++;
1170 *dest16++ += *line++;
1171 line += inComponents - 3;
1179 inBandData += inRowbytes;
1187 *dest8++ = (uint8_t)( *dest16++ >> 2 );
1188 *dest8++ = (uint8_t)( *dest16++ >> 2 );
1189 *dest8++ = (uint8_t)( *dest16++ >> 2 );
1193 evenLine = !evenLine;
1203 mProfile->Dispose();
1205 PDF::Renderer* renderer = mDocument->GetRenderer();
1209void AOI_SoftProofRenderer::RenderBand( uint8_t* doubleBandData, uint32_t y, uint32_t height, uint32_t renderingWidth, uint32_t renderingHeight )
1215 map.map[0][0] = mDPU;
1216 map.map[1][1] = mDPU;
1217 map.map[2][1] = - float( y );
1219 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->SetMapping( map );
1220 mDocument->Invalidate();
1221 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->RenderDocument( mDocument,
true,
true, NULL );
1223 PDF::LRectangle ubounds;
1226 ubounds.right = renderingWidth;
1227 ubounds.bottom = renderingHeight;
1229 ( (ThumbnailRenderer*)mDocument->GetRenderer() )->CopyBits( doubleBandData, ubounds, renderingWidth * 4 );
1232void AOI_SoftProofRenderer::SaveMultichannelRender( aur::ACPL::FileStream& stream, uint32_t renderingWidth, uint32_t renderingHeight )
1234 if( stream.GetMarker() == 0 )
1237 stream << mDocument->GetRenderer()->mDestPixelBytes;
1238 stream << mDocument->GetRenderer()->mDestLineBytes;
1239 stream << mDocument->GetRenderer()->mHasAlpha;
1241 int32_t size = mDocument->GetRenderer()->mDestLineBytes * renderingHeight;
1242 stream.PutBytes( mDocument->GetRenderer()->mDestImage, size );
1245void AOI_SoftProofRenderer::LoadMultiChannelRender( uint8_t* doubleBandData, int16_t channelIndex, aur::ACPL::FileStream& stream, uint32_t renderingWidth, uint32_t renderingHeight, uint32_t pixelBytes, uint32_t lineBytes,
bool hasAlpha )
1248 uint8_t* linePointer =
new uint8_t[ lineBytes ];
1251 register uint8_t backDrop8;
1253 for( uint32_t y = 0; y != renderingHeight; ++y )
1256 stream.GetBytes( linePointer, size );
1258 for (uint32_t x = 0; x != renderingWidth; ++x)
1260 if( ( alpha = hasAlpha ? p[pixelBytes - 1] : 255 ) == 255 )
1261 backDrop8 = 255 - p[channelIndex];
1262 else if( alpha == 0 )
1268 register uint16_t backDrop;
1269 backDrop = ( 255 - alpha ) << 8;
1270 backDrop8 = uint8_t( ( backDrop + ( 255 - p[channelIndex] ) * alpha ) >> 8 );
1272 doubleBandData[0] = doubleBandData[1] = doubleBandData[2] = backDrop8;
1273 doubleBandData += 3;
1277 delete[] linePointer;
1280void AOI_SoftProofRenderer::SaveBand(
const uint8_t* bandData, ACPL::FileStream& fileStream, int32_t byteCount )
1282 fileStream.PutBytes( bandData, byteCount );
1285void AOI_SoftProofRenderer::LoadBand( uint8_t* bandData, ACPL::FileStream& fileStream, int32_t byteCount )
1287 fileStream.GetBytes( bandData, byteCount );
1290AOI_SoftProofRenderer::TileGenerator::TileGenerator(
const TileSettings& settings ) :
1291mSettings( settings )
1295void AOI_SoftProofRenderer::TileGenerator::InitPage(
float pageWidth,
float pageHeight )
1297 mPageWidth = (uint32_t)( pageWidth / 18 * mSettings.mMaxDpi );
1298 mPageHeight = (uint32_t)( pageHeight / 18 * mSettings.mMaxDpi );
1300 uint32_t maxSize = mPageHeight;
1302 if (mPageWidth > mPageHeight)
1303 maxSize = mPageWidth;
1305 mNrOfzoomLevels = 1;
1306 while (maxSize > mSettings.mTileSize)
1312 int32_t currentZoomlevel = mNrOfzoomLevels - 1;
1313 mTotalNrOfTiles = 1;
1314 uint32_t tilesperColumn, tilesPerRows;
1315 while( currentZoomlevel )
1317 tilesPerRows = ( ( mPageWidth >> ( mNrOfzoomLevels - currentZoomlevel - 1 ) ) + mSettings.mTileSize - 1 ) / mSettings.mTileSize;
1318 tilesperColumn = ( ( mPageHeight >> ( mNrOfzoomLevels - currentZoomlevel - 1 ) ) + mSettings.mTileSize - 1 ) / mSettings.mTileSize;
1319 mTotalNrOfTiles += tilesPerRows * tilesperColumn;
1324void AOI_SoftProofRenderer::TileGenerator::SetZoomLevel( uint32_t level )
1326 mCurrentZoomLevel = level;
1327 mScaledHeight = mPageHeight >> ( mNrOfzoomLevels - level - 1 );
1328 mScaledWidth = mPageWidth >> ( mNrOfzoomLevels - level - 1 );
1329 mTilesHorizontal = ( mScaledWidth + mSettings.mTileSize - 1 ) / mSettings.mTileSize;
1330 mTilesVertical = ( mScaledHeight + mSettings.mTileSize - 1 ) / mSettings.mTileSize;
1331 uint32_t maxMem = mSettings.mMaxMemoryUsage * 1024 * 1024;
1332 uint32_t maxLines = maxMem / ( 3 * mScaledWidth );
1333 if( maxLines >= mScaledHeight )
1336 mBandHeight = mScaledHeight;
1340 mBandHeight = maxLines / mSettings.mTileSize;
1341 mBandHeight = mBandHeight * mSettings.mTileSize;
1342 if( mBandHeight < mSettings.mTileSize )
1343 mBandHeight = mSettings.mTileSize;
1344 mNrBands = ( mScaledHeight + mBandHeight - 1 ) / mBandHeight;
1348bool AOI_SoftProofRenderer::TileGenerator::WriteTile( uint32_t x, uint32_t y, uint32_t remainingNrOfTiles, uint32_t yInBand, uint8_t* bandData, uint32_t rowbytes,
const FileSpec& outputPath, uint32_t positionInZoomLevel )
1351 uint32_t tileX = mSettings.mTileSize * x;
1352 uint32_t tileY = mSettings.mTileSize * yInBand;
1354 if( tileX > mScaledWidth|| tileY > mScaledHeight )
1358 uint32_t tileWidth = mSettings.mTileSize;
1359 if ( tileWidth > mScaledWidth )
1361 tileWidth = mScaledWidth;
1363 else if( ( x + 1 ) * mSettings.mTileSize > mScaledWidth )
1365 tileWidth = mScaledWidth - tileX;
1372 uint32_t tileHeight = mSettings.mTileSize;
1373 if( tileHeight > mScaledHeight )
1375 tileHeight = mScaledHeight;
1377 else if( ( y + 1 ) * mSettings.mTileSize > mScaledHeight )
1379 tileHeight = mScaledHeight - mSettings.mTileSize * y;
1382 if( tileHeight <= 0 )
1385 uint32_t folderIndex = ( remainingNrOfTiles - ( mTilesVertical * mTilesHorizontal - positionInZoomLevel ) - 1 ) / mSettings.mTileSize;
1389 ACPL::UString folderName;
1390 folderName.Format( L
"TileGroup%d", folderIndex );
1391 ACPL::FileSpec outputFolder;
1392 outputFolder.Make( outputPath, folderName );
1393 if( !outputFolder.DirectoryExists() )
1394 outputFolder.CreateDirectory();
1396 ACPL::UString tileName;
1397 tileName.Format( L
"%d-%d-%d.jpg", mCurrentZoomLevel, x, y );
1398 tileSpec.Make( outputFolder, tileName );
1400 struct jpeg_compress_struct cinfo;
1401 struct jpeg_error_mgr jerr;
1403 JSAMPROW row_pointer[1];
1405 cinfo.err = jpeg_std_error(&jerr);
1406 jpeg_create_compress(&cinfo);
1409 fp = _wfopen( tileSpec.GetPOSIXPath().w_str(), L
"wb" );
1411 fp = fopen( tileSpec.GetPOSIXPath().ToUTF8(),
"wb" );
1416 jpeg_stdio_dest(&cinfo, fp);
1423 cinfo.image_width = tileWidth;
1424 cinfo.image_height = tileHeight;
1425 cinfo.input_components = 3;
1426 cinfo.in_color_space = JCS_RGB;
1427 jpeg_set_defaults(&cinfo);
1428 jpeg_set_quality(&cinfo, mSettings.mJpgQuality, TRUE );
1429 jpeg_start_compress(&cinfo, TRUE);
1431 row_stride = tileWidth * 3;
1433 uint8_t* buffer = bandData + tileY * rowbytes + tileX * 3;
1435 while (cinfo.next_scanline < cinfo.image_height) {
1440 row_pointer[0] = (JSAMPROW)buffer;
1441 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
1444 jpeg_finish_compress(&cinfo);
1446 jpeg_destroy_compress(&cinfo);
1451void AOI_SoftProofRenderer::TileGenerator::CreateTilesXML(
const FileSpec& outputPath )
1453 ACPL::FileSpec imageProperties;
1454 imageProperties.Make( outputPath, L
"ImageProperties.xml" );
1456 ACPL::XML imagePropertiesXML(
"IMAGE_PROPERTIES" );
1457 ACPL::XML::Node* xmlRoot = imagePropertiesXML.root;
1458 xmlRoot->AddAttribute(
"WIDTH", mPageWidth );
1459 xmlRoot->AddAttribute(
"HEIGHT", mPageHeight );
1460 xmlRoot->AddAttribute(
"NUMTILES", mTotalNrOfTiles );
1461 xmlRoot->AddAttribute(
"NUMIMAGES", 1 );
1462 xmlRoot->AddAttribute(
"VERSION", 1.8 );
1463 xmlRoot->AddAttribute(
"TILESIZE", mSettings.mTileSize );
1464 xmlRoot->AddAttribute(
"THUMBNAIL_WIDTH", 128 );
1465 xmlRoot->AddAttribute(
"THUMBNAIL_HEIGHT", 128 );
1466 xmlRoot->AddAttribute(
"RESOLUTION", mSettings.mMaxDpi );
1467 imagePropertiesXML.Save( imageProperties );
1470uint32_t AOI_SoftProofRenderer::TileGenerator::GetPageWidth()
const
1475uint32_t AOI_SoftProofRenderer::TileGenerator::GetPageHeight()
const
1480uint32_t AOI_SoftProofRenderer::TileGenerator::GetNrBands()
const
1485uint32_t AOI_SoftProofRenderer::TileGenerator::GetBandHeight()
const
1490uint32_t AOI_SoftProofRenderer::TileGenerator::GetScaledHeight()
const
1492 return mScaledHeight;
1495uint32_t AOI_SoftProofRenderer::TileGenerator::GetScaledWidth()
const
1497 return mScaledWidth;
1500uint32_t AOI_SoftProofRenderer::TileGenerator::GetTilesHorizontal()
const
1502 return mTilesHorizontal;
1505uint32_t AOI_SoftProofRenderer::TileGenerator::GetTilesVertical()
const
1507 return mTilesVertical;
1510uint32_t AOI_SoftProofRenderer::TileGenerator::GetTilesVerticalInBand()
const
1512 return ( mBandHeight + mSettings.mTileSize - 1 ) / mSettings.mTileSize;
1515uint32_t AOI_SoftProofRenderer::TileGenerator::GetNrZoomLevels()
const
1517 return mNrOfzoomLevels;
1520uint32_t AOI_SoftProofRenderer::TileGenerator::GetCurrentZoomLevel()
const
1522 return mCurrentZoomLevel;
1525uint32_t AOI_SoftProofRenderer::TileGenerator::GetTotalNrOfTiles()
const
1527 return mTotalNrOfTiles;
1546AOI_SoftProofRenderer::TileSettings::TileSettings( uint32_t tileSize, uint32_t minZoomSize, uint32_t maxMemoryUsage,
float maxDpi, int16_t jpgQuality, uint64_t visiblePlates )
1548 mTileSize = tileSize;
1549 mMinZoomSize = minZoomSize;
1550 mMaxMemoryUsage = maxMemoryUsage;
1552 mJpgQuality = jpgQuality;
1553 mVisiblePlates = visiblePlates;
1562void AOI_SoftProofRenderer::TileSettings::SetVisiblePlates( uint64_t visiblePlates )
1564 mVisiblePlates = visiblePlates;
1568ThumbnailRenderer::ThumbnailRenderer() :
1570 mProofProfile( NULL ),
1572 mProofIntent( PDF::eRelativeColorimetric ),
1573 mProofProfileOpen( false ),
1574 mWhichCopy( eNoMatch )
1576 SetAntiAliasGlyph(
true );
1579 for( uint32_t i = 0; i != MAX_CHANNELS; ++i )
1580 mChannelSolidity[i] = 0;
1583ThumbnailRenderer::~ThumbnailRenderer()
1587 if( mProofProfileOpen )
1588 mProofProfile->Close( PDF::CMM::eInput, mProofIntent );
1589 mProofProfile->Dispose();
1591 mDeviceCMM->Dispose();
1594void ThumbnailRenderer::SetProfile( PDF::Document* doc, PDF::ProfilePtr refProf, PDF::Intent intent, PDF::CMM* deviceCMM )
1599 if( mProofProfileOpen )
1600 mProofProfile->Close( PDF::CMM::eInput, mProofIntent );
1601 mProofProfile->Dispose();
1603 mProofProfile = refProf;
1604 mProofIntent = intent;
1606 mDeviceCMM->Dispose();
1607 mDeviceCMM = deviceCMM;
1608 mProofProfileOpen =
false;
1609 mVisiblePlates = UINT64_MAX;
1614 for( uint32_t i = 0; i != MAX_CHANNELS; ++i )
1615 mChannelSolidity[i] = 0;
1616 mChannelRGB.clear();
1617 mExtraPlates.clear();
1623 DeterminePlates( doc );
1624 AddDocumentColorants( doc );
1627 Setup( mProofProfile->GetFileSpec(), mExtraPlates, mDeviceWidth, mDeviceHeight,
true,
false,
true );
1629 switch( mProofProfile->GetSpace() )
1631 case PDF::RGBSpace :
1632 if( mComponents > 3 )
1633 mWhichCopy = eDeviceN;
1635 mWhichCopy = ::memcmp( &mProofProfile->GetHeader(), &mDeviceCMM->GetHeader(), 16 *
sizeof(uint32_t) ) == 0 &&
1636 ::memcmp( &mProofProfile->GetHeader().illuminant, &mDeviceCMM->GetHeader().illuminant, 6 + 4 ) == 0 ? eNoMatch : eICC;
1638 case PDF::CMYKSpace :
1639 if( mComponents > 4 )
1640 mWhichCopy = eDeviceN;
1645 mWhichCopy = eDeviceN;
1649 if( mWhichCopy == eICC || mWhichCopy == eDeviceN )
1651 mProofProfile->Open( PDF::CMM::eInput, mProofIntent );
1656 mProofProfileOpen =
true;
1660bool ThumbnailRenderer::Update( int32_t inWidth, int32_t inHeight )
1662 if( mDeviceWidth != inWidth || mDeviceHeight != inHeight )
1664 Setup( mProofProfile->GetFileSpec(), mExtraPlates, inWidth, inHeight,
true,
false,
true );
1670static void DetermineCIELab(
const double* in, PDF::ColorSpaceObject* inSpace, PDF::CMM* destCMM,
double outLab[3] )
1673 if( inSpace->Space() == PDF::LABSpace )
1682 uint32_t inComps = inSpace->NrOfComponents();
1683 uint32_t outComps = destCMM->GetSpaceComponents();
1684 if( inComps <= outComps &&
dynamic_cast<PDF::DeviceColorSpace*
>( inSpace ) != NULL )
1687 uint32_t linkCnt = 0;
1688 double val[MAX_CHANNELS];
1689 ::memset( val, 0, MAX_CHANNELS*
sizeof(
double) );
1690 for( uint32_t i = 0; i != inComps && linkCnt == i; ++i )
1692 const char* inChannelName = inSpace->ChannelName( i );
1693 for( uint32_t j = 0; j != outComps; ++j )
1695 const char* outChannelName = destCMM->GetChannelName( j );
1696 if( ::stricmp( inChannelName, outChannelName ) == 0 )
1705 if( linkCnt == inComps )
1707 destCMM->Color2Lab( val, outLab );
1712 uint16_t in16[MAX_CHANNELS];
1713 for( uint32_t i = 0; i != inComps; ++i )
1714 in16[i] = uint16_t( in[i] * PDF::Component1 );
1715 inSpace->GetCIELab( in16, outLab );
1718void ThumbnailRenderer::DeterminePlates( PDF::Document* doc )
1724 int32_t profileChannelCount = ColorSpaceComponents( mProofProfile->GetSpace() );
1725 std::vector<PDF::Document::Colorant> extraPlates;
1726 std::vector<PDF::Function*> colorantFunc;
1727 std::vector<PDF::ColorSpaceObject*> colorantSpace;
1728 std::vector<PDF::DeviceN*> devNs;
1729 PDF::Document::Colorant colorant;
1731 PDF::DeviceN* devn = NULL;
1732 int32_t devNCnt = 0;
1733 while( ( devn = (PDF::DeviceN*)doc->TraverseCommitedResources( PDF::DeviceN::eResourceType, devn ) ) != NULL )
1736 for( j = 0; j != devn->NrOfComponents(); ++j )
1738 const char* n = devn->ChannelName( j );
1739 bool found = ::strcmp( n,
"None" ) == 0 || ::strcmp( n,
"All" ) == 0;
1741 if( mProofProfile->GetSpace() == PDF::GraySpace || mProofProfile->GetSpace() == PDF::RGBSpace )
1744 for( int32_t ch = 0; !found && ch != profileChannelCount; ++ch )
1746 String profChannelName = mProofProfile->GetChannel( ch );
1747 found = profChannelName == n;
1751 found = doc->colorantIndex( n ) >= 0;
1754 for( i = 0; i != extraPlates.size() && ::stricmp( n, extraPlates[i].name ); ++i )
1756 if( i < uint32_t( doc->GetInstance()->GetMaxChannels()-profileChannelCount-doc->colorantCount() ) )
1758 if( i == extraPlates.size() )
1761 bool inRepo =
false;
1762 if( devn->NrOfComponents() == 1 && devn->OwnerCount() == 1 )
1763 for( int32_t r = 0 ; r != doc->GetRepositoryStyleCount(); ++r )
1765 PDF::Style* s = doc->GetRepositoryStyle( r );
1766 if( s->ResourceType() == PDF::Solid::eResourceType )
1768 if( devn->GetResourceID() == PDF::SolidPtr(s)->GetSpace()->GetResourceID() )
1773 if( inRepo ==
false )
1775 colorant = PDF::Document::Colorant();
1777 extraPlates.push_back( colorant );
1778 colorantSpace.push_back( devn->ChannelSpace( j ) );
1779 colorantFunc.push_back( devn->ChannelFunction( j ) );
1780 devNs.push_back( devn );
1783 else if( colorantSpace[i] == NULL )
1785 colorantSpace[i] = devn->ChannelSpace( j );
1786 colorantFunc[i] = devn->ChannelFunction( j );
1793 if( extraPlates.empty() )
1796 mProofProfile->Open( PDF::CMM::eInput, PDF::eAbsoluteColorimetric );
1797 PDF::CMM* proofCMM = mProofProfile->GetCMM( PDF::CMM::eInput, PDF::eAbsoluteColorimetric );
1799 PDF::LookupSpotColor fe;
1800 for(
size_t col = 0; col != extraPlates.size(); ++col )
1802 colorant = extraPlates[col];
1803 double tr[MAX_CHANNELS];
1804 if( colorantSpace[col] )
1807 colorantFunc[col]->Transform( &in, tr );
1808 DetermineCIELab( tr, colorantSpace[col], proofCMM, colorant.lab );
1812 if( fe.FindInLibraries( colorant.name ) && fe.mSpace == PDF::LABSpace )
1814 colorant.lab[0] = fe.mLab[ 0 ];
1815 colorant.lab[1] = fe.mLab[ 1 ];
1816 colorant.lab[2] = fe.mLab[ 2 ];
1820 if( !::stricmp( colorant.name,
"Red" ) ||
1821 !::stricmp( colorant.name,
"Green" ) ||
1822 !::stricmp( colorant.name,
"Blue" ) )
1824 uint16_t rgb16[3] = { 0, 0, 0 };
1825 if( !::stricmp( colorant.name,
"Red" ) )
1826 rgb16[1] = rgb16[2] = PDF::Component1;
1827 else if( !::stricmp( colorant.name,
"Green" ) )
1828 rgb16[0] = rgb16[2] = PDF::Component1;
1830 rgb16[0] = rgb16[1] = PDF::Component1;
1832 doc->GetDeviceCMYKColorSpace()->GetCIELab( rgb16, lab );
1833 colorant.lab[0] = float( lab[0] );
1834 colorant.lab[1] = float( lab[1] );
1835 colorant.lab[2] = float( lab[2] );
1839 PDF::DeviceN* devN = devNs[ col ];
1841 double in[MAX_CHANNELS];
1842 ::memset( in, 0, MAX_CHANNELS *
sizeof(
double ) );
1845 while( ::stricmp( devN->ChannelName( index ), colorant.name ) )
1849 devN->GetFunction()->Transform( in, tr );
1850 DetermineCIELab( tr, devN->GetAlternate(), proofCMM, colorant.lab );
1856 if( doc->GetPageCount() == 1 &&
1857 doc->GetPage()->GetFirstLayer()->GetNext() == NULL &&
1858 doc->GetPage()->GetFirstLayer()->GetFirstChild() &&
1859 doc->GetPage()->GetFirstLayer()->GetFirstChild()->GetNext() == NULL &&
1860 doc->GetPage()->GetFirstLayer()->GetFirstChild()->GetType() == PDF::gRasterType )
1862 PDF::RasterPtr ras = (PDF::RasterPtr)doc->GetPage()->GetFirstLayer()->GetFirstChild();
1863 XML* xml = ras->MetaData(
false );
1866 for(
auto& chan : *xml->root->GetNodeByName(
"ChannelInfo" ) )
1867 if( chan.GetAttributeByName(
"Name" )->ToString() == colorant.name )
1868 colorant.solidity = chan.GetNodeByName(
"Opacity" )->ToFloat();
1874 while( cIdx != doc->colorantCount() )
1876 if( ::stricmp( doc->colorant( cIdx ).name, colorant.name ) == 0 )
1880 doc->setColorant( cIdx, colorant );
1883 mProofProfile->Close( PDF::CMM::eInput, PDF::eAbsoluteColorimetric );
1886void ThumbnailRenderer::AddDocumentColorants( PDF::Document* doc )
1893 int32_t profileChannelCount = ColorSpaceComponents( mProofProfile->GetSpace() );
1894 for( i = 0; i != doc->colorantCount() && i < uint32_t( doc->GetInstance()->GetMaxChannels() - profileChannelCount ); ++i )
1897 const PDF::Document::Colorant& colorant = doc->colorant(i);
1898 if( mProofProfile->GetSpace() == PDF::GraySpace || mProofProfile->GetSpace() == PDF::RGBSpace )
1901 for( int32_t ch = 0; !found && ch != profileChannelCount; ++ch )
1903 ACPL::String profChannelName = mProofProfile->GetChannel( ch );
1904 found = profChannelName == colorant.name;
1908 j = mExtraPlates.size();
1909 mExtraPlates.push_back( colorant.name );
1913 RGBValues channelRGB;
1915 double dL = ( ( colorant.lab[0] / 100 ) - 1 ) * 0xFF;
1916 double da = colorant.lab[1];
1917 double db = colorant.lab[2];
1919 if( colorant.tvi == 0 )
1921 for( v = 0; v != 256; ++v )
1923 labV[0] = uint16_t( 0xFF00 + v * dL );
1924 labV[1] = uint16_t( 0x8000 + v * da );
1925 labV[2] = uint16_t( 0x8000 + v * db );
1926 mDeviceCMM->Lab2Image( labV, rgb8, 1 );
1927 channelRGB.v[v][0] = rgb8[ 0 ];
1928 channelRGB.v[v][1] = rgb8[ 1 ];
1929 channelRGB.v[v][2] = rgb8[ 2 ];
1934 for( v = 0; v != 256; ++v )
1936 double percentage = v / 255.0;
1937 percentage += sin( percentage * M_PI ) * colorant.tvi;
1938 if( percentage < 0 )
1940 else if( percentage > 1 )
1944 labV[0] = uint16_t( 0xFF00 + percentage * dL );
1945 labV[1] = uint16_t( 0x8000 + percentage * da );
1946 labV[2] = uint16_t( 0x8000 + percentage * db );
1947 mDeviceCMM->Lab2Image( labV, rgb8, 1 );
1948 channelRGB.v[v][0] = rgb8[ 0 ];
1949 channelRGB.v[v][1] = rgb8[ 1 ];
1950 channelRGB.v[v][2] = rgb8[ 2 ];
1953 mChannelRGB.push_back( channelRGB );
1954 mChannelSolidity[j] = colorant.solidity;
1959void ThumbnailRenderer::CopyBitsDeviceN( uint8_t* dest,
const PDF::LRectangle& updateBounds, int32_t rowBytes,
bool bImageAlphaBlending )
1961 int32_t w = updateBounds.right - updateBounds.left;
1968 int32_t top = updateBounds.top - int32_t( mState.mapping.map[2][1] );
1969 int32_t bottom = top + updateBounds.bottom - updateBounds.top;
1970 int32_t left = updateBounds.left - int32_t( mState.mapping.map[2][0] );
1971 int32_t right = left + w;
1974 int32_t components = mComponents;
1975 int32_t profComponents = ColorSpaceComponents( mProofProfile->GetSpace() );
1976 bool showBack =
false;
1977 bool mask[MAX_CHANNELS];
1979 for( c = 0, x = 0; c != components; ++c )
1980 if( ( mask[c] = ( ( 1ll << c ) & mVisiblePlates ) == 0 ) ==
false )
1984 CopyBitsSingleChannel( dest, updateBounds, rowBytes, bImageAlphaBlending );
1987 uint16_t* lab =
new uint16_t[ w * 3 ];
1988 uint8_t* blended =
new uint8_t[ w * ( mComponents > 3 ? mComponents : 3 ) ];
1990 src = mDestImage + updateBounds.top * mDestLineBytes + updateBounds.left * mDestPixelBytes;
1992 for( y = top; y != bottom; ++y )
1996 if( mIsSubstractive )
1998 for( x = left; x != right; ++x )
2000 if( ( alpha = srcX[components] ) == 255 )
2002 for( c = 0; c != profComponents; ++c )
2004 *destX = mask[c] ? 0 : *srcX;
2008 srcX += components - profComponents;
2010 else if( alpha == 0 )
2012 for( c = 0; c != profComponents; ++c )
2018 for( c = 0; c != profComponents; ++c )
2020 *destX = mask[c] ? 0 : uint8_t( ( *srcX * alpha ) >> 8 );
2024 srcX += components - profComponents;
2031 for( x = left; x != right; ++x )
2033 if( ( alpha = srcX[components] ) == 255 )
2035 for( c = 0; c != profComponents; ++c )
2037 *destX = mask[c] ? 0 : *srcX;
2041 srcX += components - profComponents;
2043 else if( alpha == 0 )
2045 for( c = 0; c != profComponents; ++c )
2051 backDrop = ( 255 - alpha ) << 8;
2052 for( c = 0; c != profComponents; ++c )
2054 *destX = mask[c] ? 0 : uint8_t( ( backDrop + *srcX * alpha ) >> 8 );
2058 srcX += components - profComponents;
2066 mProofProfile->Image2Lab( mProofIntent, blended, lab, w );
2067 mDeviceCMM->Lab2Image( lab, blended, w );
2071 for( c = profComponents; c != components; ++c )
2072 if( mask[c] ==
false )
2074 const uint8_t (*mul)[256] = GetMUL8();
2075 const RGBValues& component = mChannelRGB[c-profComponents];
2077 srcAlpha = src + components;
2079 if( mChannelSolidity[c-profComponents] == 0 )
2081 for( x = left; x != right; ++x )
2083 if( ( alpha = *srcAlpha ) == 255 )
2085 else if( alpha != 0 )
2086 alpha = ( *srcX * alpha ) >> 8;
2087 uint8_t srcR = component.v[alpha][0];
2088 uint8_t srcG = component.v[alpha][1];
2089 uint8_t srcB = component.v[alpha][2];
2090 srcX += components + 1;
2091 srcAlpha += components + 1;
2092 *destX = mul[ srcR ][ *destX ];
2094 *destX = mul[ srcG ][ *destX ];
2096 *destX = mul[ srcB ][ *destX ];
2102 double solidity = mChannelSolidity[c-profComponents];
2104 for( x = left; x != right; ++x )
2106 if( ( alpha = *srcAlpha ) == 255 )
2108 else if( alpha != 0 )
2109 alpha = ( *srcX * alpha ) >> 8;
2110 uint8_t srcR = component.v[alpha][0];
2111 uint8_t srcG = component.v[alpha][1];
2112 uint8_t srcB = component.v[alpha][2];
2113 srcX += components + 1;
2114 srcAlpha += components + 1;
2125 if( ( invSolidity = 1 - ( solidity * alpha / 255 ) ) == 1 )
2127 *destX = mul[ srcR ][ *destX ];
2129 *destX = mul[ srcG ][ *destX ];
2131 *destX = mul[ srcB ][ *destX ];
2136 *destX = mul[ srcR ][ 255 - uint8_t( ( 255 - *destX ) * invSolidity ) ];
2138 *destX = mul[ srcG ][ 255 - uint8_t( ( 255 - *destX ) * invSolidity ) ];
2140 *destX = mul[ srcB ][ 255 - uint8_t( ( 255 - *destX ) * invSolidity ) ];
2151 srcAlpha = src + components;
2152 for( x = left; x != right; ++x )
2157 if( !bImageAlphaBlending )
2158 *destX++ = *srcAlpha;
2159 srcAlpha += components + 1;
2161 src += mDestLineBytes;
2168void ThumbnailRenderer::CopyBitsNoMatch( uint8_t* dest,
const PDF::LRectangle& updateBounds, int32_t rowBytes,
bool bImageAlphaBlending )
2170 if( ( mVisiblePlates&7 ) == ( 1 << 0 ) || ( mVisiblePlates&7 ) == ( 1 << 1 ) || ( mVisiblePlates&7 ) == ( 1 << 2 ) )
2172 CopyBitsSingleChannel( dest, updateBounds, rowBytes, bImageAlphaBlending );
2181 bool showBack =
false;
2183 int32_t top = updateBounds.top - int32_t( mState.mapping.map[2][1] );
2184 int32_t bottom = top + updateBounds.bottom - updateBounds.top;
2185 int32_t left = updateBounds.left - int32_t( mState.mapping.map[2][0] );
2186 int32_t right = left + updateBounds.right - updateBounds.left;
2188 mask[0] = ( ( 1 << 0 ) & mVisiblePlates ) == 0;
2189 mask[1] = ( ( 1 << 1 ) & mVisiblePlates ) == 0;
2190 mask[2] = ( ( 1 << 2 ) & mVisiblePlates ) == 0;
2192 src = mDestImage + updateBounds.top * mDestLineBytes + updateBounds.left * mDestPixelBytes;
2194 for( int32_t y = top; y != bottom; ++y )
2198 src += mDestLineBytes;
2200 for( int32_t x = left; x != right; ++x )
2202 if( !bImageAlphaBlending )
2211 if( ( alpha = srcX[3] ) == 255 )
2213 *destX++ = mask[0] ? 0 : srcX[0];
2214 *destX++ = mask[1] ? 0 : srcX[1];
2215 *destX++ = mask[2] ? 0 : srcX[2];
2217 else if( alpha == 0 )
2219 register uint8_t backDrop8;
2220 if( showBack && ( ( ( x >> 3 ) + ( y >> 3 ) ) & 1 ) == 0 )
2224 *destX++ = backDrop8;
2225 *destX++ = backDrop8;
2226 *destX++ = backDrop8;
2230 if( showBack && ( ( ( x >> 3 ) + ( y >> 3 ) ) & 1 ) == 0 )
2231 backDrop = ( 255 - alpha ) * 192;
2233 backDrop = ( 255 - alpha ) << 8;
2234 *destX++ = uint8_t( ( backDrop + ( mask[0] ? 0 : srcX[0] ) * alpha ) >> 8 );
2235 *destX++ = uint8_t( ( backDrop + ( mask[1] ? 0 : srcX[1] ) * alpha ) >> 8 );
2236 *destX++ = uint8_t( ( backDrop + ( mask[2] ? 0 : srcX[2] ) * alpha ) >> 8 );
2244void ThumbnailRenderer::CopyBitsICC( uint8_t* dest,
const PDF::LRectangle& updateBounds, int32_t rowBytes,
bool bImageAlphaBlending )
2246 int32_t w = updateBounds.right - updateBounds.left;
2253 int32_t top = updateBounds.top - int32_t( mState.mapping.map[2][1] );
2254 int32_t bottom = top + updateBounds.bottom - updateBounds.top;
2255 int32_t left = updateBounds.left - int32_t( mState.mapping.map[2][0] );
2256 int32_t right = left + w;
2259 int32_t components = mComponents;
2260 bool mask[MAX_CHANNELS];
2262 for( c = 0, x = 0; c != components; ++c )
2263 if( ( mask[c] = ( int64_t( 1LL << c ) & mVisiblePlates ) == 0 ) ==
false )
2267 CopyBitsSingleChannel( dest, updateBounds, rowBytes, bImageAlphaBlending );
2270 uint16_t* lab =
new uint16_t[ w * 3 ];
2271 uint8_t* blended =
new uint8_t[ w * ( mComponents > 3 ? mComponents : 3 ) ];
2273 src = mDestImage + updateBounds.top * mDestLineBytes + updateBounds.left * mDestPixelBytes;
2275 for( y = top; y != bottom; ++y )
2279 if( mIsSubstractive )
2281 for( x = left; x != right; ++x )
2283 if( ( alpha = srcX[components] ) == 255 )
2285 for( c = 0; c != components; ++c )
2287 *destX = mask[c] ? 0 : *srcX;
2292 else if( alpha == 0 )
2294 for( c = 0; c != components; ++c )
2300 for( c = 0; c != components; ++c )
2302 *destX = mask[c] ? 0 : uint8_t( ( *srcX * alpha ) >> 8 );
2312 for( x = left; x != right; ++x )
2314 if( ( alpha = srcX[components] ) == 255 )
2316 for( c = 0; c != components; ++c )
2318 *destX = mask[c] ? 0 : *srcX;
2323 else if( alpha == 0 )
2325 for( c = 0; c != components; ++c )
2331 backDrop = ( 255 - alpha ) << 8;
2332 for( c = 0; c != components; ++c )
2334 *destX = mask[c] ? 0 : uint8_t( ( backDrop + *srcX * alpha ) >> 8 );
2342 mProofProfile->Image2Lab( mProofIntent, blended, lab, w );
2343 mDeviceCMM->Lab2Image( lab, blended, w );
2346 srcAlpha = src + components;
2347 for( x = left; x != right; ++x )
2352 if( !bImageAlphaBlending )
2353 *destX++ = *srcAlpha;
2354 srcAlpha += components + 1;
2356 src += mDestLineBytes;
2363void ThumbnailRenderer::CopyBitsSingleChannel( uint8_t* dest,
const PDF::LRectangle& updateBounds, int32_t rowBytes,
bool bImageAlphaBlending )
2369 bool showBack =
false;
2370 int32_t top = updateBounds.top - int32_t( mState.mapping.map[2][1] );
2371 int32_t bottom = top + updateBounds.bottom - updateBounds.top;
2372 int32_t left = updateBounds.left - int32_t( mState.mapping.map[2][0] );
2373 int32_t right = left + updateBounds.right - updateBounds.left;
2374 int32_t components = mComponents;
2376 register uint8_t backDrop8;
2378 for( c = 0; c != components; ++c )
2379 if( ( int64_t( 1LL << c ) & mVisiblePlates ) != 0 )
2382 src = mDestImage + updateBounds.top * mDestLineBytes + updateBounds.left * mDestPixelBytes;
2384 for( int32_t y = top; y != bottom; ++y )
2388 src += mDestLineBytes;
2390 if( mIsSubstractive )
2392 for( int32_t x = left; x != right; ++x )
2394 if( ( alpha = srcX[components] ) == 255 )
2395 backDrop8 = 255 - srcX[c];
2396 else if( alpha == 0 )
2398 if( showBack && ( ( ( x >> 3 ) + ( y >> 3 ) ) & 1 ) == 0 )
2405 register uint16_t backDrop;
2406 if( showBack && ( ( ( x >> 3 ) + ( y >> 3 ) ) & 1 ) == 0 )
2407 backDrop = ( 255 - alpha ) * 192;
2409 backDrop = ( 255 - alpha ) << 8;
2410 backDrop8 = uint8_t( ( backDrop + ( 255 - srcX[c] ) * alpha ) >> 8 );
2412 *destX++ = backDrop8;
2413 *destX++ = backDrop8;
2414 *destX++ = backDrop8;
2416 if( !bImageAlphaBlending )
2421 srcX += mDestPixelBytes;
2426 for( int32_t x = left; x != right; ++x )
2428 if( ( alpha = srcX[components] ) == 255 )
2429 backDrop8 = srcX[c];
2430 else if( alpha == 0 )
2432 if( showBack && ( ( ( x >> 3 ) + ( y >> 3 ) ) & 1 ) == 0 )
2439 register uint16_t backDrop;
2440 if( showBack && ( ( ( x >> 3 ) + ( y >> 3 ) ) & 1 ) == 0 )
2441 backDrop = ( 255 - alpha ) * 192;
2443 backDrop = ( 255 - alpha ) << 8;
2444 backDrop8 = uint8_t( ( backDrop + srcX[c] * alpha ) >> 8 );
2446 *destX++ = backDrop8;
2447 *destX++ = backDrop8;
2448 *destX++ = backDrop8;
2450 if( !bImageAlphaBlending )
2455 srcX += mDestPixelBytes;
2461void ThumbnailRenderer::CopyBits( uint8_t* dest,
const PDF::LRectangle& updateBounds, int32_t rowBytes,
bool bImageAlphaBlending )
2463 switch( mWhichCopy )
2466 CopyBitsNoMatch( dest, updateBounds, rowBytes, bImageAlphaBlending );
2469 CopyBitsDeviceN( dest, updateBounds, rowBytes, bImageAlphaBlending );
2472 CopyBitsICC( dest, updateBounds, rowBytes, bImageAlphaBlending );
2477void ThumbnailRenderer::SetVisiblePlates( uint64_t mask )
2479 mVisiblePlates = mask;
bool RenderTiles(const TileSettings &tileSettings, const aur::ACPL::FileSpec &outputPath, int16_t channelIndex, const aur::ACPL::UString &multichannelRender)
void AssignInputProfiles(const aur::ACPL::FileSpec &rgbProfile, const aur::ACPL::FileSpec &cmykProfile, const aur::ACPL::FileSpec &grayProfile, int32_t intent)
bool Render(const aur::ACPL::FileSpec &outputPath, const char *thumbnailType, int32_t x, int32_t y, int32_t width, int32_t height, uint32_t quality=100, uint64_t visiblePlates=UINT64_MAX)
bool Setup(const aur::ACPL::FileSpec &profileFile, const aur::ACPL::FileSpec &cmmFile)
const char * GetDocumentChannelName(uint32_t index)
AOI_SoftProofRenderer(AOI_Document *document)
uint32_t GetDocumentChannelCount()
void UpdateRenderer(uint32_t width, uint32_t height)