[test] Freeing memory during unittests
[platform/upstream/nnstreamer.git] / tests / bmp2png.c
1 /**
2  * BMP2PNG Converter with libpng
3  * Copyright (C) 2018 MyungJoo Ham <myungjoo.ham@samsung.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation;
8  * version 2.1 of the License.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  */
16 /**
17  * @file        bmp2png.c
18  * @date        13 Jul 2018
19  * @brief       Simple bmp2png converter for testcases
20  * @see         http://github.com/nnstreamer/nnstreamer
21  * @author      MyungJoo Ham <myungjoo.ham@samsung.com>
22  * @bug         No known bugs except for NYI items
23  *
24  * This converts bmp files created by gen24bBMP.py.
25  * This won't support general bmp files.
26  *
27  * Adopted code from https://www.lemoda.net/c/write-png/
28  * The author, "Ben Bullock <benkasminbullock@gmail.com>", has authorized
29  * to adopt the code as LGPL-2.1 on 2018-07-13
30  */
31
32 #include <png.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdint.h>
36 #include <string.h>
37 #include <glib.h>
38
39 typedef enum
40 {
41   RGB = 0,
42   GRAY8,
43 } colorformat_t;
44
45 typedef union
46 {
47   struct
48   {
49     uint8_t red;
50     uint8_t green;
51     uint8_t blue;
52   };
53   struct
54   {
55     uint8_t gray;
56   };
57 } pixel_t;
58
59 typedef struct
60 {
61   pixel_t *pixels;
62   size_t width;
63   size_t height;
64   colorformat_t color_format;
65 } bitmap_t;
66
67 /**
68  * @brief Given "bitmap", this returns the pixel of bitmap at the point
69  *  ("x", "y").
70  */
71 static pixel_t *
72 pixel_at (bitmap_t * bitmap, int x, int y)
73 {
74   return bitmap->pixels + bitmap->width * y + x;
75 }
76
77 /**
78  * @brief Write "bitmap" to a PNG file specified by "path"
79  * @return 0 on success, non-zero on error.
80  */
81 static int
82 save_png_to_file (bitmap_t * bitmap, const char *path)
83 {
84   FILE *fp;
85   png_structp png_ptr = NULL;
86   png_infop info_ptr = NULL;
87   size_t x, y;
88   png_byte **row_pointers = NULL;
89   /**
90    * "status" contains the return value of this function. At first
91    * it is set to a value which means 'failure'. When the routine
92    * has finished its work, it is set to a value which means
93    * 'success'.
94    */
95   int status = -1;
96   /**
97    * The following number is set by trial and error only. I cannot
98    * see where it it is documented in the libpng manual.
99    */
100   int pixel_size;
101   int depth = 8;
102   int color_type;
103
104   fp = fopen (path, "wb");
105   if (!fp) {
106     goto fopen_failed;
107   }
108
109   png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
110   if (png_ptr == NULL) {
111     goto png_create_write_struct_failed;
112   }
113
114   info_ptr = png_create_info_struct (png_ptr);
115   if (info_ptr == NULL) {
116     goto png_create_info_struct_failed;
117   }
118
119   /** Set up error handling. */
120
121   if (setjmp (png_jmpbuf (png_ptr))) {
122     status = -1;
123     goto png_failure;
124   }
125
126   /** Set image attributes. */
127   if (bitmap->color_format == GRAY8) {
128     pixel_size = 1;
129     color_type = PNG_COLOR_TYPE_GRAY;
130   } else {
131     pixel_size = 3;
132     color_type = PNG_COLOR_TYPE_RGB;
133   }
134
135   png_set_IHDR (png_ptr,
136       info_ptr,
137       bitmap->width,
138       bitmap->height,
139       depth,
140       color_type,
141       PNG_INTERLACE_NONE,
142       PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
143
144   /** Initialize rows of PNG. */
145   row_pointers = png_malloc (png_ptr, bitmap->height * sizeof (png_byte *));
146   g_assert (row_pointers != NULL);
147   for (y = 0; y < bitmap->height; y++) {
148     png_byte *row =
149         png_malloc (png_ptr, sizeof (uint8_t) * bitmap->width * pixel_size);
150     g_assert (row != NULL);
151     row_pointers[y] = row;
152     for (x = 0; x < bitmap->width; x++) {
153       pixel_t *pixel = pixel_at (bitmap, x, y);
154       if (bitmap->color_format == GRAY8) {
155         *row++ = pixel->gray;
156       } else {
157         *row++ = pixel->red;
158         *row++ = pixel->green;
159         *row++ = pixel->blue;
160       }
161     }
162   }
163
164   /** Write the image data to "fp". */
165
166   png_init_io (png_ptr, fp);
167   png_set_rows (png_ptr, info_ptr, row_pointers);
168   png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
169
170   /**
171    * The routine has successfully written the file, so we set
172    * "status" to a value which indicates success.
173    */
174
175   status = 0;
176
177   for (y = 0; y < bitmap->height; y++) {
178     png_free (png_ptr, row_pointers[y]);
179   }
180   png_free (png_ptr, row_pointers);
181
182 png_failure:
183 png_create_info_struct_failed:
184   png_destroy_write_struct (&png_ptr, &info_ptr);
185 png_create_write_struct_failed:
186   fclose (fp);
187 fopen_failed:
188   return status;
189 }
190
191 /**
192  * @brief The main function, provide filename of a bmp file as the 1st argument.
193  */
194 int
195 main (int argc, char *argv[])
196 {
197   const char option_gray[] = "--GRAY8";
198   FILE *bmpF;
199   bitmap_t bmp;
200   int x, y;
201   uint16_t width, height, *ptr16;
202   size_t size;
203   char byte;
204   char header[26];              /** gen24bBMP.py gives you 24B headered bmp file */
205   int ret;
206   char *pngfilename;
207   unsigned int strn;
208
209   /** Read the .bmp file (argv[1]) */
210   if (argc < 2 || argc > 3) {
211     printf ("Usage: %s BMPfilename [OPTION:--GRAY8]\n\n", argv[0]);
212     return 1;
213   }
214   strn = strlen (argv[1]);
215   if (strn < 5 || argv[1][strn - 4] != '.' || argv[1][strn - 3] != 'b' ||
216       argv[1][strn - 2] != 'm' || argv[1][strn - 1] != 'p') {
217     printf ("The BMPfilename must be ending with \".bmp\"\n\n");
218     return 1;
219   }
220   /** Check the option, --GRAY8 */
221   strn = strlen (option_gray);
222   if ((argc == 3) && (strlen (argv[2]) == strn)
223       && (!strncmp (option_gray, argv[2], strn))) {
224     bmp.color_format = GRAY8;
225   } else {
226     bmp.color_format = RGB;
227   }
228
229   bmpF = fopen (argv[1], "rb");
230   if (!bmpF) {
231     printf ("Cannot open the file: %s\n", argv[1]);
232     return 2;
233   }
234
235   size = fread (header, 1, 26, bmpF);
236   if (size != 26) {
237     printf ("Cannot read the header from the file: %s\n", argv[1]);
238     fclose (bmpF);
239     return 3;
240   }
241
242   ptr16 = (uint16_t *) & (header[18]);
243   width = *ptr16;
244   ptr16 = (uint16_t *) & (header[20]);
245   height = *ptr16;
246
247   /** Let's not accept BMP files larger than 10000 x 10000 (Fix Covertify Issue #1029514) */
248   if (width > 10000 || height > 10000 || width < 4 || height < 4) {
249     printf
250         ("We do not accept BMP files with height or width larger than 10000.\n");
251     fclose (bmpF);
252     return 100;
253   }
254   bmp.width = width;
255   bmp.height = height;
256
257   bmp.pixels = calloc (bmp.width * bmp.height, sizeof (pixel_t));
258   g_assert (bmp.pixels != NULL);
259
260   for (y = (int) height - 1; y >= 0; y--) {
261     for (x = 0; x < (int) width; x++) {
262       pixel_t *pixel = pixel_at (&bmp, x, y);
263       if (bmp.color_format == GRAY8) {
264         uint8_t gray;
265         size = fread (&gray, 1, 1, bmpF);
266         if (size != 1) {
267           printf ("x = %d / y = %d / (%d,%d) / size = %zu\n", x, y, width,
268               height, size);
269           goto error;
270         }
271         pixel->gray = gray;
272       } else {
273         uint8_t bgr[3];
274         size = fread (bgr, 1, 3, bmpF);
275         if (size != 3) {
276           printf ("x = %d / y = %d / (%d,%d) / size = %zu\n", x, y, width,
277               height, size);
278           goto error;
279         }
280         pixel->red = bgr[2];
281         pixel->green = bgr[1];
282         pixel->blue = bgr[0];
283       }
284     }
285     for (x = 0; x < (width * 3) % 4; x++) {
286       size = fread (&byte, 1, 1, bmpF);
287       /** Go through zero padding */
288       if (size != 1)
289         goto error;
290     }
291   }
292   fclose (bmpF);
293
294   pngfilename = g_strdup (argv[1]);
295
296   /** Assume the last 4 characters are ".bmp" */
297   strncpy (pngfilename + strlen (argv[1]) - 4, ".png", 5);
298   ret = save_png_to_file (&bmp, pngfilename);
299   free (bmp.pixels);
300
301   return ret;
302 error:
303   printf ("File read size error.\n");
304   free (bmp.pixels);
305   fclose (bmpF);
306   return 10;
307 }