~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to ksplash/ksplashx/qpngio.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** This file is based on sources of the Qt GUI Toolkit, used under the terms
 
4
** of the GNU General Public License version 2 (see the original copyright
 
5
** notice below).
 
6
** All further contributions to this file are (and are required to be)
 
7
** licensed under the terms of the GNU General Public License as published by
 
8
** the Free Software Foundation; either version 2 of the License, or
 
9
** (at your option) any later version.
 
10
**
 
11
** The original Qt license header follows:
 
12
** 
 
13
**
 
14
** Implementation of PNG QImage IOHandler
 
15
**
 
16
** Created : 970521
 
17
**
 
18
** Copyright (C) 1992-2003 Trolltech AS.  All rights reserved.
 
19
**
 
20
** This file is part of the kernel module of the Qt GUI Toolkit.
 
21
**
 
22
** This file may be distributed under the terms of the Q Public License
 
23
** as defined by Trolltech AS of Norway and appearing in the file
 
24
** LICENSE.QPL included in the packaging of this file.
 
25
**
 
26
** This file may be distributed and/or modified under the terms of the
 
27
** GNU General Public License version 2 as published by the Free Software
 
28
** Foundation and appearing in the file LICENSE.GPL included in the
 
29
** packaging of this file.
 
30
**
 
31
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
 
32
** licenses may use this file in accordance with the Qt Commercial License
 
33
** Agreement provided with the Software.
 
34
**
 
35
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
36
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
37
**
 
38
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
39
**   information about Qt Commercial License Agreements.
 
40
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
41
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
42
**
 
43
** Contact info@trolltech.com if any conditions of this licensing are
 
44
** not clear to you.
 
45
**
 
46
**********************************************************************/
 
47
 
 
48
#ifndef QT_NO_IMAGEIO_PNG
 
49
 
 
50
#include "qimage.h"
 
51
#include "qcolor.h"
 
52
 
 
53
#include <png.h>
 
54
 
 
55
 
 
56
#ifdef Q_OS_TEMP
 
57
#define CALLBACK_CALL_TYPE      __cdecl
 
58
#else
 
59
#define CALLBACK_CALL_TYPE
 
60
#endif
 
61
 
 
62
 
 
63
/*
 
64
  All PNG files load to the minimal QImage equivalent.
 
65
 
 
66
  All QImage formats output to reasonably efficient PNG equivalents.
 
67
  Never to grayscale.
 
68
*/
 
69
 
 
70
#if defined(Q_C_CALLBACKS)
 
71
extern "C" {
 
72
#endif
 
73
 
 
74
static
 
75
void CALLBACK_CALL_TYPE iod_read_fn(png_structp png_ptr, png_bytep data, png_size_t length)
 
76
{
 
77
    FILE* in = (FILE*)png_get_io_ptr(png_ptr);
 
78
 
 
79
    while (length) {
 
80
        int nr = fread( (char*)data, 1, length, in );
 
81
        if (nr <= 0) {
 
82
            png_error(png_ptr, "Read Error");
 
83
            return;
 
84
        }
 
85
        length -= nr;
 
86
    }
 
87
}
 
88
 
 
89
 
 
90
#if defined(Q_C_CALLBACKS)
 
91
}
 
92
#endif
 
93
 
 
94
static
 
95
void setup_qt( QImage& image, png_structp png_ptr, png_infop info_ptr, float screen_gamma=0.0 )
 
96
{
 
97
    if ( 0.0 == screen_gamma )
 
98
        // PNG docs say this is a good guess for a PC monitor
 
99
        // in a dark room
 
100
        screen_gamma = 2.2;
 
101
    if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA) ) {
 
102
        // the file has a gAMA attribute
 
103
        double file_gamma;
 
104
        if ( png_get_gAMA(png_ptr, info_ptr, &file_gamma))
 
105
            png_set_gamma( png_ptr, screen_gamma, file_gamma );
 
106
    } else {
 
107
        // no file gamma, use a reasonable default
 
108
        png_set_gamma( png_ptr, screen_gamma, 0.45455 ); 
 
109
    }
 
110
 
 
111
    png_uint_32 width;
 
112
    png_uint_32 height;
 
113
    int bit_depth;
 
114
    int color_type;
 
115
    png_bytep trans_alpha = 0;
 
116
    png_color_16p trans_color_p = 0;
 
117
    int num_trans;
 
118
    png_colorp palette = 0;
 
119
    int num_palette;
 
120
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
 
