Files
Cesarus85--mjolnir-vr/source/bitmaps/tiff_file.c
T

453 lines
11 KiB
C

/*
TIFF_FILE.C
symbols in this file:
0006DBE0 0070:
_tiff_get_bounds (0000)
0006DC50 0420:
_tiff_export (0000)
0006E070 0540:
_tiff_import (0000)
00255454 0002:
??_C@_01KDCPPGHE@r?$AA@ (0000)
00255458 0014:
??_C@_0BE@FPJPBLAF@failed?5to?5open?5tiff?$AA@ (0000)
0025546C 000e:
??_C@_0O@BNNCBLEN@out?5of?5memory?$AA@ (0000)
0025547C 0019:
??_C@_0BJ@EDBMJEAG@failed?5to?5write?5scanline?$AA@ (0000)
00255498 0029:
??_C@_0CJ@CNFFKPJI@invalid?5bitmap?5encoding?5for?5tiff@ (0000)
002554C4 0023:
??_C@_0CD@MEPHMAHO@c?3?2halo?2SOURCE?2bitmaps?2tiff_file@ (0000)
002554E8 0002:
??_C@_01NOFIACDB@w?$AA@ (0000)
002554EC 0014:
??_C@_0BE@DABJOKOK@file?5does?5not?5exist?$AA@ (0000)
00255500 0010:
??_C@_0BA@GNLHBLFA@not?5a?5TIFF?5file?$AA@ (0000)
00255510 0030:
??_C@_0DA@NCFNHNBH@unsupported?5TIFF?5orientation?5?$CImu@ (0000)
00255540 0036:
??_C@_0DG@CEDAGLPJ@unsupported?5bits?5per?5sample?5?$CI?$CFd?$CJ@ (0000)
00255578 0033:
??_C@_0DD@OCPJGOKH@unsupported?5TIFF?5photometric?0?5pl@ (0000)
002555AC 000f:
??_C@_0P@HCMCPNNJ@TIFF?5too?5large?$AA@ (0000)
002555BC 001e:
??_C@_0BO@DJPDCIEM@failed?5to?5read?5TIFF?5scan?5line?$AA@ (0000)
002555DC 0013:
??_C@_0BD@NKJFFLKL@unsupported?5format?$AA@ (0000)
0031C320 0200:
_bss_0031c320 (0000)
*/
/* ---------- headers */
#include "cseries.h"
#include "bitmaps/bitmap_group.h"
#include "bitmaps/libtiff/tiffio.h"
#include "math/integer_math.h"
#include "tag_files/files.h"
/* ---------- constants */
enum
{
_bitmap_format_a8 = 0,
_bitmap_format_y8 = 1,
_bitmap_format_ay8 = 2,
_bitmap_format_r5g6b5 = 6,
_bitmap_format_a1r5g5b5 = 8,
_bitmap_format_a4r4g4b4 = 9,
_bitmap_format_x8r8g8b8 = 10,
_bitmap_format_a8r8g8b8 = 11,
};
/* ---------- macros */
/* ---------- structures */
/* ---------- prototypes */
short bitmap_format_get_bits_per_pixel(short format);
void *bitmap_2d_address(
struct bitmap_data *bitmap,
short x,
short y,
short mipmap_index);
struct bitmap_data *bitmap_2d_new(short width, short height, short mipmap_count, short format);
void bitmap_delete(struct bitmap_data *bitmap);
/* ---------- globals */
char bss_0031c320[512];
/* ---------- public code */
boolean
tiff_get_bounds(
struct file_reference *file,
unsigned long *width,
unsigned long *height)
{
char path[256];
TIFF *tiff;
boolean result = FALSE;
tiff = TIFFOpen(
file_reference_get_name(file, 0xD, path),
"r");
if (tiff)
{
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, width);
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, height);
TIFFClose(tiff);
result = TRUE;
}
return result;
}
char const *
tiff_export(
struct file_reference *file,
struct bitmap_data *bitmap)
{
char const *error_message = NULL;
long tiff_format;
long photometric;
long samples_per_pixel;
char path[256];
TIFF *tiff;
long row_size;
byte *row_buffer;
long y;
switch (bitmap->format)
{
case _bitmap_format_a8:
case _bitmap_format_y8:
case _bitmap_format_ay8:
tiff_format = _bitmap_format_a8;
photometric = PHOTOMETRIC_MINISBLACK;
samples_per_pixel = 1;
break;
case _bitmap_format_r5g6b5:
case _bitmap_format_a1r5g5b5:
case _bitmap_format_a4r4g4b4:
case _bitmap_format_x8r8g8b8:
case _bitmap_format_a8r8g8b8:
tiff_format = _bitmap_format_a8r8g8b8;
photometric = PHOTOMETRIC_RGB;
samples_per_pixel = 4;
break;
default:
return "invalid bitmap encoding for tiff export.";
}
tiff = TIFFOpen(
file_reference_get_name(file, 0xD, path),
"w");
if (!tiff)
return "failed to open tiff";
{
long row_bits = bitmap_format_get_bits_per_pixel((short)tiff_format) * bitmap->width;
row_size = (short)((row_bits + ((row_bits >> 31) & 7)) >> 3);
}
row_buffer = debug_malloc(row_size, FALSE, "c:\\halo\\SOURCE\\bitmaps\\tiff_file.c", 107);
if (!row_buffer)
{
TIFFClose(tiff);
return "out of memory";
}
TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, bitmap->width);
TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, bitmap->height);
TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric);
TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel);
TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tiff, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
for (y = 0; y < bitmap->height; y++)
{
byte *source_row = bitmap_2d_address(bitmap, 0, (short)y, 0);
long x;
switch (bitmap->format)
{
case _bitmap_format_r5g6b5:
for (x = 0; x < bitmap->width; x++)
{
word pixel = ((word *)source_row)[x];
byte high = (byte)(pixel >> 8);
row_buffer[x * 4 + 2] = ((byte)(pixel >> 2) & 7) | (byte)(pixel << 3);
row_buffer[x * 4 + 1] = ((high >> 1) & 3) | ((byte)(pixel >> 5) << 2);
row_buffer[x * 4] = (high & 0xF8) | (high >> 5);
row_buffer[x * 4 + 3] = 0xFF;
}
break;
case _bitmap_format_a1r5g5b5:
for (x = 0; x < bitmap->width; x++)
{
word pixel = ((word *)source_row)[x];
byte middle = (byte)(pixel >> 5);
row_buffer[x * 4 + 2] = (((byte)pixel & 0x1F) | ((byte)pixel << 1)) << 2;
row_buffer[x * 4 + 1] = ((middle & 0x1F) | (middle << 1)) << 2;
row_buffer[x * 4] = (((byte)(pixel >> 7) & 0xFB) | (byte)(pixel >> 8)) & 0xFC;
row_buffer[x * 4 + 3] = 0xFF;
}
break;
case _bitmap_format_a4r4g4b4:
for (x = 0; x < bitmap->width; x++)
{
word pixel = ((word *)source_row)[x];
byte high = (byte)(pixel >> 8);
byte middle = (byte)(pixel >> 4);
row_buffer[x * 4 + 3] = (high >> 4) | ((high >> 4) << 4);
row_buffer[x * 4 + 2] = ((byte)pixel & 0xF) | ((byte)pixel << 4);
row_buffer[x * 4 + 1] = (middle & 0xF) | (middle << 4);
row_buffer[x * 4] = (high & 0xF) | (high << 4);
}
break;
case _bitmap_format_x8r8g8b8:
for (x = 0; x < bitmap->width; x++)
{
unsigned long pixel = ((unsigned long *)source_row)[x];
row_buffer[x * 4 + 2] = (byte)pixel;
row_buffer[x * 4 + 1] = (byte)(pixel >> 8);
row_buffer[x * 4] = (byte)(pixel >> 16);
row_buffer[x * 4 + 3] = 0xFF;
}
break;
case _bitmap_format_a8r8g8b8:
for (x = 0; x < bitmap->width; x++)
{
unsigned long pixel = ((unsigned long *)source_row)[x];
row_buffer[x * 4 + 3] = (byte)(pixel >> 24);
row_buffer[x * 4 + 2] = (byte)pixel;
row_buffer[x * 4 + 1] = (byte)(pixel >> 8);
row_buffer[x * 4] = (byte)(pixel >> 16);
}
break;
default:
csmemcpy(row_buffer, source_row, row_size);
break;
}
if (TIFFWriteScanline(tiff, row_buffer, y, 0) < 0)
{
error_message = "failed to write scanline";
break;
}
}
debug_free(row_buffer, "c:\\halo\\SOURCE\\bitmaps\\tiff_file.c", 231);
TIFFClose(tiff);
return error_message;
}
char const *
tiff_import(
struct file_reference *file,
struct bitmap_data **bitmap_result,
rectangle2d const *requested_bounds,
short format)
{
char const *error_message = NULL;
char path[256];
TIFF *tiff;
long scanline_size;
word bits_per_sample;
word orientation;
word samples_per_pixel;
word planar_config;
word photometric;
unsigned long image_width;
unsigned long image_height;
rectangle2d bounds;
short width;
short height;
struct bitmap_data *bitmap;
byte *scanline;
long y;
if (!file_exists(file))
return "file does not exist";
tiff = TIFFOpen(file_reference_get_name(file, 0xD, path), "r");
if (!tiff)
return "not a TIFF file";
scanline_size = TIFFScanlineSize(tiff);
TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
TIFFGetFieldDefaulted(tiff, TIFFTAG_ORIENTATION, &orientation);
TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
TIFFGetField(tiff, TIFFTAG_PLANARCONFIG, &planar_config);
TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &image_width);
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &image_height);
if (requested_bounds)
bounds = *requested_bounds;
else
{
bounds.y0 = 0;
bounds.x0 = 0;
bounds.y1 = (short)image_height;
bounds.x1 = (short)image_width;
}
if (orientation != ORIENTATION_TOPLEFT)
{
TIFFClose(tiff);
return "unsupported TIFF orientation (must be top left)";
}
if (bits_per_sample != 8 ||
(samples_per_pixel != 1 && samples_per_pixel != 2 &&
samples_per_pixel != 3 && samples_per_pixel != 4))
{
snprintf(
bss_0031c320,
NUMBEROF(bss_0031c320),
"unsupported bits per sample (%d) or sample count (%d)",
bits_per_sample,
samples_per_pixel);
TIFFClose(tiff);
return bss_0031c320;
}
if (format != NONE && format != _bitmap_format_a8r8g8b8)
{
TIFFClose(tiff);
return "unsupported format";
}
if (planar_config != PLANARCONFIG_CONTIG)
{
TIFFClose(tiff);
return "unsupported TIFF photometric, planar configuration";
}
width = rectangle2d_width(&bounds);
height = rectangle2d_height(&bounds);
if (width < 0 || width > 30000 || height < 0 || height > 30000)
{
TIFFClose(tiff);
return "TIFF too large";
}
bitmap = bitmap_2d_new(width, height, 0, _bitmap_format_a8r8g8b8);
scanline = debug_malloc(
scanline_size,
FALSE,
"c:\\halo\\SOURCE\\bitmaps\\tiff_file.c",
319);
if (!bitmap || !scanline)
{
error_message = "out of memory";
goto cleanup;
}
*bitmap_result = bitmap;
for (y = bounds.y0; y < bounds.y1; y++)
{
long source_y;
long x;
if (y < 0)
source_y = 0;
else if (y > image_height - 1)
source_y = image_height - 1;
else
source_y = y;
if (TIFFReadScanline(tiff, scanline, source_y, 0) < 0)
{
error_message = "failed to read TIFF scan line";
goto cleanup;
}
switch (samples_per_pixel)
{
case 1:
{
unsigned long *destination = bitmap_2d_address(bitmap, 0, (short)(y - bounds.y0), 0);
for (x = bounds.x0; x < bounds.x1; x++)
{
long source_x = x < 0 ? 0 : (x > image_width - 1 ? image_width - 1 : x);
byte value = scanline[source_x];
destination[x - bounds.x0] =
(value << 24) | (value << 16) | (value << 8) | value;
}
}
break;
case 2:
{
unsigned long *destination = bitmap_2d_address(bitmap, 0, (short)(y - bounds.y0), 0);
for (x = bounds.x0; x < bounds.x1; x++)
{
long source_x = x < 0 ? 0 : (x > image_width - 1 ? image_width - 1 : x);
byte *pixel = scanline + source_x * 2;
destination[x - bounds.x0] =
(pixel[1] << 24) | (pixel[0] << 16) | (pixel[0] << 8) | pixel[0];
}
}
break;
case 3:
{
unsigned long *destination = bitmap_2d_address(bitmap, 0, (short)(y - bounds.y0), 0);
for (x = bounds.x0; x < bounds.x1; x++)
{
long source_x = x < 0 ? 0 : (x > image_width - 1 ? image_width - 1 : x);
byte *pixel = scanline + source_x * 3;
destination[x - bounds.x0] =
0xFF000000 | (pixel[0] << 16) | (pixel[1] << 8) | pixel[2];
}
}
break;
case 4:
{
unsigned long *destination = bitmap_2d_address(bitmap, 0, (short)(y - bounds.y0), 0);
for (x = bounds.x0; x < bounds.x1; x++)
{
long source_x = x < 0 ? 0 : (x > image_width - 1 ? image_width - 1 : x);
byte *pixel = scanline + source_x * 4;
destination[x - bounds.x0] =
(pixel[3] << 24) | (pixel[0] << 16) | (pixel[1] << 8) | pixel[2];
}
}
break;
default:
display_assert(NULL, "c:\\halo\\SOURCE\\bitmaps\\tiff_file.c", 406, TRUE);
system_exit(-1);
break;
}
}
cleanup:
/*
* Original bug preserved: on a scan-line failure, bitmap_result still points
* at the bitmap deleted below. A non-matching safety fix would assign
* *bitmap_result = NULL after bitmap_delete().
*/
if (error_message && bitmap)
bitmap_delete(bitmap);
if (scanline)
debug_free(scanline, "c:\\halo\\SOURCE\\bitmaps\\tiff_file.c", 422);
TIFFClose(tiff);
return error_message;
}
/* ---------- private code */