blob: 2c3fac078d915d1b1c65e8eaf003a28ac0559494 [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
Dominik Behrbb728f32019-09-03 17:52:13 -070016#include "fb.h"
David Sodman8ef20062015-01-06 09:23:40 -080017#include "image.h"
David Sodman8ef20062015-01-06 09:23:40 -080018#include "util.h"
19
20typedef union {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080021 uint32_t* as_pixels;
22 png_byte* as_png_bytes;
23 char* address;
David Sodman8ef20062015-01-06 09:23:40 -080024} layout_t;
25
26struct _image_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080027 char* filename;
28 bool use_offset;
29 bool use_location;
30 int32_t offset_x;
31 int32_t offset_y;
32 uint32_t location_x;
33 uint32_t location_y;
Dominik Behr92d9e312016-05-04 20:10:48 -070034 uint32_t scale;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080035 uint32_t duration;
36 layout_t layout;
37 png_uint_32 width;
38 png_uint_32 height;
39 png_uint_32 pitch;
David Sodman8ef20062015-01-06 09:23:40 -080040};
41
42image_t* image_create()
43{
44 image_t* image;
45
46 image = (image_t*)calloc(1, sizeof(image_t));
Dominik Behr92d9e312016-05-04 20:10:48 -070047 image->scale = 1;
David Sodman8ef20062015-01-06 09:23:40 -080048 return image;
49}
50
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080051static void image_rgb(png_struct* png, png_row_info* row_info, png_byte* data)
David Sodman8ef20062015-01-06 09:23:40 -080052{
Stéphane Marchesinac14d292015-12-14 15:27:18 -080053 for (unsigned int i = 0; i < row_info->rowbytes; i+= 4) {
Manoj Guptaa2c76ef2019-01-18 15:19:14 -080054 uint32_t r, g, b, a;
David Sodman8ef20062015-01-06 09:23:40 -080055 uint32_t pixel;
56
57 r = data[i + 0];
58 g = data[i + 1];
59 b = data[i + 2];
60 a = data[i + 3];
61 pixel = (a << 24) | (r << 16) | (g << 8) | b;
62 memcpy(data + i, &pixel, sizeof(pixel));
63 }
64}
65
66int image_load_image_from_file(image_t* image)
67{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080068 FILE* fp;
69 png_struct* png;
70 png_info* info;
71 png_uint_32 width, height, pitch, row;
72 int bpp, color_type, interlace_mthd;
73 png_byte** rows;
Dominik Behr46755a42016-04-21 18:08:33 -070074 int ret = 0;
David Sodman8ef20062015-01-06 09:23:40 -080075
76 if (image->layout.address != NULL)
Dominik Behr46755a42016-04-21 18:08:33 -070077 return EADDRINUSE;
David Sodman8ef20062015-01-06 09:23:40 -080078
79 fp = fopen(image->filename, "rb");
80 if (fp == NULL)
Dominik Behr46755a42016-04-21 18:08:33 -070081 return errno;
David Sodman8ef20062015-01-06 09:23:40 -080082
83 png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
84 info = png_create_info_struct(png);
85
86 if (info == NULL)
87 return 1;
88
89 png_init_io(png, fp);
90
Dominik Behr46755a42016-04-21 18:08:33 -070091 ret = setjmp(png_jmpbuf(png));
92 if (ret != 0)
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -080093 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -080094
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));
Dominik Behr46755a42016-04-21 18:08:33 -0700135 if (!rows) {
136 ret = -ENOMEM;
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800137 goto fail;
Dominik Behr46755a42016-04-21 18:08:33 -0700138 }
David Sodman8ef20062015-01-06 09:23:40 -0800139
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800140 image->layout.address = malloc(height * pitch);
141 if (!image->layout.address) {
142 free(rows);
Dominik Behr46755a42016-04-21 18:08:33 -0700143 ret = -ENOMEM;
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800144 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800145 }
146
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800147 for (row = 0; row < height; row++)
148 rows[row] = &image->layout.as_png_bytes[row * pitch];
149
David Sodman8ef20062015-01-06 09:23:40 -0800150 png_read_image(png, rows);
151 free(rows);
152
David Sodman8ef20062015-01-06 09:23:40 -0800153 image->width = width;
154 image->height = height;
155 image->pitch = pitch;
Dominik Behr46755a42016-04-21 18:08:33 -0700156 png_read_end(png, info);
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800157
158fail:
159 png_destroy_read_struct(&png, &info, NULL);
160 fclose(fp);
Dominik Behr46755a42016-04-21 18:08:33 -0700161 fp = NULL;
162 return ret;
David Sodman8ef20062015-01-06 09:23:40 -0800163}
164
Dominik Behr83010f82016-03-18 18:43:08 -0700165int image_show(image_t* image, fb_t* fb)
David Sodman8ef20062015-01-06 09:23:40 -0800166{
Dominik Behrbb728f32019-09-03 17:52:13 -0700167 fb_stepper_t s;
Dominik Behr92d9e312016-05-04 20:10:48 -0700168 int32_t startx, starty;
Dominik Behrbb728f32019-09-03 17:52:13 -0700169 uint32_t w, h;
David Sodman8ef20062015-01-06 09:23:40 -0800170
Dominik Behrbb728f32019-09-03 17:52:13 -0700171 if (fb_lock(fb) == NULL)
Stéphane Marchesind47f8742016-01-06 16:44:00 -0800172 return -1;
David Sodman8ef20062015-01-06 09:23:40 -0800173
174 if (image->use_offset && image->use_location) {
175 LOG(WARNING, "offset and location set, using location");
176 image->use_offset = false;
177 }
178
Dominik Behrbb728f32019-09-03 17:52:13 -0700179 w = image->width * image->scale;
180 h = image->height * image->scale;
Dominik Behr92d9e312016-05-04 20:10:48 -0700181
David Sodman8ef20062015-01-06 09:23:40 -0800182 if (image->use_location) {
183 startx = image->location_x;
184 starty = image->location_y;
185 } else {
Dominik Behr92d9e312016-05-04 20:10:48 -0700186 startx = (fb_getwidth(fb) - w)/2;
187 starty = (fb_getheight(fb) - h)/2;
David Sodman8ef20062015-01-06 09:23:40 -0800188 }
189
190 if (image->use_offset) {
Dominik Behr92d9e312016-05-04 20:10:48 -0700191 startx += image->offset_x * (int32_t)image->scale;
192 starty += image->offset_y * (int32_t)image->scale;
David Sodman8ef20062015-01-06 09:23:40 -0800193 }
194
Dominik Behrbb728f32019-09-03 17:52:13 -0700195 if (!fb_stepper_init(&s, fb, startx, starty, w, h))
196 goto done;
David Sodman8ef20062015-01-06 09:23:40 -0800197
Dominik Behrbb728f32019-09-03 17:52:13 -0700198 do {
199 do {
200 } while (fb_stepper_step_x(&s, image->layout.as_pixels[(s.y / image->scale) * (image->pitch >> 2) + (s.x / image->scale)]));
201 } while (fb_stepper_step_y(&s));
Dominik Behr92d9e312016-05-04 20:10:48 -0700202
Dominik Behrbb728f32019-09-03 17:52:13 -0700203done:
Dominik Behr83010f82016-03-18 18:43:08 -0700204 fb_unlock(fb);
David Sodman8ef20062015-01-06 09:23:40 -0800205 return 0;
206}
207
208void image_release(image_t* image)
209{
210 if (image->layout.address != NULL) {
211 free(image->layout.address);
212 image->layout.address = NULL;
213 }
David Sodman8ef20062015-01-06 09:23:40 -0800214}
215
216void image_destroy(image_t* image)
217{
218 image_release(image);
219
220 if (image->filename != NULL) {
221 free(image->filename);
222 image->filename = NULL;
223 }
224
225 free(image);
226}
227
228void image_set_filename(image_t* image, char* filename)
229{
230 if (image->filename != NULL)
231 free(image->filename);
232
233 image->filename = strdup(filename);
234}
235
Dominik Behr46755a42016-04-21 18:08:33 -0700236char* image_get_filename(image_t* image)
237{
238 return image->filename;
239}
240
David Sodman8ef20062015-01-06 09:23:40 -0800241void image_set_offset(image_t* image, int32_t offset_x, int32_t offset_y)
242{
243 image->offset_x = offset_x;
244 image->offset_y = offset_y;
245
246 image->use_offset = true;
247}
248
249void image_set_location(image_t* image,
Stéphane Marchesinedece332015-12-14 15:10:58 -0800250 uint32_t location_x, uint32_t location_y)
David Sodman8ef20062015-01-06 09:23:40 -0800251{
252 image->location_x = location_x;
253 image->location_y = location_y;
254
255 image->use_location = true;
256}
Dominik Behr92d9e312016-05-04 20:10:48 -0700257
258void image_set_scale(image_t* image, uint32_t scale)
259{
260 if (scale > MAX_SCALE_FACTOR)
261 scale = MAX_SCALE_FACTOR;
262 if (scale == 0)
263 image->scale = 1;
264 else
265 image->scale = scale;
266}
267
Brian Norrisb86eb582017-12-04 12:31:06 -0800268int image_is_hires(fb_t* fb)
269{
270 return fb_getwidth(fb) > HIRES_THRESHOLD_HR ||
271 fb_getheight(fb) > HIRES_THRESHOLD_VR;
272}
273
Dominik Behr92d9e312016-05-04 20:10:48 -0700274int32_t image_get_auto_scale(fb_t* fb)
275{
Brian Norrisb86eb582017-12-04 12:31:06 -0800276 if (image_is_hires(fb))
Dominik Behr92d9e312016-05-04 20:10:48 -0700277 return 2;
278 else
279 return 1;
280}