Solved

Help on metafiles

Posted on 2001-08-23
24
696 Views
Last Modified: 2013-11-20
Hi all!

I have programmed an application that display 1D and 2D plots. In this application I'm using MM_TWIPS mapping mode to get a WYSIWYG interface with zooming capabilities. All this works just fine.
Now I want to copy the graphics to the clipboard as an enhanced metafiles but until now I wasn't able to get it to work correctly. The following is the code I'm using, pretty simple:

void CMyView::OnCopyMetafile()
{

     CMetaFileDC * m_pMetaDC = new CMetaFileDC();
     //draw meta file
     CClientDC clientDC(this);
     OnPrepareDC(&clientDC);
     m_pMetaDC->CreateEnhanced(&clientDC,NULL,NULL,"whatever");
     
     
     m_pMetaDC->m_hAttribDC = clientDC.m_hDC;

     
     OnDraw(m_pMetaDC);
     
     //close meta file dc and prepare for clipboard;
     HENHMETAFILE hMF = m_pMetaDC->CloseEnhanced();

     //copy to clipboard
     OpenClipboard();
     EmptyClipboard();
     ::SetClipboardData(CF_ENHMETAFILE,hMF);
     CloseClipboard();
     //DeleteMetaFile(hMF);
     delete m_pMetaDC;
     
}

This code used to work properly in older versions of my application in which I used MM_TEXT mapping mode. However, with MM_TWIPS, after pasting the metafile into MS Word, I get an inversed metafile along the Y-axis.
I also had to use a little trick in order the metifle DC to support GDI functions such as LPtoDP, GetClipBox and others. This trick was the line m_pMetaDC->m_hAttribDC = clientDC.m_hDC;


Any idea about how to solve this problem?

Thanks,
Carlos
0
Comment
Question by:qocarlos
  • 14
  • 9
24 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 6419888
I hae not worked with MM_TWIPS, but...

from Q180330:

A non-normalized rectangle can often be produced unintentionally if you use mapping modes other than MM_TEXT.

MM_HIENGLISH, MM_LOENGLISH, MM_HIMETRIC, MM_LOMETRIC, and MM_TWIPS cause the y-axis to have the reverse direction of that for the default mapping mode (MM_TEXT). This can result in non- normalized RECTs.

When you specify to draw the metafile, try swapping the rc.top and rc.bottom in the destination rectangle.

-- Dan
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6419893
Also in CDC::SetMapMode, it explictly states:

MM_TWIPS   Each logical unit is converted to 1/20 of a point. (Because a point is 1/72 inch, a twip is 1/1440 inch.) Positive x is to the right; positive y is up.

(see the last clause of the last sentence)

-- Dan
0
 
LVL 3

Author Comment

by:qocarlos
ID: 6419969
Hi Dan,