121
 
 
122
    if ( color_type == PNG_COLOR_TYPE_GRAY ) {
 
123
        // Black & White or 8-bit grayscale
 
124
        if ( bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1 ) {
 
125
            png_set_invert_mono( png_ptr );
 
126
            png_read_update_info( png_ptr, info_ptr );
 
127
            if (!image.create( width, height, 1, 2, QImage::BigEndian ))
 
128
                return;
 
129
            image.setColor( 1, qRgb(0,0,0) );
 
130
            image.setColor( 0, qRgb(255,255,255) );
 
131
        } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
 
132
            png_set_expand(png_ptr);
 
133
            png_set_strip_16(png_ptr);
 
134
            png_set_gray_to_rgb(png_ptr);
 
135
 
 
136
            if (!image.create(width, height, 32))
 
137
                return;
 
138
            image.setAlphaBuffer(true);
 
139
 
 
140
            if (QImage::systemByteOrder() == QImage::BigEndian)
 
141
                png_set_swap_alpha(png_ptr);
 
142
 
 
143
            png_read_update_info(png_ptr, info_ptr);
 
144
        } else {
 
145
            if ( bit_depth == 16 )
 
146
                png_set_strip_16(png_ptr);
 
147
            else if ( bit_depth < 8 )
 
148
                png_set_packing(png_ptr);
 
149
            int ncols = bit_depth < 8 ? 1 << bit_depth : 256;
 
150
            png_read_update_info(png_ptr, info_ptr);
 
151
            if (!image.create(width, height, 8, ncols))
 
152
                return;
 
153
            for (int i=0; i<ncols; i++) {
 
154
                int c = i*255/(ncols-1);
 
155
                image.setColor( i, qRgba(c,c,c,0xff) );
 
156
            }
 
157
            if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) {
 
158
                const int g = trans_color_p->gray;
 
159
                if (g < ncols) {
 
160
                    image.setColor(g, 0);
 
161
                }
 
162
            }
 
163
        }
 
164
    } else if (color_type == PNG_COLOR_TYPE_PALETTE
 
165
               && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)
 
166
               && num_palette <= 256)
 
167
    {
 
168
        // 1-bit and 8-bit color
 
169
        if ( bit_depth != 1 )
 
170
            png_set_packing( png_ptr );
 
171
        png_read_update_info( png_ptr, info_ptr );
 
172
        png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
 
173
        if (!image.create(width, height, bit_depth, num_palette,
 
174
            QImage::BigEndian))
 
175
            return;
 
176
        int i = 0;
 
177
        png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
 
178
        if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) {
 
179
            image.setAlphaBuffer( true );
 
180
            while ( i < num_trans ) {
 
181
                image.setColor(i, qRgba(
 
182
                    palette[i].red,
 
183
                    palette[i].green,
 
184
                    palette[i].blue,
 
185
                    trans_alpha[i]
 
186
                    )
 
187
                );
 
188
                i++;
 
189
            }
 
190
        }
 
191
        while ( i < num_palette ) {
 
192
            image.setColor(i, qRgba(
 
193
                palette[i].red,
 
194
                palette[i].green,
 
195
                palette[i].blue,
 
196
                0xff
 
197
                )
 
198
            );
 
199
            i++;
 
200
        }
 
201
    } else {
 
202
        // 32-bit
 
203
        if ( bit_depth == 16 )
 
204
            png_set_strip_16(png_ptr);
 
205
 
 
206
        png_set_expand(png_ptr);
 
207
 
 
208
        if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
 
209
            png_set_gray_to_rgb(png_ptr);
 
210
 
 
211
        if (!image.create(width, height, 32))
 
212
            return;
 
213
 
 
214
        // Only add filler if no alpha, or we can get 5 channel data.
 
215
        if (!(color_type & PNG_COLOR_MASK_ALPHA)
 
216
           && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
 
217
            png_set_filler(png_ptr, 0xff,
 
218
                QImage::systemByteOrder() == QImage::BigEndian ?
 
219
                    PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
 
220
            // We want 4 bytes, but it isn't an alpha channel
 
221
        } else {
 
222
            image.setAlphaBuffer(true);
 
223
        }
 
224
 
 
225
        if ( QImage::systemByteOrder() == QImage::BigEndian ) {
 
226
            png_set_swap_alpha(png_ptr);
 
227
        }
 
228
 
 
229
        png_read_update_info(png_ptr, info_ptr);
 
230
    }
 
231
 
 
232
    // Qt==ARGB==Big(ARGB)==Little(BGRA)
 
233
    if ( QImage::systemByteOrder() == QImage::LittleEndian ) {
 
234
        png_set_bgr(png_ptr);
 
235
    }
 
236
}
 
237
 
 
238
 
 
239
#if defined(Q_C_CALLBACKS)
 
240
extern "C" {
 
241
#endif
 
242
static void CALLBACK_CALL_TYPE qt_png_warning(png_structp /*png_ptr*/, png_const_charp message)
 
243
{
 
244
    qWarning("libpng warning: %s", message);
 
245
}
 
246
 
 
247
#if defined(Q_C_CALLBACKS)
 
248
}
 
