Coin Logo Coin3D is Free Software,
published under the BSD 3-clause license.
https://coin3d.github.io
https://www.kongsberg.com/en/kogt/
simage_rgb.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) Kongsberg Oil & Gas Technologies
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * An SGI RGB loader. By pederb@sim.no.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif /* HAVE_CONFIG_H */
24 
25 #ifdef SIMAGE_RGB_SUPPORT
26 
27 #include <simage_rgb.h>
28 #include <simage_private.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 
33 #define ERR_NO_ERROR 0
34 #define ERR_OPEN 1
35 #define ERR_READ 2
36 #define ERR_MEM 3
37 #define ERR_SIZEZ 4
38 #define ERR_OPEN_WRITE 5
39 
40 static int rgberror = ERR_NO_ERROR;
41 
42 typedef struct {
43  FILE * in;
44  int w;
45  int h;
46  int nc;
47  int compressed;
48  unsigned int * rowseek;
49  int * rowlen;
50  unsigned char * rlebuf;
51  int rlebuflen;
52  unsigned char * tmpbuf[4];
53 } simage_rgb_opendata;
54 
55 unsigned char *
56 simage_rgb_load(const char * filename,
57  int * width,
58  int * height,
59  int * numcomponents)
60 {
61  simage_rgb_opendata * od = (simage_rgb_opendata*)
62  simage_rgb_open(filename, width, height, numcomponents);
63 
64  if (od) {
65  int i;
66  int bpr = *width * *numcomponents;
67  unsigned char * buf = (unsigned char *) malloc((size_t)bpr * *height);
68 
69  for (i = 0; i < *height; i++) {
70  if (simage_rgb_read_line(od, i, buf+bpr*i) == 0) {
71  /* rgberror will be set by simage_rgb_read_line() */
72  free(buf);
73  simage_rgb_close(od);
74  return NULL;
75  }
76  }
77  simage_rgb_close(od);
78  return buf;
79  }
80  return NULL;
81 }
82 
83 static int
84 write_short(FILE * fp, unsigned short val)
85 {
86  unsigned char tmp[2];
87  tmp[0] = (unsigned char)(val >> 8);
88  tmp[1] = (unsigned char)(val & 0xff);
89  return (int)fwrite(&tmp, 2, 1, fp);
90 }
91 
92 int
93 simage_rgb_save(const char * filename,
94  const unsigned char * bytes,
95  int width,
96  int height,
97  int comp)
98 {
99  int x, y, c;
100  unsigned char * tmpbuf;
101  unsigned char buf[500];
102 
103  FILE * fp = fopen(filename, "wb");
104  if (!fp) {
105  rgberror = ERR_OPEN_WRITE;
106  return 0;
107  }
108 
109  write_short(fp, 0x01da); /* imagic */
110  write_short(fp, 0x0001); /* raw (no rle yet) */
111 
112  if (comp == 1)
113  write_short(fp, 0x0002); /* 2 dimensions (heightmap) */
114  else
115  write_short(fp, 0x0003); /* 3 dimensions */
116 
117  write_short(fp, (unsigned short) width);
118  write_short(fp, (unsigned short) height);
119  write_short(fp, (unsigned short) comp);
120 
121  memset(buf, 0, 500);
122  buf[7] = 255; /* set maximum pixel value to 255 */
123  strcpy((char *)buf+8, "https://coin3d.github.io");
124  fwrite(buf, 1, 500, fp);
125 
126  tmpbuf = (unsigned char *) malloc(width);
127 
128  for (c = 0; c < comp; c++) {
129  for (y = 0; y < height; y++) {
130  for (x = 0; x < width; x++) {
131  tmpbuf[x] = bytes[x * comp + y * comp * width + c];
132  }
133  fwrite(tmpbuf, 1, width, fp);
134  }
135  }
136  free(tmpbuf);
137  fclose(fp);
138  return 1;
139 }
140 
141 int
142 simage_rgb_identify(const char * filename,
143  const unsigned char * header,
144  int headerlen)
145 {
146  static unsigned char rgbcmp[] = {0x01, 0xda};
147  if (headerlen < 2) return 0;
148  if (memcmp((const void*)header,
149  (const void*)rgbcmp, 2) == 0) return 1;
150  return 0;
151 }
152 
153 int
154 simage_rgb_error(char * buffer, int buflen)
155 {
156  switch (rgberror) {
157  case ERR_OPEN:
158  strncpy(buffer, "RGB loader: Error opening file", buflen);
159  break;
160  case ERR_READ:
161  strncpy(buffer, "RGB loader: Error reading file", buflen);
162  break;
163  case ERR_MEM:
164  strncpy(buffer, "RGB loader: Out of memory error", buflen);
165  break;
166  case ERR_SIZEZ:
167  strncpy(buffer, "RGB loader: Unsupported zsize", buflen);
168  break;
169  case ERR_OPEN_WRITE:
170  strncpy(buffer, "RGB loader: Error opening file for writing", buflen);
171  }
172  return rgberror;
173 }
174 
175 static int
176 read_short(FILE * in, short * dst, int n, int swap)
177 {
178  int i;
179  unsigned char * ptr;
180  unsigned char tmp;
181  int num = (int)fread(dst, sizeof(short), n, in);
182  if (num == n && swap) {
183  ptr = (unsigned char *) dst;
184  for (i = 0; i < n; i++) {
185  tmp = ptr[0];
186  ptr[0] = ptr[1];
187  ptr[1] = tmp;
188  ptr += 2;
189  }
190  }
191  return num == n;
192 }
193 
194 static int
195 read_ushort(FILE * in, unsigned short * dst, int n, int swap)
196 {
197  return read_short(in, (short*) dst, n, swap);
198 }
199 
200 static int
201 read_int(FILE * in, int * dst, int n, int swap)
202 {
203  int i;
204  unsigned char tmp;
205  unsigned char * ptr;
206  int num = (int)fread(dst, sizeof(int), n, in);
207  if (num == n && swap) {
208  ptr = (unsigned char *) dst;
209  for (i = 0; i < n; i++) {
210  tmp = ptr[0];
211  ptr[0] = ptr[3];
212  ptr[3] = tmp;
213  tmp = ptr[1];
214  ptr[1] = ptr[2];
215  ptr[2] = tmp;
216  ptr += 4;
217  }
218  }
219  return num == n;
220 }
221 
222 static int
223 read_uint(FILE * in, unsigned int * dst, int n, int swap)
224 {
225  return read_int(in, (int*)dst, n, swap);
226 }
227 
228 void *
229 simage_rgb_open(const char * filename,
230  int * width,
231  int * height,
232  int * numcomponents)
233 {
234  int i;
235  int swap;
236  FILE * in;
237  unsigned short type;
238  unsigned short size[3];
239  simage_rgb_opendata * od;
240 
241  union {
242  int data;
243  char bytedata[4];
244  } endiantest;
245 
246  endiantest.data = 1;
247  /* need to swap shorts and integers on little endian systems */
248  swap = endiantest.bytedata[0] == 1;
249 
250  in = fopen(filename, "rb");
251  if (!in) {
252  rgberror = ERR_OPEN;
253  return NULL;
254  }
255  /* skip imagic */
256  (void) fseek(in, 2, SEEK_SET);
257  if (!read_ushort(in, &type, 1, swap)) {
258  rgberror = ERR_READ;
259  fclose(in);
260  return NULL;
261  }
262  /* skip dim */
263  (void) fseek(in, 6, SEEK_SET);
264  if (!read_ushort(in, size, 3, swap)) {
265  rgberror = ERR_READ;
266  fclose(in);
267  return NULL;
268  }
269 
270  od = (simage_rgb_opendata*) malloc(sizeof(simage_rgb_opendata));
271  memset(od, 0, sizeof(simage_rgb_opendata));
272  od->in = in;
273  od->w = (int) size[0];
274  od->h = (int) size[1];
275  od->nc = (int) size[2];
276  od->compressed = (type & 0xFF00) == 0x0100;
277  od->rlebuf = (unsigned char*) malloc(od->w * 2);
278  od->rlebuflen = od->w * 2;
279 
280  for (i = 0; i < od->nc; i++) {
281  od->tmpbuf[i] = (unsigned char *) malloc(od->w);
282  }
283  if (od->compressed) {
284  /* create row lookup table */
285  int numlookup = od->h * od->nc;
286  od->rowseek = (unsigned int*) malloc(numlookup * 4);
287  od->rowlen = (int*) malloc(numlookup * 4);
288 
289  (void) fseek(in, 512, SEEK_SET);
290  (void) read_uint(in, od->rowseek, numlookup, swap);
291  if (!read_int(in, od->rowlen, numlookup, swap)) {
292  rgberror = ERR_READ;
293  simage_rgb_close(od);
294  return NULL;
295  }
296  }
297  *width = od->w;
298  *height = od->h;
299  *numcomponents = od->nc;
300  return (void*) od;
301 }
302 
303 void
304 simage_rgb_close(void * opendata)
305 {
306  int i;
307  simage_rgb_opendata * od =
308  (simage_rgb_opendata*) opendata;
309 
310  fclose(od->in);
311  for (i = 0; i < od->nc; i++) {
312  free(od->tmpbuf[i]);
313  }
314  if (od->rowseek) free(od->rowseek);
315  if (od->rowlen) free(od->rowlen);
316  if (od->rlebuf) free(od->rlebuf);
317  free(od);
318 }
319 
320 static int
321 read_rgb_row_component(simage_rgb_opendata * od, int y, int c)
322 {
323  if (od->compressed) {
324  unsigned char * src, * dst;
325  unsigned char * srcstop, * dststop;
326  unsigned char pixel;
327  int count;
328  int rowlen;
329 
330  if (fseek(od->in, od->rowseek[y+c*od->h], SEEK_SET) != 0) {
331  rgberror = ERR_READ;
332  return 0;
333  }
334  rowlen = od->rowlen[y+c*od->h];
335  if (rowlen > od->rlebuflen) {
336  free(od->rlebuf);
337  od->rlebuflen = rowlen;
338  od->rlebuf = (unsigned char*) malloc(od->rlebuflen);
339  }
340  if (fread(od->rlebuf, 1, rowlen, od->in) != rowlen) {
341  rgberror = ERR_READ;
342  return 0;
343  }
344 
345  src = od->rlebuf;
346  dst = od->tmpbuf[c];
347  srcstop = src + rowlen;
348  dststop = dst + od->w;
349 
350  pixel = *src++;
351  count = (int)(pixel & 0x7F);
352 
353  while (count) {
354  if (dst + count > dststop) { rgberror = ERR_READ; return 0; }
355  if (pixel & 0x80) {
356  if (src + count > srcstop) { rgberror = ERR_READ; return 0; }
357  while (count--) {
358  *dst++ = *src++;
359  }
360  }
361  else {
362  if (src >= srcstop) { rgberror = ERR_READ; return 0; }
363  pixel = *src++;
364  while (count--) {
365  *dst++ = pixel;
366  }
367  }
368  pixel = *src++;
369  count = (int)(pixel & 0x7F);
370  }
371  }
372  else {
373  if (fseek(od->in, 512+(y*od->w)+(c*od->w*od->h), SEEK_SET) != 0) {
374  rgberror = ERR_READ;
375  return 0;
376  }
377  if (fread(od->tmpbuf[c], 1, od->w, od->in) != od->w) {
378  rgberror = ERR_READ;
379  return 0;
380  }
381  }
382  return 1;
383 }
384 
385 int
386 simage_rgb_read_line(void * opendata, int y, unsigned char * buf)
387 {
388  int i, c;
389  unsigned char * ptr;
390 
391  simage_rgb_opendata * od =
392  (simage_rgb_opendata*) opendata;
393 
394  /* read each component into tmpbufs */
395  for (c = 0; c < od->nc; c++) {
396  if (!read_rgb_row_component(od, y, c)) {
397  rgberror = ERR_READ;
398  return 0;
399  }
400  }
401 
402  ptr = buf;
403  /* merge components into pixels */
404  for (i = 0; i < od->w; i++) {
405  for (c = 0; c < od->nc; c++) {
406  *ptr++ = od->tmpbuf[c][i];
407  }
408  }
409  return 1;
410 }
411 
412 #endif /* SIMAGE_RGB_SUPPORT */
unsigned char * simage_rgb_load(const char *filename, int *width, int *height, int *numcomponents)
int simage_rgb_read_line(void *opendata, int y, unsigned char *buf)
int simage_rgb_save(const char *filename, const unsigned char *bytes, int width, int height, int numcomponents)
void simage_rgb_close(void *opendata)
int simage_rgb_error(char *buffer, int bufferlen)
#define ERR_OPEN
int simage_rgb_identify(const char *filename, const unsigned char *header, int headerlen)
#define ERR_MEM
#define ERR_NO_ERROR
void * simage_rgb_open(const char *filename, int *width, int *height, int *numcomponents)