Thanks for your comments. I've tried to swap the top and bottom in the destination rectangle but I'm getting the same result :-(
I know that in MM_TWIPS positive y is up. Everything works correctly while drawing both in the screen and in the printer but not in the metafile.
Is there any special issue regarding metafiles? I can't find anything useful in the documentation.

Thanks,
Carlos
0
 
LVL 3

Author Comment

by:qocarlos
ID: 6420014
More information ...
I'm using a printing framework from codeguru. If you want to reproduce my problem you can download a sample application from this link:

http://www.codeguru.com/printing/textbmp.shtml

(if you want to build the sample app with VC 6.0 you have to make the changes commented in http://www.codeguru.com/mfc/comments/7759.shtml)

Then you can add exactly the code I wrote in my question (CMyView::OnCopyMetafile() ) and you will see the problem I'm having ...



0
 
LVL 3

Author Comment

by:qocarlos
ID: 6420019
More information ...
I'm using a printing framework from codeguru. If you want to reproduce my problem you can download a sample application from this link:

http://www.codeguru.com/printing/textbmp.shtml

(if you want to build the sample app with VC 6.0 you have to make the changes commented in http://www.codeguru.com/mfc/comments/7759.shtml)

Then you can add exactly the code I wrote in my question (CMyView::OnCopyMetafile() ) and you will see the problem I'm having ...



0
 
LVL 3

Author Comment

by:qocarlos
ID: 6420022
I believe this question is hard, so I feel like I should increase the points.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6420281
It does not fail when I test it.

I used the ClassWizard to add an OnEditCopy() handler to the CTextbmpView class.  I then pasted your code verbatim into that function.

I then run the program and choose Edit/Copy.  When I go to Ms Word and choose Paste, the image comes out right side up.

However, it is pretty clear that this code uses MM_TEXT.  Where have you changed it in you version so that it uses MM_TWIPS?

Also, why are you using MM_TWIPS?

-- Dan
0
 
LVL 3

Author Comment

by:qocarlos
ID: 6422258
Hi Dan,

I did something wrong in the metafile code I wrote here. I forgot to include the following line:

m_pMetaDC->m_hAttribDC = clientDC.m_hDC;
m_pMetaDC->m_bPrinting = true; //I FORGOT THIS LINE

Why am I adding this line? because the metafile I want to export should be equivalent to the printer version of the view.

In all my OnDraw() functions I have code like this:

if (!pDC->IsPrinting())
{
(...)
}

The code inside this condition shouln't be either executed when the DC is a metafile.

Is there a way to know if the device context corresponds to a metafile? i.e. I'd like to do something like this:

if (!pDC->IsPrinting() && pDC->IsMetafile())
{
(...)
}


Besides this clarification, there is something I don't understand. You say that "it is pretty clear that this code uses MM_TEXT". I don't see that. AFAIK, the code uses MM_TWIPS. It onl uses MM_TEXT to BitBlt the Bitmap in the OnDraw() function. The code sets the mapping mode to MM_TWIPS in function SetScreenGlobals().

Thanks,
Carlos
0
 
LVL 12

Expert Comment

by:migel
ID: 6422911
Hi!
did you try ajust drawing org/extents (that is call SetViewPortOrg SetWindowOrg) before calling OnDraw?
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6423649
>>It onl uses MM_TEXT to BitBlt the Bitmap in the OnDraw() function.

Yes, that is why I said that.  But coudn't that be the core of the problem?

-- Dan
0
 
LVL 3

Author Comment

by:qocarlos
ID: 6426522
Hi,

If I don't use the line
m_pMetaDC->m_bPrinting = true;

what I get is a metafile which displays exactly the same contents as the view, but this is not what I want. I want to create a metafile that representes exactly the same content as the print preview.
The main problem is I don't want a metafile with the screen resolution but with the printer resolution because if the user wants to print the bitmap out from MS Word, he will get a poor resolution plot.

I tried to use create a printer device context instead of using CClientDC, but this wasn't fix the problem.

This is the new code:

void CMyView::OnCopyMetafile()
{
     CMetaFileDC * m_pMetaDC = new CMetaFileDC();
     //Get printer DC
     CDC dc;
     CPrintDialog dlg(FALSE);
     if (AfxGetApp()->GetPrinterDeviceDefaults(&dlg.m_pd))
     {
          // GetPrinterDC returns a HDC so attach it
         
          HDC hDC= dlg.CreatePrinterDC();
          ASSERT(hDC != NULL);
          dc.Attach(hDC);
     }

     
     OnPrepareDC(&dc);
     m_pMetaDC->CreateEnhanced(&dc,NULL,NULL,"whatever");
     
     
     m_pMetaDC->m_hAttribDC = dc.m_hDC;
     
     m_pMetaDC->m_bPrinting = true;
     
     OnDraw(m_pMetaDC);
     
     //close meta file dc and prepare for clipboard;
     HENHMETAFILE hMF = m_pMetaDC->CloseEnhanced();
     
     //copy to clipboard
     OpenClipboard();
     EmptyClipboard();
     ::SetClipboardData(CF_ENHMETAFILE,hMF);
     CloseClipboard();
     delete m_pMetaDC;    
}

Could you please try this code and explain me what's wrong with it?

Thanks in advance,
Carlos
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6427133
I think you are on the wrong track.

Remember, you are capturing a MetaFile and not a bitmap.  That means that a drawing command such as

  pDC->RoundRect( 500, -3000, 4500, -5000, 1000, 1000 );

is recorded as a command, and not low-res or hi-res image of a rounded-corner rectangle.

There is no need to mess with the IsPrinting flag.  When a program renders that metafile into a DC, the command will be executed in a way that makes sense of the device.

So, I'm saying it works perfectly.  I have copied the metafile (without the IsPrining turned on), and pasted it into Ms Word and the result prints out very nicely.  It even shows that tiny little circle that is produced when you left-click.

But I really do understand that there is something you are seeing that makes you think that it is broken.    So...

Please explain, in the most precise, descriptive language possible, exactly what bad thing is happening.  

I might be able to figure out why it is happening, or describe how to make it look better, or explain why it is not really bad after all.

-- Dan
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 3

Author Comment

by:qocarlos
ID: 6428272
Hi Dan,

Sorry for not being able to explain clearly what's the problem I'm having. English is not my mother language but I'm trying to do my best ...

You say that it works perfectly. After pasing the metafile in Word and if you enlarge it (eg. make the metafile twice of big), does the result still print out nicely? In addition, I don't want to draw the paper borders and I would liket to obtain the full page in the metafile, I would like to get the same result as the print preview's (the whole page fits on the paper).

I believe the best way to explain my problem is sending the executable of my application to you so you can see exactly what's my problem. My email is qocarlos@usc.es, if you send me an email I could send my application to you.
Do you agree?
Thanks again,
Carlos





0
 
LVL 3

Author Comment

by:qocarlos
ID: 6428275
Oops, when I said "After pasing the metafile ...." I wanted to say "After pasting the metafile ..."
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6431071
I sent you email.  I'll look at the project.  

>>I would like to obtain the full page in the metafile

This is the kind of thing I don't understand.  It seems to me that the metafile should contain whatever you drew.  Word will scale it up or down.  Whether it gets shunk down to 1-inch by 1-inch or expanded to fill a full page later should not make any difference.

-- Dan
0
 
LVL 3

Author Comment

by:qocarlos
ID: 6440824
Hi Dan,

Did you receive my application? Is there anything else I should explain?
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6442053
Yes, I got it gocarlos.  Sorry, I've been tied up. I should be able to look at it tonight.  However, if you sent just the EXE, well, chances that I can help are about halfway between slim and none.

-- Dan
0
 
LVL 3

Author Comment

by:qocarlos
ID: 6443280
Hi Dan,
I believe it really makes no difference if I send you the whole project with the source code or just the EXE, because the problem I have can be reproduced with the Codeguru sample app. Did you try to print a metafile created from my app? Did you note that the resolution is really poort (actually you get screen resolution) ? Anyway, I could send you the full application with the source code if you believe this is important to solve my problem.

Thanks,
Carlos
0
 
LVL 3

Author Comment

by:qocarlos
ID: 6443281
Hi Dan,
Don't worry, there is no rush :-)
I believe it really makes no difference if I send you the whole project with the source code or just the EXE, because the problem I have can be reproduced with the Codeguru sample app. Did you try to print a metafile created from my app? Did you note that the resolution is really poor (actually you get screen resolution) ? Well, I could send you the full application with the source code if you believe this is important to solve my problem.

Thanks,
Carlos
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 200 total points
ID: 6443745
There are numerous problems, as you know.  The resizing is messed up.  WHen you resize the MDI child, the graph also resizes.  I don't know what that's all about.

But the real problem is that you are making a metafile of the entire view and not just the graph.

Try this.  Resize the MDI child window until it is about 3 inches by 4 inches.  Now play around with the handles on the corners of the graph until it fits the window pretty closely.  Then copy the metafile to the clipboard and paste it in WORD.

The result is that it looks very nearly correct -- except for the parts of the MDI child gray background.

When you make the Metafile, set the Draw routine so that it only captures the graph ... not the drawing of the entire MDI child client area.  

That will fix your problems
.
-- Dan

P.S it is not upside down or inverted in any way.
0
 
LVL 3

Author Comment

by:qocarlos
ID: 6445404
Thanks, I will try it out this weekend and let you know the results.

Carlos
0
 
LVL 3

Author Comment

by:qocarlos
ID: 6453831
Hi Dan,
I have almost fixed it. I still have some problems but I don't have the time to solve them right now. I'll be back to them later on ...
I have an additional question related to this one, can you help me out? I can increase the points here or create a new question, just let me know what you prefer.
The problem is the following. In the sample application from codeguru, how can I get the device-context of the view? i.e. I'm trying to directly draw in my view from a dialog outside of a WM_PAINT handler.

Normally I'd do it using this method:


CMyDialog::SomeFunction()
{
   CMyView* pView: GetMyView(); //This function just returns a pointer to the view I want to draw in
   CDC* pDrawDC;
   pDrawDC = pView->GetDC();
   ASSERT_VALID(pDrawDC);
   //Drawing code will go here
   pView->ReleaseDC(pDrawDC);
}

But now this doesn't work because this DC uses the default metrics mode (MM_TEXT) and I want to reuse all the page setup implemented in the view.
Is there another way?

Thanks,
Carlos
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6454428
>>I'm trying to directly draw in my view from a dialog outside of a WM_PAINT handler.

This is not recommended.  Why?  Because the WM_PAINT handler won't know that you have drawn there.  For instance, let's say your CMyDialog::SomeFunction() draws a diaagonal red line across the graph.  Now you drag another app's window acrosss your own or pop up Word the pop it down, or whatever.  When your app is asked to refresh its screen, it will not draw that diagonal red line.

So the recommended way to add some lines or whatever to the view would be to, perhaps, create a fn and have OnDraw call it.  You just pass the CDC that have there.

CMyView::OnDraw( CDC* pCDC)
{
 ... all the stuff that is there...
 AddSomeOtherStuff(pCDC);
}

CMyView::AddSomeOtherStuff( CDC* pCDC)
{
  .. draw a diagnonal line, the DC is all set as needed...
}

Now I can conceive of some case where you would *want* the stuff you draw to be temporary (some sort of animation to blink the graph handles or something).  I think that you would need to just be careful to set up your DC to match the same settings as used in the OnDraw() fn

-- Dan
0
 
LVL 3

Author Comment

by:qocarlos
ID: 6454819
Hi Dan,
Thanks for your comment.
Yes, I need to do a sort of temporary draws, they don't have to persist along all the time. I found a workaround and now is working properly.

Carlos
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Introduction: Displaying information on the statusbar.   Continuing from the third article about sudoku.   Open the project in visual studio. Status bar – let’s display the timestamp there.  We need to get the timestamp from the document s…
Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now