* Now also saves the EXIF data in the supplied message in Translate() (decompress
only, you cannot add EXIF data yet). * Preparations to honour the orientation of JPEG images stored in the EXIF tags. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20633 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -32,9 +32,13 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
#include "JPEGTranslator.h"
|
#include "JPEGTranslator.h"
|
||||||
|
|
||||||
|
#include "exif_parser.h"
|
||||||
|
|
||||||
#include <TabView.h>
|
#include <TabView.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define MARKER_EXIF 0xe1
|
||||||
|
|
||||||
// Set these accordingly
|
// Set these accordingly
|
||||||
#define JPEG_ACRONYM "JPEG"
|
#define JPEG_ACRONYM "JPEG"
|
||||||
#define JPEG_FORMAT 'JPEG'
|
#define JPEG_FORMAT 'JPEG'
|
||||||
@@ -79,6 +83,12 @@ translation_format outputFormats[] = {
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Main functions of translator :)
|
||||||
|
static status_t Copy(BPositionIO *in, BPositionIO *out);
|
||||||
|
static status_t Compress(BPositionIO *in, BPositionIO *out);
|
||||||
|
static status_t Decompress(BPositionIO *in, BPositionIO *out, BMessage* ioExtension);
|
||||||
|
static status_t Error(j_common_ptr cinfo, status_t error = B_ERROR);
|
||||||
|
|
||||||
|
|
||||||
bool gAreSettingsRunning = false;
|
bool gAreSettingsRunning = false;
|
||||||
|
|
||||||
@@ -1054,14 +1064,14 @@ Translate(BPositionIO *inSource, const translator_info *inInfo,
|
|||||||
} else if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JPEG_FORMAT) {
|
} else if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JPEG_FORMAT) {
|
||||||
return Compress(inSource, outDestination);
|
return Compress(inSource, outDestination);
|
||||||
} else if (inInfo->type == JPEG_FORMAT && outType == B_TRANSLATOR_BITMAP) {
|
} else if (inInfo->type == JPEG_FORMAT && outType == B_TRANSLATOR_BITMAP) {
|
||||||
return Decompress(inSource, outDestination);
|
return Decompress(inSource, outDestination, ioExtension);
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_NO_TRANSLATOR;
|
return B_NO_TRANSLATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! The user has requested the same format for input and output, so just copy */
|
/*! The user has requested the same format for input and output, so just copy */
|
||||||
status_t
|
static status_t
|
||||||
Copy(BPositionIO *in, BPositionIO *out)
|
Copy(BPositionIO *in, BPositionIO *out)
|
||||||
{
|
{
|
||||||
int block_size = 65536;
|
int block_size = 65536;
|
||||||
@@ -1095,7 +1105,7 @@ Copy(BPositionIO *in, BPositionIO *out)
|
|||||||
|
|
||||||
|
|
||||||
/*! Encode into the native format */
|
/*! Encode into the native format */
|
||||||
status_t
|
static status_t
|
||||||
Compress(BPositionIO *in, BPositionIO *out)
|
Compress(BPositionIO *in, BPositionIO *out)
|
||||||
{
|
{
|
||||||
// Load Settings
|
// Load Settings
|
||||||
@@ -1307,8 +1317,8 @@ Compress(BPositionIO *in, BPositionIO *out)
|
|||||||
|
|
||||||
|
|
||||||
/*! Decode the native format */
|
/*! Decode the native format */
|
||||||
status_t
|
static status_t
|
||||||
Decompress(BPositionIO *in, BPositionIO *out)
|
Decompress(BPositionIO *in, BPositionIO *out, BMessage* ioExtension)
|
||||||
{
|
{
|
||||||
// Load Settings
|
// Load Settings
|
||||||
jpeg_settings settings;
|
jpeg_settings settings;
|
||||||
@@ -1321,16 +1331,39 @@ Decompress(BPositionIO *in, BPositionIO *out)
|
|||||||
jpeg_create_decompress(&cinfo);
|
jpeg_create_decompress(&cinfo);
|
||||||
be_jpeg_stdio_src(&cinfo, in);
|
be_jpeg_stdio_src(&cinfo, in);
|
||||||
|
|
||||||
|
jpeg_save_markers(&cinfo, MARKER_EXIF, 131072);
|
||||||
|
// make sure the EXIF tag is stored
|
||||||
|
|
||||||
// Read info about image
|
// Read info about image
|
||||||
jpeg_read_header(&cinfo, TRUE);
|
jpeg_read_header(&cinfo, TRUE);
|
||||||
|
|
||||||
|
BMessage exif;
|
||||||
|
|
||||||
|
if (ioExtension != NULL) {
|
||||||
|
// add EXIF data to message, if any
|
||||||
|
jpeg_marker_struct* marker = cinfo.marker_list;
|
||||||
|
while (marker != NULL) {
|
||||||
|
if (marker->marker == MARKER_EXIF
|
||||||
|
&& !strncmp((char*)marker->data, "Exif", 4)) {
|
||||||
|
// Strip EXIF header from TIFF data
|
||||||
|
ioExtension->AddData("exif", B_RAW_TYPE,
|
||||||
|
(uint8 *)marker->data + 6, marker->data_length - 6);
|
||||||
|
|
||||||
|
BMemoryIO io(marker->data + 6, marker->data_length - 6);
|
||||||
|
convert_exif_to_message(io, exif);
|
||||||
|
}
|
||||||
|
marker = marker->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Default color info
|
// Default color info
|
||||||
color_space out_color_space = B_RGB32;
|
color_space outColorSpace = B_RGB32;
|
||||||
int out_color_components = 4;
|
int outColorComponents = 4;
|
||||||
|
|
||||||
// Function pointer to convert function
|
// Function pointer to convert function
|
||||||
// It will point to proper function if needed
|
// It will point to proper function if needed
|
||||||
void (*converter)(uchar *inscanline, uchar *outscanline, int inrow_bytes) = convert_from_24_to_32;
|
void (*converter)(uchar *inScanLine, uchar *outScanLine,
|
||||||
|
int inRowBytes) = convert_from_24_to_32;
|
||||||
|
|
||||||
// If color space isn't rgb
|
// If color space isn't rgb
|
||||||
if (cinfo.out_color_space != JCS_RGB) {
|
if (cinfo.out_color_space != JCS_RGB) {
|
||||||
@@ -1342,8 +1375,8 @@ Decompress(BPositionIO *in, BPositionIO *out)
|
|||||||
// Check if user wants to read only as RGB32 or not
|
// Check if user wants to read only as RGB32 or not
|
||||||
if (!settings.Always_B_RGB32) {
|
if (!settings.Always_B_RGB32) {
|
||||||
// Grayscale
|
// Grayscale
|
||||||
out_color_space = B_GRAY8;
|
outColorSpace = B_GRAY8;
|
||||||
out_color_components = 1;
|
outColorComponents = 1;
|
||||||
converter = NULL;
|
converter = NULL;
|
||||||
} else {
|
} else {
|
||||||
// RGB
|
// RGB
|
||||||
@@ -1376,12 +1409,21 @@ Decompress(BPositionIO *in, BPositionIO *out)
|
|||||||
// Initialize decompression
|
// Initialize decompression
|
||||||
jpeg_start_decompress(&cinfo);
|
jpeg_start_decompress(&cinfo);
|
||||||
|
|
||||||
// !!! Initialize this bounds rect to the size of your image
|
int32 orientation;
|
||||||
BRect bounds(0, 0, cinfo.output_width-1, cinfo.output_height-1);
|
if (exif.FindInt32("Orientation", &orientation) != B_OK)
|
||||||
|
orientation = 1;
|
||||||
|
|
||||||
|
// Initialize this bounds rect to the size of your image
|
||||||
|
BRect bounds(0, 0, cinfo.output_width - 1, cinfo.output_height - 1);
|
||||||
|
if (orientation & 4) {
|
||||||
|
// image is rotated
|
||||||
|
bounds.right = cinfo.output_height - 1;
|
||||||
|
bounds.bottom = cinfo.output_width - 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Bytes count in one line of image (scanline)
|
// Bytes count in one line of image (scanline)
|
||||||
int64 row_bytes = cinfo.output_width * out_color_components;
|
int64 rowBytes = cinfo.output_width * outColorComponents;
|
||||||
|
|
||||||
// Fill out the B_TRANSLATOR_BITMAP's header
|
// Fill out the B_TRANSLATOR_BITMAP's header
|
||||||
TranslatorBitmap header;
|
TranslatorBitmap header;
|
||||||
header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
|
header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
|
||||||
@@ -1389,9 +1431,9 @@ Decompress(BPositionIO *in, BPositionIO *out)
|
|||||||
header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
|
header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
|
||||||
header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
|
header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
|
||||||
header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
|
header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
|
||||||
header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space);
|
header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(outColorSpace);
|
||||||
header.rowBytes = B_HOST_TO_BENDIAN_INT32(row_bytes);
|
header.rowBytes = B_HOST_TO_BENDIAN_INT32(rowBytes);
|
||||||
header.dataSize = B_HOST_TO_BENDIAN_INT32(row_bytes * cinfo.output_height);
|
header.dataSize = B_HOST_TO_BENDIAN_INT32(rowBytes * cinfo.output_height);
|
||||||
|
|
||||||
// Write out the header
|
// Write out the header
|
||||||
status_t err = out->Write(&header, sizeof(TranslatorBitmap));
|
status_t err = out->Write(&header, sizeof(TranslatorBitmap));
|
||||||
@@ -1408,14 +1450,14 @@ Decompress(BPositionIO *in, BPositionIO *out)
|
|||||||
// Allocate scanline
|
// Allocate scanline
|
||||||
// Use libjpeg memory allocation functions, so in case of error it will free them itself
|
// Use libjpeg memory allocation functions, so in case of error it will free them itself
|
||||||
in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
|
in_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
|
||||||
JPOOL_PERMANENT, row_bytes);
|
JPOOL_PERMANENT, rowBytes);
|
||||||
|
|
||||||
// We need 2nd scanline storage only for conversion
|
// We need 2nd scanline storage only for conversion
|
||||||
if (converter != NULL) {
|
if (converter != NULL) {
|
||||||
// There will be conversion, allocate second scanline...
|
// There will be conversion, allocate second scanline...
|
||||||
// Use libjpeg memory allocation functions, so in case of error it will free them itself
|
// Use libjpeg memory allocation functions, so in case of error it will free them itself
|
||||||
out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
|
out_scanline = (unsigned char *)(cinfo.mem->alloc_large)((j_common_ptr)&cinfo,
|
||||||
JPOOL_PERMANENT, row_bytes);
|
JPOOL_PERMANENT, rowBytes);
|
||||||
// ... and make it the one to write to file
|
// ... and make it the one to write to file
|
||||||
writeline = out_scanline;
|
writeline = out_scanline;
|
||||||
} else
|
} else
|
||||||
@@ -1427,11 +1469,11 @@ Decompress(BPositionIO *in, BPositionIO *out)
|
|||||||
|
|
||||||
// Convert if needed
|
// Convert if needed
|
||||||
if (converter != NULL)
|
if (converter != NULL)
|
||||||
converter(in_scanline, out_scanline, row_bytes);
|
converter(in_scanline, out_scanline, rowBytes);
|
||||||
|
|
||||||
// Write the scanline buffer to the output stream
|
// Write the scanline buffer to the output stream
|
||||||
err = out->Write(writeline, row_bytes);
|
err = out->Write(writeline, rowBytes);
|
||||||
if (err < row_bytes)
|
if (err < rowBytes)
|
||||||
return err < B_OK ? Error((j_common_ptr)&cinfo, err)
|
return err < B_OK ? Error((j_common_ptr)&cinfo, err)
|
||||||
: Error((j_common_ptr)&cinfo, B_ERROR);
|
: Error((j_common_ptr)&cinfo, B_ERROR);
|
||||||
}
|
}
|
||||||
@@ -1445,7 +1487,7 @@ Decompress(BPositionIO *in, BPositionIO *out)
|
|||||||
Frees jpeg alocated memory
|
Frees jpeg alocated memory
|
||||||
Returns given error (B_ERROR by default)
|
Returns given error (B_ERROR by default)
|
||||||
*/
|
*/
|
||||||
status_t
|
static status_t
|
||||||
Error(j_common_ptr cinfo, status_t error)
|
Error(j_common_ptr cinfo, status_t error)
|
||||||
{
|
{
|
||||||
jpeg_destroy(cinfo);
|
jpeg_destroy(cinfo);
|
||||||
|
|||||||
@@ -215,10 +215,4 @@ EXTERN(void) be_jpeg_stdio_dest(j_compress_ptr cinfo, BPositionIO *outfile); //
|
|||||||
EXTERN(struct jpeg_error_mgr *) be_jpeg_std_error (struct jpeg_error_mgr * err, jpeg_settings * settings); // from "be_jerror.cpp"
|
EXTERN(struct jpeg_error_mgr *) be_jpeg_std_error (struct jpeg_error_mgr * err, jpeg_settings * settings); // from "be_jerror.cpp"
|
||||||
|
|
||||||
|
|
||||||
// Main functions of translator :)
|
|
||||||
status_t Copy(BPositionIO *in, BPositionIO *out);
|
|
||||||
status_t Compress(BPositionIO *in, BPositionIO *out);
|
|
||||||
status_t Decompress(BPositionIO *in, BPositionIO *out);
|
|
||||||
status_t Error(j_common_ptr cinfo, status_t error = B_ERROR);
|
|
||||||
|
|
||||||
#endif // _JPEGTRANSLATOR_H_
|
#endif // _JPEGTRANSLATOR_H_
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ SubDirC++Flags [ FDefines BEOS_R5_COMPATIBLE ] ;
|
|||||||
|
|
||||||
SubDirSysHdrs [ FDirName $(SUBDIR) libjpeg ] ;
|
SubDirSysHdrs [ FDirName $(SUBDIR) libjpeg ] ;
|
||||||
|
|
||||||
|
SubDirSysHdrs [ FDirName $(SUBDIR) $(DOTDOT) raw ] ;
|
||||||
|
# for TIFF.h and ReadHelper.h
|
||||||
|
|
||||||
local jpeg_files =
|
local jpeg_files =
|
||||||
# libjpeg
|
# libjpeg
|
||||||
jcapimin.c
|
jcapimin.c
|
||||||
@@ -82,6 +85,7 @@ Translator JPEGTranslator :
|
|||||||
be_jdatadst.cpp
|
be_jdatadst.cpp
|
||||||
be_jdatasrc.cpp
|
be_jdatasrc.cpp
|
||||||
be_jerror.cpp
|
be_jerror.cpp
|
||||||
|
exif_parser.cpp
|
||||||
JPEGTranslator.cpp
|
JPEGTranslator.cpp
|
||||||
|
|
||||||
$(jpeg_files)
|
$(jpeg_files)
|
||||||
|
|||||||
@@ -0,0 +1,327 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "exif_parser.h"
|
||||||
|
|
||||||
|
#include <ReadHelper.h>
|
||||||
|
|
||||||
|
#include <Message.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TAG_EXIF_OFFSET = 0x8769,
|
||||||
|
TAG_SUB_DIR_OFFSET = 0xa005,
|
||||||
|
|
||||||
|
TAG_MAKER = 0x10f,
|
||||||
|
TAG_MODEL = 0x110,
|
||||||
|
TAG_ORIENTATION = 0x112,
|
||||||
|
TAG_EXPOSURE_TIME = 0x829a,
|
||||||
|
TAG_ISO = 0x8827,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const convert_tag kDefaultTags[] = {
|
||||||
|
{TAG_MAKER, B_ANY_TYPE, "Maker"},
|
||||||
|
{TAG_MODEL, B_ANY_TYPE, "Model"},
|
||||||
|
{TAG_ORIENTATION, B_INT32_TYPE, "Orientation"},
|
||||||
|
{TAG_EXPOSURE_TIME, B_DOUBLE_TYPE, "ExposureTime"},
|
||||||
|
{TAG_ISO, B_INT32_TYPE, "ISO"},
|
||||||
|
};
|
||||||
|
static const size_t kNumDefaultTags = sizeof(kDefaultTags)
|
||||||
|
/ sizeof(kDefaultTags[0]);
|
||||||
|
|
||||||
|
|
||||||
|
static status_t parse_tiff_directory(TReadHelper& read, BMessage& target,
|
||||||
|
const convert_tag* tags, size_t tagCount);
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
add_to_message(TReadHelper& source, BMessage& target, tiff_tag& tag,
|
||||||
|
const char* name, type_code type)
|
||||||
|
{
|
||||||
|
type_code defaultType = B_INT32_TYPE;
|
||||||
|
double doubleValue = 0.0;
|
||||||
|
int32 intValue = 0;
|
||||||
|
|
||||||
|
switch (tag.type) {
|
||||||
|
case TIFF_STRING_TYPE:
|
||||||
|
{
|
||||||
|
if (type != B_ANY_TYPE && type != B_STRING_TYPE)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
char* buffer = (char*)malloc(tag.length);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
source(buffer, tag.length);
|
||||||
|
|
||||||
|
// remove trailing spaces
|
||||||
|
int32 i = tag.length;
|
||||||
|
while (--i > 0 && isspace(buffer[i]) || !buffer[i]) {
|
||||||
|
buffer[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t status = target.AddString(name, buffer);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TIFF_UNDEFINED_TYPE:
|
||||||
|
{
|
||||||
|
if (type != B_ANY_TYPE && type != B_STRING_TYPE && type != B_RAW_TYPE)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
char* buffer = (char*)malloc(tag.length);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
source(buffer, tag.length);
|
||||||
|
|
||||||
|
status_t status;
|
||||||
|
if (type == B_STRING_TYPE)
|
||||||
|
status = target.AddString(name, buffer);
|
||||||
|
else
|
||||||
|
status = target.AddData(name, B_RAW_TYPE, buffer, tag.length);
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsigned
|
||||||
|
case TIFF_UINT8_TYPE:
|
||||||
|
intValue = source.Next<uint8>();
|
||||||
|
break;
|
||||||
|
case TIFF_UINT16_TYPE:
|
||||||
|
defaultType = B_INT32_TYPE;
|
||||||
|
intValue = source.Next<uint16>();
|
||||||
|
break;
|
||||||
|
case TIFF_UINT32_TYPE:
|
||||||
|
defaultType = B_INT32_TYPE;
|
||||||
|
intValue = source.Next<uint32>();
|
||||||
|
break;
|
||||||
|
case TIFF_UFRACTION_TYPE:
|
||||||
|
{
|
||||||
|
defaultType = B_DOUBLE_TYPE;
|
||||||
|
double value = source.Next<uint32>();
|
||||||
|
doubleValue = value / source.Next<uint32>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// signed
|
||||||
|
case TIFF_INT8_TYPE:
|
||||||
|
intValue = source.Next<int8>();
|
||||||
|
break;
|
||||||
|
case TIFF_INT16_TYPE:
|
||||||
|
intValue = source.Next<int16>();
|
||||||
|
break;
|
||||||
|
case TIFF_INT32_TYPE:
|
||||||
|
intValue = source.Next<int32>();
|
||||||
|
break;
|
||||||
|
case TIFF_FRACTION_TYPE:
|
||||||
|
{
|
||||||
|
defaultType = B_DOUBLE_TYPE;
|
||||||
|
double value = source.Next<int32>();
|
||||||
|
doubleValue = value / source.Next<int32>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// floating point
|
||||||
|
case TIFF_FLOAT_TYPE:
|
||||||
|
defaultType = B_FLOAT_TYPE;
|
||||||
|
doubleValue = source.Next<float>();
|
||||||
|
break;
|
||||||
|
case TIFF_DOUBLE_TYPE:
|
||||||
|
defaultType = B_DOUBLE_TYPE;
|
||||||
|
doubleValue = source.Next<double>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defaultType == B_INT32_TYPE)
|
||||||
|
doubleValue = intValue;
|
||||||
|
else
|
||||||
|
intValue = int32(doubleValue + 0.5);
|
||||||
|
|
||||||
|
if (type == B_ANY_TYPE)
|
||||||
|
type = defaultType;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case B_INT32_TYPE:
|
||||||
|
return target.AddInt32(name, intValue);
|
||||||
|
case B_FLOAT_TYPE:
|
||||||
|
return target.AddFloat(name, doubleValue);
|
||||||
|
case B_DOUBLE_TYPE:
|
||||||
|
return target.AddDouble(name, doubleValue);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const convert_tag*
|
||||||
|
find_convert_tag(uint16 id, const convert_tag* tags, size_t count)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
if (tags[i].tag == id)
|
||||||
|
return &tags[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Reads a TIFF tag and positions the file stream to its data section
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
parse_tiff_tag(TReadHelper& read, tiff_tag& tag, off_t& offset)
|
||||||
|
{
|
||||||
|
read(tag.tag);
|
||||||
|
read(tag.type);
|
||||||
|
read(tag.length);
|
||||||
|
|
||||||
|
offset = read.Position() + 4;
|
||||||
|
|
||||||
|
uint32 length = tag.length;
|
||||||
|
|
||||||
|
switch (tag.type) {
|
||||||
|
case TIFF_UINT16_TYPE:
|
||||||
|
case TIFF_INT16_TYPE:
|
||||||
|
length *= 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TIFF_UINT32_TYPE:
|
||||||
|
case TIFF_INT32_TYPE:
|
||||||
|
case TIFF_FLOAT_TYPE:
|
||||||
|
length *= 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TIFF_UFRACTION_TYPE:
|
||||||
|
case TIFF_FRACTION_TYPE:
|
||||||
|
case TIFF_DOUBLE_TYPE:
|
||||||
|
length *= 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > 4) {
|
||||||
|
uint32 position;
|
||||||
|
read(position);
|
||||||
|
|
||||||
|
read.Seek(position, SEEK_SET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
parse_tiff_directory(TReadHelper& read, off_t offset, BMessage& target,
|
||||||
|
const convert_tag* convertTags, size_t convertTagCount)
|
||||||
|
{
|
||||||
|
read.Seek(offset, SEEK_SET);
|
||||||
|
|
||||||
|
uint16 tags;
|
||||||
|
read(tags);
|
||||||
|
if (tags > 512)
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
while (tags--) {
|
||||||
|
off_t nextOffset;
|
||||||
|
tiff_tag tag;
|
||||||
|
parse_tiff_tag(read, tag, nextOffset);
|
||||||
|
|
||||||
|
//printf("TAG %u\n", tag.tag);
|
||||||
|
|
||||||
|
switch (tag.tag) {
|
||||||
|
case TAG_EXIF_OFFSET:
|
||||||
|
case TAG_SUB_DIR_OFFSET:
|
||||||
|
{
|
||||||
|
status_t status = parse_tiff_directory(read, target,
|
||||||
|
convertTags, convertTagCount);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
const convert_tag* convertTag = find_convert_tag(tag.tag,
|
||||||
|
convertTags, convertTagCount);
|
||||||
|
if (convertTag != NULL) {
|
||||||
|
add_to_message(read, target, tag, convertTag->name,
|
||||||
|
convertTag->type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read.Seek(nextOffset, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
parse_tiff_directory(TReadHelper& read, BMessage& target,
|
||||||
|
const convert_tag* tags, size_t tagCount)
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
int32 offset;
|
||||||
|
read(offset);
|
||||||
|
if (offset == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
status_t status = parse_tiff_directory(read, offset, target,
|
||||||
|
tags, tagCount);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
convert_exif_to_message(BPositionIO& source, BMessage& target,
|
||||||
|
const convert_tag* tags, size_t tagCount)
|
||||||
|
{
|
||||||
|
TReadHelper read(source);
|
||||||
|
|
||||||
|
uint16 endian;
|
||||||
|
read(endian);
|
||||||
|
if (endian != 'MM' && endian != 'II')
|
||||||
|
return B_BAD_TYPE;
|
||||||
|
|
||||||
|
#if B_HOST_IS_LENDIAN
|
||||||
|
read.SetSwap(endian == 'MM');
|
||||||
|
#else
|
||||||
|
read.SetSwap(endian == 'II');
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int16 magic;
|
||||||
|
read(magic);
|
||||||
|
if (magic != 42)
|
||||||
|
return B_BAD_TYPE;
|
||||||
|
|
||||||
|
return parse_tiff_directory(read, target, tags, tagCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
convert_exif_to_message(BPositionIO& source, BMessage& target)
|
||||||
|
{
|
||||||
|
return convert_exif_to_message(source, target, kDefaultTags,
|
||||||
|
kNumDefaultTags);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef EXIF_PARSER_H
|
||||||
|
#define EXIF_PARSER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <DataIO.h>
|
||||||
|
#include <TypeConstants.h>
|
||||||
|
|
||||||
|
class BMessage;
|
||||||
|
|
||||||
|
|
||||||
|
struct convert_tag {
|
||||||
|
uint16 tag;
|
||||||
|
type_code type;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
status_t convert_exif_to_message(BPositionIO& source, BMessage& target);
|
||||||
|
status_t convert_exif_to_message_etc(BPositionIO& source, BMessage& target,
|
||||||
|
const convert_tag* tags, size_t tagCount);
|
||||||
|
|
||||||
|
#endif // EXIF_PARSER_H
|
||||||
Reference in New Issue
Block a user