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