Within a StartPage/EndPage sequence of calls, calling SetLayer with a valid layer title will start a new layer and place all subsequent drawing instructions within that layer. Calling SetLayer with an empty string will end the last layer.
If multiple layers are nested, multiple calls to SetLayer with an empty string are needed to close all layers. If all layers are not closed at the call to EndPage, the PDF printer will automatically close all open layers. for example:
// start parent layer
SetLayer( hDC, L"Blue Layer" );
SetTextColor( hDC, RGB(0, 0, 255) );
TextOut( hDC, 200, yPos, buf, lstrlen(buf) );
yPos += 200;
// start blue sub-layer 1
SetLayer( hDC, L"Blue Layer - 1" );
SetTextColor( hDC, RGB(0, 0, 128) );
TextOut( hDC, 800, yPos, "Blue Layer - 1", lstrlen("Blue Layer - 1") );
yPos += 200;
SetLayer( hDC, L"" ); // close blue sub-layer 1
SetLayer( hDC, L"" ); // close blue parent layer
The sequence of opening and closing layers should be consistent with the order string for the PDF viewer to show or hide layers with their sub-layers in a consistent way.
#include <Windows.h>
#include <windowsx.h>
#include <iostream>
#include <tchar.h>
#define LAYERS
using namespace std;
#define ESCAPE_SETALPHA 247
#define ESCAPE_SETLAYER 248
#define ESCAPE_SETMARKEDCONTENT 246
#define ESCAPE_SETBOOKMARK 250 // set bookmark on current drawing operation
#define ESCAPE_SETHYPERLINK 252 // set hyperlink on current drawing operation
void SetLayer( HDC hDC, LPWSTR LayerInfo )
{
#ifdef LAYERS
switch ( ExtEscape( hDC, ESCAPE_SETLAYER, (int)((wcslen(LayerInfo) + 1) * sizeof(LayerInfo[0])), (LPCSTR)LayerInfo, 0, NULL ) )
{
default:
// positive return indicates success
case 0:
// no error
return;
case -1:
// error occured, closing a layer when none was open
break;
case -2:
// memory allocation error (low memory or invalid string)
break;
}
#endif
}
void SetMarkedContent( HDC hDC, LPSTR LayerInfo )
{
switch ( ExtEscape( hDC, ESCAPE_SETMARKEDCONTENT, (int)((strlen(LayerInfo) + 1) * sizeof(LayerInfo[0])), (LPCSTR)LayerInfo, 0, NULL ) )
{
default:
// 0 or positive return indicates success
return;
case -1:
// error occured, closing a layer when none was open
break;
case -2:
// memory allocation error (low memory or invalid string)
break;
}
}
// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // /
long SetAlphaLevel( HDC hdc, int lStrokeAlpha, int lFillAlpha )
// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // /
{
#pragma pack( push, 1 )
struct
{
int lStrokeAlpha;
int lFillAlpha;
} Alpha;
Alpha.lStrokeAlpha = lStrokeAlpha;
Alpha.lFillAlpha = lFillAlpha;
return ExtEscape( hdc, ESCAPE_SETALPHA, sizeof(Alpha), (LPCSTR)&Alpha, 0, NULL );
#pragma pack( pop )
}
long SetBookmark(HDC hdc, long lParent, LPCTSTR szTitle)
{
#pragma pack( push, 1 )
struct
{
long lParent;
char szTitle[255];
} Bookmark;
Bookmark.lParent = lParent;
lstrcpyn( Bookmark.szTitle, szTitle, 254 );
return ExtEscape( hdc, ESCAPE_SETBOOKMARK, sizeof( DWORD ) + lstrlen( Bookmark.szTitle ) + 1,
(LPCSTR)&Bookmark, 0, NULL );
#pragma pack( pop )
}
long SetHyperLink(HDC hdc, LPCTSTR szURL)
{
return ExtEscape( hdc, ESCAPE_SETHYPERLINK, lstrlen( szURL ) + 1,
szURL, 0, NULL );
}
int _tmain(int argc, _TCHAR* argv[])
{
int ret = 0;
HDC hDC = NULL;
HFONT hfnt = NULL;
LPDEVMODE devmode = NULL;
int PageCount = 2;
cout << "Press ENTER to continue..." << endl;
cin.get();
while( TRUE )
{
if ( argc < 2 )
{
cout << "Usage: LayerSample \"Printer Name\" PageCount\n";
ret = -1;
break;
}
// create device context from printer
hDC = CreateDC( NULL, argv[1], NULL, NULL );
if ( hDC == NULL )
{
cout << "Failed to retrieve printer DC for printer " << argv[1] << "\n";
ret = -2;
break;
}
// get information about the printer
HANDLE hPrinter = NULL;
DWORD dw = 0;
if ( !OpenPrinter( argv[1], &hPrinter, NULL )
|| hPrinter == NULL
)
{
ret = -3;
break;
}
// get default devmode
if ( (dw = DocumentProperties( NULL, hPrinter, argv[1],
NULL, NULL, 0 )) <= 0 )
{
ret = -4;
break;
}
devmode = (LPDEVMODE)GlobalAllocPtr( GHND, dw );
DocumentProperties( NULL, hPrinter, argv[1], devmode, NULL, DM_OUT_BUFFER );
ClosePrinter( hPrinter );
// read the page count from the command line
if ( argc > 2 && argv[2][0] )
{
PageCount = atol( argv[2] );
}
// start new document
DOCINFO di;
int nPage = 1;
memset( &di, 0, sizeof(di) );
di.cbSize = sizeof(di);
di.lpszDocName = _T("Layered PDF");
// check if PDF printer supports layers
CHAR technology[4];
int escape = ESCAPE_SETLAYER;
ExtEscape( hDC, GETTECHNOLOGY, 0, NULL, sizeof(technology), (LPSTR)technology );
// the technology should be PDF
if ( lstrcmp(technology, "PDF") )
{
MessageBox( 0, "Not an Amyuni PDF driver", "Error", MB_ICONERROR );
}
// and support the SETLAYER escape
if ( !ExtEscape( hDC, QUERYESCSUPPORT, sizeof(escape), (LPCSTR)&escape, 0, NULL ) )
{
MessageBox( 0, "Not an Amyuni PDF driver", "Error", MB_ICONERROR );
}
// trigger PDF-1.5 header
SetLayer( hDC, L"" );
ret = StartDoc( hDC, &di );
if ( ret < 0 )
{
cout << "StartDoc failed\n";
break;
}
for ( nPage = 1; nPage <= PageCount; nPage++ )
{
cerr << "********** Printing page " << nPage << " **********\n";
ret = StartPage( hDC );
if ( ret < 0 )
{
cout << "StartPage failed\n";
// fall through
}
LOGFONT lf;
HFONT oldFont;
CHAR buf[255];
int yPos = 200;
memset( &lf, 0, sizeof(lf) );
lstrcpy( lf.lfFaceName, "Arial" );
lf.lfHeight = -48;
hfnt = CreateFontIndirect( &lf );
oldFont = (HFONT)SelectObject( hDC, hfnt );
SetBkMode( hDC, TRANSPARENT );
// set a bookmark on page 1
wsprintf( buf, "Bookmark %d", nPage );
SetBookmark(hDC, 0, buf);
SetLayer( hDC, L"Blue Layer" );
SetTextColor( hDC, RGB(0, 0, 255) );
wsprintf( buf, "Page %d", nPage );
TextOut( hDC, 200, yPos, buf, lstrlen(buf) );
yPos += 200;
SetLayer( hDC, L"Blue Layer - 1" );
SetTextColor( hDC, RGB(0, 0, 128) );
TextOut( hDC, 800, yPos, "Blue Layer - 1", lstrlen("Blue Layer - 1") );
yPos += 200;
SetLayer( hDC, L"" ); // close blue sub-layer 1
if ( nPage == 1 )
// add a hyperlink to our web site
SetHyperLink(hDC, "http:// www.amyuni.com");
else
// set a hyperlink to page 1
SetHyperLink(hDC, "#Bookmark 1");
SetLayer( hDC, L"Green Layer\t1" );
SetTextColor( hDC, RGB(0, 128, 0) );
TextOut( hDC, 800, yPos, "Green Sub Layer", lstrlen("Green Sub Layer") );
yPos += 200;
SetLayer( hDC, L"" ); // close blue sub-layer 2
SetLayer( hDC, L"" ); // close blue layer
SetLayer( hDC, L"Red Layer" );
SetTextColor( hDC, RGB(255, 0, 0) );
TextOut( hDC, 200, yPos, buf, lstrlen(buf) );
yPos += 200;
SetLayer( hDC, L"" ); // close red layer
SetLayer( hDC, L"Green Layer" );
SetMarkedContent( hDC, "Figure" );
SetAlphaLevel( hDC, 100, 20 );
// draw a green rectangle to show the effects of Alpha levels
HBRUSH hbr = CreateSolidBrush( RGB(0, 200, 0) );
RECT rc = { 200, yPos - 800, 2000, yPos - 200 };
FillRect( hDC, &rc, hbr );
DeleteObject( hbr );
yPos += 200;
// restore the alpha level
SetAlphaLevel( hDC, 100, 100 );
SetMarkedContent( hDC, "" ); // close marked content
SetLayer( hDC, L"" ); // close green layer
cout << "Printed one single line\n";
SelectObject( hDC, oldFont );
ret = EndPage( hDC );
if ( ret < 0 )
{
cout << "EndPage failed\n";
// fall through
}
}
// set the order and radio/button groups of layers
SetLayer( hDC, L"/Order[(Blue Layer)[(Blue Layer - 1)(Green Layer\t1)](Red Layer)(Green Layer)]" \
L"/RBGroups[[(Red Layer)(Green Layer)]]/OFF[(Red Layer)]/ON[(Green Layer)]"
);
ret = EndDoc( hDC );
if ( ret < 0 )
{
cout << "EndDoc failed\n";
break;
}
break;
}
if ( hfnt != NULL )
{
DeleteObject( hfnt );
}
if ( hDC != NULL )
{
DeleteDC( hDC );
}
if ( devmode != NULL )
{
GlobalFreePtr( devmode );
}
if ( ret < 0 )
{
cerr << "Error code " << ret << ", GetLastError returned " << GetLastError() << "\n";
}
cout << "Press ENTER to continue..." << endl;
cin.get();
return ret;
}