1 // SPDX-License-Identifier: Apache-2.0
3 * BMP2PNG Converter with libpng
4 * Copyright (C) 2018 MyungJoo Ham <myungjoo.ham@samsung.com>
9 * @brief Simple bmp2png converter for testcases
10 * @see http://github.com/nnstreamer/nnstreamer
11 * @author MyungJoo Ham <myungjoo.ham@samsung.com>
12 * @bug No known bugs except for NYI items
14 * This converts bmp files created by gen24bBMP.py.
15 * This won't support general bmp files.
17 * Adopted code from https://www.lemoda.net/c/write-png/
18 * The author, "Ben Bullock <benkasminbullock@gmail.com>", has authorized
19 * to adopt the code as LGPL-2.1 on 2018-07-13
21 * Then, migrated code from https://github.com/nnstreamer/nnstreamer
22 * by the author, "MyungJoo Ham <myungjoo.ham@samsung.com>", changing
23 * the licence to Apache 2.0
58 colorformat_t color_format;
62 * @brief Given "bitmap", this returns the pixel of bitmap at the point
66 pixel_at (bitmap_t * bitmap, int x, int y)
68 return bitmap->pixels + bitmap->width * y + x;
72 * @brief Write "bitmap" to a PNG file specified by "path"
73 * @return 0 on success, non-zero on error.
76 save_png_to_file (bitmap_t * bitmap, const char *path)
79 png_structp png_ptr = NULL;
80 png_infop info_ptr = NULL;
82 png_byte **row_pointers = NULL;
84 * "status" contains the return value of this function. At first
85 * it is set to a value which means 'failure'. When the routine
86 * has finished its work, it is set to a value which means
91 * The following number is set by trial and error only. I cannot
92 * see where it it is documented in the libpng manual.
98 fp = fopen (path, "wb");
103 png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
104 if (png_ptr == NULL) {
105 goto png_create_write_struct_failed;
108 info_ptr = png_create_info_struct (png_ptr);
109 if (info_ptr == NULL) {
110 goto png_create_info_struct_failed;
113 /** Set up error handling. */
115 if (setjmp (png_jmpbuf (png_ptr))) {
120 /** Set image attributes. */
121 if (bitmap->color_format == GRAY8) {
123 color_type = PNG_COLOR_TYPE_GRAY;
126 color_type = PNG_COLOR_TYPE_RGB;
129 png_set_IHDR (png_ptr,
136 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
138 /** Initialize rows of PNG. */
139 row_pointers = png_malloc (png_ptr, bitmap->height * sizeof (png_byte *));
140 g_assert (row_pointers != NULL);
141 for (y = 0; y < bitmap->height; y++) {
143 png_malloc (png_ptr, sizeof (uint8_t) * bitmap->width * pixel_size);
144 g_assert (row != NULL);
145 row_pointers[y] = row;
146 for (x = 0; x < bitmap->width; x++) {
147 pixel_t *pixel = pixel_at (bitmap, x, y);
148 if (bitmap->color_format == GRAY8) {
149 *row++ = pixel->gray;
152 *row++ = pixel->green;
153 *row++ = pixel->blue;
158 /** Write the image data to "fp". */
160 png_init_io (png_ptr, fp);
161 png_set_rows (png_ptr, info_ptr, row_pointers);
162 png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
165 * The routine has successfully written the file, so we set
166 * "status" to a value which indicates success.
171 for (y = 0; y < bitmap->height; y++) {
172 png_free (png_ptr, row_pointers[y]);
174 png_free (png_ptr, row_pointers);
177 png_create_info_struct_failed:
178 png_destroy_write_struct (&png_ptr, &info_ptr);
179 png_create_write_struct_failed:
186 * @brief The main function, provide filename of a bmp file as the 1st argument.
189 main (int argc, char *argv[])
191 const char option_gray[] = "--GRAY8";
195 uint16_t width, height, *ptr16;
198 char header[26]; /** gen24bBMP.py gives you 24B headered bmp file */
203 /** Read the .bmp file (argv[1]) */
204 if (argc < 2 || argc > 3) {
205 printf ("Usage: %s BMPfilename [OPTION:--GRAY8]\n\n", argv[0]);
208 strn = strlen (argv[1]);
209 if (strn < 5 || argv[1][strn - 4] != '.' || argv[1][strn - 3] != 'b' ||
210 argv[1][strn - 2] != 'm' || argv[1][strn - 1] != 'p') {
211 printf ("The BMPfilename must be ending with \".bmp\"\n\n");
214 /** Check the option, --GRAY8 */
215 strn = strlen (option_gray);
216 if ((argc == 3) && (strlen (argv[2]) == strn)
217 && (!strncmp (option_gray, argv[2], strn))) {
218 bmp.color_format = GRAY8;
220 bmp.color_format = RGB;
223 bmpF = fopen (argv[1], "rb");
225 printf ("Cannot open the file: %s\n", argv[1]);
229 size = fread (header, 1, 26, bmpF);
231 printf ("Cannot read the header from the file: %s\n", argv[1]);
236 ptr16 = (uint16_t *) & (header[18]);
238 ptr16 = (uint16_t *) & (header[20]);
241 /** Let's not accept BMP files larger than 10000 x 10000 (Fix Covertify Issue #1029514) */
242 if (width > 10000 || height > 10000 || width < 4 || height < 4) {
244 ("We do not accept BMP files with height or width larger than 10000.\n");
251 bmp.pixels = calloc (bmp.width * bmp.height, sizeof (pixel_t));
252 g_assert (bmp.pixels != NULL);
254 for (y = (int) height - 1; y >= 0; y--) {
255 for (x = 0; x < (int) width; x++) {
256 pixel_t *pixel = pixel_at (&bmp, x, y);
257 if (bmp.color_format == GRAY8) {
259 size = fread (&gray, 1, 1, bmpF);
261 printf ("x = %d / y = %d / (%d,%d) / size = %zu\n", x, y, width,
268 size = fread (bgr, 1, 3, bmpF);
270 printf ("x = %d / y = %d / (%d,%d) / size = %zu\n", x, y, width,
275 pixel->green = bgr[1];
276 pixel->blue = bgr[0];
279 for (x = 0; x < (width * 3) % 4; x++) {
280 size = fread (&byte, 1, 1, bmpF);
281 /** Go through zero padding */
288 pngfilename = g_strdup (argv[1]);
290 /** Assume the last 4 characters are ".bmp" */
291 strncpy (pngfilename + strlen (argv[1]) - 4, ".png", 5);
292 ret = save_png_to_file (&bmp, pngfilename);
297 printf ("File read size error.\n");