1 /***************************************************************************
2 *
3 * Copyright (C) 2020 Advanced Driver Information Technology Joint Venture GmbH
4 *
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 ****************************************************************************/
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <arpa/inet.h>
23 #include <png.h>
24 #include "ivi-wm-client-protocol.h"
25 #include "writepng.h"
26
27 typedef struct _image_info {
28 png_structp png_ptr;
29 png_infop info_ptr;
30 jmp_buf jmpbuf;
31 FILE *outfile;
32 } image_info;
33
34
35 static void
writepng_error_handler(png_structp png_ptr,png_const_charp msg)36 writepng_error_handler(png_structp png_ptr,
37 png_const_charp msg)
38 {
39 fprintf(stderr, "writepng libpng error: %s\n", msg);
40 }
41
42 static int
create_png_header(image_info * info,int32_t width,int32_t height,uint32_t format)43 create_png_header(image_info *info,
44 int32_t width,
45 int32_t height,
46 uint32_t format)
47 {
48 int color_type = 0;
49 int sample_depth = 8;
50
51 info->info_ptr = png_create_info_struct(info->png_ptr);
52 if (!info->info_ptr) {
53 fprintf(stderr, "png_create_info_struct: failed, out of memory\n");
54 png_destroy_write_struct(&info->png_ptr, NULL);
55 return -1;
56 }
57
58 if (setjmp(info->jmpbuf)) {
59 fprintf(stderr, "setjmp: failed\n");
60 png_destroy_write_struct(&info->png_ptr, &info->info_ptr);
61 return -1;
62 }
63
64 png_init_io(info->png_ptr, info->outfile);
65
66 png_set_compression_level(info->png_ptr, PNG_Z_DEFAULT_COMPRESSION);
67
68 switch (format) {
69 case WL_SHM_FORMAT_ARGB8888:
70 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
71 png_set_swap_alpha(info->png_ptr);
72 break;
73 case WL_SHM_FORMAT_XRGB8888:
74 color_type = PNG_COLOR_TYPE_RGB;
75 break;
76 case WL_SHM_FORMAT_ABGR8888:
77 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
78 png_set_bgr(info->png_ptr);
79 png_set_swap_alpha(info->png_ptr);
80 break;
81 case WL_SHM_FORMAT_XBGR8888:
82 color_type = PNG_COLOR_TYPE_RGB;
83 png_set_bgr(info->png_ptr);
84 break;
85 default:
86 fprintf(stderr, "unsupported pixelformat 0x%x\n", format);
87 return -1;
88 }
89
90 png_set_IHDR(info->png_ptr, info->info_ptr, width, height,
91 sample_depth, color_type, PNG_INTERLACE_NONE,
92 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
93
94 png_write_info(info->png_ptr, info->info_ptr);
95
96 return 0;
97 }
98
99 static int
write_png_file(image_info * info,const char * buffer,int32_t width,int32_t height,uint32_t format,int bytes_per_pixel)100 write_png_file(image_info *info,
101 const char *buffer,
102 int32_t width,
103 int32_t height,
104 uint32_t format,
105 int bytes_per_pixel)
106 {
107 info->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
108 writepng_error_handler, NULL);
109 if (!info->png_ptr) {
110 fprintf(stderr, "png_create_write_struct: failed, out of memory\n");
111 return -1;
112 }
113
114 if (create_png_header(info, width, height, format) != 0) {
115 return -1;
116 }
117
118 for(int j = 0; j < height ; ++j) {
119 png_const_bytep pointer = (png_const_bytep)buffer;
120 pointer += j * width * bytes_per_pixel;
121
122 if (setjmp(info->jmpbuf)) {
123 fprintf(stderr, "setjmp: failed, j=%d\n", j);
124 png_destroy_write_struct(&info->png_ptr, &info->info_ptr);
125 info->png_ptr = NULL;
126 info->info_ptr = NULL;
127 return -1;
128 }
129
130 png_write_row(info->png_ptr, pointer);
131 }
132
133 if (setjmp(info->jmpbuf)) {
134 fprintf(stderr, "final setjmp failed\n");
135 png_destroy_write_struct(&info->png_ptr, &info->info_ptr);
136 info->png_ptr = NULL;
137 info->info_ptr = NULL;
138 return -1;
139 }
140
141 png_write_end(info->png_ptr, NULL);
142
143 if (info->png_ptr && info->info_ptr) {
144 png_destroy_write_struct(&info->png_ptr, &info->info_ptr);
145 }
146
147 return 0;
148 }
149
150 int
save_as_png(const char * filename,const char * buffer,int32_t width,int32_t height,uint32_t format)151 save_as_png(const char *filename,
152 const char *buffer,
153 int32_t width,
154 int32_t height,
155 uint32_t format)
156 {
157 int32_t image_stride = 0;
158 int32_t image_size = 0;
159 char *image_buffer = NULL;
160 int32_t row = 0;
161 int32_t col = 0;
162 int32_t image_offset = 0;
163 int32_t offset = 0;
164 int bytes_per_pixel = 0;
165 bool has_alpha = false;
166 image_info info;
167
168 if ((filename == NULL) || (buffer == NULL)) {
169 return -1;
170 }
171
172 info.outfile = fopen(filename, "wb");
173 if (!info.outfile) {
174 fprintf(stderr, "could not open the file %s\n", filename);
175 return -1;
176 }
177
178 switch (format) {
179 case WL_SHM_FORMAT_ARGB8888:
180 case WL_SHM_FORMAT_ABGR8888:
181 has_alpha = true;
182 break;
183 default:
184 has_alpha = false;
185 break;
186 }
187
188 bytes_per_pixel = has_alpha ? 4 : 3;
189 image_stride = (((width * bytes_per_pixel) + 3) & ~3);
190 image_size = image_stride * height;
191
192 image_buffer = malloc(image_size);
193 if (image_buffer == NULL) {
194 fprintf(stderr, "failed to allocate %d bytes for image buffer: %m\n",
195 image_size);
196 return -1;
197 }
198
199 for (row = 0; row < height; ++row) {
200 for (col = 0; col < width; ++col) {
201 offset = row * width + col;
202 uint32_t pixel = htonl(((uint32_t*)buffer)[offset]);
203 char * pixel_p = (char*) &pixel;
204 image_offset = row * image_stride + col * bytes_per_pixel;
205 for (int i=0; i<bytes_per_pixel; ++i){
206 image_buffer[image_offset + i] = pixel_p[i + (has_alpha ? 0 : 1)];
207 }
208 }
209 }
210
211 if (write_png_file(&info, image_buffer, width, height, format, bytes_per_pixel) != 0) {
212 free(image_buffer);
213 return -1;
214 }
215
216 free(image_buffer);
217 return 0;
218 }
219