Increase warning level and resolve compiler warnings.
[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   if (bitmap->color_format == GRAY8) {
105     pixel_size = 1;
106     color_type = PNG_COLOR_TYPE_GRAY;
107   } else {
108     pixel_size = 3;
109     color_type = PNG_COLOR_TYPE_RGB;
110   }
111
112   fp = fopen (path, "wb");
113   if (!fp) {
114     goto fopen_failed;
115   }
116
117   png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
118   if (png_ptr == NULL) {
119     goto png_create_write_struct_failed;
120   }
121
122   info_ptr = png_create_info_struct (png_ptr);
123   if (info_ptr == NULL) {
124     goto png_create_info_struct_failed;
125   }
126
127   /** Set up error handling. */
128
129   if (setjmp (png_jmpbuf (png_ptr))) {
130     goto png_failure;
131   }
132
133   /** Set image attributes. */
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   }
219   /** Check the option, --GRAY8 */
220   strn = strlen (option_gray);
221   if ((argc == 3) && (strlen (argv[2]) == strn)
222       && (!strncmp (option_gray, argv[2], strn))) {
223     bmp.color_format = GRAY8;
224   } else {
225     bmp.color_format = RGB;
226   }
227
228   bmpF = fopen (argv[1], "rb");
229   if (!bmpF) {
230     printf ("Cannot open the file: %s\n", argv[1]);
231     return 2;
232   }
233
234   size = fread (header, 1, 26, bmpF);
235   if (size != 26) {
236     printf ("Cannot read the header from the file: %s\n", argv[1]);
237     fclose (bmpF);
238     return 3;
239   }
240
241   ptr16 = (uint16_t *) & (header[18]);
242   width = *ptr16;
243   ptr16 = (uint16_t *) & (header[20]);
244   height = *ptr16;
245
246   /** Let's not accept BMP files larger than 10000 x 10000 (Fix Covertify Issue #1029514) */
247   if (width > 10000 || height > 10000 || width < 4 || height < 4) {
248     printf
249         ("We do not accept BMP files with height or width larger than 10000.\n");
250     fclose (bmpF);
251     return 100;
252   }
253   bmp.width = width;
254   bmp.height = height;
255
256   bmp.pixels = calloc (bmp.width * bmp.height, sizeof (pixel_t));
257
258   for (y = (int) height - 1; y >= 0; y--) {
259     for (x = 0; x < (int) width; x++) {
260       pixel_t *pixel = pixel_at (&bmp, x, y);
261       if (bmp.color_format == GRAY8) {
262         uint8_t gray;
263         size = fread (&gray, 1, 1, bmpF);
264         if (size != 1) {
265           printf ("x = %d / y = %d / (%d,%d) / size = %zu\n", x, y, width,
266               height, size);
267           goto error;
268         }
269         pixel->gray = gray;
270       } else {
271         uint8_t bgr[3];
272         size = fread (bgr, 1, 3, bmpF);
273         if (size != 3) {
274           printf ("x = %d / y = %d / (%d,%d) / size = %zu\n", x, y, width,
275               height, size);
276           goto error;
277         }
278         pixel->red = bgr[2];
279         pixel->green = bgr[1];
280         pixel->blue = bgr[0];
281       }
282     }
283     for (x = 0; x < (width * 3) % 4; x++) {
284       size = fread (&byte, 1, 1, bmpF);
285       /** Go through zero padding */
286       if (size != 1)
287         goto error;
288     }
289   }
290   fclose (bmpF);
291
292   pngfilename = g_strdup (argv[1]);
293
294   /** Assume the last 4 characters are ".bmp" */
295   strncpy (pngfilename + strlen (argv[1]) - 4, ".png", 5);
296   ret = save_png_to_file (&bmp, pngfilename);
297   free (bmp.pixels);
298
299   return ret;
300 error:
301   printf ("File read size error.\n");
302   free (bmp.pixels);
303   fclose (bmpF);
304   return 10;
305 }