249
#endif
 
250
 
 
251
 
 
252
QImage splash_read_png_image(FILE* f)
 
253
{
 
254
    png_structp png_ptr;
 
255
    png_infop info_ptr;
 
256
    png_infop end_info;
 
257
    png_bytep* row_pointers;
 
258
 
 
259
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
 
260
    if (!png_ptr) {
 
261
        return QImage();
 
262
    }
 
263
 
 
264
    png_set_error_fn(png_ptr, 0, 0, qt_png_warning);
 
265
 
 
266
    info_ptr = png_create_info_struct(png_ptr);
 
267
    if (!info_ptr) {
 
268
        png_destroy_read_struct(&png_ptr, 0, 0);
 
269
        return QImage();
 
270
    }
 
271
 
 
272
    end_info = png_create_info_struct(png_ptr);
 
273
    if (!end_info) {
 
274
        png_destroy_read_struct(&png_ptr, &info_ptr, 0);
 
275
        return QImage();
 
276
    }
 
277
 
 
278
    if (setjmp(png_jmpbuf(png_ptr))) {
 
279
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 
280
        return QImage();
 
281
    }
 
282
 
 
283
    png_set_read_fn(png_ptr, (void*)f, iod_read_fn);
 
284
    png_read_info(png_ptr, info_ptr);
 
285
 
 
286
    QImage image;
 
287
    setup_qt(image, png_ptr, info_ptr, 0);
 
288
    if (image.isNull()) {
 
289
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 
290
        return QImage();
 
291
    }
 
292
 
 
293
    png_uint_32 width;
 
294
    png_uint_32 height;
 
295
    int bit_depth;
 
296
    int color_type;
 
297
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
 
298
        0, 0, 0);
 
299
 
 
300
    uchar** jt = image.jumpTable();
 
301
    row_pointers=new png_bytep[height];
 
302
 
 
303
    for (uint y=0; y<height; y++) {
 
304
        row_pointers[y]=jt[y];
 
305
    }
 
306
 
 
307
    png_read_image(png_ptr, row_pointers);
 
308
 
 
309
#if 0 // libpng takes care of this.
 
310
png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)
 
311
    if (image.depth()==32 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
 
312
        QRgb trans = 0xFF000000 | qRgb(
 
313
              (info_ptr->trans_values.red << 8 >> bit_depth)&0xff,
 
314
              (info_ptr->trans_values.green << 8 >> bit_depth)&0xff,
 
315
              (info_ptr->trans_values.blue << 8 >> bit_depth)&0xff);
 
316
        for (uint y=0; y<height; y++) {
 
317
            for (uint x=0; x<info_ptr->width; x++) {
 
318
                if (((uint**)jt)[y][x] == trans) {
 
319
                    ((uint**)jt)[y][x] &= 0x00FFFFFF;
 
320
                } else {
 
321
                }
 
322
            }
 
323
        }
 
324
    }
 
325
#endif
 
326
 
 
327
    image.setDotsPerMeterX(png_get_x_pixels_per_meter(png_ptr,info_ptr));
 
328
    image.setDotsPerMeterY(png_get_y_pixels_per_meter(png_ptr,info_ptr));
 
329
 
 
330
#ifndef QT_NO_IMAGE_TEXT
 
331
    png_textp text_ptr;
 
332
    int num_text=0;
 
333
    png_get_text(png_ptr,info_ptr,&text_ptr,&num_text);
 
334
    while (num_text--) {
 
335
        image.setText(text_ptr->key,0,text_ptr->text);
 
336
        text_ptr++;
 
337
    }
 
338
#endif
 
339
 
 
340
    delete [] row_pointers;
 
341
 
 
342
    if ( image.hasAlphaBuffer() ) {
 
343
        // Many PNG files lie (eg. from PhotoShop). Fortunately this loop will
 
344
        // usually be quick to find those that tell the truth.
 
345
        QRgb* c;
 
346
        int n;
 
347
        if (image.depth()==32) {
 
348
            c = (QRgb*)image.bits();
 
349
            n = image.bytesPerLine() * image.height() / 4;
 
350
        } else {
 
351
            c = image.colorTable();
 
352
            n = image.numColors();
 
353
        }
 
354
        while ( n-- && qAlpha(*c++)==0xff )
 
355
            ;
 
356
        if ( n<0 ) // LIAR!
 
357
            image.setAlphaBuffer(false);
 
358
    }
 
359
 
 
360
    png_read_end(png_ptr, end_info);
 
361
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 
362
 
 
363
    return image;
 
364
}
 
365
#endif // QT_NO_IMAGEIO_PNG