3 * Todd Kirby <doubleshot@pacbell.net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 /* sgi image file signature */
28 #define SGI_HEADER_SIZE 512
30 #define SGI_GRAYSCALE 1
34 #define SGI_SINGLE_CHAN 2
35 #define SGI_MULTI_CHAN 3
37 typedef struct SGIInfo{
40 char bytes_per_channel;
41 unsigned short dimension;
48 static int sgi_probe(AVProbeData *pd)
50 /* test for sgi magic */
51 if (pd->buf_size >= 2 && BE_16(&pd->buf[0]) == SGI_MAGIC) {
52 return AVPROBE_SCORE_MAX;
58 /* read sgi header fields */
59 static void read_sgi_header(ByteIOContext *f, SGIInfo *info)
61 info->magic = (unsigned short) get_be16(f);
62 info->rle = get_byte(f);
63 info->bytes_per_channel = get_byte(f);
64 info->dimension = (unsigned short)get_be16(f);
65 info->xsize = (unsigned short) get_be16(f);
66 info->ysize = (unsigned short) get_be16(f);
67 info->zsize = (unsigned short) get_be16(f);
70 printf("sgi header fields:\n");
71 printf(" magic: %d\n", info->magic);
72 printf(" rle: %d\n", info->rle);
73 printf(" bpc: %d\n", info->bytes_per_channel);
74 printf(" dim: %d\n", info->dimension);
75 printf(" xsize: %d\n", info->xsize);
76 printf(" ysize: %d\n", info->ysize);
77 printf(" zsize: %d\n", info->zsize);
84 /* read an uncompressed sgi image */
85 static int read_uncompressed_sgi(const SGIInfo *si,
86 AVPicture *pict, ByteIOContext *f)
88 int x, y, z, chan_offset, ret = 0;
89 uint8_t *dest_row, *tmp_row = NULL;
91 tmp_row = av_malloc(si->xsize);
94 url_fseek(f, SGI_HEADER_SIZE, SEEK_SET);
96 pict->linesize[0] = si->xsize;
98 for (z = 0; z < si->zsize; z++) {
100 #ifndef WORDS_BIGENDIAN
101 /* rgba -> bgra for rgba32 on little endian cpus */
102 if (si->zsize == 4 && z != 3)
108 for (y = si->ysize - 1; y >= 0; y--) {
109 dest_row = pict->data[0] + (y * si->xsize * si->zsize);
111 if (!get_buffer(f, tmp_row, si->xsize)) {
115 for (x = 0; x < si->xsize; x++) {
116 dest_row[chan_offset] = tmp_row[x];
117 dest_row += si->zsize;
128 /* expand an rle row into a channel */
129 static void expand_rle_row(unsigned char *optr, unsigned char *iptr,
130 int chan_offset, int pixelstride)
132 unsigned char pixel, count;
134 #ifndef WORDS_BIGENDIAN
135 /* rgba -> bgra for rgba32 on little endian cpus */
136 if (pixelstride == 4 && chan_offset != 3) {
137 chan_offset = 2 - chan_offset;
146 if (!(count = (pixel & 0x7f))) {
167 /* read a run length encoded sgi image */
168 static int read_rle_sgi(const SGIInfo *sgi_info,
169 AVPicture *pict, ByteIOContext *f)
171 uint8_t *dest_row, *rle_data = NULL;
172 unsigned long *start_table, *length_table;
173 int y, z, xsize, ysize, zsize, tablen;
174 long start_offset, run_length;
177 xsize = sgi_info->xsize;
178 ysize = sgi_info->ysize;
179 zsize = sgi_info->zsize;
181 rle_data = av_malloc(xsize);
184 url_fseek(f, SGI_HEADER_SIZE, SEEK_SET);
186 /* size of rle offset and length tables */
187 tablen = ysize * zsize * sizeof(long);
189 start_table = (unsigned long *)av_malloc(tablen);
190 length_table = (unsigned long *)av_malloc(tablen);
192 if (!get_buffer(f, (uint8_t *)start_table, tablen)) {
197 if (!get_buffer(f, (uint8_t *)length_table, tablen)) {
202 for (z = 0; z < zsize; z++) {
203 for (y = 0; y < ysize; y++) {
204 dest_row = pict->data[0] + (ysize - 1 - y) * (xsize * zsize);
206 start_offset = BE_32(&start_table[y + z * ysize]);
207 run_length = BE_32(&length_table[y + z * ysize]);
209 /* don't seek if already in the correct spot */
210 if (url_ftell(f) != start_offset) {
211 url_fseek(f, start_offset, SEEK_SET);
214 get_buffer(f, rle_data, run_length);
216 expand_rle_row(dest_row, rle_data, z, zsize);
221 av_free(start_table);
222 av_free(length_table);
229 static int sgi_read(ByteIOContext *f,
230 int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
232 SGIInfo sgi_info, *s = &sgi_info;
233 AVImageInfo info1, *info = &info1;
236 read_sgi_header(f, s);
238 if (s->bytes_per_channel != 1) {
239 return AVERROR_INVALIDDATA;
242 /* check for supported image dimensions */
243 if (s->dimension != 2 && s->dimension != 3) {
244 return AVERROR_INVALIDDATA;
247 if (s->zsize == SGI_GRAYSCALE) {
248 info->pix_fmt = PIX_FMT_GRAY8;
249 } else if (s->zsize == SGI_RGB) {
250 info->pix_fmt = PIX_FMT_RGB24;
251 } else if (s->zsize == SGI_RGBA) {
252 info->pix_fmt = PIX_FMT_RGBA32;
254 return AVERROR_INVALIDDATA;
257 info->width = s->xsize;
258 info->height = s->ysize;
260 ret = alloc_cb(opaque, info);
265 return read_rle_sgi(s, &info->pict, f);
267 return read_uncompressed_sgi(s, &info->pict, f);
270 return 0; /* not reached */
273 #ifdef CONFIG_ENCODERS
274 static void write_sgi_header(ByteIOContext *f, const SGIInfo *info)
278 put_be16(f, SGI_MAGIC);
279 put_byte(f, info->rle);
280 put_byte(f, info->bytes_per_channel);
281 put_be16(f, info->dimension);
282 put_be16(f, info->xsize);
283 put_be16(f, info->ysize);
284 put_be16(f, info->zsize);
286 /* The rest are constant in this implementation */
287 put_be32(f, 0L); /* pixmin */
288 put_be32(f, 255L); /* pixmax */
289 put_be32(f, 0L); /* dummy */
292 for (i = 0; i < 80; i++) {
296 put_be32(f, 0L); /* colormap */
298 /* The rest of the 512 byte header is unused. */
299 for (i = 0; i < 404; i++) {
305 static int rle_row(ByteIOContext *f, char *row, int stride, int rowsize)
307 int length, count, i, x;
308 char *start, repeat = 0;
310 for (x = rowsize, length = 0; x > 0;) {
315 while (x > 0 && (row[-2 * stride] != row[-1 * stride] ||
316 row[-1 * stride] != row[0])) {
324 count = (row - start) / stride;
326 i = count > 126 ? 126 : count;
329 put_byte(f, 0x80 | i);
350 while (x > 0 && *row == repeat) {
355 count = (row - start) / stride;
357 i = count > 126 ? 126 : count;
375 static int sgi_write(ByteIOContext *pb, AVImageInfo *info)
377 SGIInfo sgi_info, *si = &sgi_info;
378 long *offsettab, *lengthtab;
380 int tablesize, chan_offset;
383 si->xsize = info->width;
384 si->ysize = info->height;
386 si->bytes_per_channel = 1;
388 switch(info->pix_fmt) {
390 si->dimension = SGI_SINGLE_CHAN;
391 si->zsize = SGI_GRAYSCALE;
394 si->dimension = SGI_MULTI_CHAN;
398 si->dimension = SGI_MULTI_CHAN;
399 si->zsize = SGI_RGBA;
402 return AVERROR_INVALIDDATA;
405 write_sgi_header(pb, si);
407 tablesize = si->zsize * si->ysize * sizeof(long);
409 /* skip rle offset and length tables, write them at the end. */
410 url_fseek(pb, tablesize * 2, SEEK_CUR);
411 put_flush_packet(pb);
413 lengthtab = av_malloc(tablesize);
414 offsettab = av_malloc(tablesize);
416 for (z = 0; z < si->zsize; z++) {
418 #ifndef WORDS_BIGENDIAN
419 /* rgba -> bgra for rgba32 on little endian cpus */
420 if (si->zsize == 4 && z != 3)
426 srcrow = info->pict.data[0] + chan_offset;
428 for (y = si->ysize -1; y >= 0; y--) {
429 offsettab[(z * si->ysize) + y] = url_ftell(pb);
430 lengthtab[(z * si->ysize) + y] = rle_row(pb, srcrow,
431 si->zsize, si->xsize);
432 srcrow += info->pict.linesize[0];
436 url_fseek(pb, 512, SEEK_SET);
438 /* write offset table */
439 for (i = 0; i < (si->ysize * si->zsize); i++) {
440 put_be32(pb, offsettab[i]);
443 /* write length table */
444 for (i = 0; i < (si->ysize * si->zsize); i++) {
445 put_be32(pb, lengthtab[i]);
448 put_flush_packet(pb);
455 #endif // CONFIG_ENCODERS
457 AVImageFormat sgi_image_format = {
462 (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_RGBA32),
463 #ifdef CONFIG_ENCODERS
467 #endif // CONFIG_ENCODERS