New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Layout raster image exports #5837
Conversation
YES!
…On Mon, Dec 11, 2017 at 3:18 PM, Nyall Dawson ***@***.***> wrote:
Restores raster image exports for layouts.
Big improvement here is that all the useful functionality is now exposed
through QgsLayoutExporter. In composer in 2.x it was a pain to export
compositions because so much of the useful api was locked away in app. This
led to a ton of duplicated code for every plugin dealing with
compositions...
------------------------------
You can view, comment on, or merge this pull request online at:
#5837
Commit Summary
- Decouple QgsLayoutExporter from QgsLayout
- Forward declare some classes
- Remember window position
- Port method to retrieve items of a set type on a page
- Port method to determine whether page should be exported
- Avoid Qt warning
- Remove incorrect TransferThis annotation
- Work on resizing layouts to item bounds
- Fix unit test
- Add unit test for resizing pages
- Port pageItemBounds method from composer
- Add method to determine largest page size
- Expand docs
- Sipify
- Implement methods for exporting layouts as raster, add tests
- Port reference map functionality from composer
- Add some masks for scalebar tests
- Fix updating gui after undoing layout settings change
- Port georeferencing from compositions
- Port world file generation code to layouts
- Port some more world file generation related code
- Expose some more export related settings to GUI
- Fix a crash on exit
- Add method to detect whether layout has uniform page sizes
- Add method to determine file path for exports which encountered
errors
- Port method for pausing layout view updates
- [layouts] Resurrect action for exporting to raster images
- Expose world file option in image settings dialog
- Expose antialiasing option in image export dialog
File Changes
- *M* python/core/layout/qgslayout.sip
<https://github.com/qgis/QGIS/pull/5837/files#diff-0> (55)
- *M* python/core/layout/qgslayoutexporter.sip
<https://github.com/qgis/QGIS/pull/5837/files#diff-1> (168)
- *M* python/core/layout/qgslayoutitempage.sip
<https://github.com/qgis/QGIS/pull/5837/files#diff-2> (2)
- *M* python/core/layout/qgslayoutpagecollection.sip
<https://github.com/qgis/QGIS/pull/5837/files#diff-3> (39)
- *M* python/gui/layout/qgslayoutview.sip
<https://github.com/qgis/QGIS/pull/5837/files#diff-4> (3)
- *M* src/app/CMakeLists.txt
<https://github.com/qgis/QGIS/pull/5837/files#diff-5> (2)
- *M* src/app/layout/qgslayoutaddpagesdialog.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-6> (1)
- *M* src/app/layout/qgslayoutappmenuprovider.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-7> (2)
- *M* src/app/layout/qgslayoutdesignerdialog.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-8> (162)
- *M* src/app/layout/qgslayoutdesignerdialog.h
<https://github.com/qgis/QGIS/pull/5837/files#diff-9> (5)
- *M* src/app/layout/qgslayoutguidewidget.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-10> (2)
- *M* src/app/layout/qgslayouthtmlwidget.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-11> (1)
- *A* src/app/layout/qgslayoutimageexportoptionsdialog.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-12> (187)
- *A* src/app/layout/qgslayoutimageexportoptionsdialog.h
<https://github.com/qgis/QGIS/pull/5837/files#diff-13> (143)
- *M* src/app/layout/qgslayoutmapwidget.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-14> (1)
- *M* src/app/layout/qgslayoutpagepropertieswidget.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-15> (2)
- *M* src/app/layout/qgslayoutpolygonwidget.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-16> (1)
- *M* src/app/layout/qgslayoutpolylinewidget.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-17> (1)
- *M* src/app/layout/qgslayoutpropertieswidget.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-18> (89)
- *M* src/app/layout/qgslayoutpropertieswidget.h
<https://github.com/qgis/QGIS/pull/5837/files#diff-19> (7)
- *M* src/core/layout/qgslayout.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-20> (71)
- *M* src/core/layout/qgslayout.h
<https://github.com/qgis/QGIS/pull/5837/files#diff-21> (55)
- *M* src/core/layout/qgslayoutaligner.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-22> (1)
- *M* src/core/layout/qgslayoutexporter.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-23> (469)
- *M* src/core/layout/qgslayoutexporter.h
<https://github.com/qgis/QGIS/pull/5837/files#diff-24> (201)
- *M* src/core/layout/qgslayoutgridsettings.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-25> (2)
- *M* src/core/layout/qgslayoutguidecollection.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-26> (2)
- *M* src/core/layout/qgslayoutitem.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-27> (2)
- *M* src/core/layout/qgslayoutitemgroup.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-28> (2)
- *M* src/core/layout/qgslayoutitemmap.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-29> (2)
- *M* src/core/layout/qgslayoutitempage.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-30> (2)
- *M* src/core/layout/qgslayoutitempage.h
<https://github.com/qgis/QGIS/pull/5837/files#diff-31> (2)
- *M* src/core/layout/qgslayoutitemundocommand.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-32> (1)
- *M* src/core/layout/qgslayoutmultiframe.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-33> (2)
- *M* src/core/layout/qgslayoutpagecollection.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-34> (132)
- *M* src/core/layout/qgslayoutpagecollection.h
<https://github.com/qgis/QGIS/pull/5837/files#diff-35> (55)
- *M* src/core/layout/qgslayoutsnapper.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-36> (1)
- *M* src/core/layout/qgslayouttable.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-37> (1)
- *M* src/core/layout/qgslayoututils.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-38> (11)
- *M* src/core/qgsmultirenderchecker.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-39> (3)
- *M* src/gui/layout/qgslayoutitemwidget.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-40> (1)
- *M* src/gui/layout/qgslayoutmousehandles.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-41> (1)
- *M* src/gui/layout/qgslayoutnewitempropertiesdialog.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-42> (5)
- *M* src/gui/layout/qgslayoutruler.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-43> (1)
- *M* src/gui/layout/qgslayoutview.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-44> (15)
- *M* src/gui/layout/qgslayoutview.h
<https://github.com/qgis/QGIS/pull/5837/files#diff-45> (10)
- *M* src/gui/layout/qgslayoutviewtooladditem.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-46> (1)
- *M* src/gui/layout/qgslayoutviewtooleditnodes.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-47> (1)
- *M* src/gui/layout/qgslayoutviewtoolmoveitemcontent.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-48> (1)
- *M* src/gui/layout/qgslayoutviewtoolselect.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-49> (8)
- *M* src/gui/layout/qgslayoutviewtoolselect.h
<https://github.com/qgis/QGIS/pull/5837/files#diff-50> (2)
- *M* src/ui/layout/qgslayoutdesignerbase.ui
<https://github.com/qgis/QGIS/pull/5837/files#diff-51> (38)
- *A* src/ui/layout/qgslayoutimageexportoptions.ui
<https://github.com/qgis/QGIS/pull/5837/files#diff-52> (340)
- *M* src/ui/layout/qgslayoutwidgetbase.ui
<https://github.com/qgis/QGIS/pull/5837/files#diff-53> (239)
- *M* tests/src/core/testqgslayout.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-54> (257)
- *M* tests/src/core/testqgslayoutitem.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-55> (2)
- *M* tests/src/core/testqgslayoutitemgroup.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-56> (1)
- *M* tests/src/core/testqgslayoutmap.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-57> (41)
- *M* tests/src/core/testqgslayoutmultiframe.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-58> (2)
- *M* tests/src/core/testqgslayoutpage.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-59> (1)
- *M* tests/src/core/testqgslayoututils.cpp
<https://github.com/qgis/QGIS/pull/5837/files#diff-60> (25)
- *M* tests/src/python/CMakeLists.txt
<https://github.com/qgis/QGIS/pull/5837/files#diff-61> (1)
- *M* tests/src/python/qgslayoutchecker.py
<https://github.com/qgis/QGIS/pull/5837/files#diff-62> (5)
- *M* tests/src/python/test_qgslayout.py
<https://github.com/qgis/QGIS/pull/5837/files#diff-63> (3)
- *A* tests/src/python/test_qgslayoutexporter.py
<https://github.com/qgis/QGIS/pull/5837/files#diff-64> (322)
- *M* tests/src/python/test_qgslayoutpagecollection.py
<https://github.com/qgis/QGIS/pull/5837/files#diff-65> (104)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_exporttoimagecropped_page1/expected_layoutexporter_
exporttoimagecropped_page1.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-66> (0)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_exporttoimagecropped_page2/expected_layoutexporter_
exporttoimagecropped_page2.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-67> (0)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_exporttoimagedpi_page1/expected_layoutexporter_
exporttoimagedpi_page1.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-68> (0)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_exporttoimagedpi_page2/expected_layoutexporter_
exporttoimagedpi_page2.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-69> (0)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_exporttoimagesize_page2/expected_layoutexporter_
exporttoimagesize_page2.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-70> (0)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_renderpage/expected_layoutexporter_renderpage.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-71> (0)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_renderregion/expected_layoutexporter_renderregion.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-72> (0)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_rendertoimagepage/expected_layoutexporter_
rendertoimagepage.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-73> (0)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_rendertoimageregiondpi/expected_layoutexporter_
rendertoimageregiondpi.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-74> (0)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_rendertoimageregionoverridedpi/expected_layoutexporter_
rendertoimageregionoverridedpi.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-75> (0)
- *A* tests/testdata/control_images/layout_exporter/expected_
layoutexporter_rendertoimageregionsize/expected_layoutexporter_
rendertoimageregionsize.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-76> (0)
- *A* tests/testdata/control_images/layout_scalebar/expected_
layoutscalebar_doublebox/expected_layoutscalebar_doublebox_mask.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-77> (0)
- *A* tests/testdata/control_images/layout_scalebar/expected_
layoutscalebar_numeric/fedora/expected_layoutscalebar_numeric_mask.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-78> (0)
- *A* tests/testdata/control_images/layout_scalebar/expected_
layoutscalebar_singlebox/expected_layoutscalebar_singlebox_mask.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-79> (0)
- *A* tests/testdata/control_images/layout_scalebar/expected_
layoutscalebar_singlebox_alpha/expected_layoutscalebar_
singlebox_alpha_mask.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-80> (0)
- *A* tests/testdata/control_images/layout_scalebar/expected_
layoutscalebar_tick/expected_layoutscalebar_tick_mask.png
<https://github.com/qgis/QGIS/pull/5837/files#diff-81> (0)
Patch Links:
- https://github.com/qgis/QGIS/pull/5837.patch
- https://github.com/qgis/QGIS/pull/5837.diff
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#5837>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAXS3O5SRs1y828LMsjlAJGvVHfSyZ1Aks5s_LsegaJpZM4Q84LT>
.
|
a1e1c43
to
010d9ae
Compare
@nyalldawson , page size is wrong for PDF outputs: |
BTW, I think we need to add a "Add page(s)..." toolbar button somewhere (possibly in the toolbox's toolbar?). I keep looking for it. |
break; | ||
|
||
case QgsLayoutExporter::MemoryError: | ||
QMessageBox::warning( nullptr, tr( "Memory Allocation Error" ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it wanted that the parent of QMessageBox
is this
in case of FileError
and nullptr
in case of MemoryError
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch - it was a copy/paste from the old composer code. I'll add the parent to all these. Or @nirvn should I use the message bar here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
|
||
|
||
case QgsLayoutExporter::MemoryError: | ||
QMessageBox::warning( nullptr, tr( "Memory Allocation Error" ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question about the parent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
//make sure print as raster checkbox is updated | ||
mLayoutPropertiesWidget->updateGui(); | ||
|
||
delete m; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think that a unique_ptr
could used in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - actually doesn't need to be on the heap here at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
{ | ||
settings.setValue( QStringLiteral( "LayoutDesigner/hideForceVectorWarning" ), true, QgsSettings::App ); | ||
} | ||
delete m; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question about unique_ptr
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
|
||
|
||
/** | ||
* A dialog for customising the properties of an exported image file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
\since QGIS 3.0
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure here. It's in app, so is the version information really useful for anything? Happy to add it if you think there's value.
return renderRegionToImage( paperRect, imageSize, dpi ); | ||
} | ||
|
||
///@cond PRIVATE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain to me the meaning of this notation ///@cond PRIVATE
? Thank you :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's used to hide code from doxygen. We use it to mark parts of headers (and cpp files) which we don't want doxygen to know about, with the belief that hiding them from doxygen is sufficient enough to dissuade most users from relying on non-stable api.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that because we have doxygen also scanning cpp files (can't remember why, but there was a good reason for it sometime ago) you need to make sure the cond notation is used both in headers and cpp files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, thank you for the explanation, I didn't know that!
LayoutItemCacheSettingRestorer( QgsLayout *layout ) | ||
: mLayout( layout ) | ||
{ | ||
mLayout->context().mIsPreviewRender = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mLayout
could be checked to ensure that it's not null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'll just assert here... there's absolutely no valid use for this object with no layout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
|
||
~LayoutItemCacheSettingRestorer() | ||
{ | ||
for ( auto it = mPrevCacheMode.constBegin(); it != mPrevCacheMode.constEnd(); ++it ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a lot of auto
in QGIS source code. Do we have some kind of rules about its usage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not officially (but we should open a discussion on dev list). From scattered conversation my summary is:
- don't use auto for declaring most variables. Explicit type declaration is preferred, as it helps readability and also qt creator code completion.
- let's use it only for annoying declarations, like
QMap< blah, blah >::const_iterator
I'm happy with this approach... personally I hate having to declare iterators, so always use auto for them now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- don't use auto for declaring most variables. Explicit type declaration is preferred, as it helps readability and also qt creator code completion.
- let's use it only for annoying declarations, like QMap< blah, blah >::const_iterator
Fully agree 👍
LayoutContextSettingsRestorer( QgsLayout *layout ) | ||
: mLayout( layout ) | ||
, mPreviousDpi( layout->context().dpi() ) | ||
, mPreviousFlags( layout->context().flags() ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could check that layout
is not null before using it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, there's no use for this class if layout is null. If it is, an assert would be better... but we would have crashed long before this class is used anyway :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
~LayoutContextSettingsRestorer() | ||
{ | ||
mLayout->context().setDpi( mPreviousDpi ); | ||
mLayout->context().setFlags( mPreviousFlags ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that mLayout
may be a nullptr in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
{ | ||
ImageExportSettings settings = s; | ||
if ( settings.dpi <= 0 ) | ||
settings.dpi = mLayout->context().dpi(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that mLayout
may be null at this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW I think it may be the case in other methods too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a valid point for QgsLayoutExporter. I'll make the constructor require a reference instead of the pointer to avoid this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
GDALSetProjection( outputDS.get(), map->crs().toWkt().toLocal8Bit().constData() ); | ||
} | ||
CPLSetConfigOption( "GDAL_PDF_DPI", nullptr ); | ||
delete[] t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think that a unique_ptr
may be used for t
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
{ | ||
if ( details.page == 0 ) | ||
{ | ||
return details.directory + '/' + details.baseName + '.' + details.extension; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A QStringLiteral().arg()
is not to be preferred in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure here - my understanding is that the QString single character based methods are very fast, so I suspect that the extra allocations here would be faster than parsing the string literal for the % tokens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably QStringBuilder would be preferable here actually
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably QStringBuilder would be preferable here actually
Good point
{ | ||
double maxArea = 0; | ||
QSizeF maxSize; | ||
for ( QgsLayoutItemPage *page : mPages ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not qgis::as_const( mPages )
in this case? Sorry if it's a dumb question...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's already const here, because the method it's contained in is const.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed :)
Hi @nyalldawson! Sorry, I have mainly questions and not so much valuable comments... In any case, good job 👍 :) |
Thanks so much for the review - it's very much appreciated!! |
010d9ae
to
f5391cb
Compare
Fixed |
Ok so the description of this PR is a travesty. There's LOTS of cool introduced by this PR now, including a new messagebar in layouts for feedback after exports, complete with hyperlinks to immediately open the outputed file for testing, and a new option to control antialiasing or not for raster exports. But the main killer feature here now is that PDF exports no longer force rasterization of the entire output if map layer settings such as blend modes or layer opacity are present!! Now, there's more intelligent logic in place so that only items which HAVE to be rasterized are... this means the map may be included as a raster image in the PDF, while all the rest of the accompanying items will be left as vectors or pure text objects. No more rasterized legends just to have layer opacity in your maps! To accompany this there's a new layout setting to "force vector output". If set, the output will always be vectors, even when it changes the actual appearance of the map. |
YAY! |
@nirvn / others. Keen for some UX advice. Currently, after exporting a layout you get a message bar with a clickable link which directly opens the generated image/pdf in the default program. I'm thinking of changing this behavior so that clicking the link opens instead the folder containing the exported images/pdfs. To me this would be more flexible - it's still only going to be an extra double click to open the generated files if you want to view them, but opening instead the folder would also allow much more options, like right clicking and opening in a non-default application, sending via email, renaming/copying/moving, etc... Thoughts? |
2144711
to
ea38a27
Compare
+1 to opening the folder, with the exported file selected if at all possible. |
subclasses can be made which customise the generated file names
And start a generic test library for all item types to ensure correct behavior for QgsLayoutItem subclasses Currently justs tests to ensure that overriden containsAdvancedEffects methods also call the base class test
when exporting to PDF If an individual layout item needs rasterisation in order to be exported correctly, it can now be individually rasterised without forcing every other item to also be rasterised. This allows exports to PDF keeping as much as possible as vectors, e.g. a map with layer opacity won't force labels, scalebars, etc to be rasterised too. To accompany this, a new "Always export as vectors" checkbox was added to layout properties. If checked, this will force the export to keep items as vectors, even when it causes the output to look different to layouts. Fixes qgis#7885
to be rasterised
of layout items when exporting (i.e. disabling of cached item render) The old issue of semi-transparent pixels around the edge of the page had reared again. This is caused by the antialiasing while rendering the page symbol. In order to avoid this, we cater to the most common use case of having pages with a solid, borderless fill and slightly extend the fill symbol polygon outside the page by 2 pixels (determined by trial-and-error). The less common use case of having a page symbol containing a border suffers by this border being clipped by a couple of pixels, but we must address the much more common use case over this.
exported, including data defined setting This replaces the 2.x data-defined "number of pages" setting. Instead of requiring users to develop an expression to return the number of pages, instead we allow individual pages to have a data defined control of whether that page should be included in the export. This is more flexible, and works correctly with the mixed page size model for layouts.
e240ef7
to
492f9ea
Compare
Restores raster image exports for layouts.
Big improvement here is that all the useful functionality is now exposed through QgsLayoutExporter. In composer in 2.x it was a pain to export compositions because so much of the useful api was locked away in app. This led to a ton of duplicated code for every plugin dealing with compositions...