EMF print preview fails

Please post bug reports, feature requests, or any question regarding the DELPHI AREA projects here.

EMF print preview fails

Postby norbert » May 13th, 2006, 3:07 pm

Well, I also experience that in the latest verion of PrintPreview EMF file import fails.
The cause for it seems not to be the 'Load' procedure but thomething else I did not yet find out.
I'm using nearly the same code as in PrintPreview and it runs well.
Here follows an extraction of MY code:
/
Code: Select all
/Load procedure of the EMF file:
//......... 
  if FileExists(sMetaPathFileName) then begin
    //Picture Objekt für MetaFile erzeugen
    tPIC := tPicture.Create;
    //MetaFile Objekt erstellen
    tEMF := TMetaFile.Create;
    tEMF.Handle := ReadMetafileFromFile(sMetaPathFileName);
//.........

//Now in detail the read procedure:
//------------------------------------------------------------------------------
function TImageForm.ReadMetafileFromFile (sMetaPathFileName: String):HENHMETAFILE;
// Liest ein WMF (inkl. Placable Meta File) oder ein EMF-Format - Reads a WMF (including placeable Metafiles) or EMF from a file
//und gibt das Handle zum EMF-Format zurück. - and returns a handle to an enhanced Metafile.
var pFileName: array [0..MAX_PATH] of char;
    hMetafile: HENHMETAFILE;
    fileStream: TFileStream;
begin
  StrPCopy (pFileName, sMetaPathFileName);
  hMetafile := GetEnhMetaFile (pFileName);
  // convert WMF to EMF if necessary
  if hMetafile = 0 then
  begin
    fileStream := TFileStream.Create (sMetaPathFileName, fmOpenRead);

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//The following is comparable with the correspondent code line in PrintPreview:
    hMetafile := ReadWMFfromStream (fileStream, fileStream.size);
//Here, it runs well, but in PrintPreview, it fails.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    fileStream.Free;
  end;
  result := hMetafile;
end;

//------------------------------------------------------------------------------
function TImageForm.ReadWMFfromStream(Stream: TStream; Length: integer): HENHMETAFILE;
// Lesen des alten WMF Formats. - Reads an old WMF metafile from a stream
type
  //Header des placable Metafile hat 22 Byte. -  Header for placeable Metafile, 22 byte in size
  METAFILEHEADER = packed record
    key: DWORD;
    hmf: WORD;
    left:   integer;
    top:    integer;
    right:  integer;
    bottom: integer;
    inch: WORD;
    reserved: DWORD;
    checksum: WORD;
  end;
var
  WMF: MetaFileHeader;
  BitMem: Pointer;
  MFP: TMetaFilePict;
  width: integer;
  height: integer;
  dx: integer;
  dy: integer;
begin
  // Den Header lesen. - Read in Header
  Stream.Read(WMF, SizeOf(WMF));
  // Test, ob placable Metafile gefunden. - check if it is a placeable metafile
  if (WMF.key = $9AC6CDD7)  then
  begin
    // Placable Metafile gefunden. - placeable Metafile found
    Dec(Length, SizeOF(WMF));
    // WMF Abmessungen in MM_HIENGLISH abrufen. - calculate WMF size in MM_HIENGLISH units
    if WMF.Inch = 0 then WMF.Inch := 96;
    dx := WMF.Right - WMF.Left;
    dy := WMF.Bottom - WMF.Top;
    if dx < 0 then dx := 0;
    if dy < 0 then dy := 0;
    height := MulDiv (dy, 2540, WMF.Inch);
    width  := MulDiv (dx, 2540, WMF.Inch);
    with MFP do
    begin
      MM := MM_HIENGLISH;
      xExt := width;
      yExt := height;
      hmf := 0;
    end;
  end
  else begin
    // Normales altes WMF Format - normal old WMF Metafile
    Stream.Seek (soFromBeginning ,0);
    with MFP do
    begin
      MM := MM_HIENGLISH; //MM_HIMETRIC;
      xExt := 0;
      yExt := 0;
      hmf := 0;
    end;
  end;
  try
    GetMem(Bitmem, Length);
    Stream.Read(BitMem^, Length);
    result := SetWinMetaFileBits(Length, BitMem, 0, MFP);
  finally
    Freemem(BitMem, Length);
  end;
