File indexing completed on 2024-04-28 04:18:51

0001 // vim: set tabstop=4 shiftwidth=4 expandtab:
0002 /*
0003 Gwenview: an image viewer
0004 Copyright 2008 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 "iodevicejpegsourcemanager.h"
0023 
0024 // Qt
0025 #include <QIODevice>
0026 
0027 // KF
0028 
0029 // libjpeg
0030 #include <cstdio>
0031 #define XMD_H
0032 extern "C" {
0033 #include <jpeglib.h>
0034 }
0035 
0036 // Local
0037 #include "gwenview_lib_debug.h"
0038 
0039 namespace Gwenview
0040 {
0041 namespace IODeviceJpegSourceManager
0042 {
0043 #define SOURCE_MANAGER_BUFFER_SIZE 4096
0044 struct IODeviceJpegSourceManager : public jpeg_source_mgr {
0045     QIODevice *mIODevice;
0046     JOCTET mBuffer[SOURCE_MANAGER_BUFFER_SIZE];
0047 };
0048 
0049 static boolean fill_input_buffer(j_decompress_ptr cinfo)
0050 {
0051     auto src = static_cast<IODeviceJpegSourceManager *>(cinfo->src);
0052     Q_ASSERT(src->mIODevice);
0053     int readSize = src->mIODevice->read((char *)src->mBuffer, SOURCE_MANAGER_BUFFER_SIZE);
0054     if (readSize > 0) {
0055         src->next_input_byte = src->mBuffer;
0056         src->bytes_in_buffer = readSize;
0057     } else {
0058         /**
0059          * JPEG file is broken. We feed the decoder with fake EOI, as specified
0060          * in the libjpeg documentation.
0061          */
0062         static JOCTET fakeEOI[2] = {JOCTET(0xFF), JOCTET(JPEG_EOI)};
0063         qCWarning(GWENVIEW_LIB_LOG) << "Image is incomplete";
0064         cinfo->src->next_input_byte = fakeEOI;
0065         cinfo->src->bytes_in_buffer = 2;
0066     }
0067     return true;
0068 }
0069 
0070 static void init_source(j_decompress_ptr cinfo)
0071 {
0072     fill_input_buffer(cinfo);
0073 }
0074 
0075 static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
0076 {
0077     if (num_bytes > 0) {
0078         while (num_bytes > (long)cinfo->src->bytes_in_buffer) {
0079             num_bytes -= (long)cinfo->src->bytes_in_buffer;
0080             fill_input_buffer(cinfo);
0081             /**
0082              * we assume that fill_input_buffer will never return FALSE, so
0083              * suspension need not be handled.
0084              */
0085         }
0086         cinfo->src->next_input_byte += (size_t)num_bytes;
0087         cinfo->src->bytes_in_buffer -= (size_t)num_bytes;
0088     }
0089 }
0090 
0091 static void term_source(j_decompress_ptr)
0092 {
0093 }
0094 
0095 void setup(j_decompress_ptr cinfo, QIODevice *ioDevice)
0096 {
0097     Q_ASSERT(!cinfo->src);
0098     auto src = (IODeviceJpegSourceManager *)(*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(IODeviceJpegSourceManager));
0099     cinfo->src = src;
0100 
0101     src->init_source = init_source;
0102     src->fill_input_buffer = fill_input_buffer;
0103     src->skip_input_data = skip_input_data;
0104     src->resync_to_restart = jpeg_resync_to_restart;
0105     src->term_source = term_source;
0106 
0107     src->mIODevice = ioDevice;
0108 }
0109 
0110 } // IODeviceJpegSourceManager namespace
0111 } // Gwenview namespace