blob: f595817a34916b4fb2b17f4adbd7f8be37bc157d [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
Dominik Behr46755a42016-04-21 18:08:33 -07007#include <errno.h>
David Sodman8ef20062015-01-06 09:23:40 -08008#include <fcntl.h>
9#include <math.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/mman.h>
14#include <unistd.h>
15
16#include "image.h"
David Sodman8ef20062015-01-06 09:23:40 -080017#include "util.h"
18
19typedef union {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080020 uint32_t* as_pixels;
21 png_byte* as_png_bytes;
22 char* address;
David Sodman8ef20062015-01-06 09:23:40 -080023} layout_t;
24
25struct _image_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080026 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;
Dominik Behr92d9e312016-05-04 20:10:48 -070033 uint32_t scale;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080034 uint32_t duration;
35 layout_t layout;
36 png_uint_32 width;
37 png_uint_32 height;
38 png_uint_32 pitch;
David Sodman8ef20062015-01-06 09:23:40 -080039};
40
41image_t* image_create()
42{
43 image_t* image;
44
45 image = (image_t*)calloc(1, sizeof(image_t));
Dominik Behr92d9e312016-05-04 20:10:48 -070046 image->scale = 1;
David Sodman8ef20062015-01-06 09:23:40 -080047 return image;
48}
49
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080050static void image_rgb(png_struct* png, png_row_info* row_info, png_byte* data)
David Sodman8ef20062015-01-06 09:23:40 -080051{
Stéphane Marchesinac14d292015-12-14 15:27:18 -080052 for (unsigned int i = 0; i < row_info->rowbytes; i+= 4) {
David Sodman8ef20062015-01-06 09:23:40 -080053 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{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080067 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;
Dominik Behr46755a42016-04-21 18:08:33 -070073 int ret = 0;
David Sodman8ef20062015-01-06 09:23:40 -080074
75 if (image->layout.address != NULL)
Dominik Behr46755a42016-04-21 18:08:33 -070076 return EADDRINUSE;
David Sodman8ef20062015-01-06 09:23:40 -080077
78 fp = fopen(image->filename, "rb");
79 if (fp == NULL)
Dominik Behr46755a42016-04-21 18:08:33 -070080 return errno;
David Sodman8ef20062015-01-06 09:23:40 -080081
82 png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
83 info = png_create_info_struct(png);
84
85 if (info == NULL)
86 return 1;
87
88 png_init_io(png, fp);
89
Dominik Behr46755a42016-04-21 18:08:33 -070090 ret = setjmp(png_jmpbuf(png));
91 if (ret != 0)
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -080092 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -080093
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));
Dominik Behr46755a42016-04-21 18:08:33 -0700134 if (!rows) {
135 ret = -ENOMEM;
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800136 goto fail;
Dominik Behr46755a42016-04-21 18:08:33 -0700137 }
David Sodman8ef20062015-01-06 09:23:40 -0800138
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800139 image->layout.address = malloc(height * pitch);
140 if (!image->layout.address) {
141 free(rows);
Dominik Behr46755a42016-04-21 18:08:33 -0700142 ret = -ENOMEM;
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800143 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800144 }
145
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800146 for (row = 0; row < height; row++)
147 rows[row] = &image->layout.as_png_bytes[row * pitch];
148
David Sodman8ef20062015-01-06 09:23:40 -0800149 png_read_image(png, rows);
150 free(rows);
151
David Sodman8ef20062015-01-06 09:23:40 -0800152 image->width = width;
153 image->height = height;
154 image->pitch = pitch;
Dominik Behr46755a42016-04-21 18:08:33 -0700155 png_read_end(png, info);
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800156
157fail:
158 png_destroy_read_struct(&png, &info, NULL);
159 fclose(fp);
Dominik Behr46755a42016-04-21 18:08:33 -0700160 fp = NULL;
161 return ret;
David Sodman8ef20062015-01-06 09:23:40 -0800162}
163
Dominik Behr83010f82016-03-18 18:43:08 -0700164int image_show(image_t* image, fb_t* fb)
David Sodman8ef20062015-01-06 09:23:40 -0800165{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800166 uint32_t* buffer;
Dominik Behr92d9e312016-05-04 20:10:48 -0700167 int32_t startx, starty;
168 uint32_t pitch4;
169 int32_t x, y, w, h;
170 int32_t ox = 0, oy = 0;
David Sodman8ef20062015-01-06 09:23:40 -0800171
Dominik Behr83010f82016-03-18 18:43:08 -0700172 buffer = fb_lock(fb);
Stéphane Marchesind47f8742016-01-06 16:44:00 -0800173 if (buffer == NULL)
174 return -1;
David Sodman8ef20062015-01-06 09:23:40 -0800175
176 if (image->use_offset && image->use_location) {
177 LOG(WARNING, "offset and location set, using location");
178 image->use_offset = false;
179 }
180
Dominik Behr92d9e312016-05-04 20:10:48 -0700181 w = (int32_t)(image->width * image->scale);
182 h = (int32_t)(image->height * image->scale);
183
David Sodman8ef20062015-01-06 09:23:40 -0800184 if (image->use_location) {
185 startx = image->location_x;
186 starty = image->location_y;
187 } else {
Dominik Behr92d9e312016-05-04 20:10:48 -0700188 startx = (fb_getwidth(fb) - w)/2;
189 starty = (fb_getheight(fb) - h)/2;
David Sodman8ef20062015-01-06 09:23:40 -0800190 }
191
192 if (image->use_offset) {
Dominik Behr92d9e312016-05-04 20:10:48 -0700193 startx += image->offset_x * (int32_t)image->scale;
194 starty += image->offset_y * (int32_t)image->scale;
David Sodman8ef20062015-01-06 09:23:40 -0800195 }
196
Dominik Behr92d9e312016-05-04 20:10:48 -0700197 pitch4 = fb_getpitch(fb) / 4;
David Sodman8ef20062015-01-06 09:23:40 -0800198
Dominik Behr92d9e312016-05-04 20:10:48 -0700199 if (startx >= fb_getwidth(fb) || startx + w <= 0)
200 return 0;
201
202 if (starty >= fb_getheight(fb) || starty + h <= 0)
203 return 0;
204
205 if (startx < 0) {
206 ox = -startx;
207 w += startx;
208 startx = 0;
209 }
210
211 if (startx + w > fb_getwidth(fb))
212 w = fb_getwidth(fb) - startx;
213
214 if (starty < 0) {
215 oy = -starty;
216 h += starty;
217 starty = 0;
218 }
219
220 if (starty + h > fb_getheight(fb))
221 h = fb_getheight(fb) - starty;
222
223 for (y = 0; y < h; y++) {
224 uint32_t *o = buffer + (starty + y) * pitch4 + startx;
225 int32_t iy = (oy + y) / image->scale;
226 uint32_t *i = image->layout.as_pixels + iy * (image->pitch >> 2);
227
228 for (x = 0; x < w; x++) {
229 int32_t ix = (ox + x) / image->scale;
230 o[x] = i[ix];
231 }
232 }
David Sodman8ef20062015-01-06 09:23:40 -0800233
Dominik Behr83010f82016-03-18 18:43:08 -0700234 fb_unlock(fb);
David Sodman8ef20062015-01-06 09:23:40 -0800235 return 0;
236}
237
238void image_release(image_t* image)
239{
240 if (image->layout.address != NULL) {
241 free(image->layout.address);
242 image->layout.address = NULL;
243 }
David Sodman8ef20062015-01-06 09:23:40 -0800244}
245
246void image_destroy(image_t* image)
247{
248 image_release(image);
249
250 if (image->filename != NULL) {
251 free(image->filename);
252 image->filename = NULL;
253 }
254
255 free(image);
256}
257
258void image_set_filename(image_t* image, char* filename)
259{
260 if (image->filename != NULL)
261 free(image->filename);
262
263 image->filename = strdup(filename);
264}
265
Dominik Behr46755a42016-04-21 18:08:33 -0700266char* image_get_filename(image_t* image)
267{
268 return image->filename;
269}
270
David Sodman8ef20062015-01-06 09:23:40 -0800271void image_set_offset(image_t* image, int32_t offset_x, int32_t offset_y)
272{
273 image->offset_x = offset_x;
274 image->offset_y = offset_y;
275
276 image->use_offset = true;
277}
278
279void image_set_location(image_t* image,
Stéphane Marchesinedece332015-12-14 15:10:58 -0800280 uint32_t location_x, uint32_t location_y)
David Sodman8ef20062015-01-06 09:23:40 -0800281{
282 image->location_x = location_x;
283 image->location_y = location_y;
284
285 image->use_location = true;
286}
Dominik Behr92d9e312016-05-04 20:10:48 -0700287
288void image_set_scale(image_t* image, uint32_t scale)
289{
290 if (scale > MAX_SCALE_FACTOR)
291 scale = MAX_SCALE_FACTOR;
292 if (scale == 0)
293 image->scale = 1;
294 else
295 image->scale = scale;
296}
297
Brian Norrisb86eb582017-12-04 12:31:06 -0800298int image_is_hires(fb_t* fb)
299{
300 return fb_getwidth(fb) > HIRES_THRESHOLD_HR ||
301 fb_getheight(fb) > HIRES_THRESHOLD_VR;
302}
303
Dominik Behr92d9e312016-05-04 20:10:48 -0700304int32_t image_get_auto_scale(fb_t* fb)
305{
Brian Norrisb86eb582017-12-04 12:31:06 -0800306 if (image_is_hires(fb))
Dominik Behr92d9e312016-05-04 20:10:48 -0700307 return 2;
308 else
309 return 1;
310}