end;


Attached You find an EMF '001.EMF' which was extracted from the SPL spool file of my virtual printer code. It is displayable with any viewer and the standard File for my current print monitor made for net printing.

by the way, I replaced the corresponding code in PrintPreview just with the code above. The result is again a crash at the SAME code line as shown above between the two lines with exclamations. I don't want to spend much time finding the bug inside PrintPreview because there exists someone else knowing it much better than me. :-)
norbert
Active Member
Active Member
 
Posts: 17
Joined: May 13th, 2006, 8:49 am
Location: Germany

Some inconstitencies with PrintPreview EMF

Postby norbert » May 15th, 2006, 8:57 am

Looking at the PrintPreview code more intensively, i found out that the EMF load routine is invoked twice, once for preview and once for thumbnail.
In my first trial, i only replaced the original function for preview, not for thumbnails, and the component still crashed with generating thumbnails. Replacing both made the component run very well with standard EMF structures.

Then, i had a deeper look at the original EMF routine.
Why do You use a signature of "K-PP" instead of "EMF"? Does PrintPreview depend on an existing spool file EMF extractor (print processor) not published in the forum?
I'm new here and don't know if such a disussion is wanted.

My time is very much limited, but today I'd like to have a look for the EMF header bytes because I think they don't have the correct order. I don't know however, if this is a wanted post here in this forum. I derive this at least from the fact that you use a signature different from MS standard. This could simply be a mistake or merely a wanted feature. I think that kind of EMF handling in PrintPreview doesn't differ from the original without a special reason.
norbert
Active Member
Active Member
 
Posts: 17
Joined: May 13th, 2006, 8:49 am
Location: Germany

Postby Kambiz » May 15th, 2006, 1:59 pm

I got a bit confused by your post.

PrintPreview doesn't keep or export pages as a single metafile. The TMetafileList class keeps pages in a stream of saved metafiles. Therefore the signature is not related to the metafile, but also it's the signature of the whole stream, and the format can be described as folloe:

Code: Select all
[SIGNATURE]
[NUMBER OF METAFILES]
[METAFILE 1 OFFSET]
[METAFILE 2 OFFSET]
.
.
.
[METAFILE N OFFSET]
[METAFILE 1]
[METAFILE 2]
.
.
.
[METAFILE N]
Kambiz
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2429
Joined: March 7th, 2003, 7:10 pm

Postby norbert » May 15th, 2006, 4:15 pm

Oh yes, then it's also clear to me why You don't read the metafile header first but the integer (data) address offsets of the metafiles instead. That's also why I constated on the fly that You might be using a metafile header different from MS standard.

The metafiles I produce with my cad program, however, rely on standard MS structures, but they may each contain a list of metadata, too. The meta contents of one .SPL meta file are signed by startbytes and extracted from the generated .spl spool file as single standard .emf meta files.

I'm doing it the following way in my print processor:

Code: Select all
// 6 emf Header Bytes suchen - detect six emf header bytes
function fDetectHeaderBytes(InFileName: String) : string;
var i      : Integer;
    F      : TFileStream; // .spl file
    Head   : EMFheader;
    strTmp : string;
    Buf    : array[0..5] of char; // die 6 Bytes - six emf header bytes
begin
  F:= TFileStream.Create(InFileName, 0);
  // SPL Signatur lesen - Read SPL signature
  F.Read(i, 4);
  if i <> $00010000 then begin
    // bad file -> abort
    MessageBox(0, 'Ungültige Spool Datei.', 'Fehler', mb_Ok or  mb_DefButton1); //Invalid file message
    F.Free;
    Exit;
  end;

//Notice: The following lines remind me on Your code: :-)

  // Ersten EMF Chunk binär lesen - Read first emf chunk
  F.Read(i, 4);
  F.Position := i;
  F.Read(Head, sizeof(Head));
  if (Head.Signature <> EMFheaderSignature) or (Head.EMFsize = 0) then begin
    // ungültige Datei - bad file
    MessageBox(0, 'Ungültige Spooldatei ohne EMF Header.', 'Fehler', mb_Ok or mb_DefButton1); //SPL file without header
    Buf := '';
  end else
    f.ReadBuffer(Buf, SizeOf(Buf));
  F.Free;
  // Der Buffer enthält die 6 gesuchten Bytes - Buf contains the six emf header bytes
  for i:=0 to length(Buf) - 1 do
    strTmp := strTmp + Buf[i];
  fDetectHeaderBytes := strTmp;
