~alan-griffiths/compiz-core/Bug-931283

« back to all changes in this revision

Viewing changes to src/readpng.c

  • Committer: David Reveman
  • Date: 2006-02-09 06:03:09 UTC
  • Revision ID: git-v1:9959c2b13ded64a5e66359a8097250dc9d87fc1c
Initial revision

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2005 Novell, Inc.
 
3
 *
 
4
 * Permission to use, copy, modify, distribute, and sell this software
 
5
 * and its documentation for any purpose is hereby granted without
 
6
 * fee, provided that the above copyright notice appear in all copies
 
7
 * and that both that copyright notice and this permission notice
 
8
 * appear in supporting documentation, and that the name of
 
9
 * Novell, Inc. not be used in advertising or publicity pertaining to
 
10
 * distribution of the software without specific, written prior permission.
 
11
 * Novell, Inc. makes no representations about the suitability of this
 
12
 * software for any purpose. It is provided "as is" without express or
 
13
 * implied warranty.
 
14
 *
 
15
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
16
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 
17
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
18
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 
19
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 
20
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 
21
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
22
 *
 
23
 * Author: David Reveman <davidr@novell.com>
 
24
 */
 
25
 
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
#include <png.h>
 
30
#include <setjmp.h>
 
31
 
 
32
#include <compiz.h>
 
33
 
 
34
#define HOME_IMAGEDIR ".compiz/images"
 
35
 
 
36
#define PNG_SIG_SIZE 8
 
37
 
 
38
static void
 
39
premultiplyData (png_structp   png,
 
40
                 png_row_infop row_info,
 
41
                 png_bytep     data)
 
42
{
 
43
    unsigned int i;
 
44
 
 
45
    for (i = 0; i < row_info->rowbytes; i += 4)
 
46
    {
 
47
        unsigned char *base = &data[i];
 
48
        unsigned char blue  = base[0];
 
49
        unsigned char green = base[1];
 
50
        unsigned char red   = base[2];
 
51
        unsigned char alpha = base[3];
 
52
        int           p;
 
53
 
 
54
        red   = (unsigned) red   * (unsigned) alpha / 255;
 
55
        green = (unsigned) green * (unsigned) alpha / 255;
 
56
        blue  = (unsigned) blue  * (unsigned) alpha / 255;
 
57
 
 
58
        p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
 
59
        memcpy (base, &p, sizeof (int));
 
60
    }
 
61
}
 
62
 
 
63
static Bool
 
64
readPngData (png_struct   *png,
 
65
             png_info     *info,
 
66
             char         **data,
 
67
             unsigned int *width,
 
68
             unsigned int *height)
 
69
{
 
70
    png_uint_32  png_width, png_height;
 
71
    int          depth, color_type, interlace, i;
 
72
    unsigned int pixel_size;
 
73
    png_byte     **row_pointers;
 
74
 
 
75
    png_read_info (png, info);
 
76
 
 
77
    png_get_IHDR (png, info,
 
78
                  &png_width, &png_height, &depth,
 
79
                  &color_type, &interlace, NULL, NULL);
 
80
 
 
81
    *width  = png_width;
 
82
    *height = png_height;
 
83
 
 
84
    /* convert palette/gray image to rgb */
 
85
    if (color_type == PNG_COLOR_TYPE_PALETTE)
 
86
        png_set_palette_to_rgb (png);
 
87
 
 
88
    /* expand gray bit depth if needed */
 
89
    if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8)
 
90
        png_set_gray_1_2_4_to_8 (png);
 
91
 
 
92
    /* transform transparency to alpha */
 
93
    if (png_get_valid(png, info, PNG_INFO_tRNS))
 
94
        png_set_tRNS_to_alpha (png);
 
95
 
 
96
    if (depth == 16)
 
97
        png_set_strip_16 (png);
 
98
 
 
99
    if (depth < 8)
 
100
        png_set_packing (png);
 
101
 
 
102
    /* convert grayscale to RGB */
 
103
    if (color_type == PNG_COLOR_TYPE_GRAY ||
 
104
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
 
105
        png_set_gray_to_rgb (png);
 
106
 
 
107
    if (interlace != PNG_INTERLACE_NONE)
 
108
        png_set_interlace_handling (png);
 
109
 
 
110
    png_set_bgr (png);
 
111
    png_set_filler (png, 0xff, PNG_FILLER_AFTER);
 
112
 
 
113
    png_set_read_user_transform_fn (png, premultiplyData);
 
114
 
 
115
    png_read_update_info (png, info);
 
116
 
 
117
    pixel_size = 4;
 
118
    *data = (char *) malloc (png_width * png_height * pixel_size);
 
119
    if (*data == NULL)
 
120
        return FALSE;
 
121
 
 
122
    row_pointers = (png_byte **) malloc (png_height * sizeof (char *));
 
123
    if (!row_pointers)
 
124
    {
 
125
        free (*data);
 
126
        return FALSE;
 
127
    }
 
128
 
 
129
    for (i = 0; i < png_height; i++)
 
130
        row_pointers[i] = (png_byte *) (*data + i * png_width * pixel_size);
 
131
 
 
132
    png_read_image (png, row_pointers);
 
133
    png_read_end (png, info);
 
134
 
 
135
    free (row_pointers);
 
136
 
 
137
    return TRUE;
 
138
}
 
