• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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