blob: 4066cf72aee96741581155f8f467a9cfb1857ce9 [file] [log] [blame]
David Sodman8ef20062015-01-06 09:23:40 -08001/*
2 * Copyright 2015 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <fcntl.h>
8#include <math.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/mman.h>
13#include <unistd.h>
14
15#include "image.h"
16
17#include "util.h"
18
19typedef union {
20 uint32_t *as_pixels;
21 png_byte *as_png_bytes;
22 char *address;
23} layout_t;
24
25struct _image_t {
26 char *filename;
27 bool use_offset;
28 bool use_location;
29 int32_t offset_x;
30 int32_t offset_y;
31 uint32_t location_x;
32 uint32_t location_y;
33 uint32_t duration;
34 layout_t layout;
35 png_uint_32 width;
36 png_uint_32 height;
37 png_uint_32 pitch;
38};
39
40image_t* image_create()
41{
42 image_t* image;
43
44 image = (image_t*)calloc(1, sizeof(image_t));
45 return image;
46}
47
48static void image_rgb(png_struct *png, png_row_info *row_info, png_byte *data)
49{
50 unsigned int i;
51
52 for (i = 0; i < row_info->rowbytes; i+= 4) {
53 uint8_t r, g, b, a;
54 uint32_t pixel;
55
56 r = data[i + 0];
57 g = data[i + 1];
58 b = data[i + 2];
59 a = data[i + 3];
60 pixel = (a << 24) | (r << 16) | (g << 8) | b;
61 memcpy(data + i, &pixel, sizeof(pixel));
62 }
63}
64
65int image_load_image_from_file(image_t* image)
66{
67 FILE *fp;
68 png_struct *png;
69 png_info *info;
70 png_uint_32 width, height, pitch, row;
71 int bpp, color_type, interlace_mthd;
72 png_byte **rows;
73
74 if (image->layout.address != NULL)
75 return 1;
76
77 fp = fopen(image->filename, "rb");
78 if (fp == NULL)
79 return 1;
80
81 png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
82 info = png_create_info_struct(png);
83
84 if (info == NULL)
85 return 1;
86
87 png_init_io(png, fp);
88
89 if (setjmp(png_jmpbuf(png)) != 0) {
90 png_destroy_read_struct(&png, &info, NULL);
91 fclose(fp);
92 return 1;
93 }
94
95 png_read_info(png, info);
96 png_get_IHDR(png, info, &width, &height, &bpp, &color_type,
97 &interlace_mthd, NULL, NULL);
98
99 pitch = 4 * width;
100
101 switch (color_type)
102 {
103 case PNG_COLOR_TYPE_PALETTE:
104 png_set_palette_to_rgb(png);
105 break;
106
107 case PNG_COLOR_TYPE_GRAY:
108 case PNG_COLOR_TYPE_GRAY_ALPHA:
109 png_set_gray_to_rgb(png);
110 }
111
112 if (png_get_valid(png, info, PNG_INFO_tRNS))
113 png_set_tRNS_to_alpha(png);
114
115 switch (bpp)
116 {
117 default:
118 if (bpp < 8)
119 png_set_packing(png);
120 break;
121 case 16:
122 png_set_strip_16(png);
123 break;
124 }
125
126 if (interlace_mthd != PNG_INTERLACE_NONE)
127 png_set_interlace_handling(png);
128
129 png_set_filler(png, 0xff, PNG_FILLER_AFTER);
130
131 png_set_read_user_transform_fn(png, image_rgb);
132 png_read_update_info(png, info);
133
134 rows = malloc(height * sizeof(*rows));
135 image->layout.address = malloc(height * pitch);
136
137 for (row = 0; row < height; row++) {
138 rows[row] = &image->layout.as_png_bytes[row * pitch];
139 }
140
141 png_read_image(png, rows);
142 free(rows);
143
144 png_read_end(png, info);
145 fclose(fp);
146 fp = NULL;
147 png_destroy_read_struct(&png, &info, NULL);
148
149 image->width = width;
150 image->height = height;
151 image->pitch = pitch;
152
153 return 0;
154}
155
156int image_show(image_t* image, video_t *video)
157{
158 uint32_t j;
159 uint32_t *buffer;
160 uint32_t startx, starty;
161 uint32_t pitch;
162
163 buffer = video_lock(video);
164
165 if (image->use_offset && image->use_location) {
166 LOG(WARNING, "offset and location set, using location");
167 image->use_offset = false;
168 }
169
170 if (image->use_location) {
171 startx = image->location_x;
172 starty = image->location_y;
173 } else {
174 startx = (video_getwidth(video) - image->width)/2;
175 starty = (video_getheight(video) - image->height)/2;
176 }
177
178 if (image->use_offset) {
179 startx += image->offset_x;
180 starty += image->offset_y;
181 }
182
183 pitch = video_getpitch(video);
184
185 if (buffer != NULL) {
186 for (j = starty; j < starty + image->height; j++) {
187 memcpy(buffer + j * pitch/4 + startx,
188 image->layout.address + (j - starty)*image->pitch, image->pitch);
189 }
190 }
191
192 video_unlock(video);
193 return 0;
194}
195
196void image_release(image_t* image)
197{
198 if (image->layout.address != NULL) {
199 free(image->layout.address);
200 image->layout.address = NULL;
201 }
202
203}
204
205void image_destroy(image_t* image)
206{
207 image_release(image);
208
209 if (image->filename != NULL) {
210 free(image->filename);
211 image->filename = NULL;
212 }
213
214 free(image);
215}
216
217void image_set_filename(image_t* image, char* filename)
218{
219 if (image->filename != NULL)
220 free(image->filename);
221
222 image->filename = strdup(filename);
223}
224
225void image_set_offset(image_t* image, int32_t offset_x, int32_t offset_y)
226{
227 image->offset_x = offset_x;
228 image->offset_y = offset_y;
229
230 image->use_offset = true;
231}
232
233void image_set_location(image_t* image,
234 uint32_t location_x, uint32_t location_y)
235{
236 image->location_x = location_x;
237 image->location_y = location_y;
238
239 image->use_location = true;
240}