From: Pat Thoyts Date: Mon, 22 Sep 2025 13:32:23 +0000 (+0100) Subject: Emit EXIF information for Surface images for old and new formats. X-Git-Url: http://privyetmir.co.uk/gitweb?a=commitdiff_plain;ds=sidebyside;p=srfdump Emit EXIF information for Surface images for old and new formats. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index a136d62..099e3bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.20) project(srfdump VERSION 1.0) -add_executable(srfdump srfdump.c surfacefile.h) +add_executable(srfdump srfdump.c jpegrdr.c exif.c jpegrdr.h exif.h surfacefile.h) target_compile_features(srfdump PRIVATE c_std_11) if (WIN32) target_compile_definitions(srfdump PRIVATE -DWIN32 -D_CRT_SECURE_NO_WARNINGS) @@ -20,7 +20,7 @@ endif() add_executable(jpegrdr jpegrdr.c exif.c exif.h) target_compile_features(jpegrdr PRIVATE c_std_11) if (WIN32) - target_compile_definitions(jpegrdr PRIVATE -DWIN32 -D_CRT_SECURE_NO_WARNINGS) + target_compile_definitions(jpegrdr PRIVATE -DWIN32 _CRT_SECURE_NO_WARNINGS JPEGRDR_MAIN) else() #target_compile_options(jpegrdr PRIVATE -pedantic) endif() diff --git a/exif.c b/exif.c index 97decbb..3dfe2ff 100644 --- a/exif.c +++ b/exif.c @@ -13,9 +13,9 @@ static const char *EXIF_TYPE_NAMES[11] = { // 0 1 2 3 4 5 - "?", "byte", "ascii", "short", "long", "rational", + "?", "BYTE", "ASCII", "USHORT", "ULONG", "URATIONAL", // 6 7 8 9 10 - "char", "binary", "sshort", "slong", "srational" + "CHAR", "BINARY", "SHORT", "LONG", "RATIONAL" }; static bool big_endian_data = false; @@ -185,16 +185,72 @@ static size_t exif_parse_item(const uint8_t *buffer, const uint8_t *entry, exif_ return item_count; } -void exif_print_item(const exif_item_t* item) +typedef struct tag_name_t { + uint16_t tag; + const char *name; +} tag_name_t; + +tag_name_t tag_names[] = { + { 0x0100, "ImageWidth" }, + { 0x0101, "ImageHeight" }, + { 0x0102, "BitsPerSample" }, + { 0x0103, "Compression" }, + { 0x0106, "PhotometricInterpretation" }, + { 0x0107, "Thresholding" }, + { 0x010e, "ImageDescription" }, + { 0x010f, "Make" }, + { 0x0112, "Orientation" }, + { 0x011a, "XResolution" }, + { 0x011b, "YResolution" }, + { 0x011c, "PlanarConfiguration" }, + { 0x011e, "XPosition" }, + { 0x011f, "YPosition" }, + { 0x0128, "ResolutionUnit" }, + { 0x0131, "Software" }, + { 0x0132, "ModifyDate" }, + { 0xa001, "ColorSpace" }, + { 0xa002, "ExifImageWidth" }, + { 0xa003, "ExifImageHeight" }, + { 0xa20e, "FocalPlaneXResolution" }, + { 0xa20f, "FocalPlaneYResolution" }, + { 0xa210, "FocalPlaneResolutionUnit" }, + /* Renishaw WiRE Custom Tags */ + { 0xfea0, "WiREPosition" }, + { 0xfea1, "WiREFoV" }, + { 0xfea2, "WiREObjective" }, + { 0xfea3, "WiRELUTLimits" }, + { 0xfea4, "WiRERotationAngle" }, + { 0xfea5, "WiRERotationCenter" }, + { 0xfea6, "WiREZPosition" } +}; + +void exif_print_item(FILE *fp, const exif_item_t* item, const char *prefix) { - fprintf(stderr, " %04x %-10s %u: ", - item->tag, EXIF_TYPE_NAMES[item->type], item->count); + char name_buf[5] = {0}; + const char *name = NULL; + for (int ndx = 0; ndx < sizeof(tag_names)/sizeof(tag_names[0]); ++ndx) + { + if (item->tag == tag_names[ndx].tag) + { + name = tag_names[ndx].name; + break; + } + } + if (name == NULL) + { + sprintf(name_buf, "%04x", item->tag); + name = name_buf; + } + + fprintf(fp, "%s%s %s[%u] ", + prefix == NULL ? "" : prefix, + name, EXIF_TYPE_NAMES[item->type], item->count); if (item->type == EXIF_TYPE_ASCII) - fprintf(stderr, "'%s'", item->u.strVal); + fprintf(fp, "'%s'", item->u.strVal); else if ((item->type == EXIF_TYPE_UNDEFINED || item->type == EXIF_TYPE_BYTE) && item->count > 8) { - fprintf(stderr, "[%hu bytes]", item->count); + fprintf(fp, "[%hu bytes]", item->count); } else { @@ -204,45 +260,45 @@ void exif_print_item(const exif_item_t* item) { case EXIF_TYPE_BYTE: case EXIF_TYPE_UNDEFINED: - fprintf(stderr, "%02x", item->u.values[n].byteVal); + fprintf(fp, "%02x", item->u.values[n].byteVal); break; case EXIF_TYPE_SBYTE: - fprintf(stderr, "%d", item->u.values[n].cVal); + fprintf(fp, "%d", item->u.values[n].cVal); break; case EXIF_TYPE_SSHORT: - fprintf(stderr, "%hd", item->u.values[0].hVal); + fprintf(fp, "%hd", item->u.values[0].hVal); break; case EXIF_TYPE_SHORT: - fprintf(stderr, "%hu", item->u.values[0].uhVal); + fprintf(fp, "%hu", item->u.values[0].uhVal); break; case EXIF_TYPE_LONG: - fprintf(stderr, "%u", item->u.values[0].ulVal); + fprintf(fp, "%u", item->u.values[0].ulVal); break; case EXIF_TYPE_SLONG: - fprintf(stderr, "%d", item->u.values[0].lVal); + fprintf(fp, "%d", item->u.values[0].lVal); break; case EXIF_TYPE_RATIONAL: - fprintf(stderr, "%u/%u", + fprintf(fp, "%u/%u", item->u.values[n].rationalVal.numerator, item->u.values[n].rationalVal.denominator); break; case EXIF_TYPE_SRATIONAL: - fprintf(stderr, "%d/%d", + fprintf(fp, "%d/%d", item->u.values[n].srationalVal.numerator, item->u.values[n].srationalVal.denominator); break; case EXIF_TYPE_FLOAT32: - fprintf(stderr, "%f", item->u.values[n].fltVal); + fprintf(fp, "%f", item->u.values[n].fltVal); break; case EXIF_TYPE_FLOAT64: - fprintf(stderr, "%lf", item->u.values[n].dblVal); + fprintf(fp, "%lf", item->u.values[n].dblVal); break; case EXIF_TYPE_ASCII: break; } if (n < item->count - 1) - fprintf(stderr, ", "); + fprintf(fp, ", "); } } - fprintf(stderr, "\n"); + fprintf(fp, "\n"); } void exif_free(exif_item_t *items) diff --git a/exif.h b/exif.h index 79cb54f..cc15e45 100644 --- a/exif.h +++ b/exif.h @@ -2,6 +2,7 @@ #define _exif_h_INCLUDE #include +#include typedef enum exif_type_t { EXIF_TYPE_BYTE = 1, // uint8_t @@ -52,7 +53,7 @@ typedef struct exif_item_t { } u; } exif_item_t; -void exif_print_item(const exif_item_t* item); +void exif_print_item(FILE *fp, const exif_item_t* item, const char *prefix); exif_item_t *exif_parse(const uint8_t *data, size_t datalen); void exif_free(exif_item_t *items); diff --git a/jpegrdr.c b/jpegrdr.c index 8642b57..99f3159 100644 --- a/jpegrdr.c +++ b/jpegrdr.c @@ -3,8 +3,10 @@ #include #include #include +#include #include #include "exif.h" +#include "jpegrdr.h" typedef uint16_t marker_t; @@ -91,14 +93,15 @@ jfif_frame_t* jfif_read_frame(FILE* fp, size_t len) return frame; } -void jfif_read_app0(FILE *fp, size_t len) +exif_item_t * jfif_read_app0(FILE *fp, size_t len, logfunc_t log) { + exif_item_t *exif_items = NULL; char label[6] = {0}; size_t count = fread(label, 1, 5, fp); if (strncmp("JFIF", label, 4) == 0) { jfif_header_t *hdr = jfif_read_header(fp, len - 5); - fprintf(stderr, " %s version %u.%u density %hu,%hu %s\n", + log(" %s version %u.%u density %hu,%hu %s\n", label, hdr->major_version, hdr->minor_version, hdr->x_density, hdr->y_density, hdr->units == 1 ? "dpi" : "???"); @@ -107,33 +110,29 @@ void jfif_read_app0(FILE *fp, size_t len) else if (strncmp("Exif", label, 4) == 0) { uint8_t pad = 0; - fprintf(stderr, " %s\n", label); fread(&pad, 1, 1, fp); // read the pad char // read the EXIF data into a buffer uint8_t *data = (uint8_t*)calloc(len - 6, 1); assert(data != NULL); fread(data, len - 6, 1, fp); - exif_item_t *items = exif_parse(data, len - 6); + exif_items = exif_parse(data, len - 6); free(data); - - // print the items - for (exif_item_t* item = items; item; item = item->nextPtr) - exif_print_item(item); - exif_free(items); } else { - fprintf(stderr, " %s\n", label); + log(" %s\n", label); fseek(fp, (long)(len - 5), SEEK_CUR); } + return exif_items; } + // // JFIF images have SOI APP0[JFIF] ... // EXIF sections use APP0 as well and in JFIF must follow the JFIF segment. // -void get_jpeg_exif(FILE *fp) +exif_item_t *jpegrdr_get_exif(FILE *fp, logfunc_t log) { size_t start = ftell(fp); size_t len = 0; @@ -145,59 +144,77 @@ void get_jpeg_exif(FILE *fp) { case JFIF_SOI: len = 0; - fprintf(stderr, "%08lx SOI\n", ftell(fp)); + log("%08lx SOI\n", ftell(fp)); break; case JFIF_SOF0: { len = jfif_get_size(fp); - fprintf(stderr, "%08lx SOF0 %04zx\n", ftell(fp), len); + log("%08lx SOF0 %04zx\n", ftell(fp), len); jfif_frame_t* frame = jfif_read_frame(fp, len); - fprintf(stderr, " image size %u,%u\n", frame->width, frame->height); + log(" image size %u,%u\n", frame->width, frame->height); free(frame); len = 0; break; } case JFIF_DQT: len = jfif_get_size(fp); - fprintf(stderr, "%08lx DQT %04zx\n", ftell(fp), len); + log("%08lx DQT %04zx\n", ftell(fp), len); break; case JFIF_DHT: len = jfif_get_size(fp); - fprintf(stderr, "%08lx DHT %04zx\n", ftell(fp), len); + log("%08lx DHT %04zx\n", ftell(fp), len); break; case JFIF_SOS: len = jfif_get_size(fp); - fprintf(stderr, "%08lx SOS %04zx\n", ftell(fp), len); - return; + log("%08lx SOS %04zx\n", ftell(fp), len); + return NULL; default: { if (JFIF_IS_RST(mark) && JFIF_GET_RST_N(mark) < 8) { len = jfif_get_size(fp); - fprintf(stderr, "%08lx RST%d %04zx\n", ftell(fp), JFIF_GET_RST_N(mark), len); + log("%08lx RST%d %04zx\n", ftell(fp), JFIF_GET_RST_N(mark), len); } else if (JFIF_IS_APP(mark)) { len = jfif_get_size(fp); - fprintf(stderr, "%08lx APP%u %04zx\n", ftell(fp), JFIF_GET_APP_N(mark), len); - jfif_read_app0(fp, len); + log("%08lx APP%u %04zx\n", ftell(fp), JFIF_GET_APP_N(mark), len); + exif_item_t *items = jfif_read_app0(fp, len, log); + if (items != NULL) + return items; len = 0; } else { - fprintf(stderr, "OOPS %04x\n", mark); + log("OOPS %04x\n", mark); exit(1); } } } fseek(fp, (long)len, SEEK_CUR); } + return NULL; +} + +#ifdef JPEGRDR_MAIN + +static void _cdecl logger(const char *format, ...) +{ + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); } int main(int argc, char const * const argv[]) { FILE *fp = fopen(argv[1], "rb"); - get_jpeg_exif(fp); + exif_item_t *items = jpegrdr_get_exif(fp, logger); + for (exif_item_t *item = items; item; item = item->nextPtr) + exif_print_item(stderr, item, " "); + exif_free(items); fclose(fp); return 0; } + +#endif diff --git a/jpegrdr.h b/jpegrdr.h new file mode 100644 index 0000000..546416e --- /dev/null +++ b/jpegrdr.h @@ -0,0 +1,11 @@ +#ifndef _jpegrdr_h_INCLUDE +#define _jpegrdr_h_INCLUDE + +#include +#include "exif.h" + +typedef void (_cdecl * logfunc_t)(const char *format, ...); + +exif_item_t *jpegrdr_get_exif(FILE *fp, logfunc_t log); + +#endif /* _jpegrdr_h_INCLUDE */ diff --git a/srfdump.c b/srfdump.c index ce297fa..736ceda 100644 --- a/srfdump.c +++ b/srfdump.c @@ -6,11 +6,14 @@ */ #include +#include #include #include #include #include #include "surfacefile.h" +#include "exif.h" +#include "jpegrdr.h" #ifdef WIN32 #include @@ -19,6 +22,14 @@ #include "compat/tchar.h" #endif /* !WIN32 */ +static void _cdecl logger(const char *format, ...) +{ + va_list args; + va_start(args, format); + //vfprintf(stderr, format, args); + va_end(args); +} + static size_t fcopy(FILE *src, FILE *dst, size_t count) { char buf[4096]; @@ -33,7 +44,26 @@ static size_t fcopy(FILE *src, FILE *dst, size_t count) return total; } -// For a single image the table just contains the end of the image. +// Read a BSTR record from the current file position/. +// Reads a uint32_t to get the size in bytes +// Then allocates and returns a Unicode string with terminating NUL +static wchar_t* read_name(FILE* fp) +{ + uint32_t length = 0; + fread(&length, sizeof(uint32_t), 1, fp); + wchar_t* name = NULL; + if (length) + { + name = (wchar_t*)calloc(1, length + sizeof(wchar_t)); + fread(name, 1, length, fp); + } + return name; +} + +// Read the image table and return an array of absolute file position offsets +// to the start of each image information structure. +// The final element in the array should point to the end of the final image +// ie: the end of the file. static uint32_t * ReadImageTable(SurfaceFileHeader *hdrPtr, FILE *fp) { uint32_t *table = NULL; @@ -46,11 +76,20 @@ static uint32_t * ReadImageTable(SurfaceFileHeader *hdrPtr, FILE *fp) exit(1); } size_t check = fread(table + 1, sizeof(uint32_t), hdrPtr->num_images, fp); - // set first image to the end of the table. + uint32_t table_end = ftell(fp); + // read the directory name from after the offset table for rev7+ + if (hdrPtr->revision > 6) + { + hdrPtr->dirname = read_name(fp); + } + uint32_t name_end = ftell(fp); + // set first image offset to the current position (after all header info) table[0] = (long)ftell(fp); - // convert offsets from relative to table to file absolute positions + // The offsets in the table are relative to the end of the table but do not account for the + // directory name being inserted at the end. + // Convert offsets from relative to table to file absolute positions for (uint32_t n = 1; n < hdrPtr->num_images + 1; ++n) - table[n] += table[0]; + table[n] += table_end; } return table; } @@ -94,8 +133,14 @@ static SurfacePoint * ReadPoints(SurfaceFileHeader *hdrPtr, FILE *fp) return points; } -static int SrfDump(FILE *fp) +static int SrfDump(const char *filename) { + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) { + perror("fopen"); + return 1; + } + int r = 0; SurfaceFileHeader hdr = {0}; fread(&hdr, sizeof(SurfaceFileHeaderRev0), 1, fp); @@ -108,6 +153,8 @@ static int SrfDump(FILE *fp) hdrsize += sizeof(SurfaceFileHeaderRev4); if (hdr.revision > 4) hdrsize += sizeof(SurfaceFileHeaderRev5); + if (hdr.revision > 8) + hdrsize += sizeof(SurfaceFileHeaderRev9); fseek(fp, 0, SEEK_SET); fread(&hdr, hdrsize, 1, fp); @@ -129,10 +176,22 @@ static int SrfDump(FILE *fp) printf("use background removal: %s\n", hdr.use_background_removal ? "true" : "false"); if (hdr.revision > 4) printf("extrapolation mode: %d\n", (int)hdr.extrapolation_mode); + if (hdr.revision > 8) + { + printf("objective: %.3lf\n", hdr.objective); + printf("motor info:\n"); + printf(" stage min: %g, %g, %g\n", + hdr.motor_info.stage_min.x, hdr.motor_info.stage_min.y, hdr.motor_info.stage_min.z); + printf(" stage max: %g, %g, %g\n", + hdr.motor_info.stage_max.x, hdr.motor_info.stage_max.y, hdr.motor_info.stage_max.z); + printf(" reference: %g, %g\n", hdr.motor_info.reference.x, hdr.motor_info.reference.y); + printf(" resolution: %g, %g\n", hdr.motor_info.resolution.x, hdr.motor_info.resolution.y); + } SurfacePoint *points = ReadPoints(&hdr, fp); if (points) { + printf("points:\n"); for (uint32_t n = 0; n < hdr.num_points; ++n) { printf(" point %u: %.6g %.6g %.6g\n", @@ -149,9 +208,9 @@ static int SrfDump(FILE *fp) } uint32_t image_table = ftell(fp); - printf(" image table: %#08x\n", image_table); + printf("image table: %#08x\n", image_table); uint32_t *offsets = ReadImageTable(&hdr, fp); - uint32_t table_base = ftell(fp); + if (offsets) { if (hdr.num_images < 10) @@ -159,27 +218,67 @@ static int SrfDump(FILE *fp) for (uint32_t n = 0; n < hdr.num_images + 1; ++n) printf(" %u: %#08x\n", n, offsets[n]); } - printf(" image base: %#08x\n", table_base); +#if 0 #ifdef WIN32 _tmkdir(_T("images")); #else mkdir("images", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); #endif // !WIN32 +#endif for (uint32_t n = 0; n < hdr.num_images; ++n) { + SurfaceImageInfo info = { 0 }; + fseek(fp, offsets[n], SEEK_SET); + fread(&info, sizeof(SurfaceImageInfo5), 1, fp); + if (hdr.revision >= 8) + { + SurfaceImageInfo8 *ptr = (SurfaceImageInfo8 *)&info.rotation_angle; + fread(ptr, sizeof(SurfaceImageInfo8), 1, fp); + } + if (hdr.revision >= 9) + { + SurfaceImageInfo9 *ptr = (SurfaceImageInfo9 *)&info.objective; + fread(ptr, sizeof(SurfaceImageInfo9), 1, fp); + } + + uint32_t image_size = 0; + exif_item_t *items = NULL; + if (hdr.revision < 7) + { + fread(&image_size, sizeof(uint32_t), 1, fp); + items = jpegrdr_get_exif(fp, logger); + } + else + { + fread(&info.width, sizeof(uint32_t), 2, fp); + info.imagepath = read_name(fp); + info.backuppath = read_name(fp); + + wchar_t wfilename[260] = {0}; + + mbstowcs(wfilename, filename, strlen(filename)); + wchar_t *ext = wcsrchr(wfilename, L'\\'); + assert(ext != NULL); + ext[1] = L'\0'; + wcscat(wfilename, hdr.dirname); + wcscat(wfilename, L"\\"); + wcscat(wfilename, info.imagepath); + FILE *imagefp = _wfopen(wfilename, L"rb"); + assert(imagefp != NULL); + items = jpegrdr_get_exif(imagefp, logger); + fclose(imagefp); + } + +#if 0 TCHAR name[32 + 16] = {0}; _stprintf(name, _T("images/img%u.jpg"), n); + FILE *fp2 = _tfopen(name, "wb"); if (fp2 == NULL) { _tperror("fopen image file"); exit(1); } - - uint32_t image_section_size = offsets[n + 1] - offsets[n] - sizeof(SurfaceImageInfo); - SurfaceImageInfo info = { 0 }; - fseek(fp, offsets[n], SEEK_SET); - fread(&info, sizeof(SurfaceImageInfo), 1, fp); - size_t len = fcopy(fp, fp2, info.image_size); + size_t len = fcopy(fp, fp2, image_size); fclose(fp2); // For revision > 2 we have the size of the 'original' image if present and the image data. if (hdr.revision > 2) @@ -190,39 +289,55 @@ static int SrfDump(FILE *fp) len += sizeof(backup_size) + backup_size; // account for 'backup image' and its size printf(" orig:%u: %u\n", n, backup_size); } - - printf(" img:%u: %#08x @(%.3f,%.3f,%.3f) fov:%.3f,%.3f res:%u,%u off:%d,%d siz:%#08x\n", - n, offsets[n], +#endif + printf(" img %u: %u@%#08x @(%.3f,%.3f,%.3f) fov:%.3f,%.3f res:%u,%u off:%d,%d\n", + n, image_size, offsets[n], info.point.x, info.point.y, info.point.z, info.image_width_microns, info.image_height_microns, info.resolution_x, info.resolution_y, - info.xoffset, info.yoffset, info.image_size); - if ((len - image_section_size) != 0) + info.xoffset, info.yoffset); + if (hdr.revision >= 7) + { + char path[256] = { 0 }; + wcstombs(path, info.imagepath, sizeof(path)); + printf(" image: %s\n", path); + if (info.backuppath != NULL && info.backuppath[0] != L'\0') + { + wcstombs(path, info.backuppath, sizeof(path)); + printf(" original: %s\n", path); + } + } + if (items) { - printf(" image size error of %zu bytes\n", (len - image_section_size)); + for (exif_item_t* item = items; item; item = item->nextPtr) + { + if (!(item->tag == 0x010f || item->tag == 0x010e)) + exif_print_item(stdout, item, " "); + } + exif_free(items); } + + free(info.imagepath); + free(info.backuppath); } free(offsets); + free(hdr.dirname); } + fclose(fp); return r; } -int _tmain(int argc, TCHAR *argv[]) +int main(int argc, char *const argv[]) { + // add `-debug` to enable more log output + // add `-info` to just read the main header and output csv + // add `-export dirname` to output the images for rev < 7 surfaces if (argc != 2) { - _fputts(_T("usage: srfdump filename"), stderr); + fputs("usage: srfdump filename", stderr); return 1; } - FILE *fp = _tfopen(argv[1], _T("rb")); - if (fp == NULL) { - _tperror(_T("fopen")); - return 1; - } - - int r = SrfDump(fp); - - fclose(fp); + int r = SrfDump(argv[1]); return r; } diff --git a/srfinfo.c b/srfinfo.c index e1bf9f7..579d10f 100644 --- a/srfinfo.c +++ b/srfinfo.c @@ -2,7 +2,7 @@ * * Print out some header information from a surface file. */ - + #include #include #include @@ -31,9 +31,11 @@ static int SrfInfo(const char *filename, FILE *fp) hdrsize += sizeof(SurfaceFileHeaderRev4); if (hdr.revision > 4) hdrsize += sizeof(SurfaceFileHeaderRev5); + if (hdr.revision > 8) + hdrsize += sizeof(SurfaceFileHeaderRev9); fseek(fp, 0, SEEK_SET); fread(&hdr, hdrsize, 1, fp); - + char ver[5] = { 0 }; memcpy(ver, &hdr.fileversion, 4); char path[1024] = { 0 }; diff --git a/surfacefile.h b/surfacefile.h index 26e9c53..5232c84 100644 --- a/surfacefile.h +++ b/surfacefile.h @@ -19,6 +19,11 @@ typedef struct SurfaceExtents { double max_y; } SurfaceExtents; +typedef struct SurfacePoint2 { + double x; + double y; +} SurfacePoint2; + typedef struct SurfacePoint { double x; double y; @@ -40,6 +45,13 @@ typedef struct SurfaceTranslationCoords { float ztrans; } SurfaceTranslationCoords; +typedef struct SurfaceMotorPositionInfo { + SurfacePoint stage_min; // minimum position in firmware steps + SurfacePoint stage_max; // maximum position in firmware steps + SurfacePoint2 reference; // reference position in firmware steps + SurfacePoint2 resolution; // motor steps per unit (x and y) +} SurfaceMotorPositionInfo; + typedef struct SurfaceFileHeaderRev0 { uint32_t fileversion; uint16_t revision; @@ -65,6 +77,15 @@ typedef struct SurfaceFileHeaderRev5 { uint8_t extrapolation_mode; } SurfaceFileHeaderRev5; +typedef struct SurfaceFileHeaderRev7 { + wchar_t* dirname; +} SurfaceFileHeaderRev7; + +typedef struct SurfaceFileHeaderRev9 { + double objective; + struct SurfaceMotorPositionInfo motor_info; +} SurfaceFileHeaderRev9; + typedef struct SurfaceFileHeader { struct { uint32_t fileversion; @@ -86,9 +107,16 @@ typedef struct SurfaceFileHeader { struct { uint8_t extrapolation_mode; }; + struct { + double objective; + struct SurfaceMotorPositionInfo motor_info; + }; + struct { + wchar_t* dirname; + }; } SurfaceFileHeader; -typedef struct SurfaceImageInfo +typedef struct SurfaceImageInfo5 { /// Position of the top left point of the image in microns /// EXIF custom field 0xFEA0 @@ -107,8 +135,50 @@ typedef struct SurfaceImageInfo int xoffset; /// Vertical offset in pixels (from where?) int yoffset; - /// Size of the stored image data in bytes. - uint32_t image_size; +} SurfaceImageInfo5; + +typedef struct SurfaceImageInfo7 { + uint32_t width; + uint32_t height; + wchar_t *imagepath; + wchar_t *backuppath; +} SurfaceImageInfo7; + +typedef struct SurfaceImageInfo8 { + /// Rotation angle in degrees + double rotationAngle; + /// Rotation center in microns + SurfacePoint2 rotation_center; +} SurfaceImageInfo8; + +typedef struct SurfaceImageInfo9 { + /// Objective magnification + double objective; +} SurfaceImageInfo9; + +typedef struct SurfaceImageInfo { + struct { + struct SurfacePoint point; + double image_width_microns; + double image_height_microns; + uint32_t resolution_x; + uint32_t resolution_y; + int xoffset; + int yoffset; + }; + struct { // rev 8 + double rotation_angle; + SurfacePoint2 rotation_center; + }; + struct { // rev 9 + double objective; + }; + struct { // rev 7 + uint32_t width; + uint32_t height; + wchar_t *imagepath; + wchar_t *backuppath; + }; } SurfaceImageInfo; #pragma pack(pop)