end;


I see I'd have either to add the TMetafileList Class structure to my EMF files or just to keep the PrintPreview code changed to the needs of my EMF data. Normally, there is only one single emf file extracted. So a list is not even necessary in my special case.

If somebody may be interested in getting PrintPreview suitable to single standard meta files in .emf format I would be pleased, because PrintPreview seems to be an excellent base and sample.

Thank you very much for Your answer, Kambiz.

Norbert
norbert
Active Member
Active Member
 
Posts: 17
Joined: May 13th, 2006, 8:49 am
Location: Germany

Postby Kambiz » May 15th, 2006, 4:35 pm

I'm wondering why you changed the PrintPreview code. The metafile of each page is accessible via Pages property.
Kambiz
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2429
Joined: March 7th, 2003, 7:10 pm

Postby norbert » May 15th, 2006, 8:17 pm

Kambiz,

I have to explain some more details of my current project:

I wrote a virtual printer driver for use with my own cad program. I had to do it because more and more 'modern' printer drivers are faulty or even don't use original EMF from MS but a clone from 'Atis' or similiar, just don't remember the exact name, as discussed in 'NT Insider' forum.
I don't want to make my cad program a multimedia player for those cheap 'modern' printers. So I decided to use the pure MS EMF spool files as a source for an additional print processor which extracts the emf contents from the spl file and shows it in an additional preview generated interactively with my cad program. Thus, in all cases, I have only to add 'correcting' code to the print processor source to be able to send the meta file to any printer, even via LAN or internet. Recompilation of the CAD program is not necessary. The only thing to be done is an acceptable precice preview which only has to be able to move, scale an rotate the image and place it correctly inside the printable area of the just active printer.
When I saw Your code I was at once pleased with it but had to aknowledge that most of it cannot be used for my project. The first error I ran into was that I was shure You let load a single EMF with the menu 'Load *.*' command.
Additionally, I don't need a preview list because there is always only one single EMF to be extracted from the spool file. .EMF is not really a standard file format. So it is quite useless to offer EMF load to the preview tool in my special case. You printpreview helps me a lot with all formal things like units calculation and so on. My CAD program uses mm_hienglish or even mm_loenglish for the big paper sizes just not to get an overflow with the 32767 API limitation. Therefore, I currently tend to using only the preview part and add it simply to my print processor.

And now we both come to a limit set by MS:
As on optimal solution I need to create a background EMF image showing the contours of the paper, for instance DIN A0, the printable area rect and it's offset to the paper frame, and all that derived from the current printer.
Then, I'd like to overlay this image with another image and the drawing contents of the spooler EMF, move it, rotate it and scale it exactly to the printable area. In CAD this is simply done using real world coordinates, but externaly I have to achieve it with the limitations of graphics programming. (one of my plotters here has a printable area up to 30 meters length an 1,50 meters width.)

But as always in graphics programming, the 'VISIBLE' problem kink reveals as a big blocker.
Perhaps I'll manage a similiar solution using Your code showing at least the printable area. By the way, is it possible to contribute a visible frame to a Delphi image object? I never tested it but just don't see it as an option in the object inspector. (i think normally via API?)

I have also to explain why I'm not willing to use .net programming languages: I don't want to loose my independency to a monopolistic concern. in future no authority, no company can afford relying on only one single concern. So I always decided to use compilers having a sharp look from outside into the API of Windows. Well, I have been a programmer since 1969! and retired from my CEO business, but I'm still active and will remain active as long as I can.

Norbert
norbert
Active Member
Active Member
 
Posts: 17
Joined: May 13th, 2006, 8:49 am
Location: Germany

Postby Kambiz » May 16th, 2006, 12:04 am

I'm very pleased to know about you and your project. And, it's very nice to hear after 37 years programming, you are still an active programmer.
Kambiz
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2429
Joined: March 7th, 2003, 7:10 pm


Return to DELPHI AREA Projects

Who is online

Users browsing this forum: No registered users and 2 guests

cron