wxPDFDocument: bitmaps on consecutive pages Topic is solved
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
wxPDFDocument: bitmaps on consecutive pages
Hi,
I have a weird problem: two bitmaps are supposed to be copied on two consecutive pages, like this: but what actually happens is that the second bitmap uses the pixels of the first one. position and dimensions are correct, just not the data.
this is the resulting pdf: https://drive.google.com/file/d/1VCLHkc ... sp=sharing
when i save the bitmaps in a file right after drawing them to the pdf, they are drawn correctly, they just not appear like this in the pdf. the problem stays the same when I switch pages, the one on the first page is repeated on the second.
what might be wrong?
I have a weird problem: two bitmaps are supposed to be copied on two consecutive pages, like this: but what actually happens is that the second bitmap uses the pixels of the first one. position and dimensions are correct, just not the data.
this is the resulting pdf: https://drive.google.com/file/d/1VCLHkc ... sp=sharing
when i save the bitmaps in a file right after drawing them to the pdf, they are drawn correctly, they just not appear like this in the pdf. the problem stays the same when I switch pages, the one on the first page is repeated on the second.
what might be wrong?
Re: wxPDFDocument: bitmaps on consecutive pages
Without seeing the code that was used to produce the PDF it is impossible to tell what exactly went wrong. Looking at the internals of the PDF it seems that you used the template feature of wxPdfDocument to produce the PDF file. There are 2 template objects which both refer to the same image (bitmap) data - this explains why the same bitmap is used on both pages. So, I suspect that the code to generate the PDF uses the template feature somehow incorrectly.mael15 wrote: ↑Sun Jul 19, 2020 11:13 am I have a weird problem: two bitmaps are supposed to be copied on two consecutive pages, like this:
twoPages.jpg
but what actually happens is that the second bitmap uses the pixels of the first one. position and dimensions are correct, just not the data.
this is the resulting pdf: https://drive.google.com/file/d/1VCLHkc ... sp=sharing
when i save the bitmaps in a file right after drawing them to the pdf, they are drawn correctly, they just not appear like this in the pdf. the problem stays the same when I switch pages, the one on the first page is repeated on the second.
what might be wrong?
Please show your code (or send it to me in a private message if it is confidential) for further inspection. Thanks.
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPDFDocument: bitmaps on consecutive pages
thanx, I know it is hard without the code, it just is so fragmented that hours of trying to create a minimal version did not work out. Yes, I use the template feature (not sure why though). is there an example of how to use it correctly?
Re: wxPDFDocument: bitmaps on consecutive pages
Again, without code there is only wild guessing what might be wrong ...
The file templates.cpp in the samples/minimal directory of the wxPdfDocument distribution shows template examples. Maybe you could modify the sample to reproduce what you are doing in your own application. There is always a chance that there is still a bug in wxPdfDocument, although it is not very likely.
Typically, you create a template by starting a new one using method BeginTemplate, then writing all elements which should be part of the template, and eventually finalizing the template by calling method EndTemplate. Thereafter use method UseTemplate to show the template on a page.
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPDFDocument: bitmaps on consecutive pages
i there a documentation about when to use templates at all? I suspect I do not need them. It is so long ago that I started using them that I do not remember why I did it.
Re: wxPDFDocument: bitmaps on consecutive pages
Unfortunately, no. However, from the template sample it should get clear that using a template makes sense, if you want for example to use the same (complex) element over and over again in the same PDF. Instead of creating the same element multiple times - and thus increasing the size of the resulting PDF - you can reuse the template as often as you need, but the template data are only saved once to the PDF. Another use case is, if you want to create a graphics element using wxDC. Then you create a wxPdfDC in template mode and can use the graphics generated by the wxDC resp wxPdfDC class as a template.
If you simply want to add wxImage or wxBitmap graphics to a PDF, then you don't need templates. With teh Image method you can add graphics files or wxImage instances directly to a PDF document.
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPDFDocument: bitmaps on consecutive pages
That seems to be the cause of my problem.
That is what I am doing, so I need templates.
Here is the most upper level of my code, am I using templates wrong?
Code: Select all
wxPdfDocument pdfDcmt;
wxFont defaultFont(wxFontInfo(10).Family(wxFONTFAMILY_DEFAULT).Underlined(false));
wxPdfFont pdfArialFont = wxPdfFontManager::GetFontManager()->RegisterFont(defaultFont, wxT("Arial"));
bool ok = pdfDcmt.SetFont(pdfArialFont);
int tpl = -1;
auto createDC = [&](){
wxSize pageSzMM = page->getPageSizeMM(papSize, orient);
if (dc)
delete dc;
dc = new wxPdfDC(&pdfDcmt, pageSzMM.x, pageSzMM.y);
dc->SetResolution(600);
dc->SetBackground(*wxWHITE_BRUSH);
};
wxProgressDialog *prog = new wxProgressDialog(_i("PDF speichern"), _i("Das PDF wird erstellt."), 100, ss->getMainFrame(), wxPD_AUTO_HIDE | wxPD_SMOOTH);
double progPerPage = 100.0 / numPrintPages, totalProg = 0;
for (unsigned int i = 1; i < pagesToPrint.size(); i++){
if (pagesToPrint.at(i)){
page = pageCont->getPage(i - 1);
orient = page->isLayoutPortait() ? wxPORTRAIT : wxLANDSCAPE;
papSize = page->isLayoutA4() ? wxPAPER_A4 : wxPAPER_A3;
pdfDcmt.AddPage(orient, papSize);
tpl = pdfDcmt.BeginTemplate();
createDC();
if (dc->StartDoc(wxT("Printing ...")))
{
//OutputDebugString(wxString::Format(wxT("Seite %i wird gedruckt\n"), i));
libClientOutput::TubeDataPrintout::printToDC(*dc, i - 1);
dc->EndDoc();
}
pdfDcmt.EndTemplate();
pdfDcmt.UseTemplate(tpl);
totalProg += progPerPage;
prog->Update(totalProg);
}
}
delete prog;
Re: wxPDFDocument: bitmaps on consecutive pages
I don't think so. If you have different templates, the data of each are saved to PDF, of course.
In your case, in the PDF document you provided, there are 2 templates. Each template references a bitmap image. For some reason, both templates reference the same bitmap image. Are the bitmap images added through wxDC/wxPdfDC code?
As far as I can tell the code seems to be correct. So, most likely the problem lies in method libClientOutput::TubeDataPrintout::printToDC. For some reason, drawing the bitmap images doesn't seem to work as expected. The question is, whether this is a bug in your application or in wxPdfDocument.mael15 wrote: ↑Mon Jul 20, 2020 2:28 pm Here is the most upper level of my code, am I using templates wrong?Code: Select all
wxPdfDocument pdfDcmt; wxFont defaultFont(wxFontInfo(10).Family(wxFONTFAMILY_DEFAULT).Underlined(false)); wxPdfFont pdfArialFont = wxPdfFontManager::GetFontManager()->RegisterFont(defaultFont, wxT("Arial")); bool ok = pdfDcmt.SetFont(pdfArialFont); int tpl = -1; auto createDC = [&](){ wxSize pageSzMM = page->getPageSizeMM(papSize, orient); if (dc) delete dc; dc = new wxPdfDC(&pdfDcmt, pageSzMM.x, pageSzMM.y); dc->SetResolution(600); dc->SetBackground(*wxWHITE_BRUSH); }; wxProgressDialog *prog = new wxProgressDialog(_i("PDF speichern"), _i("Das PDF wird erstellt."), 100, ss->getMainFrame(), wxPD_AUTO_HIDE | wxPD_SMOOTH); double progPerPage = 100.0 / numPrintPages, totalProg = 0; for (unsigned int i = 1; i < pagesToPrint.size(); i++){ if (pagesToPrint.at(i)){ page = pageCont->getPage(i - 1); orient = page->isLayoutPortait() ? wxPORTRAIT : wxLANDSCAPE; papSize = page->isLayoutA4() ? wxPAPER_A4 : wxPAPER_A3; pdfDcmt.AddPage(orient, papSize); tpl = pdfDcmt.BeginTemplate(); createDC(); if (dc->StartDoc(wxT("Printing ..."))) { //OutputDebugString(wxString::Format(wxT("Seite %i wird gedruckt\n"), i)); libClientOutput::TubeDataPrintout::printToDC(*dc, i - 1); dc->EndDoc(); } pdfDcmt.EndTemplate(); pdfDcmt.UseTemplate(tpl); totalProg += progPerPage; prog->Update(totalProg); } } delete prog;
To make it easier for me to analyze the resulting PDF document, please use
Code: Select all
pdfDcmt.SetCompression(false);
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPDFDocument: bitmaps on consecutive pages
The first one is drawn directly on the wxPdfDC and the second one is first drawn on a wxMemoryDC and then the bitmap is copied to wxPdcDC. The problem is the same when I switch the page sequence.
Here is the pdf without compression, thank you very much for your effort: https://drive.google.com/file/d/1-S59Yk ... sp=sharing
Re: wxPDFDocument: bitmaps on consecutive pages
Looking at the uncompressed PDF file I see that both templates reference the same bitmap, namely the second of 2 bitmaps. In principle, it should not make a difference whether the bitmap is drawn directly or indirectly. Nevertheless, could you please show the code used to transfer the bitmaps to the wxPdfDC instance?
Looking again at the code you use to create the templates I got an idea what might be the problem. You create a new wxPdfDC for each page. This resets the internal image counter of the wxPdfDC instance to 0. That is, drawing bitmaps on wxPdfDC uses the same internal bitmap names again. wxPdfDocument manages a list of images/bitmaps identified by names - typically the graphics file name. However, for bitmaps drawn on wxPdfDC there is no graphics file name. Therefore an artificial name is constructed consisting of a prefix string and the current image counter. Since the image counter is reset before starting the next page due to creating a new wxPdfDC instance, drawing a bitmap now reuses the already existing bitmap with the same name.
There is still something fishy. The PDF file contains 2 graphics bitmap objects, of which only the second is actually referenced from both templates. The first graphics bitmap object is not referenced at all - and that's a bit weird.
Conclusion: wxPdfDC is at least part of the problem due to using an image counter per instance. This leads to problems, if more than one wxPdfDC instance is used to create pages of the same wxPdfDocument instance, and if bitmaps are drawn on wxPdfDC.
A solution could be to use a global graphics image counter in wxPdfDC. It would be my task to implement that. And probably I should do that for the next release in any case.
However, an alternative for your application could also be to use a single wxPdfDC instance per wxPdfDocument. That is, you create the wxPdfDC instance only once before you start adding pages, instead of creating a new instance for each page. The rest of the drawing code could stay unchanged, because methods StartDoc/EndDoc, StartPage/EndPage are no-ops in template mode. However, it may be necessary to set the background color every time you start a new template.
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPDFDocument: bitmaps on consecutive pages
sure, it is just a really simpleutelle wrote: ↑Tue Jul 21, 2020 8:27 am Looking at the uncompressed PDF file I see that both templates reference the same bitmap, namely the second of 2 bitmaps. In principle, it should not make a difference whether the bitmap is drawn directly or indirectly. Nevertheless, could you please show the code used to transfer the bitmaps to the wxPdfDC instance?
Code: Select all
dc->DrawBitmap(*getBitmap(false), pos, true);
I do that because it is possible that different page layouts/sizes are combined in one multi page pdf. I my case these are DIN A2/3/4 and landscape/portrait.
I use this function to determine the template size
Code: Select all
static wxSize getPageSizeMM(wxPaperSize papSize = wxPAPER_A4, wxPrintOrientation orient = wxPORTRAIT) {
wxSize ret = wxDefaultSize;
switch (papSize) {
case wxPAPER_A2:
ret.x = orient == wxPORTRAIT ? 420 : 594;
ret.y = orient == wxPORTRAIT ? 594 : 420;
break;
case wxPAPER_A3:
ret.x = orient == wxPORTRAIT ? 297 : 420;
ret.y = orient == wxPORTRAIT ? 420 : 297;
break;
case wxPAPER_A4:
default:
ret.x = orient == wxPORTRAIT ? 210 : 297;
ret.y = orient == wxPORTRAIT ? 297 : 210;
break;
}
return ret;
}
Can I change the page size in one existing wxPdfDC?
Re: wxPDFDocument: bitmaps on consecutive pages
As expected ... but it doesn't explain, why you have 2 bitmaps in the PDF, of which only one is actually referenced. This can't be explained by the name clash of the image objects alone.mael15 wrote: ↑Tue Jul 21, 2020 9:04 amsure, it is just a really simpleCode: Select all
dc->DrawBitmap(*getBitmap(false), pos, true);
So what? In wxPdfDocument you can set the page size and orientation for each page individually, if you want to.
In template mode wxPdfDC uses the dimensions of the template. And that is fully under your control: method BeginTemplate can be used to determine the dimensions of the template. And method UseTemplate allows you to scale the template to whatever you want to see on the generated page.
The approach with a single wxPdfDC should work for you. Nevertheless, I will change the wxPdfDC implementation to use a global counter. However, this will take some time.
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPDFDocument: bitmaps on consecutive pages
Do I not have to set the page size in the wxPdfDC ctor?!
Code: Select all
wxPdfDC(&pdfDcmt, pageSzMM.x, pageSzMM.y);
Code: Select all
wxPdfDocument pdfDcmt;
pdfDcmt.SetCompression(false);
wxFont defaultFont(wxFontInfo(10).Family(wxFONTFAMILY_DEFAULT).Underlined(false));
wxPdfFont pdfArialFont = wxPdfFontManager::GetFontManager()->RegisterFont(defaultFont, wxT("Arial"));
bool ok = pdfDcmt.SetFont(pdfArialFont);
int tpl = -1;
wxProgressDialog *prog = new wxProgressDialog(_i("PDF speichern"), _i("Das PDF wird erstellt."), 100, ss->getMainFrame(), wxPD_AUTO_HIDE | wxPD_SMOOTH);
double progPerPage = 100.0 / numPrintPages, totalProg = 0;
wxSize pageSzMM = page->getPageSizeMM(papSize, orient);
wxPdfDC* dc = new wxPdfDC(&pdfDcmt, pageSzMM.x, pageSzMM.y);
dc->SetResolution(600);
dc->SetBackground(*wxWHITE_BRUSH);
if (dc->StartDoc(wxT("Printing ..."))) {
for (unsigned int i = 1; i < pagesToPrint.size(); i++) {
if (pagesToPrint.at(i)) {
page = pageCont->getPage(i - 1);
orient = page->isLayoutPortait() ? wxPORTRAIT : wxLANDSCAPE;
papSize = page->isLayoutA4() ? wxPAPER_A4 : wxPAPER_A3;
pdfDcmt.AddPage(orient, papSize);
tpl = pdfDcmt.BeginTemplate();
dc->StartPage();
libClientOutput::TubeDataPrintout::printToDC(*dc, i - 1);
dc->EndPage();
pdfDcmt.EndTemplate();
pdfDcmt.UseTemplate(tpl);
totalProg += progPerPage;
prog->Update(totalProg);
}
}
dc->EndDoc();
}
delete dc;
delete prog;
Re: wxPDFDocument: bitmaps on consecutive pages
In principle, you are right, of course. However, internally the sizes (width, height) set by the ctor do not matter under most circumstances. Only if you make use of clipping, then the size values are used to determine the bounding box. That is, if your wxDC code makes use of clipping then this might impose a problem. However, if you set width and height to the maximum width and height you will need on any of your pages, it should work.mael15 wrote: ↑Tue Jul 21, 2020 9:42 amDo I not have to set the page size in the wxPdfDC ctor?!Code: Select all
wxPdfDC(&pdfDcmt, pageSzMM.x, pageSzMM.y);
Well, only the specific ctor with a wxPdfDocument instance as the first parameter will activate template mode. And you are right, the parameters for template width and height are not optional. However, what counts in the end are the template dimensions set in method BeginTemplate. For wxPdfDC you may choose reasonable values (max needed as stated above) to make your code work.
The resulting PDF document has 2 pages, first A4 in portrait mode, second A3 in landscape mode. Most likely, you want that the graphics on the second page fills the whole page. However, it seems to use the initial paper size (A4).mael15 wrote: ↑Tue Jul 21, 2020 9:42 am and this code results in the attached pdf:Code: Select all
wxPdfDocument pdfDcmt; pdfDcmt.SetCompression(false); wxFont defaultFont(wxFontInfo(10).Family(wxFONTFAMILY_DEFAULT).Underlined(false)); wxPdfFont pdfArialFont = wxPdfFontManager::GetFontManager()->RegisterFont(defaultFont, wxT("Arial")); bool ok = pdfDcmt.SetFont(pdfArialFont); int tpl = -1; wxProgressDialog *prog = new wxProgressDialog(_i("PDF speichern"), _i("Das PDF wird erstellt."), 100, ss->getMainFrame(), wxPD_AUTO_HIDE | wxPD_SMOOTH); double progPerPage = 100.0 / numPrintPages, totalProg = 0; wxSize pageSzMM = page->getPageSizeMM(papSize, orient); wxPdfDC* dc = new wxPdfDC(&pdfDcmt, pageSzMM.x, pageSzMM.y); dc->SetResolution(600); dc->SetBackground(*wxWHITE_BRUSH); if (dc->StartDoc(wxT("Printing ..."))) { for (unsigned int i = 1; i < pagesToPrint.size(); i++) { if (pagesToPrint.at(i)) { page = pageCont->getPage(i - 1); orient = page->isLayoutPortait() ? wxPORTRAIT : wxLANDSCAPE; papSize = page->isLayoutA4() ? wxPAPER_A4 : wxPAPER_A3; pdfDcmt.AddPage(orient, papSize); tpl = pdfDcmt.BeginTemplate(); dc->StartPage(); libClientOutput::TubeDataPrintout::printToDC(*dc, i - 1); dc->EndPage(); pdfDcmt.EndTemplate(); pdfDcmt.UseTemplate(tpl); totalProg += progPerPage; prog->Update(totalProg); } } dc->EndDoc(); } delete dc; delete prog;
My guess is that the code in libClientOutput::TubeDataPrintout::printToDC asks the wxDC for its size (width and height). If that is the case you would need to adjust the code to use the right values for width and height, when you start output of a new page. I don't know whether this is feasible, because it depends on how your code works. For example, does printToDC determine width and height just once right at the beginning? Or are these values determined from the wxDC context at many places in the code? In the former case, you could pass values for width and height as parameters to printToDC. For the other uses of this method you could introduce a version of the method with the original signature, which asks the wxDC for its width and height, and passes those values on to the new method with width and height parameters.
Re: wxPDFDocument: bitmaps on consecutive pages
I adjusted the wxPdfDC implementation to use a global bitmap image counter. This avoids name clashes for bitmap images drawn to wxPdfDC. Thus, you can use your approach with creating a new wxPdfDC instance for each page. Please use the latest wxPdfDocument master.