Page 2 of 5

Re: Printing - Page number paradox

Posted: Thu Oct 20, 2016 7:58 pm
by Rathinagiri
I don't know anything about the internal structure of the EMF files, but just taking a quick look, it appears to be that strings are there, so, it could be only matter of put a placeholder for total pages in each one and then... DIRECTORY, MEMOREAD, STRTRAN, MEMOWRIT... you know...
That is right Roberto. I too have gone into deep about EMF. What that had given in Microsoft site is that 'Yes EMF can be enumerated and edited. EMF is an array of EnhanceMetaRecords (EMR) as they call it. These EMRs are in variable size.

From MSDN:

An EMF metafile consists of a sequence of EMF records. The first record in the metafile is always an EMF header record, and the last is always an EMF end-of-file record. Between these are records that specify drawing operations, the configuration of properties, and the creation of graphics objects, all of which together compose a device-independent picture.

EMF records are contiguous; this is required, because the information that is available for traversing the file from record to record depends on it. That is, from any given EMF record, including the header record, in order to move to the next sequential record in the file, the length of the record is used.

So even if we search text and replace with other text, we need to replace the exact size. Otherwise EMR size will be changed.

Or the safest way is grab the EMR using Win32API and replace it after modification.

EMR_EXTTEXTOUTW is the EMR type for Unicode Text.

https://msdn.microsoft.com/en-us/library/cc230533.aspx

And yours is a nice idea! Put some XXXX in every page and replace that with the number of pages afterwards with exactly 4 characters. I will try that!

Re: Printing - Page number paradox

Posted: Thu Oct 20, 2016 8:08 pm
by Roberto Lopez
Roberto Lopez wrote: Again... maybe I'm missing something important... sorry in advance.
And...

We should generate emf files always (preview or not) because the 'totalpages' tag must be available always (not only when preview is required).

So we always should print as from preview (from emf files) so, it could drive to a speed problem in 'no-preview' situations...

Again...again: I could be missing something (print system had suffered many changes since my watch :) )

Sorry for that.

Re: Printing - Page number paradox

Posted: Thu Oct 20, 2016 8:41 pm
by Roberto Lopez
Rathinagiri wrote: And yours is a nice idea! Put some XXXX in every page and replace that with the number of pages afterwards with exactly 4 characters. I will try that!
Exactly... the placeholder and the the total page number string must have the same size.

Printing - Page number paradox

Posted: Thu Oct 20, 2016 9:11 pm
by Pablo César
I advice you to use "@@@@" instead of "XXXXX" in order to avoid any coincidence in the text.

Re: Printing - Page number paradox

Posted: Thu Oct 20, 2016 10:27 pm
by srvet_claudio
Is possible you draw inside EMF with GDI functions. I will prepare a demo.

Re: Printing - Page number paradox

Posted: Fri Oct 21, 2016 10:42 am
by Rathinagiri
Thank you Roberto, Claudio, Pablo.

I will wait for Claudio's demo.

Re: Printing - Page number paradox

Posted: Tue Oct 25, 2016 2:11 pm
by srvet_claudio
srvet_claudio wrote:Is possible you draw inside EMF with GDI functions. I will prepare a demo.
Hi all,
sorry for the delay but I've been very busy...

Code: Select all


#include "hmg.ch"
#include "Directry.ch"

Function Main()
   DEFINE WINDOW Win_1 ;
      AT 0,0 ;
      WIDTH 400 ;
      HEIGHT 400 ;
      TITLE 'MiniPrint Library Test: Insert Page Number' ;
      MAIN 

      @ 50, 50 BUTTON Button_1 CAPTION "Test" ACTION PrintTest()

   END WINDOW
   CENTER WINDOW Win_1
   ACTIVATE WINDOW Win_1
Return


