draw rotated bitmap with wxGCDC Topic is solved

Talk here about issues with one of the components hosted at wxCode, or suggest features for it.
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

draw rotated bitmap with wxGCDC

Post by mael15 »

Hi,
I fail to be able to use wxGCDC with a wxPdfDC.
When painting to the screen I use

Code: Select all

wxBufferedPaintDC dc(this);
wxGCDC gcdc(dc);
and can rotate the wxGCDC as i wish. But the wxPdfDC cannot be used with wxGCDC.
How can I draw using a rotated wxDC?
User avatar
doublemax
Moderator
Moderator
Posts: 19102
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: draw rotated bitmap with wxGCDC

Post by doublemax »

Please provide some more information.

If i puzzle the pieces together, i assume you're using wxDC::SetTransformMatrix() which is not supported by wxPdfDC?

However, this would mean that your question has nothing to do with wxGCDC?
Use the source, Luke!
utelle
Moderator
Moderator
Posts: 1125
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: draw rotated bitmap with wxGCDC

Post by utelle »

mael15 wrote: Fri Jul 19, 2019 3:19 pm I fail to be able to use wxGCDC with a wxPdfDC.
wxGCDC uses a wxGraphicsContext internally, but provides a wxDC API externally. wxPdfDC is derived from wxDC and therefore lacks support for the wxGraphicsContext API.

There were plans to implement a wxPdfGraphicsContext derived from wxGraphicsContext, but unfortunately up to now it is not available.
mael15 wrote: Fri Jul 19, 2019 3:19 pm When painting to the screen I use

Code: Select all

wxBufferedPaintDC dc(this);
wxGCDC gcdc(dc);
and can rotate the wxGCDC as i wish. But the wxPdfDC cannot be used with wxGCDC.
How can I draw using a rotated wxDC?
wxPdfDC was first created based on wxWidgets 2.8.x. Back then wxDC did not have methods to manipulate a transformation matrix. Up to now support for manipulating the transformation matrix was not added to wxPdfDC. In principal, however, it should be possible to add such support, because the underlying wxPdfDocument instance supports various transformations.
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: draw rotated bitmap with wxGCDC

Post by mael15 »

doublemax wrote: Fri Jul 19, 2019 4:21 pm If i puzzle the pieces together, i assume you're using wxDC::SetTransformMatrix() which is not supported by wxPdfDC?
What I mean is I cannot create a wxGCDC from a wxPdfDC.
utelle wrote: Sat Jul 20, 2019 11:49 am Up to now support for manipulating the transformation matrix was not added to wxPdfDC.
The only two things I do with wxGDC are SetDeviceOrigin and GetGraphicsContext()->Rotate but I guess the later uses a transformation matrix internally? Is there any way to draw after roating the wxPdfDc? Or maybe draw an unrotated bitmap and copy it rotated to the wxPdfDc? Or do I have to draw on a bitmap including rotation and copy to wxPdfDc after?
utelle
Moderator
Moderator
Posts: 1125
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: draw rotated bitmap with wxGCDC

Post by utelle »

mael15 wrote: Mon Jul 22, 2019 8:05 am What I mean is I cannot create a wxGCDC from a wxPdfDC.
And it is very unlikely that this will ever be possible, because wxGCDC is part of wxWidgets itself while wxPdfDocument is not.
mael15 wrote: Mon Jul 22, 2019 8:05 am
utelle wrote: Sat Jul 20, 2019 11:49 am Up to now support for manipulating the transformation matrix was not added to wxPdfDC.
The only two things I do with wxGDC are SetDeviceOrigin and GetGraphicsContext()->Rotate but I guess the later uses a transformation matrix internally?
Correct.
mael15 wrote: Mon Jul 22, 2019 8:05 am Is there any way to draw after roating the wxPdfDc? Or maybe draw an unrotated bitmap and copy it rotated to the wxPdfDc? Or do I have to draw on a bitmap including rotation and copy to wxPdfDc after?
The only approach based on the current implementation of wxPdfDC, I can imagine, is to use the template mode of wxPdfDC. That is, a drawing is created with wxPdfDC in template mode without applying any rotation. Then the generated template can be added to a wxPdfDocument using the rotation as needed (see templates sample coming with wxPdfDocument).
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: draw rotated bitmap with wxGCDC

Post by mael15 »

utelle wrote: Tue Jul 23, 2019 6:37 pm The only approach based on the current implementation of wxPdfDC, I can imagine, is to use the template mode of wxPdfDC
Okay, thank you, I hope it will be possible to use wxGCDC some time in the future. Until then I will draw incl. rotation to a wxMemoryDC and copy it to the wxPdfDc after.
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: draw rotated bitmap with wxGCDC

