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