*------------------------------------------------------------------------------*
Procedure PrintTest
*------------------------------------------------------------------------------*
LOCAL lSuccess

   SELECT PRINTER DIALOG TO lSuccess PREVIEW

   If lSuccess == .F.
      MsgInfo('Print Error')
      Return
   EndIf


   // Measure Units Are Millimeters

   START PRINTDOC


         START PRINTPAGE

            @ 20,20 PRINT "Filled Rectangle Sample:" ;
               FONT "Arial" ;
               SIZE 20 

            @ 30,20 PRINT RECTANGLE ;
               TO 40,190 ;
               PENWIDTH 0.1;
               COLOR {255,255,0}

            @ 60,20 PRINT RECTANGLE ;
               TO 100,190 ;
               PENWIDTH 0.1;
               COLOR {255,255,0};
               FILLED

            @ 110,20 PRINT RECTANGLE ;
               TO 150,190 ;
               PENWIDTH 0.1;
               COLOR {255,255,0};
               ROUNDED

            @ 160,20 PRINT RECTANGLE ;
               TO 200,190 ;
               PENWIDTH 0.1;
               COLOR {255,255,0};
               FILLED;
               ROUNDED

         END PRINTPAGE


         START PRINTPAGE

            @ 20,20 PRINT "Filled Rectangle Sample:" ;
               FONT "Arial" ;
               SIZE 20 

            @ 30,20 PRINT RECTANGLE ;
               TO 40,190 ;
               PENWIDTH 0.1

            @ 60,20 PRINT RECTANGLE ;
               TO 100,190 ;
               PENWIDTH 0.1;
               FILLED

            @ 110,20 PRINT RECTANGLE ;
               TO 150,190 ;
               PENWIDTH 0.1;
               ROUNDED

            @ 160,20 PRINT RECTANGLE ;
               TO 200,190 ;
               PENWIDTH 0.1;
               FILLED;
               ROUNDED

         END PRINTPAGE

         // call this function after last END PRINTPAGE and before END PRINTDOC 
         ProcInsertPageNumber( OpenPrinterGetDC() )

   END PRINTDOC

Return


************************************************************************************************************

PROCEDURE ProcInsertPageNumber( hDC )
LOCAL cFuncNameCallBack := "ProcDrawEMFCallBack"
LOCAL cNamePrefix := GetTempFolder() + _HMG_SYSDATA [ 379 ] + "_hmg_print_preview_"
LOCAL aFiles :=  DIRECTORY( cNamePrefix + "*.EMF" )
LOCAL cFileNameOld, cFileNameNew, i
PRIVATE nPageNumber := 1

   FOR i := 1 TO HMG_LEN( aFiles ) 
      cFileNameOld := GetTempFolder() + aFiles [ i ] [ F_NAME ]
      cFileNameNew := GetTempFolder() + "New_" + aFiles [ i ] [ F_NAME ]
      nError := BT_DrawEMF( hDC, cFileNameOld, cFileNameNew, cFuncNameCallBack )
      IF nError == 0
         FERASE( cFileNameOld ) 
         FRENAME( cFileNameNew, cFileNameOld )
      ELSE
         MsgStop("Error ("+ hb_NtoS( nError ) +") in write into EMF: " + cFileNameOld )
      ENDIF
   NEXT

RETURN


*************************************************************************************************************

FUNCTION ProcDrawEMFCallBack( hDC, leftMM, topMM, rightMM, bottomMM, leftPx, topPx, rightPx, bottomPx, IsParamHDC )   // rectangle that bounded the area to draw, in milimeters and pixels
LOCAL Old_PageDC := OpenPrinterGetPageDC()

   OpenPrinterGetPageDC() := hDC
   @ 180, 100 PRINT " Page Number: " + hb_NtoS( nPageNumber++ ) + " of " + hb_NtoS( _HMG_SYSDATA [ 380 ] ) FONT "Arial" SIZE 12 
   OpenPrinterGetPageDC() := Old_PageDC

   // MsgDebug( hDC, leftMM, topMM, rightMM, bottomMM, leftPx, topPx, rightPx, bottomPx, IsParamHDC )
RETURN NIL



#pragma BEGINDUMP

#include "HMG_UNICODE.h"
#include <windows.h>
#include "hbvm.h"
#include "hbapi.h"


//*********************************************************************************************************************************
//* BT_DrawEMF ( [ hDC ] , cFileNameOld , cFileNameNew , cFuncNameCallBack )  ---> Return nError, e.g. Zero is OK
//*********************************************************************************************************************************