Post by mael15 »

One more question about wxPdfDC: DrawBitmap takes ~7 seconds for a 4700x5800px bitmap. Is there any way to speed it up?
utelle
Moderator
Moderator
Posts: 1125
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: draw rotated bitmap with wxGCDC

Post by utelle »

mael15 wrote: Wed Jul 31, 2019 8:42 am One more question about wxPdfDC: DrawBitmap takes ~7 seconds for a 4700x5800px bitmap. Is there any way to speed it up?
Well, your bitmap seems to be rather large. And unfortunately bitmaps can't be transferred to PDF directly. They have to be converted to a known graphics format like PNG or JPEG. wxPdfDC: DrawBitmap converts a wxBitmap object to a wxImage object first, and then converts the wxImage to JPEG format. Most likely this conversion process is responsible for most of the processing time. If this is the case, there is not much I can do about it, although 7 seconds really sounds very long.

There might be other factors playing a role, but without knowing more details about your application it is hard to tell, why it takes so long.
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: draw rotated bitmap with wxGCDC

Post by mael15 »

utelle wrote: Wed Jul 31, 2019 9:09 am Well, your bitmap seems to be rather large. And unfortunately bitmaps can't be transferred to PDF directly. They have to be converted to a known graphics format like PNG or JPEG. wxPdfDC: DrawBitmap converts a wxBitmap object to a wxImage object first, and then converts the wxImage to JPEG format. Most likely this conversion process is responsible for most of the processing time. If this is the case, there is not much I can do about it, although 7 seconds really sounds very long.

There might be other factors playing a role, but without knowing more details about your application it is hard to tell, why it takes so long.
Hmmmm, the pdf hast a 600dpi resolution, so a standard din a 4 page results in this bitmap size. Can I skip some conversions and/or use some other drawing method? What could be relevant details that I can tell you about my application? I use a very fast machine with lots of cpu and ram.
utelle
Moderator
Moderator
Posts: 1125
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: draw rotated bitmap with wxGCDC

Post by utelle »

mael15 wrote: Wed Jul 31, 2019 9:15 am Hmmmm, the pdf hast a 600dpi resolution, so a standard din a 4 page results in this bitmap size.
In fact, PDF files don't have a single DPI value, because PDF is a vector format. That is, vector objects like text have no resolution at all. Only bitmap objects have an associated resolution.

Generating a bitmap of a whole page with 600 DPI first, and then embedding such a bitmap per page seems not to be the right approach for using wxPdfDC.
mael15 wrote: Wed Jul 31, 2019 9:15 am Can I skip some conversions and/or use some other drawing method?
As can be seen from the wxPdfDC sample coming with wxPdfDocument, a wxPdfDC drawing context can be used almost in the same way as an onscreen drawing context. That is, one can place text, draw lines, place bitmaps, and so on.

You may have reasons for your approach to create a bitmap of a whole page first, but then you don't take advantage of the PDF vector drawing capabilities.
mael15 wrote: Wed Jul 31, 2019 9:15 am What could be relevant details that I can tell you about my application? I use a very fast machine with lots of cpu and ram.
As I said 7 seconds indeed seem to be a very long time for the task. Therefore the first step would be to track down which step exactly causes the long processing time: (a) conversion from wxBitmap to wxImage, (b) conversion from wxImage to JPEG, or (c) adding the JPEG to PDF. Only (c) can be influenced by the wxPdfDocument implementation.

If you could isolate the code exposing the problem as a small sample application, you could send it to me via private mail/message and I could take a closer look.
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: draw rotated bitmap with wxGCDC

Post by mael15 »

utelle wrote: Wed Jul 31, 2019 11:39 am You may have reasons for your approach to create a bitmap of a whole page first, but then you don't take advantage of the PDF vector drawing capabilities.
Well, yes, as we discussed in this thread, I need to rotate everything I draw, but wxPdfDC does not support wxGCDC so I have to use wxGCDC with a wxMemoryDC, draw rotated stuff to a large bitmap and then copy the large bitmap to wxPdfDC.
utelle wrote: Wed Jul 31, 2019 11:39 am (a) conversion from wxBitmap to wxImage, (b) conversion from wxImage to JPEG, or (c) adding the JPEG to PDF. Only (c) can be influenced by the wxPdfDocument implementation.
The visual studio profiler seems to point to png_write_rows as the main problem.

Here is a sample code that took 3817ms on my machine:

