File indexing completed on 2024-05-12 04:19:35

0001 // vim: set tabstop=4 shiftwidth=4 expandtab:
0002 /*
0003 Gwenview: an image viewer
0004 Copyright 2012 Aurélien Gâteau <agateau@kde.org>
0005 
0006 This program is free software; you can redistribute it and/or
0007 modify it under the terms of the GNU General Public License
0008 as published by the Free Software Foundation; either version 2
0009 of the License, or (at your option) any later version.
0010 
0011 This program is distributed in the hope that it will be useful,
0012 but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 GNU General Public License for more details.
0015 
0016 You should have received a copy of the GNU General Public License
0017 along with this program; if not, write to the Free Software
0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
0019 
0020 */
0021 // Self
0022 #include "cmsprofile_png.h"
0023 
0024 // Local
0025 #include <gvdebug.h>
0026 #include "gwenview_lib_debug.h"
0027 
0028 // KF
0029 
0030 // Qt
0031 #include <QBuffer>
0032 
0033 // lcms
0034 #include <lcms2.h>
0035 
0036 // libpng
0037 #include <png.h>
0038 
0039 namespace Gwenview
0040 {
0041 
0042 namespace Cms
0043 {
0044 
0045 static void readPngChunk(png_structp png_ptr, png_bytep data, png_size_t length)
0046 {
0047     auto in = (QIODevice *)png_get_io_ptr(png_ptr);
0048 
0049     while (length) {
0050         int nr = in->read((char*)data, length);
0051         if (nr <= 0) {
0052             png_error(png_ptr, "Read Error");
0053             return;
0054         }
0055         length -= nr;
0056     }
0057 }
0058 
0059 cmsHPROFILE loadFromPngData(const QByteArray& data)
0060 {
0061     QBuffer buffer;
0062     buffer.setBuffer(const_cast<QByteArray*>(&data));
0063     buffer.open(QIODevice::ReadOnly);
0064 
0065     // Initialize the internal structures
0066     png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
0067     GV_RETURN_VALUE_IF_FAIL(png_ptr, nullptr);
0068 
0069     png_infop info_ptr = png_create_info_struct(png_ptr);
0070     if (!info_ptr) {
0071         png_destroy_read_struct(&png_ptr, (png_infopp)nullptr, (png_infopp)nullptr);
0072         qCWarning(GWENVIEW_LIB_LOG) << "Could not create info_struct";
0073         return nullptr;
0074     }
0075 
0076     png_infop end_info = png_create_info_struct(png_ptr);
0077     if (!end_info) {
0078         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)nullptr);
0079         qCWarning(GWENVIEW_LIB_LOG) << "Could not create info_struct2";
0080         return nullptr;
0081     }
0082 
0083     // Catch errors
0084     if (setjmp(png_jmpbuf(png_ptr))) {
0085         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
0086         qCWarning(GWENVIEW_LIB_LOG) << "Error decoding png file";
0087         return nullptr;
0088     }
0089 
0090     // Initialize the special
0091     png_set_read_fn(png_ptr, &buffer, readPngChunk);
0092 
0093     // read all PNG info up to image data
0094     png_read_info(png_ptr, info_ptr);
0095 
0096     // Get profile
0097     png_charp profile_name;
0098 #if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 5
0099     png_bytep profile_data;
0100 #else
0101     png_charp profile_data;
0102 #endif
0103     int compression_type;
0104     png_uint_32 proflen;
0105 
0106     cmsHPROFILE profile = nullptr;
0107     if (png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &proflen)) {
0108         profile = cmsOpenProfileFromMem(profile_data, proflen);
0109     }
0110     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
0111     return profile;
0112 }
0113 
0114 } // namespace Cms
0115 } // namespace Gwenview