mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-23 01:00:30 +02:00
453 lines
11 KiB
C
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 */
|