HB_FUNC (BT_DRAWEMF)
{
   HDC   hDC                = (HDC)    HMG_parnl (1);
   TCHAR *cFileNameOld      = (TCHAR*) HMG_parc  (2);
   TCHAR *cFileNameNew      = (TCHAR*) HMG_parc  (3);
   CHAR  *cFuncNameCallBack = (CHAR* ) hb_parc   (4);

   BOOL IsParamHDC = ( hDC ? TRUE : FALSE );

   HDC           hDC_EMF  = NULL;
   HENHMETAFILE  hEMF_Old = NULL;
   HENHMETAFILE  hEMF_New = NULL;

   ENHMETAHEADER emh;
   HRSRC         hResourceData;
   HGLOBAL       hGlobalResource;
   LPVOID        lpGlobalResource;
   DWORD         nFileSize;


   PHB_DYNS pDynSym = hb_dynsymFindName( cFuncNameCallBack );
   if( pDynSym == NULL )
   {  hb_retni (1);
      return;
   }
    
   // Load MetaFile from Resource
   hResourceData = FindResource (NULL, cFileNameOld, _TEXT("EMF"));
   if ( hResourceData )
   {   hGlobalResource = LoadResource (NULL, hResourceData);
       if ( hGlobalResource )
       {    lpGlobalResource = LockResource (hGlobalResource);
            nFileSize = SizeofResource (NULL, hResourceData);
            hEMF_Old = SetEnhMetaFileBits (nFileSize, lpGlobalResource);
       }
   }

   // If fail, load MetaFile from Disk
   if (hEMF_Old == NULL)
       hEMF_Old = GetEnhMetaFile (cFileNameOld);

   // If fail load from Resource and Disk return False
   if (hEMF_Old == NULL)
   {  hb_retni (2);
      return;
   }

   // Get the header of MetaFile
   ZeroMemory (&emh, sizeof(ENHMETAHEADER));
   emh.nSize = sizeof(ENHMETAHEADER);
   if ( GetEnhMetaFileHeader(hEMF_Old, sizeof(ENHMETAHEADER), &emh) == 0 )
   {  DeleteEnhMetaFile (hEMF_Old);
      hb_retni (3);
      return;
   }

   if( IsParamHDC )
      hDC_EMF = CreateEnhMetaFile( hDC, cFileNameNew, (RECT *)&emh.rclFrame, _TEXT("") ); 
   else
   {
      hDC = GetDC( NULL );
      INT iWidthMM  = GetDeviceCaps( hDC, HORZSIZE );
      INT iHeightMM = GetDeviceCaps( hDC, VERTSIZE );
      INT iWidthPx  = GetDeviceCaps( hDC, HORZRES  );
      INT iHeightPx = GetDeviceCaps( hDC, VERTRES  );
      hDC_EMF = CreateEnhMetaFile( hDC, cFileNameNew, (RECT *)&emh.rclFrame, _TEXT("") );

      if (hDC_EMF == NULL)
         ReleaseDC (NULL, hDC);

      emh.rclBounds.left   = (emh.rclFrame.left   / 100) * iWidthPx  / iWidthMM;
      emh.rclBounds.top    = (emh.rclFrame.top    / 100) * iHeightPx / iHeightMM;
      emh.rclBounds.right  = (emh.rclFrame.right  / 100) * iWidthPx  / iWidthMM;
      emh.rclBounds.bottom = (emh.rclFrame.bottom / 100) * iHeightPx / iHeightMM;
   }

   if (hDC_EMF == NULL)
   {  DeleteEnhMetaFile (hEMF_Old);
      hb_retni (4);
      return;
   }
   
   // Play Old MetaFile into New MetaFile 
   PlayEnhMetaFile (hDC_EMF, hEMF_Old, (RECT *)&emh.rclBounds);

   hb_vmPushSymbol (hb_dynsymSymbol ( pDynSym ));
   hb_vmPushNil ();                                       // places NIL at Self 
   hb_vmPushNumInt ((LONG_PTR) hDC_EMF );
   hb_vmPushLong   ((LONG) emh.rclFrame.left   / 100 );   // push values in milimeters
   hb_vmPushLong   ((LONG) emh.rclFrame.top    / 100 );
   hb_vmPushLong   ((LONG) emh.rclFrame.right  / 100 );
   hb_vmPushLong   ((LONG) emh.rclFrame.bottom / 100 );
   hb_vmPushLong   ((LONG) emh.rclBounds.left   );        // push values in pixels
   hb_vmPushLong   ((LONG) emh.rclBounds.top    );
   hb_vmPushLong   ((LONG) emh.rclBounds.right  );
   hb_vmPushLong   ((LONG) emh.rclBounds.bottom );
   hb_vmPushLogical((BOOL) IsParamHDC );
   hb_vmDo ( 1+4+4+1 );

   // Release hDC
   hEMF_New = CloseEnhMetaFile (hDC_EMF);

   // Release handles
   DeleteEnhMetaFile (hEMF_Old);
   DeleteEnhMetaFile (hEMF_New);

   if( IsParamHDC == FALSE )
      ReleaseDC (NULL, hDC);

   hb_retni (0);   // OK status
}


#pragma ENDDUMP

Printing - Page number paradox

Posted: Tue Oct 25, 2016 2:20 pm
by Pablo César
WOW Geniously !

Thank you Claudio. Our C Guru.

Re: Printing - Page number paradox

Posted: Tue Oct 25, 2016 6:08 pm
by mustafa
Claudio, fabuloso !!! :idea: :roll:
Gracias
Mustafa

Re: Printing - Page number paradox

Posted: Tue Oct 25, 2016 8:10 pm
by Rathinagiri
That is unbelievable! :)