139
 
 
140
Bool
 
141
readPng (const char   *filename,
 
142
         char         **data,
 
143
         unsigned int *width,
 
144
         unsigned int *height)
 
145
{
 
146
    unsigned char png_sig[PNG_SIG_SIZE];
 
147
    FILE          *file;
 
148
    int           sig_bytes;
 
149
    png_struct    *png;
 
150
    png_info      *info;
 
151
    Bool          status;
 
152
 
 
153
    file = fopen (filename, "r");
 
154
    if (!file)
 
155
    {
 
156
        char *home, *imagedir;
 
157
 
 
158
        home = getenv ("HOME");
 
159
        if (home)
 
160
        {
 
161
            imagedir = malloc (strlen (home) +
 
162
                               strlen (HOME_IMAGEDIR) +
 
163
                               strlen (filename) + 3);
 
164
            if (imagedir)
 
165
            {
 
166
                sprintf (imagedir, "%s/%s/%s", home, HOME_IMAGEDIR, filename);
 
167
                file = fopen (imagedir, "r");
 
168
                free (imagedir);
 
169
            }
 
170
        }
 
171
 
 
172
        if (!file)
 
173
        {
 
174
            imagedir = malloc (strlen (IMAGEDIR) + strlen (filename) + 2);
 
175
            if (imagedir)
 
176
            {
 
177
                sprintf (imagedir, "%s/%s", IMAGEDIR, filename);
 
178
                file = fopen (imagedir, "r");
 
179
                free (imagedir);
 
180
            }
 
181
 
 
182
            if (!file)
 
183
                return FALSE;
 
184
        }
 
185
    }
 
186
 
 
187
    sig_bytes = fread (png_sig, 1, PNG_SIG_SIZE, file);
 
188
    if (png_check_sig (png_sig, sig_bytes) == 0)
 
189
    {
 
190
        fclose (file);
 
191
        return FALSE;
 
192
    }
 
193
 
 
194
    png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
195
    if (!png)
 
196
        return FALSE;
 
197
 
 
198
    info = png_create_info_struct (png);
 
199
    if (info == NULL)
 
200
    {
 
201
        png_destroy_read_struct (&png, NULL, NULL);
 
202
        fclose (file);
 
203
 
 
204
        return FALSE;
 
205
    }
 
206
 
 
207
    png_init_io (png, file);
 
208
    png_set_sig_bytes (png, sig_bytes);
 
209
 
 
210
    status = readPngData (png, info, data, width, height);
 
211
 
 
212
    png_destroy_read_struct (&png, &info, NULL);
 
213
    fclose (file);
 
214
 
 
215
    return status;
 
216
}
 
217
 
 
218
static void
 
219
userReadData (png_structp png_ptr,
 
220
              png_bytep   data,
 
221
              png_size_t  length)
 
222
{
 
223
    const unsigned char **buffer = (const unsigned char **)
 
224
        png_get_io_ptr (png_ptr);
 
225
 
 
226
    memcpy (data, *buffer, length);
 
227
    *buffer += length;
 
228
}
 
229
 
 
230
Bool
 
231
readPngBuffer (const unsigned char *buffer,
 
232
               char                **data,
 
233
               unsigned int        *width,
 
234
               unsigned int        *height)
 
235
{
 
236
    unsigned char       png_sig[PNG_SIG_SIZE];
 
237
    png_struct          *png;
 
238
    png_info            *info;
 
239
    const unsigned char *b = buffer + PNG_SIG_SIZE;
 
240
    Bool                status;
 
241
 
 
242
    memcpy (png_sig, buffer, PNG_SIG_SIZE);
 
243
    if (png_check_sig (png_sig, PNG_SIG_SIZE) == 0)
 
244
        return FALSE;
 
245
 
 
246
    png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
247
    if (!png)
 
248
        return FALSE;
 
249
 
 
250
    info = png_create_info_struct (png);
 
251
    if (info == NULL)
 
252
    {
 
253
        png_destroy_read_struct (&png, NULL, NULL);
 
254
        return FALSE;
 
255
    }
 
256
 
 
257
    png_set_read_fn (png, (void *) &b, userReadData);
 
258
    png_set_sig_bytes (png, PNG_SIG_SIZE);
 
259
 
 
260
    status = readPngData (png, info, data, width, height);
 
261
 
 
262
    png_destroy_read_struct (&png, &info, NULL);
 
263
 
 
264
    return status;
 
265
}
 
266