Blender  V2.93
bmp.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  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 
26 #include "BLI_fileops.h"
27 #include "BLI_utildefines.h"
28 
29 #include "imbuf.h"
30 
31 #include "IMB_filetype.h"
32 #include "IMB_imbuf.h"
33 #include "IMB_imbuf_types.h"
34 
35 #include "IMB_colormanagement.h"
37 
38 /* Some code copied from article on microsoft.com,
39  * copied here for enhanced BMP support in the future:
40  * http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0197/mfcp1/mfcp1.htm&nav=/msj/0197/newnav.htm
41  */
42 
43 typedef struct BMPINFOHEADER {
56 
57 #if 0
58 typedef struct BMPHEADER {
59  ushort biType;
60  uint biSize;
61  ushort biRes1;
62  ushort biRes2;
63  uint biOffBits;
64 } BMPHEADER;
65 #endif
66 
67 #define BMP_FILEHEADER_SIZE 14
68 
69 #define CHECK_HEADER_FIELD(_mem, _field) ((_mem[0] == _field[0]) && (_mem[1] == _field[1]))
70 #define CHECK_HEADER_FIELD_BMP(_mem) \
71  (CHECK_HEADER_FIELD(_mem, "BM") || CHECK_HEADER_FIELD(_mem, "BA") || \
72  CHECK_HEADER_FIELD(_mem, "CI") || CHECK_HEADER_FIELD(_mem, "CP") || \
73  CHECK_HEADER_FIELD(_mem, "IC") || CHECK_HEADER_FIELD(_mem, "PT"))
74 
75 static bool checkbmp(const uchar *mem, const size_t size)
76 {
77  if (size < (BMP_FILEHEADER_SIZE + sizeof(BMPINFOHEADER))) {
78  return false;
79  }
80 
81  if (!CHECK_HEADER_FIELD_BMP(mem)) {
82  return false;
83  }
84 
85  bool ok = false;
86  BMPINFOHEADER bmi;
87  uint u;
88 
89  /* skip fileheader */
90  mem += BMP_FILEHEADER_SIZE;
91 
92  /* for systems where an int needs to be 4 bytes aligned */
93  memcpy(&bmi, mem, sizeof(bmi));
94 
95  u = LITTLE_LONG(bmi.biSize);
96  /* we only support uncompressed images for now. */
97  if (u >= sizeof(BMPINFOHEADER)) {
98  if (bmi.biCompression == 0) {
99  u = LITTLE_SHORT(bmi.biBitCount);
100  if (u > 0 && u <= 32) {
101  ok = true;
102  }
103  }
104  }
105 
106  return ok;
107 }
108 
109 bool imb_is_a_bmp(const uchar *buf, size_t size)
110 {
111  return checkbmp(buf, size);
112 }
113 
114 static size_t imb_bmp_calc_row_size_in_bytes(size_t x, size_t depth)
115 {
116  /* https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader#calculating-surface-stride
117  */
118  return (((x * depth) + 31) & ~31) >> 3;
119 }
120 
121 ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
122 {
123  ImBuf *ibuf = NULL;
124  BMPINFOHEADER bmi;
125  int ibuf_depth;
126  const uchar *bmp;
127  uchar *rect;
128  ushort col;
129  bool top_to_bottom = false;
130 
131  if (checkbmp(mem, size) == 0) {
132  return NULL;
133  }
134 
136 
137  /* For systems where an int needs to be 4 bytes aligned. */
138  memcpy(&bmi, mem + BMP_FILEHEADER_SIZE, sizeof(bmi));
139 
140  const size_t palette_offset = (size_t)BMP_FILEHEADER_SIZE + LITTLE_LONG(bmi.biSize);
141  const int depth = LITTLE_SHORT(bmi.biBitCount);
142  const int xppm = LITTLE_LONG(bmi.biXPelsPerMeter);
143  const int yppm = LITTLE_LONG(bmi.biYPelsPerMeter);
144  const int x = LITTLE_LONG(bmi.biWidth);
145  int y = LITTLE_LONG(bmi.biHeight);
146 
147  /* Negative height means bitmap is stored top-to-bottom. */
148  if (y < 0) {
149  y = -y;
150  top_to_bottom = true;
151  }
152 
153  /* Validate and cross-check offsets and sizes. */
154  if (x < 1 ||
155  !(depth == 1 || depth == 4 || depth == 8 || depth == 16 || depth == 24 || depth == 32)) {
156  return NULL;
157  }
158 
159  const size_t pixel_data_offset = (size_t)LITTLE_LONG(*(int *)(mem + 10));
160  const size_t header_bytes = BMP_FILEHEADER_SIZE + sizeof(BMPINFOHEADER);
161  const size_t num_actual_data_bytes = size - pixel_data_offset;
162  const size_t row_size_in_bytes = imb_bmp_calc_row_size_in_bytes(x, depth);
163  const size_t num_expected_data_bytes = row_size_in_bytes * y;
164  if (num_actual_data_bytes < num_expected_data_bytes || num_actual_data_bytes > size ||
165  pixel_data_offset < header_bytes || pixel_data_offset > (size - num_expected_data_bytes) ||
166  palette_offset < header_bytes || palette_offset > pixel_data_offset) {
167  return NULL;
168  }
169 
170  if (depth <= 8) {
171  ibuf_depth = 24;
172  }
173  else {
174  ibuf_depth = depth;
175  }
176 
177  bmp = mem + pixel_data_offset;
178 
179 #if 0
180  printf("palette_offset: %d, x: %d y: %d, depth: %d\n", palette_offset, x, y, depth);
181 #endif
182 
183  if (flags & IB_test) {
184  ibuf = IMB_allocImBuf(x, y, ibuf_depth, 0);
185  }
186  else {
187  ibuf = IMB_allocImBuf(x, y, ibuf_depth, IB_rect);
188  if (!ibuf) {
189  return NULL;
190  }
191 
192  rect = (uchar *)ibuf->rect;
193 
194  if (depth <= 8) {
195  const char(*palette)[4] = (const char(*)[4])(mem + palette_offset);
196  const int startmask = ((1 << depth) - 1) << 8;
197  for (size_t i = y; i > 0; i--) {
198  int index;
199  int bitoffs = 8;
200  int bitmask = startmask;
201  int nbytes = 0;
202  const char *pcol;
203  if (top_to_bottom) {
204  rect = (uchar *)&ibuf->rect[(i - 1) * x];
205  }
206  for (size_t j = x; j > 0; j--) {
207  bitoffs -= depth;
208  bitmask >>= depth;
209  index = (bmp[0] & bitmask) >> bitoffs;
210  pcol = palette[index];
211  /* intentionally BGR -> RGB */
212  rect[0] = pcol[2];
213  rect[1] = pcol[1];
214  rect[2] = pcol[0];
215 
216  rect[3] = 255;
217  rect += 4;
218  if (bitoffs == 0) {
219  /* Advance to the next byte */
220  bitoffs = 8;
221  bitmask = startmask;
222  nbytes += 1;
223  bmp += 1;
224  }
225  }
226  /* Advance to the next row */
227  bmp += (row_size_in_bytes - nbytes);
228  }
229  }
230  else if (depth == 16) {
231  for (size_t i = y; i > 0; i--) {
232  if (top_to_bottom) {
233  rect = (uchar *)&ibuf->rect[(i - 1) * x];
234  }
235  for (size_t j = x; j > 0; j--) {
236  col = bmp[0] + (bmp[1] << 8);
237  rect[0] = ((col >> 10) & 0x1f) << 3;
238  rect[1] = ((col >> 5) & 0x1f) << 3;
239  rect[2] = ((col >> 0) & 0x1f) << 3;
240 
241  rect[3] = 255;
242  rect += 4;
243  bmp += 2;
244  }
245  }
246  }
247  else if (depth == 24) {
248  const int x_pad = x % 4;
249  for (size_t i = y; i > 0; i--) {
250  if (top_to_bottom) {
251  rect = (uchar *)&ibuf->rect[(i - 1) * x];
252  }
253  for (size_t j = x; j > 0; j--) {
254  rect[0] = bmp[2];
255  rect[1] = bmp[1];
256  rect[2] = bmp[0];
257 
258  rect[3] = 255;
259  rect += 4;
260  bmp += 3;
261  }
262  /* for 24-bit images, rows are padded to multiples of 4 */
263  bmp += x_pad;
264  }
265  }
266  else if (depth == 32) {
267  for (size_t i = y; i > 0; i--) {
268  if (top_to_bottom) {
269  rect = (uchar *)&ibuf->rect[(i - 1) * x];
270  }
271  for (size_t j = x; j > 0; j--) {
272  rect[0] = bmp[2];
273  rect[1] = bmp[1];
274  rect[2] = bmp[0];
275  rect[3] = bmp[3];
276  rect += 4;
277  bmp += 4;
278  }
279  }
280  }
281  }
282 
283  if (ibuf) {
284  ibuf->ppm[0] = xppm;
285  ibuf->ppm[1] = yppm;
286  ibuf->ftype = IMB_FTYPE_BMP;
287  }
288 
289  return ibuf;
290 }
291 
292 #undef CHECK_HEADER_FIELD_BMP
293 #undef CHECK_HEADER_FIELD
294 
295 /* Couple of helper functions for writing our data */
296 static int putIntLSB(uint ui, FILE *ofile)
297 {
298  putc((ui >> 0) & 0xFF, ofile);
299  putc((ui >> 8) & 0xFF, ofile);
300  putc((ui >> 16) & 0xFF, ofile);
301  return putc((ui >> 24) & 0xFF, ofile);
302 }
303 
304 static int putShortLSB(ushort us, FILE *ofile)
305 {
306  putc((us >> 0) & 0xFF, ofile);
307  return putc((us >> 8) & 0xFF, ofile);
308 }
309 
310 /* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
311 bool imb_savebmp(ImBuf *ibuf, const char *filepath, int UNUSED(flags))
312 {
313  BMPINFOHEADER infoheader;
314 
315  const size_t bytes_per_pixel = (ibuf->planes + 7) >> 3;
316  BLI_assert(ELEM(bytes_per_pixel, 1, 3));
317 
318  const size_t pad_bytes_per_scanline = (4 - ibuf->x * bytes_per_pixel % 4) % 4;
319  const size_t bytesize = (ibuf->x * bytes_per_pixel + pad_bytes_per_scanline) * ibuf->y;
320 
321  const uchar *data = (const uchar *)ibuf->rect;
322  FILE *ofile = BLI_fopen(filepath, "wb");
323  if (ofile == NULL) {
324  return 0;
325  }
326 
327  const bool is_grayscale = bytes_per_pixel == 1;
328  const size_t palette_size = is_grayscale ? 255 * 4 : 0; /* RGBA32 */
329  const size_t pixel_array_start = BMP_FILEHEADER_SIZE + sizeof(infoheader) + palette_size;
330 
331  putShortLSB(19778, ofile); /* "BM" */
332  putIntLSB(bytesize + pixel_array_start, ofile); /* Total file size */
333  putShortLSB(0, ofile); /* Res1 */
334  putShortLSB(0, ofile); /* Res2 */
335  putIntLSB(pixel_array_start, ofile); /* offset to start of pixel array */
336 
337  putIntLSB(sizeof(infoheader), ofile);
338  putIntLSB(ibuf->x, ofile);
339  putIntLSB(ibuf->y, ofile);
340  putShortLSB(1, ofile);
341  putShortLSB(is_grayscale ? 8 : 24, ofile);
342  putIntLSB(0, ofile);
343  putIntLSB(bytesize, ofile);
344  putIntLSB(round(ibuf->ppm[0]), ofile);
345  putIntLSB(round(ibuf->ppm[1]), ofile);
346  putIntLSB(0, ofile);
347  putIntLSB(0, ofile);
348 
349  /* color palette table, which is just every grayscale color, full alpha */
350  if (is_grayscale) {
351  for (char i = 0; i < 255; i++) {
352  putc(i, ofile);
353  putc(i, ofile);
354  putc(i, ofile);
355  putc(0xFF, ofile);
356  }
357  }
358 
359  if (is_grayscale) {
360  for (size_t y = 0; y < ibuf->y; y++) {
361  for (size_t x = 0; x < ibuf->x; x++) {
362  const size_t ptr = (x + y * ibuf->x) * 4;
363  if (putc(data[ptr], ofile) == EOF) {
364  return 0;
365  }
366  }
367  /* Add padding here. */
368  for (size_t t = 0; t < pad_bytes_per_scanline; t++) {
369  if (putc(0, ofile) == EOF) {
370  return 0;
371  }
372  }
373  }
374  }
375  else {
376  /* Need to write out padded image data in BGR format. */
377  for (size_t y = 0; y < ibuf->y; y++) {
378  for (size_t x = 0; x < ibuf->x; x++) {
379  const size_t ptr = (x + y * ibuf->x) * 4;
380  if (putc(data[ptr + 2], ofile) == EOF) {
381  return 0;
382  }
383  if (putc(data[ptr + 1], ofile) == EOF) {
384  return 0;
385  }
386  if (putc(data[ptr], ofile) == EOF) {
387  return 0;
388  }
389  }
390  /* Add padding here. */
391  for (size_t t = 0; t < pad_bytes_per_scanline; t++) {
392  if (putc(0, ofile) == EOF) {
393  return 0;
394  }
395  }
396  }
397  }
398  if (ofile) {
399  fflush(ofile);
400  fclose(ofile);
401  }
402  return 1;
403 }
#define BLI_assert(a)
Definition: BLI_assert.h:58
File and directory operations.
FILE * BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1003
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
unsigned short ushort
Definition: BLI_sys_types.h:84
#define UNUSED(x)
#define ELEM(...)
_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 GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
#define LITTLE_LONG
Definition: IMB_anim.h:71
@ COLOR_ROLE_DEFAULT_BYTE
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:478
#define IM_MAX_SPACE
Definition: IMB_imbuf.h:65
Contains defines and structs used throughout the imbuf module.
@ IB_test
@ IB_rect
#define CHECK_HEADER_FIELD_BMP(_mem)
Definition: bmp.c:70
bool imb_savebmp(ImBuf *ibuf, const char *filepath, int UNUSED(flags))
Definition: bmp.c:311
struct BMPINFOHEADER BMPINFOHEADER
ImBuf * imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
Definition: bmp.c:121
static bool checkbmp(const uchar *mem, const size_t size)
Definition: bmp.c:75
bool imb_is_a_bmp(const uchar *buf, size_t size)
Definition: bmp.c:109
#define BMP_FILEHEADER_SIZE
Definition: bmp.c:67
static int putIntLSB(uint ui, FILE *ofile)
Definition: bmp.c:296
static size_t imb_bmp_calc_row_size_in_bytes(size_t x, size_t depth)
Definition: bmp.c:114
static int putShortLSB(ushort us, FILE *ofile)
Definition: bmp.c:304
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
void colorspace_set_default_role(char *colorspace, int size, int role)
uint col
@ IMB_FTYPE_BMP
#define LITTLE_SHORT
Definition: imbuf.h:56
uint biYPelsPerMeter
Definition: bmp.c:52
uint biSize
Definition: bmp.c:44
ushort biPlanes
Definition: bmp.c:47
uint biCompression
Definition: bmp.c:49
uint biSizeImage
Definition: bmp.c:50
uint biHeight
Definition: bmp.c:46
uint biXPelsPerMeter
Definition: bmp.c:51
uint biClrUsed
Definition: bmp.c:53
uint biWidth
Definition: bmp.c:45
ushort biBitCount
Definition: bmp.c:48
uint biClrImportant
Definition: bmp.c:54
unsigned char planes
enum eImbFileType ftype
unsigned int * rect
double ppm[2]
PointerRNA * ptr
Definition: wm_files.c:3157