Code: Select all

	wxPdfDocument pdfDcmt;
	pdfDcmt.AddPage(wxPORTRAIT, wxPAPER_A4);
	int tpl = pdfDcmt.BeginTemplate();
	wxPdfDC *dc = new wxPdfDC(&pdfDcmt, 210, 297);
	dc->SetResolution(600);
	dc->SetBackground(*wxWHITE_BRUSH);

	if (dc->StartDoc(wxT("Printing ...")))
	{
		wxBitmap drawBtmp(5000, 5000);
		wxMemoryDC mdc(drawBtmp);
		mdc.SetBackground(*wxCYAN);
		mdc.Clear();
		mdc.SelectObject(wxNullBitmap);

		wxStopWatch sw;
		dc->DrawBitmap(drawBtmp, wxPoint(10, 10));
		sw.Pause();
		OutputDebugString(wxString::Format(wxT("DrawBitmap took %ldms\n"), sw.Time()));

		dc->EndDoc();
	}

	delete dc;
	pdfDcmt.EndTemplate();
	pdfDcmt.UseTemplate(tpl);

	wxString filename = wxGetUserHome() + wxT("\\Desktop\\pdfTest.pdf");
	pdfDcmt.SaveAsFile(filename);
	wxLaunchDefaultApplication(filename);
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: draw rotated bitmap with wxGCDC

Post by mael15 »

So I could reduce draw time by reducing the resolution (obviously), but I noticed one funny thing: wxMask does only work in my app 209dpi upwards. This is not the case with the sample code in the previous post. Is there any restriction, maybe bitmap size?
utelle
Moderator
Moderator
Posts: 1125
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: draw rotated bitmap with wxGCDC

Post by utelle »

mael15 wrote: Wed Jul 31, 2019 1:53 pm
utelle wrote: Wed Jul 31, 2019 11:39 am You may have reasons for your approach to create a bitmap of a whole page first, but then you don't take advantage of the PDF vector drawing capabilities.
Well, yes, as we discussed in this thread, I need to rotate everything I draw, but wxPdfDC does not support wxGCDC so I have to use wxGCDC with a wxMemoryDC, draw rotated stuff to a large bitmap and then copy the large bitmap to wxPdfDC.
Could you show a sample drawing? I still think that creating a PDF template without applying rotation, and then adding the template to a wxPdfDocument instance directly and applying rotation to the template, should work smoother and faster.
mael15 wrote: Wed Jul 31, 2019 1:53 pm
utelle wrote: Wed Jul 31, 2019 11:39 am (a) conversion from wxBitmap to wxImage, (b) conversion from wxImage to JPEG, or (c) adding the JPEG to PDF. Only (c) can be influenced by the wxPdfDocument implementation.
The visual studio profiler seems to point to png_write_rows as the main problem.
Ah, I see. This is one thing I simply forgot: the default image type wxPdfDC uses as the target format for bitmaps is PNG (not JPEG as I wrote before). Changing the default image type to JPEG with the following line of code after creating the wxPdfDC instance

Code: Select all

  dc->SetImageType(wxBITMAP_TYPE_JPEG);
cuts down the processing time roughly by a factor of 4 on my test machine. However, about 1 second is still a rather long time.

Therefore I would strongly recommend to try the template approach mentioned above.

P.S.:
I will consider to add support for setting a transformation matrix to wxPdfDC, but it may take some time to implement this feature properly.
utelle
Moderator
Moderator
Posts: 1125
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: draw rotated bitmap with wxGCDC

Post by utelle »

mael15 wrote: Wed Jul 31, 2019 4:17 pm So I could reduce draw time by reducing the resolution (obviously), but I noticed one funny thing: wxMask does only work in my app 209dpi upwards. This is not the case with the sample code in the previous post. Is there any restriction, maybe bitmap size?
Sorry, I don't know the answer to this question. Most likely this is a question you will have to ask one of the wxWidgets developers. You can do this by posting to the wxWidgets mailing list: [email protected].
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: draw rotated bitmap with wxGCDC

Post by mael15 »

utelle wrote: Wed Jul 31, 2019 5:59 pm Could you show a sample drawing?
Here is one, it is 600dpi, only the circles bitmap took 7.7 seconds to draw to wxPdfDC. As you can see not everything on the page needs to be rotated.
sampleOver7sec.zip
utelle wrote: Wed Jul 31, 2019 5:59 pm I still think that creating a PDF template without applying rotation, and then adding the template to a wxPdfDocument instance directly and applying rotation to the template, should work smoother and faster.
You are absolutely right, I just were too lazy to try this and stuck to the ways I knew. Thanx for mentioning it again. I just have to figure out how to position everything correctly and how transparency works, but that should be managable.
Thanx!
Post Reply