Blender  V2.93
datatoc_icon.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 /* for bool */
28 #include "../blenlib/BLI_sys_types.h"
29 
30 /* for DIR */
31 #if !defined(WIN32) || defined(FREEWINDOWS)
32 # include <dirent.h>
33 #endif
34 
35 #include "png.h"
36 
37 /* for Win32 DIR functions */
38 #ifdef WIN32
39 # include "../blenlib/BLI_winstuff.h"
40 #endif
41 
42 #ifdef WIN32
43 # define SEP '\\'
44 #else
45 # define SEP '/'
46 #endif
47 
48 /* -------------------------------------------------------------------- */
49 /* Utility functions */
50 
51 static int path_ensure_slash(char *string)
52 {
53  int len = strlen(string);
54  if (len == 0 || string[len - 1] != SEP) {
55  string[len] = SEP;
56  string[len + 1] = '\0';
57  return len + 1;
58  }
59  return len;
60 }
61 
62 static bool path_test_extension(const char *str, const char *ext)
63 {
64  const size_t a = strlen(str);
65  const size_t b = strlen(ext);
66  return !(a == 0 || b == 0 || b >= a) && (strcmp(ext, str + a - b) == 0);
67 }
68 
69 static void endian_switch_uint32(unsigned int *val)
70 {
71  unsigned int tval = *val;
72  *val = ((tval >> 24)) | ((tval << 8) & 0x00ff0000) | ((tval >> 8) & 0x0000ff00) | ((tval << 24));
73 }
74 
75 static const char *path_slash_rfind(const char *string)
76 {
77  const char *const lfslash = strrchr(string, '/');
78  const char *const lbslash = strrchr(string, '\\');
79 
80  if (!lfslash) {
81  return lbslash;
82  }
83  if (!lbslash) {
84  return lfslash;
85  }
86 
87  return (lfslash > lbslash) ? lfslash : lbslash;
88 }
89 
90 static const char *path_basename(const char *path)
91 {
92  const char *const filename = path_slash_rfind(path);
93  return filename ? filename + 1 : path;
94 }
95 
96 /* -------------------------------------------------------------------- */
97 /* Write a PNG from RGBA pixels */
98 
99 static bool write_png(const char *name,
100  const unsigned int *pixels,
101  const int width,
102  const int height)
103 {
104  png_structp png_ptr;
105  png_infop info_ptr;
106  png_bytepp row_pointers = NULL;
107 
108  FILE *fp;
109 
110  const int bytesperpixel = 4;
111  const int compression = 9;
112  int i;
113 
114  fp = fopen(name, "wb");
115  if (fp == NULL) {
116  printf("%s: Cannot open file for writing '%s'\n", __func__, name);
117  return false;
118  }
119 
120  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
121  if (png_ptr == NULL) {
122  printf("%s: Cannot png_create_write_struct for file: '%s'\n", __func__, name);
123  fclose(fp);
124  return false;
125  }
126 
127  info_ptr = png_create_info_struct(png_ptr);
128  if (info_ptr == NULL) {
129  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
130  printf("%s: Cannot png_create_info_struct for file: '%s'\n", __func__, name);
131  fclose(fp);
132  return false;
133  }
134 
135  if (setjmp(png_jmpbuf(png_ptr))) {
136  png_destroy_write_struct(&png_ptr, &info_ptr);
137  printf("%s: Cannot setjmp for file: '%s'\n", __func__, name);
138  fclose(fp);
139  return false;
140  }
141 
142  /* write the file */
143  png_init_io(png_ptr, fp);
144 
145  png_set_compression_level(png_ptr, compression);
146 
147  /* png image settings */
148  png_set_IHDR(png_ptr,
149  info_ptr,
150  width,
151  height,
152  8,
153  PNG_COLOR_TYPE_RGBA,
154  PNG_INTERLACE_NONE,
155  PNG_COMPRESSION_TYPE_DEFAULT,
156  PNG_FILTER_TYPE_DEFAULT);
157 
158  /* write the file header information */
159  png_write_info(png_ptr, info_ptr);
160 
161 #ifdef __LITTLE_ENDIAN__
162  png_set_swap(png_ptr);
163 #endif
164 
165  /* allocate memory for an array of row-pointers */
166  row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep));
167  if (row_pointers == NULL) {
168  printf("%s: Cannot allocate row-pointers array for file '%s'\n", __func__, name);
169  png_destroy_write_struct(&png_ptr, &info_ptr);
170  if (fp) {
171  fclose(fp);
172  }
173  return false;
174  }
175 
176  /* set the individual row-pointers to point at the correct offsets */
177  for (i = 0; i < height; i++) {
178  row_pointers[height - 1 - i] = (png_bytep)(
179  ((const unsigned char *)pixels) + (i * width) * bytesperpixel * sizeof(unsigned char));
180  }
181 
182  /* write out the entire image data in one call */
183  png_write_image(png_ptr, row_pointers);
184 
185  /* write the additional chunks to the PNG file (not really needed) */
186  png_write_end(png_ptr, info_ptr);
187 
188  /* clean up */
189  free(row_pointers);
190  png_destroy_write_struct(&png_ptr, &info_ptr);
191 
192  fflush(fp);
193  fclose(fp);
194 
195  return true;
196 }
197 
198 /* -------------------------------------------------------------------- */
199 /* Merge icon-data from files */
200 
201 struct IconHead {
202  unsigned int icon_w, icon_h;
203  unsigned int orig_x, orig_y;
204  unsigned int canvas_w, canvas_h;
205 };
206 
207 struct IconInfo {
208  struct IconHead head;
209  char *file_name;
210 };
211 
213  /* Information about all icons read from disk.
214  * Is used for sanity checks like prevention of two files defining icon for
215  * the same position on canvas. */
218 };
219 
221 {
222  context->num_read_icons = 0;
223  context->read_icons = NULL;
224 }
225 
226 /* Get icon information from the context which matches given icon head.
227  * Is used to check whether icon is re-defined, and to provide useful information about which
228  * files are conflicting. */
230  struct IconHead *icon_head)
231 {
232  if (context->read_icons == NULL) {
233  return NULL;
234  }
235 
236  for (int i = 0; i < context->num_read_icons; i++) {
237  struct IconInfo *read_icon_info = &context->read_icons[i];
238  const struct IconHead *read_icon_head = &read_icon_info->head;
239  if (read_icon_head->orig_x == icon_head->orig_x &&
240  read_icon_head->orig_y == icon_head->orig_y) {
241  return read_icon_info;
242  }
243  }
244 
245  return NULL;
246 }
247 
249  const char *file_name,
250  struct IconHead *icon_head)
251 {
252  context->read_icons = realloc(context->read_icons,
253  sizeof(struct IconInfo) * (context->num_read_icons + 1));
254 
255  struct IconInfo *icon_info = &context->read_icons[context->num_read_icons];
256  icon_info->head = *icon_head;
257  icon_info->file_name = strdup(path_basename(file_name));
258 
259  context->num_read_icons++;
260 }
261 
263 {
264  if (context->read_icons != NULL) {
265  for (int i = 0; i < context->num_read_icons; i++) {
266  free(context->read_icons[i].file_name);
267  }
268  free(context->read_icons);
269  }
270 }
271 
272 static bool icon_decode_head(FILE *f_src, struct IconHead *r_head)
273 {
274  if (fread(r_head, 1, sizeof(*r_head), f_src) == sizeof(*r_head)) {
275 #ifndef __LITTLE_ENDIAN__
276  endian_switch_uint32(&r_head->icon_w);
277  endian_switch_uint32(&r_head->icon_h);
278  endian_switch_uint32(&r_head->orig_x);
279  endian_switch_uint32(&r_head->orig_y);
280  endian_switch_uint32(&r_head->canvas_w);
281  endian_switch_uint32(&r_head->canvas_h);
282 #endif
283  return true;
284  }
285 
286  /* quiet warning */
287  (void)endian_switch_uint32;
288 
289  return false;
290 }
291 
292 static bool icon_decode(FILE *f_src, struct IconHead *r_head, unsigned int **r_pixels)
293 {
294  unsigned int *pixels;
295  unsigned int pixels_size;
296 
297  if (!icon_decode_head(f_src, r_head)) {
298  printf("%s: failed to read header\n", __func__);
299  return false;
300  }
301 
302  pixels_size = sizeof(char[4]) * r_head->icon_w * r_head->icon_h;
303  pixels = malloc(pixels_size);
304  if (pixels == NULL) {
305  printf("%s: failed to allocate pixels\n", __func__);
306  return false;
307  }
308 
309  if (fread(pixels, 1, pixels_size, f_src) != pixels_size) {
310  printf("%s: failed to read pixels\n", __func__);
311  free(pixels);
312  return false;
313  }
314 
315  *r_pixels = pixels;
316  return true;
317 }
318 
319 static bool icon_read(const char *file_src, struct IconHead *r_head, unsigned int **r_pixels)
320 {
321  FILE *f_src;
322  bool success;
323 
324  f_src = fopen(file_src, "rb");
325  if (f_src == NULL) {
326  printf("%s: failed to open '%s'\n", __func__, file_src);
327  return false;
328  }
329 
330  success = icon_decode(f_src, r_head, r_pixels);
331 
332  fclose(f_src);
333  return success;
334 }
335 
336 static bool icon_merge(struct IconMergeContext *context,
337  const char *file_src,
338  unsigned int **r_pixels_canvas,
339  unsigned int *r_canvas_w,
340  unsigned int *r_canvas_h)
341 {
342  struct IconHead head;
343  unsigned int *pixels;
344 
345  unsigned int x, y;
346 
347  /* canvas */
348  unsigned int *pixels_canvas;
349  unsigned int canvas_w, canvas_h;
350 
351  if (!icon_read(file_src, &head, &pixels)) {
352  return false;
353  }
354 
355  struct IconInfo *read_icon_info = icon_merge_context_info_for_icon_head(context, &head);
356  if (read_icon_info != NULL) {
357  printf(
358  "Conflicting icon files %s and %s\n", path_basename(file_src), read_icon_info->file_name);
359  free(pixels);
360  return false;
361  }
363 
364  if (*r_canvas_w == 0) {
365  /* init once */
366  *r_canvas_w = head.canvas_w;
367  *r_canvas_h = head.canvas_h;
368  *r_pixels_canvas = calloc(1, (head.canvas_w * head.canvas_h) * sizeof(const unsigned char[4]));
369  }
370 
371  canvas_w = *r_canvas_w;
372  canvas_h = *r_canvas_h;
373  pixels_canvas = *r_pixels_canvas;
374 
375  assert(head.canvas_w == canvas_w);
376  assert(head.canvas_h == canvas_h);
377 
378  for (x = 0; x < head.icon_w; x++) {
379  for (y = 0; y < head.icon_h; y++) {
380  unsigned int pixel;
381  unsigned int dst_x, dst_y;
382  unsigned int pixel_xy_dst;
383 
384  /* get pixel */
385  pixel = pixels[(y * head.icon_w) + x];
386 
387  /* set pixel */
388  dst_x = head.orig_x + x;
389  dst_y = head.orig_y + y;
390  pixel_xy_dst = (dst_y * canvas_w) + dst_x;
391  assert(pixel_xy_dst < (canvas_w * canvas_h));
392  pixels_canvas[pixel_xy_dst] = pixel;
393  }
394  }
395 
396  free(pixels);
397 
398  /* only for bounds check */
399  (void)canvas_h;
400 
401  return true;
402 }
403 
404 static bool icondir_to_png(const char *path_src, const char *file_dst)
405 {
406  /* Takes a path full of 'dat' files and writes out */
407  struct dirent **namelist;
408  int dirn;
409  const struct dirent *fname;
410  char filepath[1024];
411  char *filename;
412  int path_str_len;
413  int found = 0, fail = 0;
414 
415  struct IconMergeContext context;
416 
417  unsigned int *pixels_canvas = NULL;
418  unsigned int canvas_w = 0, canvas_h = 0;
419 
421 
422  errno = 0;
423  dirn = scandir(path_src, &namelist, NULL, alphasort);
424  if (dirn == -1) {
425  printf(
426  "%s: failed to dir '%s', (%s)\n", __func__, path_src, errno ? strerror(errno) : "unknown");
427  return false;
428  }
429 
430  strcpy(filepath, path_src);
431  path_str_len = path_ensure_slash(filepath);
432  filename = &filepath[path_str_len];
433 
434  while (dirn--) {
435  fname = namelist[dirn];
436  if (path_test_extension(fname->d_name, ".dat")) {
437 
438  strcpy(filename, fname->d_name);
439 
440  if (icon_merge(&context, filepath, &pixels_canvas, &canvas_w, &canvas_h)) {
441  found++;
442  }
443  else {
444  fail++;
445  }
446  }
447  free(fname);
448  }
449 
451 
452  free(namelist);
453 
454  if (found == 0) {
455  printf("%s: dir '%s' has no icons\n", __func__, path_src);
456  }
457 
458  if (fail != 0) {
459  printf("%s: dir '%s' failed %d icons\n", __func__, path_src, fail);
460  }
461 
462  /* write pixels */
463  write_png(file_dst, pixels_canvas, canvas_w, canvas_h);
464 
465  free(pixels_canvas);
466 
467  return (fail == 0);
468 }
469 
470 /* -------------------------------------------------------------------- */
471 /* Main and parse args */
472 
473 int main(int argc, char **argv)
474 {
475  const char *path_src;
476  const char *file_dst;
477 
478  if (argc < 3) {
479  printf("Usage: datatoc_icon <dir_icons> <data_icon_to.png>\n");
480  exit(1);
481  }
482 
483  path_src = argv[1];
484  file_dst = argv[2];
485 
486  return (icondir_to_png(path_src, file_dst) == true) ? 0 : 1;
487 }
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:116
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
static bool icon_decode(FILE *f_src, struct IconHead *r_head, unsigned int **r_pixels)
Definition: datatoc_icon.c:292
static const char * path_slash_rfind(const char *string)
Definition: datatoc_icon.c:75
static void icon_merge_context_free(struct IconMergeContext *context)
Definition: datatoc_icon.c:262
static const char * path_basename(const char *path)
Definition: datatoc_icon.c:90
static bool icon_read(const char *file_src, struct IconHead *r_head, unsigned int **r_pixels)
Definition: datatoc_icon.c:319
static bool icondir_to_png(const char *path_src, const char *file_dst)
Definition: datatoc_icon.c:404
static struct IconInfo * icon_merge_context_info_for_icon_head(struct IconMergeContext *context, struct IconHead *icon_head)
Definition: datatoc_icon.c:229
static void endian_switch_uint32(unsigned int *val)
Definition: datatoc_icon.c:69
int main(int argc, char **argv)
Definition: datatoc_icon.c:473
static void icon_merge_context_init(struct IconMergeContext *context)
Definition: datatoc_icon.c:220
static void icon_merge_context_register_icon(struct IconMergeContext *context, const char *file_name, struct IconHead *icon_head)
Definition: datatoc_icon.c:248
#define SEP
Definition: datatoc_icon.c:45
static bool icon_merge(struct IconMergeContext *context, const char *file_src, unsigned int **r_pixels_canvas, unsigned int *r_canvas_w, unsigned int *r_canvas_h)
Definition: datatoc_icon.c:336
static int path_ensure_slash(char *string)
Definition: datatoc_icon.c:51
static bool icon_decode_head(FILE *f_src, struct IconHead *r_head)
Definition: datatoc_icon.c:272
static bool path_test_extension(const char *str, const char *ext)
Definition: datatoc_icon.c:62
static bool write_png(const char *name, const unsigned int *pixels, const int width, const int height)
Definition: datatoc_icon.c:99
#define str(s)
static unsigned a[3]
Definition: RandGen.cpp:92
struct SELECTID_Context context
Definition: select_engine.c:47
unsigned int canvas_w
Definition: datatoc_icon.c:204
unsigned int icon_h
Definition: datatoc_icon.c:202
unsigned int icon_w
Definition: datatoc_icon.c:202
unsigned int orig_x
Definition: datatoc_icon.c:203
unsigned int canvas_h
Definition: datatoc_icon.c:204
unsigned int orig_y
Definition: datatoc_icon.c:203
struct IconHead head
Definition: datatoc_icon.c:208
char * file_name
Definition: datatoc_icon.c:209
struct IconInfo * read_icons
Definition: datatoc_icon.c:217
char * d_name
Definition: BLI_winstuff.h:96
uint len