Bug Summary

File:dplugins/dimg/png/dimgpngloader_load.cpp
Warning:line 145, column 15
Value of 'errno' was not checked and may be overwritten by function 'png_create_read_struct'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name dimgpngloader_load.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/gilles/devel/8.x/build.scan/core/dplugins/dimg/png -fcoverage-compilation-dir=/home/gilles/devel/8.x/build.scan/core/dplugins/dimg/png -resource-dir /usr/lib/llvm-19/lib/clang/19 -isystem /opt/qt6/include -isystem /opt/qt6/include/QtCore -isystem /opt/qt6/mkspecs/linux-g++ -isystem /opt/qt6/include/QtGui -isystem /opt/qt6/include/QtWidgets -isystem /opt/qt6/include/KF6/KConfig -isystem /opt/qt6/include/KF6/KConfigCore -isystem /opt/qt6/include/KF6/KI18n -isystem /opt/qt6/include/QtXml -D CMS_NO_REGISTER_KEYWORD=1 -D DImg_PNG_Plugin_EXPORTS -D HAVE_FFMPEG_VERSION5 -D LIBPGF_DISABLE_OPENMP -D MAGICKCORE_HDRI_ENABLE=0 -D MAGICKCORE_QUANTUM_DEPTH=16 -D QT_CORE_LIB -D QT_DEPRECATED_WARNINGS -D QT_DEPRECATED_WARNINGS_SINCE=0x060000 -D QT_DISABLE_DEPRECATED_BEFORE=0x050E00 -D QT_GUI_LIB -D QT_NO_CAST_FROM_ASCII -D QT_NO_CAST_FROM_BYTEARRAY -D QT_NO_CAST_TO_ASCII -D QT_NO_FOREACH -D QT_NO_KEYWORDS -D QT_NO_NARROWING_CONVERSIONS_IN_CONNECT -D QT_NO_URL_CAST_FROM_STRING -D QT_STRICT_ITERATORS -D QT_USE_QSTRINGBUILDER -D QT_WIDGETS_LIB -D QT_XML_LIB -D TRANSLATION_DOMAIN="digikam" -D USE_JASPER -D USE_JPEG -D USE_JPEG8 -D _GNU_SOURCE -D _LARGEFILE64_SOURCE -I /home/gilles/devel/8.x/build.scan/core/dplugins/dimg/png -I /home/gilles/devel/8.x/core/dplugins/dimg/png -I /home/gilles/devel/8.x/build.scan/core/dplugins/dimg/png/DImg_PNG_Plugin_autogen/include -I /home/gilles/devel/8.x/core/libs/video/player/qtmm -I /home/gilles/devel/8.x/core/libs/album/engine -I /home/gilles/devel/8.x/core/libs/album/manager -I /home/gilles/devel/8.x/core/libs/album/treeview -I /home/gilles/devel/8.x/core/libs/album/widgets -I /home/gilles/devel/8.x/core/libs/database/collection -I /home/gilles/devel/8.x/core/libs/database/coredb -I /home/gilles/devel/8.x/core/libs/database/dbjobs -I /home/gilles/devel/8.x/core/libs/database/engine -I /home/gilles/devel/8.x/core/libs/database/haar -I /home/gilles/devel/8.x/core/libs/database/history -I /home/gilles/devel/8.x/core/libs/database/item/containers -I /home/gilles/devel/8.x/core/libs/database/item/lister -I /home/gilles/devel/8.x/core/libs/database/item/query -I /home/gilles/devel/8.x/core/libs/database/item/scanner -I /home/gilles/devel/8.x/core/libs/database/models -I /home/gilles/devel/8.x/core/libs/database/server -I /home/gilles/devel/8.x/core/libs/database/similaritydb -I /home/gilles/devel/8.x/core/libs/database/tags -I /home/gilles/devel/8.x/core/libs/database/thumbsdb -I /home/gilles/devel/8.x/core/libs/database/utils/ifaces -I /home/gilles/devel/8.x/core/libs/database/utils/scan -I /home/gilles/devel/8.x/core/libs/database/utils/widgets -I /home/gilles/devel/8.x/core/libs/dialogs -I /home/gilles/devel/8.x/core/libs/dimg/color -I /home/gilles/devel/8.x/core/libs/dimg -I /home/gilles/devel/8.x/core/libs/dimg/filters/auto -I /home/gilles/devel/8.x/core/libs/dimg/filters/bcg -I /home/gilles/devel/8.x/core/libs/dimg/filters/bw -I /home/gilles/devel/8.x/core/libs/dimg/filters/cb -I /home/gilles/devel/8.x/core/libs/dimg/filters/curves -I /home/gilles/devel/8.x/core/libs/dimg/filters/decorate -I /home/gilles/devel/8.x/core/libs/dimg/filters -I /home/gilles/devel/8.x/core/libs/dimg/filters/film -I /home/gilles/devel/8.x/core/libs/dimg/filters/fx -I /home/gilles/devel/8.x/core/libs/dimg/filters/greycstoration/cimg -I /home/gilles/devel/8.x/core/libs/dimg/filters/greycstoration -I /home/gilles/devel/8.x/core/libs/dimg/filters/hotpixels -I /home/gilles/devel/8.x/core/libs/dimg/filters/hsl -I /home/gilles/devel/8.x/core/libs/dimg/filters/icc -I /home/gilles/devel/8.x/core/libs/dimg/filters/lc -I /home/gilles/devel/8.x/core/libs/dimg/filters/lens -I /home/gilles/devel/8.x/core/libs/dimg/filters/levels -I /home/gilles/devel/8.x/core/libs/dimg/filters/nr -I /home/gilles/devel/8.x/core/libs/dimg/filters/raw -I /home/gilles/devel/8.x/core/libs/dimg/filters/redeye -I /home/gilles/devel/8.x/core/libs/dimg/filters/sharp -I /home/gilles/devel/8.x/core/libs/dimg/filters/transform -I /home/gilles/devel/8.x/core/libs/dimg/filters/wb -I /home/gilles/devel/8.x/core/libs/dimg/history -I /home/gilles/devel/8.x/core/libs/dimg/loaders -I /home/gilles/devel/8.x/core/libs/dngwriter -I /home/gilles/devel/8.x/core/libs/dnnmodelmanager -I /home/gilles/devel/8.x/core/libs/dplugins/core -I /home/gilles/devel/8.x/core/libs/dplugins/iface -I /home/gilles/devel/8.x/core/libs/dplugins/setup -I /home/gilles/devel/8.x/core/libs/dplugins/webservices -I /home/gilles/devel/8.x/core/libs/dplugins/widgets -I /home/gilles/devel/8.x/core/libs/dragdrop -I /home/gilles/devel/8.x/core/libs/dtrash -I /home/gilles/devel/8.x/core/libs/facesengine/common -I /home/gilles/devel/8.x/core/libs/facesengine/detection -I /home/gilles/devel/8.x/core/libs/facesengine/detection/opencv-dnn -I /home/gilles/devel/8.x/core/libs/facesengine/facedb -I /home/gilles/devel/8.x/core/libs/facesengine/recognition -I /home/gilles/devel/8.x/core/libs/facesengine/recognition/opencv-dnn -I /home/gilles/devel/8.x/core/libs/fileactionmanager -I /home/gilles/devel/8.x/core/libs/filters -I /home/gilles/devel/8.x/core/libs/imgqsort/detectors -I /home/gilles/devel/8.x/core/libs/imgqsort -I /home/gilles/devel/8.x/core/libs/iojobs -I /home/gilles/devel/8.x/core/libs/jpegutils -I /home/gilles/devel/8.x/core/libs/metadataengine/containers -I /home/gilles/devel/8.x/core/libs/metadataengine/dmetadata -I /home/gilles/devel/8.x/core/libs/metadataengine/engine -I /home/gilles/devel/8.x/core/libs/metadataengine/exiftool -I /home/gilles/devel/8.x/core/libs/metadataengine/focuspoint -I /home/gilles/devel/8.x/core/libs/mlfoundation -I /home/gilles/devel/8.x/core/libs/models -I /home/gilles/devel/8.x/core/libs/networkmanager -I /home/gilles/devel/8.x/core/libs/notificationmanager -I /home/gilles/devel/8.x/core/libs/onlineversion -I /home/gilles/devel/8.x/core/libs/pgfutils -I /home/gilles/devel/8.x/core/libs/progressmanager -I /home/gilles/devel/8.x/core/libs/properties/captions -I /home/gilles/devel/8.x/core/libs/properties/geolocation -I /home/gilles/devel/8.x/core/libs/properties/history -I /home/gilles/devel/8.x/core/libs/properties/import -I /home/gilles/devel/8.x/core/libs/properties -I /home/gilles/devel/8.x/core/libs/qtopencvimg -I /home/gilles/devel/8.x/core/libs/rawengine -I /home/gilles/devel/8.x/core/libs/settings -I /home/gilles/devel/8.x/core/libs/tags/autoassignment -I /home/gilles/devel/8.x/core/libs/tags/autoassignment/classifiers -I /home/gilles/devel/8.x/core/libs/tags/autoassignment/classifiers/multiclassyolo -I /home/gilles/devel/8.x/core/libs/tags/autoassignment/classifiers/softmax -I /home/gilles/devel/8.x/core/libs/tags/autoassignment/model -I /home/gilles/devel/8.x/core/libs/tags/autoassignment/pipelines -I /home/gilles/devel/8.x/core/libs/tags/autoassignment/pipelines/object -I /home/gilles/devel/8.x/core/libs/tags/engine -I /home/gilles/devel/8.x/core/libs/tags/manager/models -I /home/gilles/devel/8.x/core/libs/tags/manager -I /home/gilles/devel/8.x/core/libs/tags/widgets -I /home/gilles/devel/8.x/core/libs/template -I /home/gilles/devel/8.x/core/libs/threadimageio/engine -I /home/gilles/devel/8.x/core/libs/threadimageio/fileio -I /home/gilles/devel/8.x/core/libs/threadimageio/preview -I /home/gilles/devel/8.x/core/libs/threadimageio/thumb -I /home/gilles/devel/8.x/core/libs/threadimageio/video -I /home/gilles/devel/8.x/core/libs/threads -I /home/gilles/devel/8.x/core/libs/timeadjust -I /home/gilles/devel/8.x/core/libs/transitionmngr -I /home/gilles/devel/8.x/core/libs/versionmanager -I /home/gilles/devel/8.x/core/libs/video -I /home/gilles/devel/8.x/core/libs/video/manager -I /home/gilles/devel/8.x/core/libs/video/osd -I /home/gilles/devel/8.x/core/libs/video/player -I /home/gilles/devel/8.x/core/libs/widgets/colors -I /home/gilles/devel/8.x/core/libs/widgets/combo -I /home/gilles/devel/8.x/core/libs/widgets/files -I /home/gilles/devel/8.x/core/libs/widgets/fonts -I /home/gilles/devel/8.x/core/libs/widgets/graphicsview -I /home/gilles/devel/8.x/core/libs/widgets/history -I /home/gilles/devel/8.x/core/libs/widgets/iccprofiles -I /home/gilles/devel/8.x/core/libs/widgets/itemview -I /home/gilles/devel/8.x/core/libs/widgets/layout -I /home/gilles/devel/8.x/core/libs/widgets/mainview -I /home/gilles/devel/8.x/core/libs/widgets/metadata/config -I /home/gilles/devel/8.x/core/libs/widgets/metadata/exiftool -I /home/gilles/devel/8.x/core/libs/widgets/metadata/exiv2 -I /home/gilles/devel/8.x/core/libs/widgets/metadata/labels -I /home/gilles/devel/8.x/core/libs/widgets/metadata/utils -I /home/gilles/devel/8.x/core/libs/widgets/range -I /home/gilles/devel/8.x/core/libs/widgets/text -I /home/gilles/devel/8.x/core/libs/jpegutils/libjpeg/84 -I /home/gilles/devel/8.x/core/app/utils -I /home/gilles/devel/8.x/build.scan/core/app/utils -I /home/gilles/devel/8.x/core/utilities/advancedrename -I /home/gilles/devel/8.x/core/utilities/advancedrename/common -I /home/gilles/devel/8.x/core/utilities/advancedrename/parser -I /home/gilles/devel/8.x/core/utilities/advancedrename/parser/modifiers -I /home/gilles/devel/8.x/core/utilities/advancedrename/parser/options -I /home/gilles/devel/8.x/core/utilities/advancedrename/parser/options/database -I /home/gilles/devel/8.x/core/utilities/advancedrename/parser/options/database/keys -I /home/gilles/devel/8.x/core/utilities/extrasupport/addressbook -I /home/gilles/devel/8.x/core/utilities/extrasupport/filesindexer -I /home/gilles/devel/8.x/core/utilities/facemanagement/bench -I /home/gilles/devel/8.x/core/utilities/facemanagement/database -I /home/gilles/devel/8.x/core/utilities/facemanagement/dialogs -I /home/gilles/devel/8.x/core/utilities/facemanagement/items -I /home/gilles/devel/8.x/core/utilities/facemanagement/pipelines/detectrecognize -I /home/gilles/devel/8.x/core/utilities/facemanagement/pipelines/edit -I /home/gilles/devel/8.x/core/utilities/facemanagement/pipelines -I /home/gilles/devel/8.x/core/utilities/facemanagement/pipelines/recognize -I /home/gilles/devel/8.x/core/utilities/facemanagement/pipelines/reset -I /home/gilles/devel/8.x/core/utilities/facemanagement/pipelines/retrain -I /home/gilles/devel/8.x/core/utilities/facemanagement/widgets -I /home/gilles/devel/8.x/core/utilities/firstrun -I /home/gilles/devel/8.x/core/utilities/focuspointmanagement -I /home/gilles/devel/8.x/core/utilities/fuzzysearch -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/astro -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/blendings -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/core -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/geodata/data -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/geodata/graphicsitem -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/geodata/handlers/dgml -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/geodata/handlers/kml -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/geodata/parser -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/geodata/scene -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/geodata/writer -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/geodata/writers/dgml -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/geodata/writers/kml -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/graphicsview -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/layers -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/models -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/osm -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/render/atmosphere -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/render/compass -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/render/crosshairs -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/render/graticule -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/render/mapscale -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/render/measure -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/render/navigation -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/render/overviewmap -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/render/progress -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/cache -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/gpsbabel -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/gpx -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/gpx/handlers -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/json -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/kml -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/nominatim-reversegeocoding -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/osm -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/osm/o5mreader -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/osm/translators -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/osm/writers -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/pn2 -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/plugins/runner/pnt -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/projections -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/runners -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/settings -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/storage -I /home/gilles/devel/8.x/core/utilities/geolocation/engine/tile -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/backends -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/bookmark -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/core -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/correlator -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/dragdrop -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/items -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/lookup -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/reversegeocoding -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/tiles -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/tracks -I /home/gilles/devel/8.x/core/utilities/geolocation/geoiface/widgets -I /home/gilles/devel/8.x/core/utilities/geolocation/geomapwrapper -I /home/gilles/devel/8.x/core/utilities/geolocation/mapsearches -I /home/gilles/devel/8.x/core/utilities/imageeditor/core -I /home/gilles/devel/8.x/core/utilities/imageeditor/dialogs -I /home/gilles/devel/8.x/core/utilities/imageeditor/editor -I /home/gilles/devel/8.x/core/utilities/imageeditor/main -I /home/gilles/devel/8.x/core/utilities/imageeditor/widgets -I /home/gilles/devel/8.x/core/utilities/import/backend -I /home/gilles/devel/8.x/core/utilities/import/dialogs -I /home/gilles/devel/8.x/core/utilities/import/items -I /home/gilles/devel/8.x/core/utilities/import/main -I /home/gilles/devel/8.x/core/utilities/import/models -I /home/gilles/devel/8.x/core/utilities/import/views -I /home/gilles/devel/8.x/core/utilities/import/widgets -I /home/gilles/devel/8.x/core/utilities/lighttable -I /home/gilles/devel/8.x/core/utilities/maintenance/main -I /home/gilles/devel/8.x/core/utilities/maintenance/manager -I /home/gilles/devel/8.x/core/utilities/maintenance/tools/dbcleaner -I /home/gilles/devel/8.x/core/utilities/maintenance/tools/dbscan -I /home/gilles/devel/8.x/core/utilities/maintenance/tools/duplicates -I /home/gilles/devel/8.x/core/utilities/maintenance/tools/facesmanagement -I /home/gilles/devel/8.x/core/utilities/maintenance/tools/fingerprints -I /home/gilles/devel/8.x/core/utilities/maintenance/tools/imgqsort -I /home/gilles/devel/8.x/core/utilities/maintenance/tools/metaremover -I /home/gilles/devel/8.x/core/utilities/maintenance/tools/metasync -I /home/gilles/devel/8.x/core/utilities/maintenance/tools/thumbs -I /home/gilles/devel/8.x/core/utilities/maintenance/utils -I /home/gilles/devel/8.x/core/utilities/queuemanager/dplugins -I /home/gilles/devel/8.x/core/utilities/queuemanager/main -I /home/gilles/devel/8.x/core/utilities/queuemanager/manager -I /home/gilles/devel/8.x/core/utilities/queuemanager/views -I /home/gilles/devel/8.x/core/utilities/searchwindow -I /home/gilles/devel/8.x/core/utilities/setup/album -I /home/gilles/devel/8.x/core/utilities/setup/camera -I /home/gilles/devel/8.x/core/utilities/setup/collections -I /home/gilles/devel/8.x/core/utilities/setup/downloader -I /home/gilles/devel/8.x/core/utilities/setup/editor -I /home/gilles/devel/8.x/core/utilities/setup/metadata -I /home/gilles/devel/8.x/core/utilities/setup/misc -I /home/gilles/devel/8.x/core/utilities/setup -I /home/gilles/devel/8.x/build.scan/core/app -I /home/gilles/devel/8.x/core/app -I /opt/qt6/include/opencv4 -I /usr/include/ImageMagick-6 -I /usr/include/x86_64-linux-gnu/ImageMagick-6 -I /opt/qt6/include/QtMultimedia -I /opt/qt6/include/QtNetwork -I /opt/qt6/include/QtMultimediaWidgets -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-long-long -Wno-deprecated-copy -std=c++20 -fdeprecated-macro -ferror-limit 19 -fvisibility=hidden -fvisibility-inlines-hidden -fno-operator-names -fopenmp -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/gilles/devel/8.x/project/reports/report.scan/2025-01-21-132859-99447-1 -x c++ /home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp
1/* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2005-11-01
7 * Description : a PNG image loader for DImg framework - load operations.
8 *
9 * SPDX-FileCopyrightText: 2005-2025 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 *
13 * ============================================================ */
14
15#define PNG_BYTES_TO_CHECK4 4
16
17#include "dimgpngloader.h"
18
19// C ANSI includes
20
21extern "C"
22{
23#ifndef Q_CC_MSVC
24# include <unistd.h>
25#endif
26}
27
28// C++ includes
29
30#include <cstdlib>
31#include <cstdio>
32
33// Qt includes
34
35#include <QFile>
36#include <QByteArray>
37#include <QSysInfo>
38
39// Local includes
40
41#include "metaengine.h"
42#include "digikam_debug.h"
43#include "digikam_config.h"
44#include "digikam_version.h"
45#include "dimgloaderobserver.h"
46
47// libPNG includes
48
49extern "C"
50{
51#include <png.h>
52}
53
54#ifdef Q_OS_WIN
55
56void _ReadProc(struct png_struct_def* png_ptr, png_bytep data, png_size_t size)
57{
58 FILE* const file_handle = (FILE*)png_get_io_ptr(png_ptr);
59 fread(data, size, 1, file_handle);
60}
61
62#endif
63
64using namespace Digikam;
65
66namespace DigikamPNGDImgPlugin
67{
68
69#if PNG_LIBPNG_VER_MAJOR1 >= 1 && PNG_LIBPNG_VER_MINOR6 >= 5
70
71typedef png_bytep iCCP_data;
72
73#else
74
75typedef png_charp iCCP_data;
76
77#endif
78
79bool DImgPNGLoader::load(const QString& filePath, DImgLoaderObserver* const observer)
80{
81 png_uint_32 w32, h32;
82 int width, height;
83 int bit_depth, color_type, interlace_type;
84 FILE* f = nullptr;
85 png_structp png_ptr = nullptr;
86 png_infop info_ptr = nullptr;
87
88 // To prevent cppcheck warnings.
89 (void)f;
90 (void)png_ptr;
91 (void)info_ptr;
92
93 readMetadata(filePath);
94
95 // -------------------------------------------------------------------
96 // Open the file
97
98 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 98, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category
.name()).debug()
<< "Opening file" << filePath;
1
Loop condition is false. Execution continues on line 106
99
100#ifdef Q_OS_WIN
101
102 f = _wfopen((const wchar_t*)filePath.utf16(), L"rb");
103
104#else
105
106 f = fopen(filePath.toUtf8().constData(), "rb");
107
108#endif
109
110 if (!f
1.1
'f' is non-null
)
2
Taking false branch
111 {
112 qCWarning(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 112, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).warning()
<< "Cannot open image file.";
113 loadingFailed();
114
115 return false;
116 }
117
118 unsigned char buf[PNG_BYTES_TO_CHECK4];
119
120 size_t membersRead = fread(buf, 1, PNG_BYTES_TO_CHECK4, f);
121
122#if PNG_LIBPNG_VER10644 >= 10400
123
124 if ((membersRead
2.1
'membersRead' is equal to PNG_BYTES_TO_CHECK
!= PNG_BYTES_TO_CHECK4) || png_sig_cmp(buf, 0, PNG_BYTES_TO_CHECK4))
3
Assuming the condition is false
4
Taking false branch
125
126#else
127
128 if ((membersRead != PNG_BYTES_TO_CHECK4) || !png_check_sig(buf, PNG_BYTES_TO_CHECK)(png_sig_cmp((buf), 0, (4)) == 0))
129
130#endif
131
132 {
133 qCWarning(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 133, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).warning()
<< "Not a PNG image file.";
134 fclose(f);
135 loadingFailed();
136
137 return false;
138 }
139
140 rewind(f);
5
After calling 'rewind' reading 'errno' is required to find out if the call has failed
141
142 // -------------------------------------------------------------------
143 // Initialize the internal structures
144
145 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING"1.6.44", nullptr, nullptr, nullptr);
6
Value of 'errno' was not checked and may be overwritten by function 'png_create_read_struct'
146
147 if (!png_ptr)
148 {
149 qCWarning(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 149, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).warning()
<< "Invalid PNG image file structure.";
150 fclose(f);
151 loadingFailed();
152
153 return false;
154 }
155
156 info_ptr = png_create_info_struct(png_ptr);
157
158 if (!info_ptr)
159 {
160 qCWarning(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 160, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).warning()
<< "Cannot reading PNG image file structure.";
161 png_destroy_read_struct(&png_ptr, nullptr, nullptr);
162 fclose(f);
163 loadingFailed();
164
165 return false;
166 }
167
168 // -------------------------------------------------------------------
169 // PNG error handling. If an error occurs during reading, libpng
170 // will jump here
171
172 // setjmp-save cleanup
173
174 class Q_DECL_HIDDEN__attribute__((visibility("hidden"))) CleanupData
175 {
176
177 public:
178
179 CleanupData() = default;
180
181 ~CleanupData()
182 {
183 delete [] data;
184 freeLines();
185
186 if (file)
187 {
188 fclose(file);
189 }
190 }
191
192 void setData(uchar* const d)
193 {
194 data = d;
195 }
196
197 void setLines(uchar** const l)
198 {
199 lines = l;
200 }
201
202 void setFile(FILE* const f)
203 {
204 file = f;
205 }
206
207 void setSize(const QSize& s)
208 {
209 size = s;
210 }
211
212 void setColorModel(int c)
213 {
214 cmod = c;
215 }
216
217 void takeData()
218 {
219 data = nullptr;
220 }
221
222 void freeLines()
223 {
224 if (lines)
225 {
226 free(lines);
227 }
228
229 lines = nullptr;
230 }
231
232 public:
233
234 uchar* data = nullptr;
235 uchar** lines = { nullptr };
236 FILE* file = nullptr;
237
238 QSize size;
239 int cmod = 0;
240
241
242 private:
243
244 // Disable
245 CleanupData(const CleanupData&) = delete;
246 CleanupData& operator=(const CleanupData&) = delete;
247 };
248
249 CleanupData* const cleanupData = new CleanupData;
250 cleanupData->setFile(f);
251
252#if PNG_LIBPNG_VER10644 >= 10400
253
254 if (setjmp(png_jmpbuf(png_ptr))_setjmp ((*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf
)))))
)
255
256#else
257
258 if (setjmp(png_ptr->jmpbuf)_setjmp (png_ptr->jmpbuf))
259
260#endif
261
262 {
263 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) nullptr);
264
265 if (
266 !cleanupData->data ||
267 !cleanupData->size.isValid()
268 )
269 {
270 qCWarning(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 270, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).warning()
<< "Internal libPNG error during reading file. Process aborted!";
271 delete cleanupData;
272 loadingFailed();
273
274 return false;
275 }
276
277 // We check only Exif metadata for ICC profile to prevent endless loop
278
279 if (m_loadFlags & LoadICCData)
280 {
281 checkExifWorkingColorSpace();
282 }
283
284 if (observer)
285 {
286 observer->progressInfo(1.0F);
287 }
288
289 imageWidth() = cleanupData->size.width();
290 imageHeight() = cleanupData->size.height();
291 imageData() = cleanupData->data;
292 imageSetAttribute(QLatin1String("format"), QLatin1String("PNG"));
293 imageSetAttribute(QLatin1String("originalColorModel"), cleanupData->cmod);
294 imageSetAttribute(QLatin1String("originalBitDepth"), m_sixteenBit ? 16 : 8);
295 imageSetAttribute(QLatin1String("originalSize"), cleanupData->size);
296
297 cleanupData->takeData();
298 delete cleanupData;
299
300 return true;
301 }
302
303#ifdef PNG_BENIGN_ERRORS_SUPPORTED
304
305 // Change some libpng errors to warnings (e.g. bug 386396).
306
307 png_set_benign_errors(png_ptr, true);
308
309 png_set_option(png_ptr, PNG_SKIP_sRGB_CHECK_PROFILE4, PNG_OPTION_ON3);
310
311#endif
312
313#ifdef Q_OS_WIN
314
315 png_set_read_fn(png_ptr, f, _ReadProc);
316
317#else
318
319 png_init_io(png_ptr, f);
320
321#endif
322
323 // -------------------------------------------------------------------
324 // Read all PNG info up to image data
325
326 png_read_info(png_ptr, info_ptr);
327
328 png_get_IHDR(png_ptr,
329 info_ptr,
330 reinterpret_cast<png_uint_32*>(&w32),
331 reinterpret_cast<png_uint_32*>(&h32),
332 &bit_depth,
333 &color_type,
334 &interlace_type,
335 nullptr,
336 nullptr);
337
338 width = (int)w32;
339 height = (int)h32;
340
341 int colorModel = DImg::COLORMODELUNKNOWN;
342 m_sixteenBit = (bit_depth == 16);
343
344 switch (color_type)
345 {
346 case PNG_COLOR_TYPE_RGB(2): // RGB
347 {
348 m_hasAlpha = false;
349 colorModel = DImg::RGB;
350
351 break;
352 }
353
354 case PNG_COLOR_TYPE_RGB_ALPHA(2 | 4): // RGBA
355 {
356 m_hasAlpha = true;
357 colorModel = DImg::RGB;
358
359 break;
360 }
361
362 case PNG_COLOR_TYPE_GRAY0: // Grayscale
363 {
364 m_hasAlpha = false;
365 colorModel = DImg::GRAYSCALE;
366
367 break;
368 }
369
370 case PNG_COLOR_TYPE_GRAY_ALPHA(4): // Grayscale + Alpha
371 {
372 m_hasAlpha = true;
373 colorModel = DImg::GRAYSCALE;
374
375 break;
376 }
377
378 case PNG_COLOR_TYPE_PALETTE(2 | 1): // Indexed
379 {
380 m_hasAlpha = false;
381 colorModel = DImg::INDEXED;
382
383 break;
384 }
385 }
386
387 cleanupData->setColorModel(colorModel);
388 cleanupData->setSize(QSize(width, height));
389
390 uchar* data = nullptr;
391
392 if (m_loadFlags & LoadImageData)
393 {
394 // TODO: Endianness:
395 // You may notice that the code for little and big endian
396 // below is now identical. This was found to work by PPC users.
397 // If this proves right, all the conditional clauses can be removed.
398
399 if (bit_depth == 16)
400 {
401 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 401, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in 16 bits/color/pixel.";
402
403 switch (color_type)
404 {
405 case PNG_COLOR_TYPE_RGB(2): // RGB
406 {
407 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 407, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in PNG_COLOR_TYPE_RGB";
408 png_set_add_alpha(png_ptr, 0xFFFF, PNG_FILLER_AFTER1);
409
410 break;
411 }
412
413 case PNG_COLOR_TYPE_RGB_ALPHA(2 | 4): // RGBA
414 {
415 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 415, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in PNG_COLOR_TYPE_RGB_ALPHA";
416
417 break;
418 }
419
420 case PNG_COLOR_TYPE_GRAY0: // Grayscale
421 {
422 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 422, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in PNG_COLOR_TYPE_GRAY";
423 png_set_gray_to_rgb(png_ptr);
424 png_set_add_alpha(png_ptr, 0xFFFF, PNG_FILLER_AFTER1);
425
426 break;
427 }
428
429 case PNG_COLOR_TYPE_GRAY_ALPHA(4): // Grayscale + Alpha
430 {
431 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 431, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in PNG_COLOR_TYPE_GRAY_ALPHA";
432 png_set_gray_to_rgb(png_ptr);
433
434 break;
435 }
436
437 case PNG_COLOR_TYPE_PALETTE(2 | 1): // Indexed
438 {
439 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 439, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in PNG_COLOR_TYPE_PALETTE";
440 png_set_palette_to_rgb(png_ptr);
441 png_set_add_alpha(png_ptr, 0xFFFF, PNG_FILLER_AFTER1);
442
443 break;
444 }
445
446 default:
447 {
448 qCWarning(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 448, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).warning()
<< "PNG color type unknown.";
449 delete cleanupData;
450 loadingFailed();
451
452 return false;
453 }
454 }
455 }
456 else
457 {
458 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 458, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in >=8 bits/color/pixel.";
459 png_set_packing(png_ptr);
460
461 switch (color_type)
462 {
463 case PNG_COLOR_TYPE_RGB(2): // RGB
464 {
465 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 465, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in PNG_COLOR_TYPE_RGB";
466 png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER1);
467
468 break;
469 }
470
471 case PNG_COLOR_TYPE_RGB_ALPHA(2 | 4): // RGBA
472 {
473 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 473, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in PNG_COLOR_TYPE_RGB_ALPHA";
474
475 break;
476 }
477
478 case PNG_COLOR_TYPE_GRAY0: // Grayscale
479 {
480 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 480, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in PNG_COLOR_TYPE_GRAY";
481
482#if PNG_LIBPNG_VER10644 >= 10400
483
484 png_set_expand_gray_1_2_4_to_8(png_ptr);
485
486#else
487
488 png_set_gray_1_2_4_to_8(png_ptr);
489
490#endif
491
492 png_set_gray_to_rgb(png_ptr);
493 png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER1);
494
495 break;
496 }
497
498 case PNG_COLOR_TYPE_GRAY_ALPHA(4): // Grayscale + alpha
499 {
500 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 500, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in PNG_COLOR_TYPE_GRAY_ALPHA";
501 png_set_gray_to_rgb(png_ptr);
502
503 break;
504 }
505
506 case PNG_COLOR_TYPE_PALETTE(2 | 1): // Indexed
507 {
508 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 508, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "PNG in PNG_COLOR_TYPE_PALETTE";
509 png_set_packing(png_ptr);
510 png_set_palette_to_rgb(png_ptr);
511 png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER1);
512
513 break;
514 }
515
516 default:
517 {
518 qCWarning(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 518, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).warning()
<< "PNG color type unknown." << color_type;
519 delete cleanupData;
520 loadingFailed();
521
522 return false;
523 }
524 }
525 }
526
527 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS0x0010U))
528 {
529 png_set_tRNS_to_alpha(png_ptr);
530 }
531
532 double file_gamma;
533
534 if (png_get_gAMA(png_ptr, info_ptr, &file_gamma))
535 {
536 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 536, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "Apply PNG file gamma" << file_gamma;
537
538 png_set_gamma(png_ptr, 2.2, file_gamma);
539 }
540
541 png_set_bgr(png_ptr);
542
543 //png_set_swap_alpha(png_ptr);
544
545 if (observer)
546 {
547 observer->progressInfo(0.1F);
548 }
549
550 // -------------------------------------------------------------------
551 // Get image data.
552
553 // Call before png_read_update_info and png_start_read_image()
554 // for non-interlaced images number_passes will be 1
555
556 int number_passes = png_set_interlace_handling(png_ptr);
557
558 png_read_update_info(png_ptr, info_ptr);
559
560 if (m_sixteenBit)
561 {
562 data = new_failureTolerant(width, height, 8); // 16 bits/color/pixel
563 }
564 else
565 {
566 data = new_failureTolerant(width, height, 4); // 8 bits/color/pixel
567 }
568
569 cleanupData->setData(data);
570
571 uchar** lines = nullptr;
572 (void)lines; // to prevent cppcheck warnings.
573 lines = reinterpret_cast<unsigned char**>(malloc(height * sizeof(uchar*)));
574 cleanupData->setLines(lines);
575
576 if (!data || !lines)
577 {
578 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 578, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "Cannot allocate memory to load PNG image data.";
579 png_read_end(png_ptr, info_ptr);
580 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) nullptr);
581 delete cleanupData;
582 loadingFailed();
583
584 return false;
585 }
586
587 for (int i = 0 ; i < height ; ++i)
588 {
589 if (m_sixteenBit)
590 {
591 lines[i] = data + ((quint64)i * (quint64)width * 8);
592 }
593 else
594 {
595 lines[i] = data + ((quint64)i * (quint64)width * 4);
596 }
597 }
598
599 // The easy way to read the whole image
600 // png_read_image(png_ptr, lines);
601 // The other way to read images is row by row. Necessary for observer.
602 // Now we need to deal with interlacing.
603
604 for (int pass = 0 ; pass < number_passes ; ++pass)
605 {
606 int checkPoint = 0;
607
608 for (int y = 0 ; y < height ; ++y)
609 {
610 if (observer && (y == checkPoint))
611 {
612 checkPoint += granularity(observer, height, 0.7F);
613
614 if (!observer->continueQuery())
615 {
616 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) nullptr);
617 delete cleanupData;
618 loadingFailed();
619
620 return false;
621 }
622
623 // use 10% - 80% for progress while reading rows
624
625 observer->progressInfo(0.1F + (0.7F * (((float)y) / ((float)height))));
626 }
627
628 png_read_rows(png_ptr, lines + y, nullptr, 1);
629 }
630 }
631
632 cleanupData->freeLines();
633
634 if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)
635 {
636 // Swap bytes in 16 bits/color/pixel for DImg
637
638 if (m_sixteenBit)
639 {
640 uchar ptr[8]; // One pixel to swap
641
642 for (uint p = 0 ; p < (uint)width * height * 8 ; p += 8)
643 {
644 memcpy(&ptr[0], &data[p], 8); // Current pixel
645
646 data[ p ] = ptr[1]; // Blue
647 data[p + 1] = ptr[0];
648 data[p + 2] = ptr[3]; // Green
649 data[p + 3] = ptr[2];
650 data[p + 4] = ptr[5]; // Red
651 data[p + 5] = ptr[4];
652 data[p + 6] = ptr[7]; // Alpha
653 data[p + 7] = ptr[6];
654 }
655 }
656 }
657 }
658
659 if (observer)
660 {
661 observer->progressInfo(0.9F);
662 }
663
664 // -------------------------------------------------------------------
665 // Read image ICC profile
666
667 if (m_loadFlags & LoadICCData)
668 {
669 png_charp profile_name;
670 iCCP_data profile_data = nullptr;
671 png_uint_32 profile_size;
672 int compression_type;
673
674 png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_size);
675
676 if (profile_data != nullptr)
677 {
678 QByteArray profile_rawdata;
679 profile_rawdata.resize(profile_size);
680 memcpy(profile_rawdata.data(), profile_data, profile_size);
681 imageSetIccProfile(IccProfile(profile_rawdata));
682 }
683 else
684 {
685 // If ICC profile is null, check Exif metadata.
686
687 checkExifWorkingColorSpace();
688 }
689 }
690
691 // -------------------------------------------------------------------
692 // Get embedded text data.
693
694 png_text* text_ptr = nullptr;
695 int num_comments = png_get_text(png_ptr, info_ptr, &text_ptr, nullptr);
696
697 /*
698 Standard Embedded text includes in PNG :
699
700 Title Short (one line) title or caption for image
701 Author Name of image's creator
702 Description Description of image (possibly long)
703 Copyright Copyright notice
704 Creation Time Time of original image creation
705 Software Software used to create the image
706 Disclaimer Legal disclaimer
707 Warning Warning of nature of content
708 Source Device used to create the image
709 Comment Miscellaneous comment; conversion from GIF comment
710
711 Extra Raw profiles tag are used by ImageMagick and defines at this Url:
712 search.cpan.org/src/EXIFTOOL/Image-ExifTool-5.87/html/TagNames/PNG.html#TextualData
713 */
714
715 if (m_loadFlags & LoadICCData)
716 {
717 for (int i = 0 ; i < num_comments ; ++i)
718 {
719 // Check if we have a Raw profile embedded using ImageMagick technique.
720
721 if ((memcmp(text_ptr[i].key, "Raw profile type exif", 21) != 0) ||
722 (memcmp(text_ptr[i].key, "Raw profile type APP1", 21) != 0) ||
723 (memcmp(text_ptr[i].key, "Raw profile type iptc", 21) != 0))
724 {
725 imageSetEmbbededText(QLatin1String(text_ptr[i].key), QLatin1String(text_ptr[i].text));
726
727 qCDebug(DIGIKAM_DIMG_LOG_PNG)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category
((DIGIKAM_DIMG_LOG_PNG)()); qt_category; qt_category.control =
false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/png/dimgpngloader_load.cpp"
), 727, static_cast<const char *>(__PRETTY_FUNCTION__),
qt_category.name()).debug()
<< "Reading PNG Embedded text: key=" << text_ptr[i].key
728 << "size=" << QLatin1String(text_ptr[i].text).size();
729 }
730 }
731 }
732
733 // -------------------------------------------------------------------
734
735 if (m_loadFlags & LoadImageData)
736 {
737 png_read_end(png_ptr, info_ptr);
738 }
739
740 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) nullptr);
741 cleanupData->takeData();
742 delete cleanupData;
743
744 if (observer)
745 {
746 observer->progressInfo(1.0F);
747 }
748
749 imageWidth() = width;
750 imageHeight() = height;
751 imageData() = data;
752 imageSetAttribute(QLatin1String("format"), QLatin1String("PNG"));
753 imageSetAttribute(QLatin1String("originalColorModel"), colorModel);
754 imageSetAttribute(QLatin1String("originalBitDepth"), bit_depth);
755 imageSetAttribute(QLatin1String("originalSize"), QSize(width, height));
756
757 return true;
758}
759
760} // namespace DigikamPNGDImgPlugin