*.EXE
*.lnk
*.LNK
+*.lbc
+*.LBC
+*.lib
+*.LIB
+*.err
+*.ERR
*.log
*.LOG
Debug
obj = $(baseobj) $(demoobj) $(sysobj)
bin = demo.exe
-opt = -5 -fp5 -otexan
+libs = imago.lib
+
+opt = -5 -fp5 -otexan -oh -oi -ei
dbg = -d1
+!ifdef __UNIX__
+incpath = -Isrc -Isrc/dos -Ilibs/imago/src
+libpath = libs/imago
+!else
+incpath = -Isrc -Isrc\dos -Ilibs\imago\src
+libpath = libs\imago
+!endif
+
AS = nasm
CC = wcc386
CXX = wpp386
ASFLAGS = -fobj
-CFLAGS = $(dbg) $(opt) -zq -bt=dos -Isrc -Isrc\dos
+CFLAGS = $(dbg) $(opt) -zq -bt=dos $(incpath)
CXXFLAGS = $(CFLAGS)
+LDFLAGS = libpath $(libpath) library { $(libs) }
LD = wlink
-$(bin): $(obj)
- %write objects.lnk system dos4g file { $(obj) }
- $(LD) debug all name $@ @objects $(LDFLAGS)
+$(bin): $(obj) libs/imago/imago.lib
+ %write objects.lnk $(obj)
+ $(LD) debug all name $@ system dos4g file { @objects } $(LDFLAGS)
.c: src;src/dos
.cc: src;src/dos
--- /dev/null
+libpng = png.obj pngerror.obj pngget.obj pngmem.obj pngpread.obj pngread.obj &
+pngrio.obj pngrtran.obj pngrutil.obj pngset.obj pngtrans.obj pngwio.obj &
+pngwrite.obj pngwtran.obj pngwutil.obj
+zlib = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj &
+inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
+jpeglib = jcapimin.obj jcapistd.obj jccoefct.obj jccolor.obj jcdctmgr.obj &
+jchuff.obj jcinit.obj jcmainct.obj jcmarker.obj jcmaster.obj jcomapi.obj &
+jcparam.obj jcphuff.obj jcprepct.obj jcsample.obj jctrans.obj jdapimin.obj &
+jdapistd.obj jdatadst.obj jdatasrc.obj jdcoefct.obj jdcolor.obj jddctmgr.obj &
+jdhuff.obj jdinput.obj jdmainct.obj jdmarker.obj jdmaster.obj jdmerge.obj &
+jdphuff.obj jdpostct.obj jdsample.obj jdtrans.obj jerror.obj jfdctflt.obj &
+jfdctfst.obj jfdctint.obj jidctflt.obj jidctfst.obj jidctint.obj jidctred.obj &
+jmemmgr.obj jmemnobs.obj jquant1.obj jquant2.obj jutils.obj
+
+obj = conv.obj filejpeg.obj filepng.obj fileppm.obj filergbe.obj &
+filetga.obj ftmodule.obj imago2.obj imago_gl.obj modules.obj &
+$(libpng) $(zlib) $(jpeglib)
+
+alib = imago.lib
+
+opt = -5 -fp5 -otexan
+dbg = -d1
+def = -DPNG_NO_SNPRINTF
+
+CC = wcc386
+CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos -Ilibpng -Izlib -Ijpeglib
+
+$(alib): $(obj)
+ %write objects.lbc $(obj)
+ wlib -b -n $@ @objects
+
+.c: src;libpng;jpeglib;zlib
+
+.c.obj: .autodepend
+ $(CC) -fo=$@ $(CFLAGS) $[*
+
+clean: .symbolic
+ del *.obj
+ del $(alib)
+++ /dev/null
-/*
-libimago - a multi-format image file input/output library.
-Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published
-by the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/* -- JPEG module -- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef WIN32
-#include <windows.h>
-#define HAVE_BOOLEAN
-#endif
-
-#include <jpeglib.h>
-#include "imago2.h"
-#include "ftype_module.h"
-
-#define INPUT_BUF_SIZE 512
-#define OUTPUT_BUF_SIZE 512
-
-/* data source manager: adapted from jdatasrc.c */
-struct src_mgr {
- struct jpeg_source_mgr pub;
-
- struct img_io *io;
- unsigned char buffer[INPUT_BUF_SIZE];
- int start_of_file;
-};
-
-/* data destination manager: adapted from jdatadst.c */
-struct dst_mgr {
- struct jpeg_destination_mgr pub;
-
- struct img_io *io;
- unsigned char buffer[OUTPUT_BUF_SIZE];
-};
-
-static int check(struct img_io *io);
-static int read(struct img_pixmap *img, struct img_io *io);
-static int write(struct img_pixmap *img, struct img_io *io);
-
-/* read source functions */
-static void init_source(j_decompress_ptr jd);
-static boolean fill_input_buffer(j_decompress_ptr jd);
-static void skip_input_data(j_decompress_ptr jd, long num_bytes);
-static void term_source(j_decompress_ptr jd);
-
-/* write destination functions */
-static void init_destination(j_compress_ptr jc);
-static boolean empty_output_buffer(j_compress_ptr jc);
-static void term_destination(j_compress_ptr jc);
-
-int img_register_jpeg(void)
-{
- static struct ftype_module mod = {".jpg", check, read, write};
- return img_register_module(&mod);
-}
-
-
-static int check(struct img_io *io)
-{
- unsigned char sig[10];
-
- long pos = io->seek(0, SEEK_CUR, io->uptr);
-
- if(io->read(sig, 10, io->uptr) < 10) {
- io->seek(pos, SEEK_SET, io->uptr);
- return -1;
- }
-
- if(memcmp(sig, "\xff\xd8\xff\xe0", 4) != 0 && memcmp(sig, "\xff\xd8\xff\xe1", 4) != 0
- && memcmp(sig, "\xff\xd8\xff\xdb", 4) != 0 && memcmp(sig + 6, "JFIF", 4) != 0) {
- io->seek(pos, SEEK_SET, io->uptr);
- return -1;
- }
- io->seek(pos, SEEK_SET, io->uptr);
- return 0;
-}
-
-static int read(struct img_pixmap *img, struct img_io *io)
-{
- int i, nlines = 0;
- struct jpeg_decompress_struct cinfo;
- struct jpeg_error_mgr jerr;
- struct src_mgr src;
- unsigned char **scanlines;
-
- io->seek(0, SEEK_CUR, io->uptr);
-
- cinfo.err = jpeg_std_error(&jerr); /* XXX change... */
- jpeg_create_decompress(&cinfo);
-
- src.pub.init_source = init_source;
- src.pub.fill_input_buffer = fill_input_buffer;
- src.pub.skip_input_data = skip_input_data;
- src.pub.resync_to_restart = jpeg_resync_to_restart;
- src.pub.term_source = term_source;
- src.pub.next_input_byte = 0;
- src.pub.bytes_in_buffer = 0;
- src.io = io;
- cinfo.src = (struct jpeg_source_mgr*)&src;
-
- jpeg_read_header(&cinfo, 1);
- cinfo.out_color_space = JCS_RGB;
-
- if(img_set_pixels(img, cinfo.image_width, cinfo.image_height, IMG_FMT_RGB24, 0) == -1) {
- jpeg_destroy_decompress(&cinfo);
- return -1;
- }
-
- if(!(scanlines = malloc(img->height * sizeof *scanlines))) {
- jpeg_destroy_decompress(&cinfo);
- return -1;
- }
- scanlines[0] = img->pixels;
- for(i=1; i<img->height; i++) {
- scanlines[i] = scanlines[i - 1] + img->width * img->pixelsz;
- }
-
- jpeg_start_decompress(&cinfo);
- while(nlines < img->height) {
- int res = jpeg_read_scanlines(&cinfo, scanlines + nlines, img->height - nlines);
- nlines += res;
- }
- jpeg_finish_decompress(&cinfo);
- jpeg_destroy_decompress(&cinfo);
-
- free(scanlines);
- return 0;
-}
-
-static int write(struct img_pixmap *img, struct img_io *io)
-{
- int i, nlines = 0;
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- struct dst_mgr dest;
- struct img_pixmap tmpimg;
- unsigned char **scanlines;
-
- img_init(&tmpimg);
-
- if(img->fmt != IMG_FMT_RGB24) {
- if(img_copy(&tmpimg, img) == -1) {
- return -1;
- }
- if(img_convert(&tmpimg, IMG_FMT_RGB24) == -1) {
- img_destroy(&tmpimg);
- return -1;
- }
- img = &tmpimg;
- }
-
- if(!(scanlines = malloc(img->height * sizeof *scanlines))) {
- img_destroy(&tmpimg);
- return -1;
- }
- scanlines[0] = img->pixels;
- for(i=1; i<img->height; i++) {
- scanlines[i] = scanlines[i - 1] + img->width * img->pixelsz;
- }
-
- cinfo.err = jpeg_std_error(&jerr); /* XXX */
- jpeg_create_compress(&cinfo);
-
- dest.pub.init_destination = init_destination;
- dest.pub.empty_output_buffer = empty_output_buffer;
- dest.pub.term_destination = term_destination;
- dest.io = io;
- cinfo.dest = (struct jpeg_destination_mgr*)&dest;
-
- cinfo.image_width = img->width;
- cinfo.image_height = img->height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
-
- jpeg_set_defaults(&cinfo);
-
- jpeg_start_compress(&cinfo, 1);
- while(nlines < img->height) {
- int res = jpeg_write_scanlines(&cinfo, scanlines + nlines, img->height - nlines);
- nlines += res;
- }
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
-
- free(scanlines);
- img_destroy(&tmpimg);
- return 0;
-}
-
-/* -- read source functions --
- * the following functions are adapted from jdatasrc.c in jpeglib
- */
-static void init_source(j_decompress_ptr jd)
-{
- struct src_mgr *src = (struct src_mgr*)jd->src;
- src->start_of_file = 1;
-}
-
-static boolean fill_input_buffer(j_decompress_ptr jd)
-{
- struct src_mgr *src = (struct src_mgr*)jd->src;
- size_t nbytes;
-
- nbytes = src->io->read(src->buffer, INPUT_BUF_SIZE, src->io->uptr);
-
- if(nbytes <= 0) {
- if(src->start_of_file) {
- return 0;
- }
- /* insert a fake EOI marker */
- src->buffer[0] = 0xff;
- src->buffer[1] = JPEG_EOI;
- nbytes = 2;
- }
-
- src->pub.next_input_byte = src->buffer;
- src->pub.bytes_in_buffer = nbytes;
- src->start_of_file = 0;
- return 1;
-}
-
-static void skip_input_data(j_decompress_ptr jd, long num_bytes)
-{
- struct src_mgr *src = (struct src_mgr*)jd->src;
-
- if(num_bytes > 0) {
- while(num_bytes > (long)src->pub.bytes_in_buffer) {
- num_bytes -= (long)src->pub.bytes_in_buffer;
- fill_input_buffer(jd);
- }
- src->pub.next_input_byte += (size_t)num_bytes;
- src->pub.bytes_in_buffer -= (size_t)num_bytes;
- }
-}
-
-static void term_source(j_decompress_ptr jd)
-{
- /* nothing to see here, move along */
-}
-
-
-/* -- write destination functions --
- * the following functions are adapted from jdatadst.c in jpeglib
- */
-static void init_destination(j_compress_ptr jc)
-{
- struct dst_mgr *dest = (struct dst_mgr*)jc->dest;
-
- dest->pub.next_output_byte = dest->buffer;
- dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
-}
-
-static boolean empty_output_buffer(j_compress_ptr jc)
-{
- struct dst_mgr *dest = (struct dst_mgr*)jc->dest;
-
- if(dest->io->write(dest->buffer, OUTPUT_BUF_SIZE, dest->io->uptr) != OUTPUT_BUF_SIZE) {
- return 0;
- }
-
- dest->pub.next_output_byte = dest->buffer;
- dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
- return 1;
-}
-
-static void term_destination(j_compress_ptr jc)
-{
- struct dst_mgr *dest = (struct dst_mgr*)jc->dest;
- size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
-
- /* write any remaining data in the buffer */
- if(datacount > 0) {
- dest->io->write(dest->buffer, datacount, dest->io->uptr);
- }
- /* XXX flush? ... */
-}
+++ /dev/null
-/*
-libimago - a multi-format image file input/output library.
-Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published
-by the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/* -- PNG module -- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <png.h>
-#include "imago2.h"
-#include "ftype_module.h"
-
-static int check_file(struct img_io *io);
-static int read_file(struct img_pixmap *img, struct img_io *io);
-static int write_file(struct img_pixmap *img, struct img_io *io);
-
-static void read_func(png_struct *png, unsigned char *data, size_t len);
-static void write_func(png_struct *png, unsigned char *data, size_t len);
-static void flush_func(png_struct *png);
-
-static int png_type_to_fmt(int color_type, int channel_bits);
-static int fmt_to_png_type(enum img_fmt fmt);
-
-
-int img_register_png(void)
-{
- static struct ftype_module mod = {".png", check_file, read_file, write_file};
- return img_register_module(&mod);
-}
-
-static int check_file(struct img_io *io)
-{
- unsigned char sig[8];
- int res;
- long pos = io->seek(0, SEEK_CUR, io->uptr);
-
- if(io->read(sig, 8, io->uptr) < 8) {
- io->seek(pos, SEEK_SET, io->uptr);
- return -1;
- }
-
- res = png_sig_cmp(sig, 0, 8) == 0 ? 0 : -1;
- io->seek(pos, SEEK_SET, io->uptr);
- return res;
-}
-
-static int read_file(struct img_pixmap *img, struct img_io *io)
-{
- png_struct *png;
- png_info *info;
- int channel_bits, color_type, ilace_type, compression, filtering, fmt;
- png_uint_32 xsz, ysz;
-
- if(!(png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
- return -1;
- }
-
- if(!(info = png_create_info_struct(png))) {
- png_destroy_read_struct(&png, 0, 0);
- return -1;
- }
-
- if(setjmp(png_jmpbuf(png))) {
- png_destroy_read_struct(&png, &info, 0);
- return -1;
- }
-
- png_set_read_fn(png, io, read_func);
- png_set_sig_bytes(png, 0);
- png_read_png(png, info, 0, 0);
-
- png_get_IHDR(png, info, &xsz, &ysz, &channel_bits, &color_type, &ilace_type,
- &compression, &filtering);
- if((fmt = png_type_to_fmt(color_type, channel_bits)) == -1) {
- png_destroy_read_struct(&png, &info, 0);
- return -1;
- }
-
- if(img_set_pixels(img, xsz, ysz, fmt, 0) == -1) {
- png_destroy_read_struct(&png, &info, 0);
- return -1;
- }
-
-
- if(channel_bits == 8) {
- unsigned int i;
- unsigned char **lineptr = (unsigned char**)png_get_rows(png, info);
- unsigned char *dest = img->pixels;
-
- for(i=0; i<ysz; i++) {
- memcpy(dest, lineptr[i], xsz * img->pixelsz);
- dest += xsz * img->pixelsz;
- }
- } else {
- unsigned int i, j, num_elem;
- unsigned char **lineptr = (unsigned char**)png_get_rows(png, info);
- float *dest = img->pixels;
-
- num_elem = img->pixelsz / sizeof(float);
- for(i=0; i<ysz; i++) {
- for(j=0; j<xsz * num_elem; j++) {
- unsigned short val = (lineptr[i][j * 2] << 8) | lineptr[i][j * 2 + 1];
- *dest++ = (float)val / 65535.0;
- }
- }
- }
-
-
- png_destroy_read_struct(&png, &info, 0);
- return 0;
-}
-
-
-static int write_file(struct img_pixmap *img, struct img_io *io)
-{
- png_struct *png;
- png_info *info;
- png_text txt;
- struct img_pixmap tmpimg;
- unsigned char **rows;
- unsigned char *pixptr;
- int i, coltype;
-
- img_init(&tmpimg);
-
- if(!(png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
- return -1;
- }
- if(!(info = png_create_info_struct(png))) {
- png_destroy_write_struct(&png, 0);
- return -1;
- }
-
- /* if the input image is floating-point, we need to convert it to integer */
- if(img_is_float(img)) {
- if(img_copy(&tmpimg, img) == -1) {
- return -1;
- }
- if(img_to_integer(&tmpimg) == -1) {
- img_destroy(&tmpimg);
- return -1;
- }
- img = &tmpimg;
- }
-
- txt.compression = PNG_TEXT_COMPRESSION_NONE;
- txt.key = "Software";
- txt.text = "libimago2";
- txt.text_length = 0;
-
- if(setjmp(png_jmpbuf(png))) {
- png_destroy_write_struct(&png, &info);
- img_destroy(&tmpimg);
- return -1;
- }
- png_set_write_fn(png, io, write_func, flush_func);
-
- coltype = fmt_to_png_type(img->fmt);
- png_set_IHDR(png, info, img->width, img->height, 8, coltype, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
- png_set_text(png, info, &txt, 1);
-
- if(!(rows = malloc(img->height * sizeof *rows))) {
- png_destroy_write_struct(&png, &info);
- img_destroy(&tmpimg);
- return -1;
- }
-
- pixptr = img->pixels;
- for(i=0; i<img->height; i++) {
- rows[i] = pixptr;
- pixptr += img->width * img->pixelsz;
- }
- png_set_rows(png, info, rows);
-
- png_write_png(png, info, 0, 0);
- png_write_end(png, info);
- png_destroy_write_struct(&png, &info);
-
- free(rows);
-
- img_destroy(&tmpimg);
- return 0;
-}
-
-static void read_func(png_struct *png, unsigned char *data, size_t len)
-{
- struct img_io *io = (struct img_io*)png_get_io_ptr(png);
-
- if(io->read(data, len, io->uptr) == -1) {
- longjmp(png_jmpbuf(png), 1);
- }
-}
-
-static void write_func(png_struct *png, unsigned char *data, size_t len)
-{
- struct img_io *io = (struct img_io*)png_get_io_ptr(png);
-
- if(io->write(data, len, io->uptr) == -1) {
- longjmp(png_jmpbuf(png), 1);
- }
-}
-
-static void flush_func(png_struct *png)
-{
- /* XXX does it matter that we can't flush? */
-}
-
-static int png_type_to_fmt(int color_type, int channel_bits)
-{
- /* only 8 and 16 bits per channel ar supported at the moment */
- if(channel_bits != 8 && channel_bits != 16) {
- return -1;
- }
-
- switch(color_type) {
- case PNG_COLOR_TYPE_RGB:
- return channel_bits == 16 ? IMG_FMT_RGBF : IMG_FMT_RGB24;
-
- case PNG_COLOR_TYPE_RGB_ALPHA:
- return channel_bits == 16 ? IMG_FMT_RGBAF : IMG_FMT_RGBA32;
-
- case PNG_COLOR_TYPE_GRAY:
- return channel_bits == 16 ? IMG_FMT_GREYF : IMG_FMT_GREY8;
-
- default:
- break;
- }
- return -1;
-}
-
-static int fmt_to_png_type(enum img_fmt fmt)
-{
- switch(fmt) {
- case IMG_FMT_GREY8:
- return PNG_COLOR_TYPE_GRAY;
-
- case IMG_FMT_RGB24:
- return PNG_COLOR_TYPE_RGB;
-
- case IMG_FMT_RGBA32:
- return PNG_COLOR_TYPE_RGBA;
-
- default:
- break;
- }
- return -1;
-}
+++ /dev/null
-/*
-libimago - a multi-format image file input/output library.
-Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published
-by the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/* -- Portable Pixmap (PPM) module -- */
-
-#include <string.h>
-#include "imago2.h"
-#include "ftype_module.h"
-
-static int check(struct img_io *io);
-static int read(struct img_pixmap *img, struct img_io *io);
-static int write(struct img_pixmap *img, struct img_io *io);
-
-int img_register_ppm(void)
-{
- static struct ftype_module mod = {".ppm", check, read, write};
- return img_register_module(&mod);
-}
-
-
-static int check(struct img_io *io)
-{
- char id[2];
- int res = -1;
- long pos = io->seek(0, SEEK_CUR, io->uptr);
-
- if(io->read(id, 2, io->uptr) < 2) {
- io->seek(pos, SEEK_SET, io->uptr);
- return -1;
- }
-
- if(id[0] == 'P' && (id[1] == '6' || id[1] == '3')) {
- res = 0;
- }
- io->seek(pos, SEEK_SET, io->uptr);
- return res;
-}
-
-static int iofgetc(struct img_io *io)
-{
- char c;
- return io->read(&c, 1, io->uptr) < 1 ? -1 : c;
-}
-
-static char *iofgets(char *buf, int size, struct img_io *io)
-{
- int c;
- char *ptr = buf;
-
- while(--size > 0 && (c = iofgetc(io)) != -1) {
- *ptr++ = c;
- if(c == '\n') break;
- }
- *ptr = 0;
-
- return ptr == buf ? 0 : buf;
-}
-
-/* TODO: implement P3 reading */
-static int read(struct img_pixmap *img, struct img_io *io)
-{
- char buf[256];
- int xsz, ysz, maxval, got_hdrlines = 1;
-
- if(!iofgets(buf, sizeof buf, io)) {
- return -1;
- }
- if(!(buf[0] == 'P' && (buf[1] == '6' || buf[1] == '3'))) {
- return -1;
- }
-
- while(got_hdrlines < 3 && iofgets(buf, sizeof buf, io)) {
- if(buf[0] == '#') continue;
-
- switch(got_hdrlines) {
- case 1:
- if(sscanf(buf, "%d %d\n", &xsz, &ysz) < 2) {
- return -1;
- }
- break;
-
- case 2:
- if(sscanf(buf, "%d\n", &maxval) < 1) {
- return -1;
- }
- default:
- break;
- }
- got_hdrlines++;
- }
-
- if(xsz < 1 || ysz < 1 || maxval != 255) {
- return -1;
- }
-
- if(img_set_pixels(img, xsz, ysz, IMG_FMT_RGB24, 0) == -1) {
- return -1;
- }
-
- if(io->read(img->pixels, xsz * ysz * 3, io->uptr) < (unsigned int)(xsz * ysz * 3)) {
- return -1;
- }
- return 0;
-}
-
-static int write(struct img_pixmap *img, struct img_io *io)
-{
- int sz;
- char buf[256];
- struct img_pixmap tmpimg;
-
- img_init(&tmpimg);
-
- if(img->fmt != IMG_FMT_RGB24) {
- if(img_copy(&tmpimg, img) == -1) {
- return -1;
- }
- if(img_convert(&tmpimg, IMG_FMT_RGB24) == -1) {
- return -1;
- }
- img = &tmpimg;
- }
-
- sprintf(buf, "P6\n#written by libimago2\n%d %d\n255\n", img->width, img->height);
- if(io->write(buf, strlen(buf), io->uptr) < strlen(buf)) {
- img_destroy(&tmpimg);
- return -1;
- }
-
- sz = img->width * img->height * 3;
- if(io->write(img->pixels, sz, io->uptr) < (unsigned int)sz) {
- img_destroy(&tmpimg);
- return -1;
- }
-
- img_destroy(&tmpimg);
- return 0;
-}
+++ /dev/null
-/* This file contains code to read and write four byte rgbe file format
- * developed by Greg Ward. It handles the conversions between rgbe and
- * pixels consisting of floats. The data is assumed to be an array of floats.
- * By default there are three floats per pixel in the order red, green, blue.
- * (RGBE_DATA_??? values control this.)
- *
- * written by Bruce Walter (bjw@graphics.cornell.edu) 5/26/95
- * based on code written by Greg Ward
- * minor modifications by John Tsiombikas (nuclear@member.fsf.org) apr.9 2007
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <ctype.h>
-#include <errno.h>
-#include "imago2.h"
-#include "ftype_module.h"
-
-
-typedef struct {
- int valid; /* indicate which fields are valid */
- char programtype[16]; /* listed at beginning of file to identify it
- * after "#?". defaults to "RGBE" */
- float gamma; /* image has already been gamma corrected with
- * given gamma. defaults to 1.0 (no correction) */
- float exposure; /* a value of 1.0 in an image corresponds to
- * <exposure> watts/steradian/m^2.
- * defaults to 1.0 */
-} rgbe_header_info;
-
-
-static int check(struct img_io *io);
-static int read(struct img_pixmap *img, struct img_io *io);
-static int write(struct img_pixmap *img, struct img_io *io);
-
-static int rgbe_read_header(struct img_io *io, int *width, int *height, rgbe_header_info * info);
-static int rgbe_read_pixels_rle(struct img_io *io, float *data, int scanline_width, int num_scanlines);
-
-
-int img_register_rgbe(void)
-{
- static struct ftype_module mod = {".rgbe", check, read, write};
- return img_register_module(&mod);
-}
-
-
-static int check(struct img_io *io)
-{
- int xsz, ysz, res;
- long pos = io->seek(0, SEEK_CUR, io->uptr);
-
- rgbe_header_info hdr;
- res = rgbe_read_header(io, &xsz, &ysz, &hdr);
-
- io->seek(pos, SEEK_SET, io->uptr);
- return res;
-}
-
-static int read(struct img_pixmap *img, struct img_io *io)
-{
- int xsz, ysz;
- rgbe_header_info hdr;
-
- if(rgbe_read_header(io, &xsz, &ysz, &hdr) == -1) {
- return -1;
- }
-
- if(img_set_pixels(img, xsz, ysz, IMG_FMT_RGBF, 0) == -1) {
- return -1;
- }
- if(rgbe_read_pixels_rle(io, img->pixels, xsz, ysz) == -1) {
- return -1;
- }
- return 0;
-}
-
-static int write(struct img_pixmap *img, struct img_io *io)
-{
- return -1; /* TODO */
-}
-
-
-static int iofgetc(struct img_io *io)
-{
- char c;
- return io->read(&c, 1, io->uptr) < 1 ? -1 : c;
-}
-
-static char *iofgets(char *buf, int size, struct img_io *io)
-{
- int c;
- char *ptr = buf;
-
- while(--size > 0 && (c = iofgetc(io)) != -1) {
- *ptr++ = c;
- if(c == '\n') break;
- }
- *ptr = 0;
-
- return ptr == buf ? 0 : buf;
-}
-
-
-/* flags indicating which fields in an rgbe_header_info are valid */
-#define RGBE_VALID_PROGRAMTYPE 0x01
-#define RGBE_VALID_GAMMA 0x02
-#define RGBE_VALID_EXPOSURE 0x04
-
-/* return codes for rgbe routines */
-#define RGBE_RETURN_SUCCESS 0
-#define RGBE_RETURN_FAILURE -1
-
-
-#if defined(__cplusplus) || defined(GNUC) || __STDC_VERSION >= 199901L
-#define INLINE inline
-#else
-#define INLINE
-#endif
-
-/* offsets to red, green, and blue components in a data (float) pixel */
-#define RGBE_DATA_RED 0
-#define RGBE_DATA_GREEN 1
-#define RGBE_DATA_BLUE 2
-
-/* number of floats per pixel */
-#define RGBE_DATA_SIZE 3
-
-enum rgbe_error_codes {
- rgbe_read_error,
- rgbe_write_error,
- rgbe_format_error,
- rgbe_memory_error
-};
-
-
-/* default error routine. change this to change error handling */
-static int rgbe_error(int rgbe_error_code, char *msg)
-{
- switch (rgbe_error_code) {
- case rgbe_read_error:
- fprintf(stderr, "RGBE read error: %s\n", strerror(errno));
- break;
-
- case rgbe_write_error:
- fprintf(stderr, "RGBE write error: %s\n", strerror(errno));
- break;
-
- case rgbe_format_error:
- fprintf(stderr, "RGBE bad file format: %s\n", msg);
- break;
-
- default:
- case rgbe_memory_error:
- fprintf(stderr, "RGBE error: %s\n", msg);
- }
- return RGBE_RETURN_FAILURE;
-}
-
-/* standard conversion from float pixels to rgbe pixels */
-/*static INLINE void float2rgbe(unsigned char rgbe[4], float red, float green, float blue)
-{
- float v;
- int e;
-
- v = red;
- if(green > v)
- v = green;
- if(blue > v)
- v = blue;
- if(v < 1e-32) {
- rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
- } else {
- v = frexp(v, &e) * 256.0 / v;
- rgbe[0] = (unsigned char)(red * v);
- rgbe[1] = (unsigned char)(green * v);
- rgbe[2] = (unsigned char)(blue * v);
- rgbe[3] = (unsigned char)(e + 128);
- }
-}*/
-
-/* standard conversion from rgbe to float pixels */
-/* note: Ward uses ldexp(col+0.5,exp-(128+8)). However we wanted pixels */
-/* in the range [0,1] to map back into the range [0,1]. */
-static INLINE void rgbe2float(float *red, float *green, float *blue, unsigned char rgbe[4])
-{
- float f;
-
- if(rgbe[3]) { /*nonzero pixel */
- f = ldexp(1.0, rgbe[3] - (int)(128 + 8));
- *red = rgbe[0] * f;
- *green = rgbe[1] * f;
- *blue = rgbe[2] * f;
- } else
- *red = *green = *blue = 0.0;
-}
-
-#if 0
-/* default minimal header. modify if you want more information in header */
-static int rgbe_write_header(FILE * fp, int width, int height, rgbe_header_info * info)
-{
- char *programtype = "RGBE";
-
- if(info && (info->valid & RGBE_VALID_PROGRAMTYPE))
- programtype = info->programtype;
- if(fprintf(fp, "#?%s\n", programtype) < 0)
- return rgbe_error(rgbe_write_error, NULL);
- /* The #? is to identify file type, the programtype is optional. */
- if(info && (info->valid & RGBE_VALID_GAMMA)) {
- if(fprintf(fp, "GAMMA=%g\n", info->gamma) < 0)
- return rgbe_error(rgbe_write_error, NULL);
- }
- if(info && (info->valid & RGBE_VALID_EXPOSURE)) {
- if(fprintf(fp, "EXPOSURE=%g\n", info->exposure) < 0)
- return rgbe_error(rgbe_write_error, NULL);
- }
- if(fprintf(fp, "FORMAT=32-bit_rle_rgbe\n\n") < 0)
- return rgbe_error(rgbe_write_error, NULL);
- if(fprintf(fp, "-Y %d +X %d\n", height, width) < 0)
- return rgbe_error(rgbe_write_error, NULL);
- return RGBE_RETURN_SUCCESS;
-}
-#endif
-
-/* minimal header reading. modify if you want to parse more information */
-static int rgbe_read_header(struct img_io *io, int *width, int *height, rgbe_header_info * info)
-{
- char buf[128];
- float tempf;
- int i;
-
- if(info) {
- info->valid = 0;
- info->programtype[0] = 0;
- info->gamma = info->exposure = 1.0;
- }
- if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == NULL)
- return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/
- if((buf[0] != '#') || (buf[1] != '?')) {
- /* if you want to require the magic token then uncomment the next line */
- /*return rgbe_error(rgbe_format_error,"bad initial token"); */
- } else if(info) {
- info->valid |= RGBE_VALID_PROGRAMTYPE;
- for(i = 0; i < sizeof(info->programtype) - 1; i++) {
- if((buf[i + 2] == 0) || isspace(buf[i + 2]))
- break;
- info->programtype[i] = buf[i + 2];
- }
- info->programtype[i] = 0;
- if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0)
- return rgbe_error(rgbe_read_error, NULL);
- }
- for(;;) {
- if((buf[0] == 0) || (buf[0] == '\n'))
- return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_format_error, "no FORMAT specifier found");*/
- else if(strcmp(buf, "FORMAT=32-bit_rle_rgbe\n") == 0)
- break; /* format found so break out of loop */
- else if(info && (sscanf(buf, "GAMMA=%g", &tempf) == 1)) {
- info->gamma = tempf;
- info->valid |= RGBE_VALID_GAMMA;
- } else if(info && (sscanf(buf, "EXPOSURE=%g", &tempf) == 1)) {
- info->exposure = tempf;
- info->valid |= RGBE_VALID_EXPOSURE;
- }
- if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0)
- return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/
- }
- if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0)
- return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/
- if(strcmp(buf, "\n") != 0)
- return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_format_error, "missing blank line after FORMAT specifier");*/
- if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0)
- return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/
- if(sscanf(buf, "-Y %d +X %d", height, width) < 2)
- return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_format_error, "missing image size specifier");*/
- return RGBE_RETURN_SUCCESS;
-}
-
-#if 0
-/* simple write routine that does not use run length encoding */
-
-/* These routines can be made faster by allocating a larger buffer and
- fread-ing and fwrite-ing the data in larger chunks */
-static int rgbe_write_pixels(FILE * fp, float *data, int numpixels)
-{
- unsigned char rgbe[4];
-
- while(numpixels-- > 0) {
- float2rgbe(rgbe, data[RGBE_DATA_RED], data[RGBE_DATA_GREEN], data[RGBE_DATA_BLUE]);
- data += RGBE_DATA_SIZE;
- if(fwrite(rgbe, sizeof(rgbe), 1, fp) < 1)
- return rgbe_error(rgbe_write_error, NULL);
- }
- return RGBE_RETURN_SUCCESS;
-}
-#endif
-
-/* simple read routine. will not correctly handle run length encoding */
-static int rgbe_read_pixels(struct img_io *io, float *data, int numpixels)
-{
- unsigned char rgbe[4];
-
- while(numpixels-- > 0) {
- if(io->read(rgbe, sizeof(rgbe), io->uptr) < 1)
- return rgbe_error(rgbe_read_error, NULL);
- rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe);
- data += RGBE_DATA_SIZE;
- }
- return RGBE_RETURN_SUCCESS;
-}
-
-#if 0
-/* The code below is only needed for the run-length encoded files. */
-
-/* Run length encoding adds considerable complexity but does */
-
-/* save some space. For each scanline, each channel (r,g,b,e) is */
-
-/* encoded separately for better compression. */
-
-static int rgbe_write_bytes_rle(struct img_io *io, unsigned char *data, int numbytes)
-{
-#define MINRUNLENGTH 4
- int cur, beg_run, run_count, old_run_count, nonrun_count;
- unsigned char buf[2];
-
- cur = 0;
- while(cur < numbytes) {
- beg_run = cur;
- /* find next run of length at least 4 if one exists */
- run_count = old_run_count = 0;
- while((run_count < MINRUNLENGTH) && (beg_run < numbytes)) {
- beg_run += run_count;
- old_run_count = run_count;
- run_count = 1;
- while((beg_run + run_count < numbytes) && (run_count < 127)
- && (data[beg_run] == data[beg_run + run_count]))
- run_count++;
- }
- /* if data before next big run is a short run then write it as such */
- if((old_run_count > 1) && (old_run_count == beg_run - cur)) {
- buf[0] = 128 + old_run_count; /*write short run */
- buf[1] = data[cur];
- if(fwrite(buf, sizeof(buf[0]) * 2, 1, fp) < 1)
- return rgbe_error(rgbe_write_error, NULL);
- cur = beg_run;
- }
- /* write out bytes until we reach the start of the next run */
- while(cur < beg_run) {
- nonrun_count = beg_run - cur;
- if(nonrun_count > 128)
- nonrun_count = 128;
- buf[0] = nonrun_count;
- if(fwrite(buf, sizeof(buf[0]), 1, fp) < 1)
- return rgbe_error(rgbe_write_error, NULL);
- if(fwrite(&data[cur], sizeof(data[0]) * nonrun_count, 1, fp) < 1)
- return rgbe_error(rgbe_write_error, NULL);
- cur += nonrun_count;
- }
- /* write out next run if one was found */
- if(run_count >= MINRUNLENGTH) {
- buf[0] = 128 + run_count;
- buf[1] = data[beg_run];
- if(fwrite(buf, sizeof(buf[0]) * 2, 1, fp) < 1)
- return rgbe_error(rgbe_write_error, NULL);
- cur += run_count;
- }
- }
- return RGBE_RETURN_SUCCESS;
-#undef MINRUNLENGTH
-}
-
-static int rgbe_write_pixels_rle(struct img_io *io, float *data, int scanline_width, int num_scanlines)
-{
- unsigned char rgbe[4];
- unsigned char *buffer;
- int i, err;
-
- if((scanline_width < 8) || (scanline_width > 0x7fff))
- /* run length encoding is not allowed so write flat */
- return rgbe_write_pixels(io, data, scanline_width * num_scanlines);
- buffer = (unsigned char *)malloc(sizeof(unsigned char) * 4 * scanline_width);
- if(buffer == NULL)
- /* no buffer space so write flat */
- return rgbe_write_pixels(fp, data, scanline_width * num_scanlines);
- while(num_scanlines-- > 0) {
- rgbe[0] = 2;
- rgbe[1] = 2;
- rgbe[2] = scanline_width >> 8;
- rgbe[3] = scanline_width & 0xFF;
- if(fwrite(rgbe, sizeof(rgbe), 1, fp) < 1) {
- free(buffer);
- return rgbe_error(rgbe_write_error, NULL);
- }
- for(i = 0; i < scanline_width; i++) {
- float2rgbe(rgbe, data[RGBE_DATA_RED], data[RGBE_DATA_GREEN], data[RGBE_DATA_BLUE]);
- buffer[i] = rgbe[0];
- buffer[i + scanline_width] = rgbe[1];
- buffer[i + 2 * scanline_width] = rgbe[2];
- buffer[i + 3 * scanline_width] = rgbe[3];
- data += RGBE_DATA_SIZE;
- }
- /* write out each of the four channels separately run length encoded */
- /* first red, then green, then blue, then exponent */
- for(i = 0; i < 4; i++) {
- if((err = rgbe_write_bytes_rle(fp, &buffer[i * scanline_width],
- scanline_width)) != RGBE_RETURN_SUCCESS) {
- free(buffer);
- return err;
- }
- }
- }
- free(buffer);
- return RGBE_RETURN_SUCCESS;
-}
-#endif
-
-static int rgbe_read_pixels_rle(struct img_io *io, float *data, int scanline_width, int num_scanlines)
-{
- unsigned char rgbe[4], *scanline_buffer, *ptr, *ptr_end;
- int i, count;
- unsigned char buf[2];
-
- if((scanline_width < 8) || (scanline_width > 0x7fff))
- /* run length encoding is not allowed so read flat */
- return rgbe_read_pixels(io, data, scanline_width * num_scanlines);
- scanline_buffer = NULL;
- /* read in each successive scanline */
- while(num_scanlines > 0) {
- if(io->read(rgbe, sizeof(rgbe), io->uptr) < 1) {
- free(scanline_buffer);
- return rgbe_error(rgbe_read_error, NULL);
- }
- if((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80)) {
- /* this file is not run length encoded */
- rgbe2float(&data[0], &data[1], &data[2], rgbe);
- data += RGBE_DATA_SIZE;
- free(scanline_buffer);
- return rgbe_read_pixels(io, data, scanline_width * num_scanlines - 1);
- }
- if((((int)rgbe[2]) << 8 | rgbe[3]) != scanline_width) {
- free(scanline_buffer);
- return rgbe_error(rgbe_format_error, "wrong scanline width");
- }
- if(scanline_buffer == NULL)
- scanline_buffer = (unsigned char *)
- malloc(sizeof(unsigned char) * 4 * scanline_width);
- if(scanline_buffer == NULL)
- return rgbe_error(rgbe_memory_error, "unable to allocate buffer space");
-
- ptr = &scanline_buffer[0];
- /* read each of the four channels for the scanline into the buffer */
- for(i = 0; i < 4; i++) {
- ptr_end = &scanline_buffer[(i + 1) * scanline_width];
- while(ptr < ptr_end) {
- if(io->read(buf, sizeof(buf[0]) * 2, io->uptr) < 1) {
- free(scanline_buffer);
- return rgbe_error(rgbe_read_error, NULL);
- }
- if(buf[0] > 128) {
- /* a run of the same value */
- count = buf[0] - 128;
- if((count == 0) || (count > ptr_end - ptr)) {
- free(scanline_buffer);
- return rgbe_error(rgbe_format_error, "bad scanline data");
- }
- while(count-- > 0)
- *ptr++ = buf[1];
- } else {
- /* a non-run */
- count = buf[0];
- if((count == 0) || (count > ptr_end - ptr)) {
- free(scanline_buffer);
- return rgbe_error(rgbe_format_error, "bad scanline data");
- }
- *ptr++ = buf[1];
- if(--count > 0) {
- if(io->read(ptr, sizeof(*ptr) * count, io->uptr) < 1) {
- free(scanline_buffer);
- return rgbe_error(rgbe_read_error, NULL);
- }
- ptr += count;
- }
- }
- }
- }
- /* now convert data from buffer into floats */
- for(i = 0; i < scanline_width; i++) {
- rgbe[0] = scanline_buffer[i];
- rgbe[1] = scanline_buffer[i + scanline_width];
- rgbe[2] = scanline_buffer[i + 2 * scanline_width];
- rgbe[3] = scanline_buffer[i + 3 * scanline_width];
- rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe);
- data += RGBE_DATA_SIZE;
- }
- num_scanlines--;
- }
- free(scanline_buffer);
- return RGBE_RETURN_SUCCESS;
-}
+++ /dev/null
-/*
-libimago - a multi-format image file input/output library.
-Copyright (C) 2010-2015 John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published
-by the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/* -- Targa (tga) module -- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "imago2.h"
-#include "ftype_module.h"
-
-
-#if defined(__i386__) || defined(__ia64__) || defined(WIN32) || \
- (defined(__alpha__) || defined(__alpha)) || \
- defined(__arm__) || \
- (defined(__mips__) && defined(__MIPSEL__)) || \
- defined(__SYMBIAN32__) || \
- defined(__x86_64__) || \
- defined(__LITTLE_ENDIAN__)
-/* little endian */
-#define read_int16_le(f) read_int16(f)
-#else
-/* big endian */
-#define read_int16_le(f) read_int16_inv(f)
-#endif /* endian check */
-
-
-enum {
- IMG_NONE,
- IMG_CMAP,
- IMG_RGBA,
- IMG_BW,
-
- IMG_RLE_CMAP = 9,
- IMG_RLE_RGBA,
- IMG_RLE_BW
-};
-
-#define IS_RLE(x) ((x) >= IMG_RLE_CMAP)
-#define IS_RGBA(x) ((x) == IMG_RGBA || (x) == IMG_RLE_RGBA)
-
-
-struct tga_header {
- uint8_t idlen; /* id field length */
- uint8_t cmap_type; /* color map type (0:no color map, 1:color map present) */
- uint8_t img_type; /* image type:
- * 0: no image data
- * 1: uncomp. color-mapped 9: RLE color-mapped
- * 2: uncomp. true color 10: RLE true color
- * 3: uncomp. black/white 11: RLE black/white */
- uint16_t cmap_first; /* color map first entry index */
- uint16_t cmap_len; /* color map length */
- uint8_t cmap_entry_sz; /* color map entry size */
- uint16_t img_x; /* X-origin of the image */
- uint16_t img_y; /* Y-origin of the image */
- uint16_t img_width; /* image width */
- uint16_t img_height; /* image height */
- uint8_t img_bpp; /* bits per pixel */
- uint8_t img_desc; /* descriptor:
- * bits 0 - 3: alpha or overlay bits
- * bits 5 & 4: origin (0 = bottom/left, 1 = top/right)
- * bits 7 & 6: data interleaving */
-};
-
-struct tga_footer {
- uint32_t ext_off; /* extension area offset */
- uint32_t devdir_off; /* developer directory offset */
- char sig[18]; /* signature with . and \0 */
-};
-
-
-static int check(struct img_io *io);
-static int read(struct img_pixmap *img, struct img_io *io);
-static int write(struct img_pixmap *img, struct img_io *io);
-static int read_pixel(struct img_io *io, int rdalpha, uint32_t *pix);
-static int16_t read_int16(struct img_io *io);
-static int16_t read_int16_inv(struct img_io *io);
-
-int img_register_tga(void)
-{
- static struct ftype_module mod = {".tga", check, read, write};
- return img_register_module(&mod);
-}
-
-
-static int check(struct img_io *io)
-{
- struct tga_footer foot;
- int res = -1;
- long pos = io->seek(0, SEEK_CUR, io->uptr);
- io->seek(-18, SEEK_END, io->uptr);
-
- if(io->read(foot.sig, 17, io->uptr) < 17) {
- io->seek(pos, SEEK_SET, io->uptr);
- return -1;
- }
-
- if(memcmp(foot.sig, "TRUEVISION-XFILE.", 17) == 0) {
- res = 0;
- }
- io->seek(pos, SEEK_SET, io->uptr);
- return res;
-}
-
-static int iofgetc(struct img_io *io)
-{
- char c;
- return io->read(&c, 1, io->uptr) < 1 ? -1 : c;
-}
-
-static int read(struct img_pixmap *img, struct img_io *io)
-{
- struct tga_header hdr;
- int x, y;
- int i, c;
- uint32_t ppixel = 0;
- int rle_mode = 0, rle_pix_left = 0;
- int rdalpha;
-
- /* read header */
- hdr.idlen = iofgetc(io);
- hdr.cmap_type = iofgetc(io);
- hdr.img_type = iofgetc(io);
- hdr.cmap_first = read_int16_le(io);
- hdr.cmap_len = read_int16_le(io);
- hdr.cmap_entry_sz = iofgetc(io);
- hdr.img_x = read_int16_le(io);
- hdr.img_y = read_int16_le(io);
- hdr.img_width = read_int16_le(io);
- hdr.img_height = read_int16_le(io);
- hdr.img_bpp = iofgetc(io);
- if((c = iofgetc(io)) == -1) {
- return -1;
- }
- hdr.img_desc = c;
-
- if(!IS_RGBA(hdr.img_type)) {
- fprintf(stderr, "only true color tga images supported\n");
- return -1;
- }
-
- io->seek(hdr.idlen, SEEK_CUR, io); /* skip the image ID */
-
- /* skip the color map if it exists */
- if(hdr.cmap_type == 1) {
- io->seek(hdr.cmap_len * hdr.cmap_entry_sz / 8, SEEK_CUR, io);
- }
-
- x = hdr.img_width;
- y = hdr.img_height;
- rdalpha = hdr.img_desc & 0xf;
-
- /* TODO make this IMG_FMT_RGB24 if there's no alpha channel */
- if(img_set_pixels(img, x, y, IMG_FMT_RGBA32, 0) == -1) {
- return -1;
- }
-
- for(i=0; i<y; i++) {
- uint32_t *ptr;
- int j;
-
- ptr = (uint32_t*)img->pixels + ((hdr.img_desc & 0x20) ? i : y - (i + 1)) * x;
-
- for(j=0; j<x; j++) {
- /* if the image is raw, then just read the next pixel */
- if(!IS_RLE(hdr.img_type)) {
- if(read_pixel(io, rdalpha, &ppixel) == -1) {
- return -1;
- }
- } else {
- /* otherwise, for RLE... */
-
- /* if we have pixels left in the packet ... */
- if(rle_pix_left) {
- /* if it's a raw packet, read the next pixel, otherwise keep the same */
- if(!rle_mode) {
- if(read_pixel(io, rdalpha, &ppixel) == -1) {
- return -1;
- }
- }
- --rle_pix_left;
- } else {
- /* read RLE packet header */
- unsigned char phdr = iofgetc(io);
- rle_mode = (phdr & 128); /* last bit shows the mode for this packet (1: rle, 0: raw) */
- rle_pix_left = (phdr & ~128); /* the rest gives the count of pixels minus one (we also read one here, so no +1) */
- /* and read the first pixel of the packet */
- if(read_pixel(io, rdalpha, &ppixel) == -1) {
- return -1;
- }
- }
- }
-
- *ptr++ = ppixel;
- }
- }
-
- return 0;
-}
-
-static int write(struct img_pixmap *img, struct img_io *io)
-{
- return -1; /* TODO */
-}
-
-#define PACK_COLOR32(r,g,b,a) \
- ((((a) & 0xff) << 24) | \
- (((r) & 0xff) << 0) | \
- (((g) & 0xff) << 8) | \
- (((b) & 0xff) << 16))
-
-static int read_pixel(struct img_io *io, int rdalpha, uint32_t *pix)
-{
- int r, g, b, a;
- b = iofgetc(io);
- g = iofgetc(io);
- r = iofgetc(io);
- a = rdalpha ? iofgetc(io) : 0xff;
- *pix = PACK_COLOR32(r, g, b, a);
- return a == -1 || r == -1 ? -1 : 0;
-}
-
-static int16_t read_int16(struct img_io *io)
-{
- int16_t v;
- io->read(&v, 2, io);
- return v;
-}
-
-static int16_t read_int16_inv(struct img_io *io)
-{
- int16_t v;
- io->read(&v, 2, io);
- return ((v >> 8) & 0xff) | (v << 8);
-}
--- /dev/null
+/*
+libimago - a multi-format image file input/output library.
+Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published
+by the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* -- JPEG module -- */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <windows.h>
+#define HAVE_BOOLEAN
+#endif
+
+#include <jpeglib.h>
+#include "imago2.h"
+#include "ftmodule.h"
+
+#define INPUT_BUF_SIZE 512
+#define OUTPUT_BUF_SIZE 512
+
+/* data source manager: adapted from jdatasrc.c */
+struct src_mgr {
+ struct jpeg_source_mgr pub;
+
+ struct img_io *io;
+ unsigned char buffer[INPUT_BUF_SIZE];
+ int start_of_file;
+};
+
+/* data destination manager: adapted from jdatadst.c */
+struct dst_mgr {
+ struct jpeg_destination_mgr pub;
+
+ struct img_io *io;
+ unsigned char buffer[OUTPUT_BUF_SIZE];
+};
+
+static int check(struct img_io *io);
+static int read(struct img_pixmap *img, struct img_io *io);
+static int write(struct img_pixmap *img, struct img_io *io);
+
+/* read source functions */
+static void init_source(j_decompress_ptr jd);
+static boolean fill_input_buffer(j_decompress_ptr jd);
+static void skip_input_data(j_decompress_ptr jd, long num_bytes);
+static void term_source(j_decompress_ptr jd);
+
+/* write destination functions */
+static void init_destination(j_compress_ptr jc);
+static boolean empty_output_buffer(j_compress_ptr jc);
+static void term_destination(j_compress_ptr jc);
+
+int img_register_jpeg(void)
+{
+ static struct ftype_module mod = {".jpg", check, read, write};
+ return img_register_module(&mod);
+}
+
+
+static int check(struct img_io *io)
+{
+ unsigned char sig[10];
+
+ long pos = io->seek(0, SEEK_CUR, io->uptr);
+
+ if(io->read(sig, 10, io->uptr) < 10) {
+ io->seek(pos, SEEK_SET, io->uptr);
+ return -1;
+ }
+
+ if(memcmp(sig, "\xff\xd8\xff\xe0", 4) != 0 && memcmp(sig, "\xff\xd8\xff\xe1", 4) != 0
+ && memcmp(sig, "\xff\xd8\xff\xdb", 4) != 0 && memcmp(sig + 6, "JFIF", 4) != 0) {
+ io->seek(pos, SEEK_SET, io->uptr);
+ return -1;
+ }
+ io->seek(pos, SEEK_SET, io->uptr);
+ return 0;
+}
+
+static int read(struct img_pixmap *img, struct img_io *io)
+{
+ int i, nlines = 0;
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ struct src_mgr src;
+ unsigned char **scanlines;
+
+ io->seek(0, SEEK_CUR, io->uptr);
+
+ cinfo.err = jpeg_std_error(&jerr); /* XXX change... */
+ jpeg_create_decompress(&cinfo);
+
+ src.pub.init_source = init_source;
+ src.pub.fill_input_buffer = fill_input_buffer;
+ src.pub.skip_input_data = skip_input_data;
+ src.pub.resync_to_restart = jpeg_resync_to_restart;
+ src.pub.term_source = term_source;
+ src.pub.next_input_byte = 0;
+ src.pub.bytes_in_buffer = 0;
+ src.io = io;
+ cinfo.src = (struct jpeg_source_mgr*)&src;
+
+ jpeg_read_header(&cinfo, 1);
+ cinfo.out_color_space = JCS_RGB;
+
+ if(img_set_pixels(img, cinfo.image_width, cinfo.image_height, IMG_FMT_RGB24, 0) == -1) {
+ jpeg_destroy_decompress(&cinfo);
+ return -1;
+ }
+
+ if(!(scanlines = malloc(img->height * sizeof *scanlines))) {
+ jpeg_destroy_decompress(&cinfo);
+ return -1;
+ }
+ scanlines[0] = img->pixels;
+ for(i=1; i<img->height; i++) {
+ scanlines[i] = scanlines[i - 1] + img->width * img->pixelsz;
+ }
+
+ jpeg_start_decompress(&cinfo);
+ while(nlines < img->height) {
+ int res = jpeg_read_scanlines(&cinfo, scanlines + nlines, img->height - nlines);
+ nlines += res;
+ }
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+
+ free(scanlines);
+ return 0;
+}
+
+static int write(struct img_pixmap *img, struct img_io *io)
+{
+ int i, nlines = 0;
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ struct dst_mgr dest;
+ struct img_pixmap tmpimg;
+ unsigned char **scanlines;
+
+ img_init(&tmpimg);
+
+ if(img->fmt != IMG_FMT_RGB24) {
+ if(img_copy(&tmpimg, img) == -1) {
+ return -1;
+ }
+ if(img_convert(&tmpimg, IMG_FMT_RGB24) == -1) {
+ img_destroy(&tmpimg);
+ return -1;
+ }
+ img = &tmpimg;
+ }
+
+ if(!(scanlines = malloc(img->height * sizeof *scanlines))) {
+ img_destroy(&tmpimg);
+ return -1;
+ }
+ scanlines[0] = img->pixels;
+ for(i=1; i<img->height; i++) {
+ scanlines[i] = scanlines[i - 1] + img->width * img->pixelsz;
+ }
+
+ cinfo.err = jpeg_std_error(&jerr); /* XXX */
+ jpeg_create_compress(&cinfo);
+
+ dest.pub.init_destination = init_destination;
+ dest.pub.empty_output_buffer = empty_output_buffer;
+ dest.pub.term_destination = term_destination;
+ dest.io = io;
+ cinfo.dest = (struct jpeg_destination_mgr*)&dest;
+
+ cinfo.image_width = img->width;
+ cinfo.image_height = img->height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+
+ jpeg_start_compress(&cinfo, 1);
+ while(nlines < img->height) {
+ int res = jpeg_write_scanlines(&cinfo, scanlines + nlines, img->height - nlines);
+ nlines += res;
+ }
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ free(scanlines);
+ img_destroy(&tmpimg);
+ return 0;
+}
+
+/* -- read source functions --
+ * the following functions are adapted from jdatasrc.c in jpeglib
+ */
+static void init_source(j_decompress_ptr jd)
+{
+ struct src_mgr *src = (struct src_mgr*)jd->src;
+ src->start_of_file = 1;
+}
+
+static boolean fill_input_buffer(j_decompress_ptr jd)
+{
+ struct src_mgr *src = (struct src_mgr*)jd->src;
+ size_t nbytes;
+
+ nbytes = src->io->read(src->buffer, INPUT_BUF_SIZE, src->io->uptr);
+
+ if(nbytes <= 0) {
+ if(src->start_of_file) {
+ return 0;
+ }
+ /* insert a fake EOI marker */
+ src->buffer[0] = 0xff;
+ src->buffer[1] = JPEG_EOI;
+ nbytes = 2;
+ }
+
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+ src->start_of_file = 0;
+ return 1;
+}
+
+static void skip_input_data(j_decompress_ptr jd, long num_bytes)
+{
+ struct src_mgr *src = (struct src_mgr*)jd->src;
+
+ if(num_bytes > 0) {
+ while(num_bytes > (long)src->pub.bytes_in_buffer) {
+ num_bytes -= (long)src->pub.bytes_in_buffer;
+ fill_input_buffer(jd);
+ }
+ src->pub.next_input_byte += (size_t)num_bytes;
+ src->pub.bytes_in_buffer -= (size_t)num_bytes;
+ }
+}
+
+static void term_source(j_decompress_ptr jd)
+{
+ /* nothing to see here, move along */
+}
+
+
+/* -- write destination functions --
+ * the following functions are adapted from jdatadst.c in jpeglib
+ */
+static void init_destination(j_compress_ptr jc)
+{
+ struct dst_mgr *dest = (struct dst_mgr*)jc->dest;
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+}
+
+static boolean empty_output_buffer(j_compress_ptr jc)
+{
+ struct dst_mgr *dest = (struct dst_mgr*)jc->dest;
+
+ if(dest->io->write(dest->buffer, OUTPUT_BUF_SIZE, dest->io->uptr) != OUTPUT_BUF_SIZE) {
+ return 0;
+ }
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+ return 1;
+}
+
+static void term_destination(j_compress_ptr jc)
+{
+ struct dst_mgr *dest = (struct dst_mgr*)jc->dest;
+ size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
+
+ /* write any remaining data in the buffer */
+ if(datacount > 0) {
+ dest->io->write(dest->buffer, datacount, dest->io->uptr);
+ }
+ /* XXX flush? ... */
+}
--- /dev/null
+/*
+libimago - a multi-format image file input/output library.
+Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published
+by the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* -- PNG module -- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <png.h>
+#include "imago2.h"
+#include "ftmodule.h"
+
+static int check_file(struct img_io *io);
+static int read_file(struct img_pixmap *img, struct img_io *io);
+static int write_file(struct img_pixmap *img, struct img_io *io);
+
+static void read_func(png_struct *png, unsigned char *data, size_t len);
+static void write_func(png_struct *png, unsigned char *data, size_t len);
+static void flush_func(png_struct *png);
+
+static int png_type_to_fmt(int color_type, int channel_bits);
+static int fmt_to_png_type(enum img_fmt fmt);
+
+
+int img_register_png(void)
+{
+ static struct ftype_module mod = {".png", check_file, read_file, write_file};
+ return img_register_module(&mod);
+}
+
+static int check_file(struct img_io *io)
+{
+ unsigned char sig[8];
+ int res;
+ long pos = io->seek(0, SEEK_CUR, io->uptr);
+
+ if(io->read(sig, 8, io->uptr) < 8) {
+ io->seek(pos, SEEK_SET, io->uptr);
+ return -1;
+ }
+
+ res = png_sig_cmp(sig, 0, 8) == 0 ? 0 : -1;
+ io->seek(pos, SEEK_SET, io->uptr);
+ return res;
+}
+
+static int read_file(struct img_pixmap *img, struct img_io *io)
+{
+ png_struct *png;
+ png_info *info;
+ int channel_bits, color_type, ilace_type, compression, filtering, fmt;
+ png_uint_32 xsz, ysz;
+
+ if(!(png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
+ return -1;
+ }
+
+ if(!(info = png_create_info_struct(png))) {
+ png_destroy_read_struct(&png, 0, 0);
+ return -1;
+ }
+
+ if(setjmp(png_jmpbuf(png))) {
+ png_destroy_read_struct(&png, &info, 0);
+ return -1;
+ }
+
+ png_set_read_fn(png, io, read_func);
+ png_set_sig_bytes(png, 0);
+ png_read_png(png, info, 0, 0);
+
+ png_get_IHDR(png, info, &xsz, &ysz, &channel_bits, &color_type, &ilace_type,
+ &compression, &filtering);
+ if((fmt = png_type_to_fmt(color_type, channel_bits)) == -1) {
+ png_destroy_read_struct(&png, &info, 0);
+ return -1;
+ }
+
+ if(img_set_pixels(img, xsz, ysz, fmt, 0) == -1) {
+ png_destroy_read_struct(&png, &info, 0);
+ return -1;
+ }
+
+
+ if(channel_bits == 8) {
+ unsigned int i;
+ unsigned char **lineptr = (unsigned char**)png_get_rows(png, info);
+ unsigned char *dest = img->pixels;
+
+ for(i=0; i<ysz; i++) {
+ memcpy(dest, lineptr[i], xsz * img->pixelsz);
+ dest += xsz * img->pixelsz;
+ }
+ } else {
+ unsigned int i, j, num_elem;
+ unsigned char **lineptr = (unsigned char**)png_get_rows(png, info);
+ float *dest = img->pixels;
+
+ num_elem = img->pixelsz / sizeof(float);
+ for(i=0; i<ysz; i++) {
+ for(j=0; j<xsz * num_elem; j++) {
+ unsigned short val = (lineptr[i][j * 2] << 8) | lineptr[i][j * 2 + 1];
+ *dest++ = (float)val / 65535.0;
+ }
+ }
+ }
+
+
+ png_destroy_read_struct(&png, &info, 0);
+ return 0;
+}
+
+
+static int write_file(struct img_pixmap *img, struct img_io *io)
+{
+ png_struct *png;
+ png_info *info;
+ png_text txt;
+ struct img_pixmap tmpimg;
+ unsigned char **rows;
+ unsigned char *pixptr;
+ int i, coltype;
+
+ img_init(&tmpimg);
+
+ if(!(png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
+ return -1;
+ }
+ if(!(info = png_create_info_struct(png))) {
+ png_destroy_write_struct(&png, 0);
+ return -1;
+ }
+
+ /* if the input image is floating-point, we need to convert it to integer */
+ if(img_is_float(img)) {
+ if(img_copy(&tmpimg, img) == -1) {
+ return -1;
+ }
+ if(img_to_integer(&tmpimg) == -1) {
+ img_destroy(&tmpimg);
+ return -1;
+ }
+ img = &tmpimg;
+ }
+
+ txt.compression = PNG_TEXT_COMPRESSION_NONE;
+ txt.key = "Software";
+ txt.text = "libimago2";
+ txt.text_length = 0;
+
+ if(setjmp(png_jmpbuf(png))) {
+ png_destroy_write_struct(&png, &info);
+ img_destroy(&tmpimg);
+ return -1;
+ }
+ png_set_write_fn(png, io, write_func, flush_func);
+
+ coltype = fmt_to_png_type(img->fmt);
+ png_set_IHDR(png, info, img->width, img->height, 8, coltype, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ png_set_text(png, info, &txt, 1);
+
+ if(!(rows = malloc(img->height * sizeof *rows))) {
+ png_destroy_write_struct(&png, &info);
+ img_destroy(&tmpimg);
+ return -1;
+ }
+
+ pixptr = img->pixels;
+ for(i=0; i<img->height; i++) {
+ rows[i] = pixptr;
+ pixptr += img->width * img->pixelsz;
+ }
+ png_set_rows(png, info, rows);
+
+ png_write_png(png, info, 0, 0);
+ png_write_end(png, info);
+ png_destroy_write_struct(&png, &info);
+
+ free(rows);
+
+ img_destroy(&tmpimg);
+ return 0;
+}
+
+static void read_func(png_struct *png, unsigned char *data, size_t len)
+{
+ struct img_io *io = (struct img_io*)png_get_io_ptr(png);
+
+ if(io->read(data, len, io->uptr) == -1) {
+ longjmp(png_jmpbuf(png), 1);
+ }
+}
+
+static void write_func(png_struct *png, unsigned char *data, size_t len)
+{
+ struct img_io *io = (struct img_io*)png_get_io_ptr(png);
+
+ if(io->write(data, len, io->uptr) == -1) {
+ longjmp(png_jmpbuf(png), 1);
+ }
+}
+
+static void flush_func(png_struct *png)
+{
+ /* XXX does it matter that we can't flush? */
+}
+
+static int png_type_to_fmt(int color_type, int channel_bits)
+{
+ /* only 8 and 16 bits per channel ar supported at the moment */
+ if(channel_bits != 8 && channel_bits != 16) {
+ return -1;
+ }
+
+ switch(color_type) {
+ case PNG_COLOR_TYPE_RGB:
+ return channel_bits == 16 ? IMG_FMT_RGBF : IMG_FMT_RGB24;
+
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ return channel_bits == 16 ? IMG_FMT_RGBAF : IMG_FMT_RGBA32;
+
+ case PNG_COLOR_TYPE_GRAY:
+ return channel_bits == 16 ? IMG_FMT_GREYF : IMG_FMT_GREY8;
+
+ default:
+ break;
+ }
+ return -1;
+}
+
+static int fmt_to_png_type(enum img_fmt fmt)
+{
+ switch(fmt) {
+ case IMG_FMT_GREY8:
+ return PNG_COLOR_TYPE_GRAY;
+
+ case IMG_FMT_RGB24:
+ return PNG_COLOR_TYPE_RGB;
+
+ case IMG_FMT_RGBA32:
+ return PNG_COLOR_TYPE_RGBA;
+
+ default:
+ break;
+ }
+ return -1;
+}
--- /dev/null
+/*
+libimago - a multi-format image file input/output library.
+Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published
+by the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* -- Portable Pixmap (PPM) module -- */
+
+#include <string.h>
+#include "imago2.h"
+#include "ftmodule.h"
+
+static int check(struct img_io *io);
+static int read(struct img_pixmap *img, struct img_io *io);
+static int write(struct img_pixmap *img, struct img_io *io);
+
+int img_register_ppm(void)
+{
+ static struct ftype_module mod = {".ppm", check, read, write};
+ return img_register_module(&mod);
+}
+
+
+static int check(struct img_io *io)
+{
+ char id[2];
+ int res = -1;
+ long pos = io->seek(0, SEEK_CUR, io->uptr);
+
+ if(io->read(id, 2, io->uptr) < 2) {
+ io->seek(pos, SEEK_SET, io->uptr);
+ return -1;
+ }
+
+ if(id[0] == 'P' && (id[1] == '6' || id[1] == '3')) {
+ res = 0;
+ }
+ io->seek(pos, SEEK_SET, io->uptr);
+ return res;
+}
+
+static int iofgetc(struct img_io *io)
+{
+ char c;
+ return io->read(&c, 1, io->uptr) < 1 ? -1 : c;
+}
+
+static char *iofgets(char *buf, int size, struct img_io *io)
+{
+ int c;
+ char *ptr = buf;
+
+ while(--size > 0 && (c = iofgetc(io)) != -1) {
+ *ptr++ = c;
+ if(c == '\n') break;
+ }
+ *ptr = 0;
+
+ return ptr == buf ? 0 : buf;
+}
+
+/* TODO: implement P3 reading */
+static int read(struct img_pixmap *img, struct img_io *io)
+{
+ char buf[256];
+ int xsz, ysz, maxval, got_hdrlines = 1;
+
+ if(!iofgets(buf, sizeof buf, io)) {
+ return -1;
+ }
+ if(!(buf[0] == 'P' && (buf[1] == '6' || buf[1] == '3'))) {
+ return -1;
+ }
+
+ while(got_hdrlines < 3 && iofgets(buf, sizeof buf, io)) {
+ if(buf[0] == '#') continue;
+
+ switch(got_hdrlines) {
+ case 1:
+ if(sscanf(buf, "%d %d\n", &xsz, &ysz) < 2) {
+ return -1;
+ }
+ break;
+
+ case 2:
+ if(sscanf(buf, "%d\n", &maxval) < 1) {
+ return -1;
+ }
+ default:
+ break;
+ }
+ got_hdrlines++;
+ }
+
+ if(xsz < 1 || ysz < 1 || maxval != 255) {
+ return -1;
+ }
+
+ if(img_set_pixels(img, xsz, ysz, IMG_FMT_RGB24, 0) == -1) {
+ return -1;
+ }
+
+ if(io->read(img->pixels, xsz * ysz * 3, io->uptr) < (unsigned int)(xsz * ysz * 3)) {
+ return -1;
+ }
+ return 0;
+}
+
+static int write(struct img_pixmap *img, struct img_io *io)
+{
+ int sz;
+ char buf[256];
+ struct img_pixmap tmpimg;
+
+ img_init(&tmpimg);
+
+ if(img->fmt != IMG_FMT_RGB24) {
+ if(img_copy(&tmpimg, img) == -1) {
+ return -1;
+ }
+ if(img_convert(&tmpimg, IMG_FMT_RGB24) == -1) {
+ return -1;
+ }
+ img = &tmpimg;
+ }
+
+ sprintf(buf, "P6\n#written by libimago2\n%d %d\n255\n", img->width, img->height);
+ if(io->write(buf, strlen(buf), io->uptr) < strlen(buf)) {
+ img_destroy(&tmpimg);
+ return -1;
+ }
+
+ sz = img->width * img->height * 3;
+ if(io->write(img->pixels, sz, io->uptr) < (unsigned int)sz) {
+ img_destroy(&tmpimg);
+ return -1;
+ }
+
+ img_destroy(&tmpimg);
+ return 0;
+}
--- /dev/null
+/* This file contains code to read and write four byte rgbe file format
+ * developed by Greg Ward. It handles the conversions between rgbe and
+ * pixels consisting of floats. The data is assumed to be an array of floats.
+ * By default there are three floats per pixel in the order red, green, blue.
+ * (RGBE_DATA_??? values control this.)
+ *
+ * written by Bruce Walter (bjw@graphics.cornell.edu) 5/26/95
+ * based on code written by Greg Ward
+ * minor modifications by John Tsiombikas (nuclear@member.fsf.org) apr.9 2007
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <errno.h>
+#include "imago2.h"
+#include "ftmodule.h"
+
+
+typedef struct {
+ int valid; /* indicate which fields are valid */
+ char programtype[16]; /* listed at beginning of file to identify it
+ * after "#?". defaults to "RGBE" */
+ float gamma; /* image has already been gamma corrected with
+ * given gamma. defaults to 1.0 (no correction) */
+ float exposure; /* a value of 1.0 in an image corresponds to
+ * <exposure> watts/steradian/m^2.
+ * defaults to 1.0 */
+} rgbe_header_info;
+
+
+static int check(struct img_io *io);
+static int read(struct img_pixmap *img, struct img_io *io);
+static int write(struct img_pixmap *img, struct img_io *io);
+
+static int rgbe_read_header(struct img_io *io, int *width, int *height, rgbe_header_info * info);
+static int rgbe_read_pixels_rle(struct img_io *io, float *data, int scanline_width, int num_scanlines);
+
+
+int img_register_rgbe(void)
+{
+ static struct ftype_module mod = {".rgbe", check, read, write};
+ return img_register_module(&mod);
+}
+
+
+static int check(struct img_io *io)
+{
+ int xsz, ysz, res;
+ long pos = io->seek(0, SEEK_CUR, io->uptr);
+
+ rgbe_header_info hdr;
+ res = rgbe_read_header(io, &xsz, &ysz, &hdr);
+
+ io->seek(pos, SEEK_SET, io->uptr);
+ return res;
+}
+
+static int read(struct img_pixmap *img, struct img_io *io)
+{
+ int xsz, ysz;
+ rgbe_header_info hdr;
+
+ if(rgbe_read_header(io, &xsz, &ysz, &hdr) == -1) {
+ return -1;
+ }
+
+ if(img_set_pixels(img, xsz, ysz, IMG_FMT_RGBF, 0) == -1) {
+ return -1;
+ }
+ if(rgbe_read_pixels_rle(io, img->pixels, xsz, ysz) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+static int write(struct img_pixmap *img, struct img_io *io)
+{
+ return -1; /* TODO */
+}
+
+
+static int iofgetc(struct img_io *io)
+{
+ char c;
+ return io->read(&c, 1, io->uptr) < 1 ? -1 : c;
+}
+
+static char *iofgets(char *buf, int size, struct img_io *io)
+{
+ int c;
+ char *ptr = buf;
+
+ while(--size > 0 && (c = iofgetc(io)) != -1) {
+ *ptr++ = c;
+ if(c == '\n') break;
+ }
+ *ptr = 0;
+
+ return ptr == buf ? 0 : buf;
+}
+
+
+/* flags indicating which fields in an rgbe_header_info are valid */
+#define RGBE_VALID_PROGRAMTYPE 0x01
+#define RGBE_VALID_GAMMA 0x02
+#define RGBE_VALID_EXPOSURE 0x04
+
+/* return codes for rgbe routines */
+#define RGBE_RETURN_SUCCESS 0
+#define RGBE_RETURN_FAILURE -1
+
+
+#if defined(__cplusplus) || defined(GNUC) || __STDC_VERSION >= 199901L
+#define INLINE inline
+#else
+#define INLINE
+#endif
+
+/* offsets to red, green, and blue components in a data (float) pixel */
+#define RGBE_DATA_RED 0
+#define RGBE_DATA_GREEN 1
+#define RGBE_DATA_BLUE 2
+
+/* number of floats per pixel */
+#define RGBE_DATA_SIZE 3
+
+enum rgbe_error_codes {
+ rgbe_read_error,
+ rgbe_write_error,
+ rgbe_format_error,
+ rgbe_memory_error
+};
+
+
+/* default error routine. change this to change error handling */
+static int rgbe_error(int rgbe_error_code, char *msg)
+{
+ switch (rgbe_error_code) {
+ case rgbe_read_error:
+ fprintf(stderr, "RGBE read error: %s\n", strerror(errno));
+ break;
+
+ case rgbe_write_error:
+ fprintf(stderr, "RGBE write error: %s\n", strerror(errno));
+ break;
+
+ case rgbe_format_error:
+ fprintf(stderr, "RGBE bad file format: %s\n", msg);
+ break;
+
+ default:
+ case rgbe_memory_error:
+ fprintf(stderr, "RGBE error: %s\n", msg);
+ }
+ return RGBE_RETURN_FAILURE;
+}
+
+/* standard conversion from float pixels to rgbe pixels */
+/*static INLINE void float2rgbe(unsigned char rgbe[4], float red, float green, float blue)
+{
+ float v;
+ int e;
+
+ v = red;
+ if(green > v)
+ v = green;
+ if(blue > v)
+ v = blue;
+ if(v < 1e-32) {
+ rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
+ } else {
+ v = frexp(v, &e) * 256.0 / v;
+ rgbe[0] = (unsigned char)(red * v);
+ rgbe[1] = (unsigned char)(green * v);
+ rgbe[2] = (unsigned char)(blue * v);
+ rgbe[3] = (unsigned char)(e + 128);
+ }
+}*/
+
+/* standard conversion from rgbe to float pixels */
+/* note: Ward uses ldexp(col+0.5,exp-(128+8)). However we wanted pixels */
+/* in the range [0,1] to map back into the range [0,1]. */
+static INLINE void rgbe2float(float *red, float *green, float *blue, unsigned char rgbe[4])
+{
+ float f;
+
+ if(rgbe[3]) { /*nonzero pixel */
+ f = ldexp(1.0, rgbe[3] - (int)(128 + 8));
+ *red = rgbe[0] * f;
+ *green = rgbe[1] * f;
+ *blue = rgbe[2] * f;
+ } else
+ *red = *green = *blue = 0.0;
+}
+
+#if 0
+/* default minimal header. modify if you want more information in header */
+static int rgbe_write_header(FILE * fp, int width, int height, rgbe_header_info * info)
+{
+ char *programtype = "RGBE";
+
+ if(info && (info->valid & RGBE_VALID_PROGRAMTYPE))
+ programtype = info->programtype;
+ if(fprintf(fp, "#?%s\n", programtype) < 0)
+ return rgbe_error(rgbe_write_error, NULL);
+ /* The #? is to identify file type, the programtype is optional. */
+ if(info && (info->valid & RGBE_VALID_GAMMA)) {
+ if(fprintf(fp, "GAMMA=%g\n", info->gamma) < 0)
+ return rgbe_error(rgbe_write_error, NULL);
+ }
+ if(info && (info->valid & RGBE_VALID_EXPOSURE)) {
+ if(fprintf(fp, "EXPOSURE=%g\n", info->exposure) < 0)
+ return rgbe_error(rgbe_write_error, NULL);
+ }
+ if(fprintf(fp, "FORMAT=32-bit_rle_rgbe\n\n") < 0)
+ return rgbe_error(rgbe_write_error, NULL);
+ if(fprintf(fp, "-Y %d +X %d\n", height, width) < 0)
+ return rgbe_error(rgbe_write_error, NULL);
+ return RGBE_RETURN_SUCCESS;
+}
+#endif
+
+/* minimal header reading. modify if you want to parse more information */
+static int rgbe_read_header(struct img_io *io, int *width, int *height, rgbe_header_info * info)
+{
+ char buf[128];
+ float tempf;
+ int i;
+
+ if(info) {
+ info->valid = 0;
+ info->programtype[0] = 0;
+ info->gamma = info->exposure = 1.0;
+ }
+ if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == NULL)
+ return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/
+ if((buf[0] != '#') || (buf[1] != '?')) {
+ /* if you want to require the magic token then uncomment the next line */
+ /*return rgbe_error(rgbe_format_error,"bad initial token"); */
+ } else if(info) {
+ info->valid |= RGBE_VALID_PROGRAMTYPE;
+ for(i = 0; i < sizeof(info->programtype) - 1; i++) {
+ if((buf[i + 2] == 0) || isspace(buf[i + 2]))
+ break;
+ info->programtype[i] = buf[i + 2];
+ }
+ info->programtype[i] = 0;
+ if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0)
+ return rgbe_error(rgbe_read_error, NULL);
+ }
+ for(;;) {
+ if((buf[0] == 0) || (buf[0] == '\n'))
+ return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_format_error, "no FORMAT specifier found");*/
+ else if(strcmp(buf, "FORMAT=32-bit_rle_rgbe\n") == 0)
+ break; /* format found so break out of loop */
+ else if(info && (sscanf(buf, "GAMMA=%g", &tempf) == 1)) {
+ info->gamma = tempf;
+ info->valid |= RGBE_VALID_GAMMA;
+ } else if(info && (sscanf(buf, "EXPOSURE=%g", &tempf) == 1)) {
+ info->exposure = tempf;
+ info->valid |= RGBE_VALID_EXPOSURE;
+ }
+ if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0)
+ return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/
+ }
+ if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0)
+ return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/
+ if(strcmp(buf, "\n") != 0)
+ return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_format_error, "missing blank line after FORMAT specifier");*/
+ if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0)
+ return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/
+ if(sscanf(buf, "-Y %d +X %d", height, width) < 2)
+ return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_format_error, "missing image size specifier");*/
+ return RGBE_RETURN_SUCCESS;
+}
+
+#if 0
+/* simple write routine that does not use run length encoding */
+
+/* These routines can be made faster by allocating a larger buffer and
+ fread-ing and fwrite-ing the data in larger chunks */
+static int rgbe_write_pixels(FILE * fp, float *data, int numpixels)
+{
+ unsigned char rgbe[4];
+
+ while(numpixels-- > 0) {
+ float2rgbe(rgbe, data[RGBE_DATA_RED], data[RGBE_DATA_GREEN], data[RGBE_DATA_BLUE]);
+ data += RGBE_DATA_SIZE;
+ if(fwrite(rgbe, sizeof(rgbe), 1, fp) < 1)
+ return rgbe_error(rgbe_write_error, NULL);
+ }
+ return RGBE_RETURN_SUCCESS;
+}
+#endif
+
+/* simple read routine. will not correctly handle run length encoding */
+static int rgbe_read_pixels(struct img_io *io, float *data, int numpixels)
+{
+ unsigned char rgbe[4];
+
+ while(numpixels-- > 0) {
+ if(io->read(rgbe, sizeof(rgbe), io->uptr) < 1)
+ return rgbe_error(rgbe_read_error, NULL);
+ rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe);
+ data += RGBE_DATA_SIZE;
+ }
+ return RGBE_RETURN_SUCCESS;
+}
+
+#if 0
+/* The code below is only needed for the run-length encoded files. */
+
+/* Run length encoding adds considerable complexity but does */
+
+/* save some space. For each scanline, each channel (r,g,b,e) is */
+
+/* encoded separately for better compression. */
+
+static int rgbe_write_bytes_rle(struct img_io *io, unsigned char *data, int numbytes)
+{
+#define MINRUNLENGTH 4
+ int cur, beg_run, run_count, old_run_count, nonrun_count;
+ unsigned char buf[2];
+
+ cur = 0;
+ while(cur < numbytes) {
+ beg_run = cur;
+ /* find next run of length at least 4 if one exists */
+ run_count = old_run_count = 0;
+ while((run_count < MINRUNLENGTH) && (beg_run < numbytes)) {
+ beg_run += run_count;
+ old_run_count = run_count;
+ run_count = 1;
+ while((beg_run + run_count < numbytes) && (run_count < 127)
+ && (data[beg_run] == data[beg_run + run_count]))
+ run_count++;
+ }
+ /* if data before next big run is a short run then write it as such */
+ if((old_run_count > 1) && (old_run_count == beg_run - cur)) {
+ buf[0] = 128 + old_run_count; /*write short run */
+ buf[1] = data[cur];
+ if(fwrite(buf, sizeof(buf[0]) * 2, 1, fp) < 1)
+ return rgbe_error(rgbe_write_error, NULL);
+ cur = beg_run;
+ }
+ /* write out bytes until we reach the start of the next run */
+ while(cur < beg_run) {
+ nonrun_count = beg_run - cur;
+ if(nonrun_count > 128)
+ nonrun_count = 128;
+ buf[0] = nonrun_count;
+ if(fwrite(buf, sizeof(buf[0]), 1, fp) < 1)
+ return rgbe_error(rgbe_write_error, NULL);
+ if(fwrite(&data[cur], sizeof(data[0]) * nonrun_count, 1, fp) < 1)
+ return rgbe_error(rgbe_write_error, NULL);
+ cur += nonrun_count;
+ }
+ /* write out next run if one was found */
+ if(run_count >= MINRUNLENGTH) {
+ buf[0] = 128 + run_count;
+ buf[1] = data[beg_run];
+ if(fwrite(buf, sizeof(buf[0]) * 2, 1, fp) < 1)
+ return rgbe_error(rgbe_write_error, NULL);
+ cur += run_count;
+ }
+ }
+ return RGBE_RETURN_SUCCESS;
+#undef MINRUNLENGTH
+}
+
+static int rgbe_write_pixels_rle(struct img_io *io, float *data, int scanline_width, int num_scanlines)
+{
+ unsigned char rgbe[4];
+ unsigned char *buffer;
+ int i, err;
+
+ if((scanline_width < 8) || (scanline_width > 0x7fff))
+ /* run length encoding is not allowed so write flat */
+ return rgbe_write_pixels(io, data, scanline_width * num_scanlines);
+ buffer = (unsigned char *)malloc(sizeof(unsigned char) * 4 * scanline_width);
+ if(buffer == NULL)
+ /* no buffer space so write flat */
+ return rgbe_write_pixels(fp, data, scanline_width * num_scanlines);
+ while(num_scanlines-- > 0) {
+ rgbe[0] = 2;
+ rgbe[1] = 2;
+ rgbe[2] = scanline_width >> 8;
+ rgbe[3] = scanline_width & 0xFF;
+ if(fwrite(rgbe, sizeof(rgbe), 1, fp) < 1) {
+ free(buffer);
+ return rgbe_error(rgbe_write_error, NULL);
+ }
+ for(i = 0; i < scanline_width; i++) {
+ float2rgbe(rgbe, data[RGBE_DATA_RED], data[RGBE_DATA_GREEN], data[RGBE_DATA_BLUE]);
+ buffer[i] = rgbe[0];
+ buffer[i + scanline_width] = rgbe[1];
+ buffer[i + 2 * scanline_width] = rgbe[2];
+ buffer[i + 3 * scanline_width] = rgbe[3];
+ data += RGBE_DATA_SIZE;
+ }
+ /* write out each of the four channels separately run length encoded */
+ /* first red, then green, then blue, then exponent */
+ for(i = 0; i < 4; i++) {
+ if((err = rgbe_write_bytes_rle(fp, &buffer[i * scanline_width],
+ scanline_width)) != RGBE_RETURN_SUCCESS) {
+ free(buffer);
+ return err;
+ }
+ }
+ }
+ free(buffer);
+ return RGBE_RETURN_SUCCESS;
+}
+#endif
+
+static int rgbe_read_pixels_rle(struct img_io *io, float *data, int scanline_width, int num_scanlines)
+{
+ unsigned char rgbe[4], *scanline_buffer, *ptr, *ptr_end;
+ int i, count;
+ unsigned char buf[2];
+
+ if((scanline_width < 8) || (scanline_width > 0x7fff))
+ /* run length encoding is not allowed so read flat */
+ return rgbe_read_pixels(io, data, scanline_width * num_scanlines);
+ scanline_buffer = NULL;
+ /* read in each successive scanline */
+ while(num_scanlines > 0) {
+ if(io->read(rgbe, sizeof(rgbe), io->uptr) < 1) {
+ free(scanline_buffer);
+ return rgbe_error(rgbe_read_error, NULL);
+ }
+ if((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80)) {
+ /* this file is not run length encoded */
+ rgbe2float(&data[0], &data[1], &data[2], rgbe);
+ data += RGBE_DATA_SIZE;
+ free(scanline_buffer);
+ return rgbe_read_pixels(io, data, scanline_width * num_scanlines - 1);
+ }
+ if((((int)rgbe[2]) << 8 | rgbe[3]) != scanline_width) {
+ free(scanline_buffer);
+ return rgbe_error(rgbe_format_error, "wrong scanline width");
+ }
+ if(scanline_buffer == NULL)
+ scanline_buffer = (unsigned char *)
+ malloc(sizeof(unsigned char) * 4 * scanline_width);
+ if(scanline_buffer == NULL)
+ return rgbe_error(rgbe_memory_error, "unable to allocate buffer space");
+
+ ptr = &scanline_buffer[0];
+ /* read each of the four channels for the scanline into the buffer */
+ for(i = 0; i < 4; i++) {
+ ptr_end = &scanline_buffer[(i + 1) * scanline_width];
+ while(ptr < ptr_end) {
+ if(io->read(buf, sizeof(buf[0]) * 2, io->uptr) < 1) {
+ free(scanline_buffer);
+ return rgbe_error(rgbe_read_error, NULL);
+ }
+ if(buf[0] > 128) {
+ /* a run of the same value */
+ count = buf[0] - 128;
+ if((count == 0) || (count > ptr_end - ptr)) {
+ free(scanline_buffer);
+ return rgbe_error(rgbe_format_error, "bad scanline data");
+ }
+ while(count-- > 0)
+ *ptr++ = buf[1];
+ } else {
+ /* a non-run */
+ count = buf[0];
+ if((count == 0) || (count > ptr_end - ptr)) {
+ free(scanline_buffer);
+ return rgbe_error(rgbe_format_error, "bad scanline data");
+ }
+ *ptr++ = buf[1];
+ if(--count > 0) {
+ if(io->read(ptr, sizeof(*ptr) * count, io->uptr) < 1) {
+ free(scanline_buffer);
+ return rgbe_error(rgbe_read_error, NULL);
+ }
+ ptr += count;
+ }
+ }
+ }
+ }
+ /* now convert data from buffer into floats */
+ for(i = 0; i < scanline_width; i++) {
+ rgbe[0] = scanline_buffer[i];
+ rgbe[1] = scanline_buffer[i + scanline_width];
+ rgbe[2] = scanline_buffer[i + 2 * scanline_width];
+ rgbe[3] = scanline_buffer[i + 3 * scanline_width];
+ rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe);
+ data += RGBE_DATA_SIZE;
+ }
+ num_scanlines--;
+ }
+ free(scanline_buffer);
+ return RGBE_RETURN_SUCCESS;
+}
--- /dev/null
+/*
+libimago - a multi-format image file input/output library.
+Copyright (C) 2010-2015 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published
+by the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* -- Targa (tga) module -- */
+
+#include <string.h>
+#include <stdlib.h>
+#include "inttypes.h"
+#include "imago2.h"
+#include "ftmodule.h"
+
+
+#if defined(__i386__) || defined(__ia64__) || defined(WIN32) || \
+ (defined(__alpha__) || defined(__alpha)) || \
+ defined(__arm__) || \
+ (defined(__mips__) && defined(__MIPSEL__)) || \
+ defined(__SYMBIAN32__) || \
+ defined(__x86_64__) || \
+ defined(__LITTLE_ENDIAN__)
+/* little endian */
+#define read_int16_le(f) read_int16(f)
+#else
+/* big endian */
+#define read_int16_le(f) read_int16_inv(f)
+#endif /* endian check */
+
+
+enum {
+ IMG_NONE,
+ IMG_CMAP,
+ IMG_RGBA,
+ IMG_BW,
+
+ IMG_RLE_CMAP = 9,
+ IMG_RLE_RGBA,
+ IMG_RLE_BW
+};
+
+#define IS_RLE(x) ((x) >= IMG_RLE_CMAP)
+#define IS_RGBA(x) ((x) == IMG_RGBA || (x) == IMG_RLE_RGBA)
+
+
+struct tga_header {
+ uint8_t idlen; /* id field length */
+ uint8_t cmap_type; /* color map type (0:no color map, 1:color map present) */
+ uint8_t img_type; /* image type:
+ * 0: no image data
+ * 1: uncomp. color-mapped 9: RLE color-mapped
+ * 2: uncomp. true color 10: RLE true color
+ * 3: uncomp. black/white 11: RLE black/white */
+ uint16_t cmap_first; /* color map first entry index */
+ uint16_t cmap_len; /* color map length */
+ uint8_t cmap_entry_sz; /* color map entry size */
+ uint16_t img_x; /* X-origin of the image */
+ uint16_t img_y; /* Y-origin of the image */
+ uint16_t img_width; /* image width */
+ uint16_t img_height; /* image height */
+ uint8_t img_bpp; /* bits per pixel */
+ uint8_t img_desc; /* descriptor:
+ * bits 0 - 3: alpha or overlay bits
+ * bits 5 & 4: origin (0 = bottom/left, 1 = top/right)
+ * bits 7 & 6: data interleaving */
+};
+
+struct tga_footer {
+ uint32_t ext_off; /* extension area offset */
+ uint32_t devdir_off; /* developer directory offset */
+ char sig[18]; /* signature with . and \0 */
+};
+
+
+static int check(struct img_io *io);
+static int read(struct img_pixmap *img, struct img_io *io);
+static int write(struct img_pixmap *img, struct img_io *io);
+static int read_pixel(struct img_io *io, int rdalpha, uint32_t *pix);
+static int16_t read_int16(struct img_io *io);
+static int16_t read_int16_inv(struct img_io *io);
+
+int img_register_tga(void)
+{
+ static struct ftype_module mod = {".tga", check, read, write};
+ return img_register_module(&mod);
+}
+
+
+static int check(struct img_io *io)
+{
+ struct tga_footer foot;
+ int res = -1;
+ long pos = io->seek(0, SEEK_CUR, io->uptr);
+ io->seek(-18, SEEK_END, io->uptr);
+
+ if(io->read(foot.sig, 17, io->uptr) < 17) {
+ io->seek(pos, SEEK_SET, io->uptr);
+ return -1;
+ }
+
+ if(memcmp(foot.sig, "TRUEVISION-XFILE.", 17) == 0) {
+ res = 0;
+ }
+ io->seek(pos, SEEK_SET, io->uptr);
+ return res;
+}
+
+static int iofgetc(struct img_io *io)
+{
+ char c;
+ return io->read(&c, 1, io->uptr) < 1 ? -1 : c;
+}
+
+static int read(struct img_pixmap *img, struct img_io *io)
+{
+ struct tga_header hdr;
+ int x, y;
+ int i, c;
+ uint32_t ppixel = 0;
+ int rle_mode = 0, rle_pix_left = 0;
+ int rdalpha;
+
+ /* read header */
+ hdr.idlen = iofgetc(io);
+ hdr.cmap_type = iofgetc(io);
+ hdr.img_type = iofgetc(io);
+ hdr.cmap_first = read_int16_le(io);
+ hdr.cmap_len = read_int16_le(io);
+ hdr.cmap_entry_sz = iofgetc(io);
+ hdr.img_x = read_int16_le(io);
+ hdr.img_y = read_int16_le(io);
+ hdr.img_width = read_int16_le(io);
+ hdr.img_height = read_int16_le(io);
+ hdr.img_bpp = iofgetc(io);
+ if((c = iofgetc(io)) == -1) {
+ return -1;
+ }
+ hdr.img_desc = c;
+
+ if(!IS_RGBA(hdr.img_type)) {
+ fprintf(stderr, "only true color tga images supported\n");
+ return -1;
+ }
+
+ io->seek(hdr.idlen, SEEK_CUR, io); /* skip the image ID */
+
+ /* skip the color map if it exists */
+ if(hdr.cmap_type == 1) {
+ io->seek(hdr.cmap_len * hdr.cmap_entry_sz / 8, SEEK_CUR, io);
+ }
+
+ x = hdr.img_width;
+ y = hdr.img_height;
+ rdalpha = hdr.img_desc & 0xf;
+
+ /* TODO make this IMG_FMT_RGB24 if there's no alpha channel */
+ if(img_set_pixels(img, x, y, IMG_FMT_RGBA32, 0) == -1) {
+ return -1;
+ }
+
+ for(i=0; i<y; i++) {
+ uint32_t *ptr;
+ int j;
+
+ ptr = (uint32_t*)img->pixels + ((hdr.img_desc & 0x20) ? i : y - (i + 1)) * x;
+
+ for(j=0; j<x; j++) {
+ /* if the image is raw, then just read the next pixel */
+ if(!IS_RLE(hdr.img_type)) {
+ if(read_pixel(io, rdalpha, &ppixel) == -1) {
+ return -1;
+ }
+ } else {
+ /* otherwise, for RLE... */
+
+ /* if we have pixels left in the packet ... */
+ if(rle_pix_left) {
+ /* if it's a raw packet, read the next pixel, otherwise keep the same */
+ if(!rle_mode) {
+ if(read_pixel(io, rdalpha, &ppixel) == -1) {
+ return -1;
+ }
+ }
+ --rle_pix_left;
+ } else {
+ /* read RLE packet header */
+ unsigned char phdr = iofgetc(io);
+ rle_mode = (phdr & 128); /* last bit shows the mode for this packet (1: rle, 0: raw) */
+ rle_pix_left = (phdr & ~128); /* the rest gives the count of pixels minus one (we also read one here, so no +1) */
+ /* and read the first pixel of the packet */
+ if(read_pixel(io, rdalpha, &ppixel) == -1) {
+ return -1;
+ }
+ }
+ }
+
+ *ptr++ = ppixel;
+ }
+ }
+
+ return 0;
+}
+
+static int write(struct img_pixmap *img, struct img_io *io)
+{
+ return -1; /* TODO */
+}
+
+#define PACK_COLOR32(r,g,b,a) \
+ ((((a) & 0xff) << 24) | \
+ (((r) & 0xff) << 0) | \
+ (((g) & 0xff) << 8) | \
+ (((b) & 0xff) << 16))
+
+static int read_pixel(struct img_io *io, int rdalpha, uint32_t *pix)
+{
+ int r, g, b, a;
+ b = iofgetc(io);
+ g = iofgetc(io);
+ r = iofgetc(io);
+ a = rdalpha ? iofgetc(io) : 0xff;
+ *pix = PACK_COLOR32(r, g, b, a);
+ return a == -1 || r == -1 ? -1 : 0;
+}
+
+static int16_t read_int16(struct img_io *io)
+{
+ int16_t v;
+ io->read(&v, 2, io);
+ return v;
+}
+
+static int16_t read_int16_inv(struct img_io *io)
+{
+ int16_t v;
+ io->read(&v, 2, io);
+ return ((v >> 8) & 0xff) | (v << 8);
+}
--- /dev/null
+/*
+libimago - a multi-format image file input/output library.
+Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published
+by the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "ftmodule.h"
+
+static struct list_node {
+ struct ftype_module *module;
+ struct list_node *next;
+} *modules;
+
+/* defined in modules.c which is generated by configure */
+void img_modules_init();
+
+static int done_init;
+
+int img_register_module(struct ftype_module *mod)
+{
+ struct list_node *node;
+
+ if(!(node = malloc(sizeof *node))) {
+ return -1;
+ }
+
+ node->module = mod;
+ node->next = modules;
+ modules = node;
+ return 0;
+}
+
+struct ftype_module *img_find_format_module(struct img_io *io)
+{
+ struct list_node *node;
+
+ if(!done_init) {
+ img_modules_init();
+ done_init = 1;
+ }
+
+ node = modules;
+ while(node) {
+ if(node->module->check(io) != -1) {
+ return node->module;
+ }
+ node = node->next;
+ }
+ return 0;
+}
+
+struct ftype_module *img_guess_format(const char *fname)
+{
+ struct list_node *node;
+ char *suffix;
+ int suffix_len;
+
+ if(!done_init) {
+ img_modules_init();
+ done_init = 1;
+ }
+
+ if(!(suffix = strrchr(fname, '.'))) {
+ return 0; /* no suffix, can't guess ... */
+ }
+ suffix_len = (int)strlen(suffix);
+
+ node = modules;
+ while(node) {
+ char *suflist = node->module->suffix;
+ char *start, *end;
+
+ while(*suflist) {
+ if(!(start = strstr(suflist, suffix))) {
+ break;
+ }
+ end = start + suffix_len;
+
+ if(*end == ':' || *end == 0) {
+ return node->module; /* found it */
+ }
+ suflist = end;
+ }
+
+ node = node->next;
+ }
+ return 0;
+}
+
+struct ftype_module *img_get_module(int idx)
+{
+ struct list_node *node;
+
+ if(!done_init) {
+ img_modules_init();
+ done_init = 1;
+ }
+
+ node = modules;
+ while(node && idx--) {
+ node = node->next;
+ }
+ return node->module;
+}
--- /dev/null
+/*
+libimago - a multi-format image file input/output library.
+Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published
+by the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef FTYPE_MODULE_H_
+#define FTYPE_MODULE_H_
+
+#include "imago2.h"
+
+struct ftype_module {
+ char *suffix; /* used for format autodetection during saving only */
+
+ int (*check)(struct img_io *io);
+ int (*read)(struct img_pixmap *img, struct img_io *io);
+ int (*write)(struct img_pixmap *img, struct img_io *io);
+};
+
+int img_register_module(struct ftype_module *mod);
+
+struct ftype_module *img_find_format_module(struct img_io *io);
+struct ftype_module *img_guess_format(const char *fname);
+struct ftype_module *img_get_module(int idx);
+
+
+#endif /* FTYPE_MODULE_H_ */
+++ /dev/null
-/*
-libimago - a multi-format image file input/output library.
-Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published
-by the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include "ftype_module.h"
-
-static struct list_node {
- struct ftype_module *module;
- struct list_node *next;
-} *modules;
-
-/* defined in modules.c which is generated by configure */
-void img_modules_init();
-
-static int done_init;
-
-int img_register_module(struct ftype_module *mod)
-{
- struct list_node *node;
-
- if(!(node = malloc(sizeof *node))) {
- return -1;
- }
-
- node->module = mod;
- node->next = modules;
- modules = node;
- return 0;
-}
-
-struct ftype_module *img_find_format_module(struct img_io *io)
-{
- struct list_node *node;
-
- if(!done_init) {
- img_modules_init();
- done_init = 1;
- }
-
- node = modules;
- while(node) {
- if(node->module->check(io) != -1) {
- return node->module;
- }
- node = node->next;
- }
- return 0;
-}
-
-struct ftype_module *img_guess_format(const char *fname)
-{
- struct list_node *node;
- char *suffix;
- int suffix_len;
-
- if(!done_init) {
- img_modules_init();
- done_init = 1;
- }
-
- if(!(suffix = strrchr(fname, '.'))) {
- return 0; /* no suffix, can't guess ... */
- }
- suffix_len = (int)strlen(suffix);
-
- node = modules;
- while(node) {
- char *suflist = node->module->suffix;
- char *start, *end;
-
- while(*suflist) {
- if(!(start = strstr(suflist, suffix))) {
- break;
- }
- end = start + suffix_len;
-
- if(*end == ':' || *end == 0) {
- return node->module; /* found it */
- }
- suflist = end;
- }
-
- node = node->next;
- }
- return 0;
-}
-
-struct ftype_module *img_get_module(int idx)
-{
- struct list_node *node;
-
- if(!done_init) {
- img_modules_init();
- done_init = 1;
- }
-
- node = modules;
- while(node && idx--) {
- node = node->next;
- }
- return node->module;
-}
+++ /dev/null
-/*
-libimago - a multi-format image file input/output library.
-Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published
-by the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef FTYPE_MODULE_H_
-#define FTYPE_MODULE_H_
-
-#include "imago2.h"
-
-struct ftype_module {
- char *suffix; /* used for format autodetection during saving only */
-
- int (*check)(struct img_io *io);
- int (*read)(struct img_pixmap *img, struct img_io *io);
- int (*write)(struct img_pixmap *img, struct img_io *io);
-};
-
-int img_register_module(struct ftype_module *mod);
-
-struct ftype_module *img_find_format_module(struct img_io *io);
-struct ftype_module *img_guess_format(const char *fname);
-struct ftype_module *img_get_module(int idx);
-
-
-#endif /* FTYPE_MODULE_H_ */
#include <stdlib.h>
#include <string.h>
#include "imago2.h"
-#include "ftype_module.h"
+#include "ftmodule.h"
static int pixel_size(enum img_fmt fmt);
static size_t def_read(void *buf, size_t bytes, void *uptr);
--- /dev/null
+/*
+colcycle - color cycling image viewer
+Copyright (C) 2016 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef INT_TYPES_H_
+#define INT_TYPES_H_
+
+#if defined(__DOS__) || defined(WIN32)
+typedef char int8_t;
+typedef short int16_t;
+typedef long int32_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+
+typedef unsigned long intptr_t;
+#else
+#include <stdint.h>
+#endif
+
+#endif /* INT_TYPES_H_ */
--- /dev/null
+cd libs\imago
+wmake %1 %2 %3 %4 %5 %6 %7 %8
+cd ..\..
*/
int kb_getkey(void);
+void kb_putback(int key);
+
#ifdef __cplusplus
}
#endif
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <math.h>
#include <assert.h>
#include "imago2.h"