From: Pat Thoyts Date: Wed, 10 Oct 2018 20:25:29 +0000 (+0100) Subject: Initial version of an srfdump surface file dump utility. X-Git-Url: http://privyetmir.co.uk/gitweb.cgi?a=commitdiff_plain;h=1ed16fc171c12665e6c451eae53e671c19289082;p=srfdump Initial version of an srfdump surface file dump utility. --- 1ed16fc171c12665e6c451eae53e671c19289082 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..092e06e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true +[*.{c,h}] +charset = utf-8 +indent_style = space +indent_size = 4 +tab_width = 4 +trim_trailing_whitespace = true +insert_final_newline = true + +[CMakeLists.txt] +charset = utf-8 +indent_style = space diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..23520ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vscode/ +build/ +images/ +*.srf diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..84ff98b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true, + "**/images": true, + "**/build": true + }, + "cppcheck.standard": [ + "c11", + "c++14" + ], + "cppcheck.language": "c" +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..264d9c6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.0) +project(srfdump VERSION 1.0) + +if (MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +else() + add_definitions(-pedantic) +endif() + +set(CMAKE_C_STANDARD 11) + +set(SOURCE srfdump.c) +add_executable(${PROJECT_NAME} ${SOURCE}) +set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11) diff --git a/compat/tchar.h b/compat/tchar.h new file mode 100644 index 0000000..f4e14a6 --- /dev/null +++ b/compat/tchar.h @@ -0,0 +1,17 @@ +/* Compatability definitions for building Windows TCHAR type + * code on Linux. + */ + +#ifndef _compat_tchar_h_INCLUDE +#define _compat_tchar_h_INCLUDE + +#define _T(x) (x) +#define TCHAR char +#define _tmain main +#define _tprintf printf +#define _stprintf sprintf +#define _fputts fputs +#define _tfopen fopen +#define _tperror perror + +#endif /* _compat_tchar_h_INCLUDE */ diff --git a/srfdump.c b/srfdump.c new file mode 100644 index 0000000..78e68fc --- /dev/null +++ b/srfdump.c @@ -0,0 +1,202 @@ +/* Copyright (c) 2018 Pat Thoyts + * + * Examine a Renishaw .srf surface file and dump the contents. + * All images are exported to an images/ subdirectory with an accompanying + * data file containing the additional data stored for each image. + */ + +#include +#include +#include +#include +#include +#include "surfacefile.h" + +#ifdef WIN32 +#include +#else +#include "compat/tchar.h" +#endif /* !WIN32 */ + +static size_t fcopy(FILE *src, FILE *dst, size_t count) +{ + size_t total = 0, n = 0; + char buf[4096]; + do { + n = fread(buf, 1, sizeof(buf), src); + total += fwrite(buf, 1, n, dst); + } while (n == sizeof(buf)); + return total; +} + +static uint32_t * ReadImageTable(SurfaceFileHeader *hdrPtr, FILE *fp) +{ + uint32_t *table = NULL; + if (hdrPtr->num_images > 0) + { + table = (uint32_t *)malloc(sizeof(uint32_t) * (hdrPtr->num_images + 1)); + fread(table + 1, sizeof(uint32_t), hdrPtr->num_images, fp); + // set first image to the end of the table. + table[0] = ftell(fp); + // convert offsets from relative to table to file absolute positions + for (int n = 1; n < hdrPtr->num_images+1; ++n) + table[n] += table[0]; + } + return table; +} + +static SurfaceTriangle * ReadTriangles(SurfaceFileHeader *hdrPtr, FILE *fp) +{ + SurfaceTriangle *triangles = NULL; + if (hdrPtr->num_triangles > 0) + { + triangles = (SurfaceTriangle *)malloc(sizeof(SurfaceTriangle) * hdrPtr->num_triangles); + fread(triangles, sizeof(SurfaceTriangle), hdrPtr->num_triangles, fp); + } + return triangles; +} + +static SurfacePoint * ReadPoints(SurfaceFileHeader *hdrPtr, FILE *fp) +{ + SurfacePoint *points = NULL; + if (hdrPtr->num_points > 0) + { + points = (SurfacePoint *)malloc(sizeof(SurfacePoint) * hdrPtr->num_points); + double *buffer = (double *)malloc(sizeof(double) * hdrPtr->num_points); + fread(buffer, sizeof(double), hdrPtr->num_points, fp); + for (int n = 0; n < hdrPtr->num_points; ++n) + points[n].x = buffer[n]; + fread(buffer, sizeof(double), hdrPtr->num_points, fp); + for (int n = 0; n < hdrPtr->num_points; ++n) + points[n].y = buffer[n]; + fread(buffer, sizeof(double), hdrPtr->num_points, fp); + for (int n = 0; n < hdrPtr->num_points; ++n) + points[n].z = buffer[n]; + free(buffer); + } + return points; +} + +static int SrfDump(FILE *fp) +{ + int r = 0; + SurfaceFileHeader hdr = {0}; + fread(&hdr, sizeof(SurfaceFileHeaderRev0), 1, fp); + size_t hdrsize = sizeof(SurfaceFileHeaderRev0); + if (hdr.revision > 1) + hdrsize += sizeof(SurfaceFileHeaderRev2); + if (hdr.revision > 2) + hdrsize += sizeof(SurfaceFileHeaderRev3); + if (hdr.revision > 3) + hdrsize += sizeof(SurfaceFileHeaderRev4); + if (hdr.revision > 4) + hdrsize += sizeof(SurfaceFileHeaderRev5); + fseek(fp, 0, SEEK_SET); + fread(&hdr, hdrsize, 1, fp); + + char ver[5] = {0}; + memcpy(ver, &hdr.fileversion, 4); + printf("ver: %s rev: %d points: %u tri: %u images: %u\n", ver, hdr.revision, hdr.num_points, hdr.num_triangles, hdr.num_images); + if (hdr.revision > 1) + printf(_T("translation: %.6f, %.6f, %.6f\n"), hdr.translation.xtrans, hdr.translation.ytrans, hdr.translation.ztrans); + if (hdr.revision > 2) + { + printf("image extents: (%.6g,%.6g) -> (%.6g,%.6g)\n", + hdr.image_extents.min_x, hdr.image_extents.min_y, + hdr.image_extents.max_x, hdr.image_extents.max_y); + printf("surface extents: (%.6g,%.6g) -> (%.6g,%.6g)\n", + hdr.surface_extents.min_x, hdr.surface_extents.min_y, + hdr.surface_extents.max_x, hdr.surface_extents.max_y); + } + if (hdr.revision > 3) + 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); + + SurfacePoint *points = ReadPoints(&hdr, fp); + if (points) + { + for (int n = 0; n < hdr.num_points; ++n) + { + printf(" point %d: %.6g %.6g %.6g\n", + n, points[n].x, points[n].y, points[n].z); + } + free(points); + } + + SurfaceTriangle *triangles = ReadTriangles(&hdr, fp); + if (triangles) + { + printf(" TRIANGLES: FIX ME\n"); + free(triangles); + } + + uint32_t *offsets = ReadImageTable(&hdr, fp); + uint32_t table_base = ftell(fp); + if (offsets) + { + printf(" image base: %#08x\n", table_base); + mkdir("images", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + for (int n = 0; n < hdr.num_images; ++n) + { + uint32_t image_size = offsets[n+1] - offsets[n] - 60; + printf(" image %d: %#08x size %#04x\n", + n, offsets[n], image_size); + + TCHAR name[32 + 16] = {0}; + _stprintf(name, _T("images/img%d.jpg"), n); + FILE *fp2 = _tfopen(name, "w"); + if (fp2 == NULL) { + _tperror("fopen"); + exit(1); + } + // TODO: deal with the 60 bytes of additional data per image.... + // first 24 bytes are the image point position + // { + // SurfacePoint point; // in um + // double image_width_microns; // field of view x + // double image_height_microns; // field of view y + // uint32_t image_width; // in pixels ? + // uint32_t image_height; // in pixels ? + // uint32_t unknown[3]; + // } + fseek(fp, offsets[n], SEEK_SET); + + char data[60] = {0}; + fread(data, 1, 60, fp); + fcopy(fp, fp2, image_size); + fclose(fp2); + + _stprintf(name, _T("images/img%d.dat"), n); + fp2 = _tfopen(name, "w"); + if (fp2 == NULL) { + _tperror("fopen data"); + exit(1); + } + fwrite(data, 1, 60, fp2); + fclose(fp2); + } + free(offsets); + } + + return r; +} + +int _tmain(int argc, TCHAR *argv[]) +{ + if (argc != 2) { + _fputts(_T("usage: srfdump filename"), stderr); + return 1; + } + + FILE *fp = _tfopen(argv[1], _T("r")); + if (fp == NULL) { + _tperror(_T("fopen")); + return 1; + } + + int r = SrfDump(fp); + + fclose(fp); + return r; +} diff --git a/surfacefile.h b/surfacefile.h new file mode 100644 index 0000000..1582ec4 --- /dev/null +++ b/surfacefile.h @@ -0,0 +1,96 @@ +#ifndef _SurfaceFile_h_INCLUDE +#define _SurfaceFile_h_INCLUDE + +#if defined(__cplusplus) +extern "C" { +#endif + +#include + +#define SURFACE_FILE_VERSION 0x46525553UL /* 'S' 'U' 'R' 'F' */ +#define SURFACE_FILE_REVISION 5 + +#pragma pack(push,1) + +typedef struct SurfaceExtents { + double min_x; + double max_x; + double min_y; + double max_y; +} SurfaceExtents; + +typedef struct SurfacePoint { + double x; + double y; + double z; +} SurfacePoint; + +typedef struct SurfaceTriangle { + int a; + int b; + int c; + int ab; + int bc; + int ca; +} SurfaceTriangle; + +typedef struct SurfaceTranslationCoords { + float xtrans; + float ytrans; + float ztrans; +} SurfaceTranslationCoords; + +typedef struct SurfaceFileHeaderRev0 { + uint32_t fileversion; + uint16_t revision; + uint32_t num_points; + uint32_t num_triangles; + uint32_t num_images; +} SurfaceFileHeaderRev0; + +typedef struct SurfaceFileHeaderRev2 { + struct SurfaceTranslationCoords translation; +} SurfaceFileHeaderRev2; + +typedef struct SurfaceFileHeaderRev3 { + struct SurfaceExtents image_extents; + struct SurfaceExtents surface_extents; +} SurfaceFileHeaderRev3; + +typedef struct SurfaceFileHeaderRev4 { + uint8_t use_background_removal; // boolean +} SurfaceFileHeaderRev4; + +typedef struct SurfaceFileHeaderRev5 { + uint8_t extrapolation_mode; +} SurfaceFileHeaderRev5; + +typedef struct SurfaceFileHeader { + struct { + uint32_t fileversion; + uint16_t revision; + uint32_t num_points; + uint32_t num_triangles; + uint32_t num_images; + }; + struct { + struct SurfaceTranslationCoords translation; + }; + struct { + struct SurfaceExtents image_extents; + struct SurfaceExtents surface_extents; + }; + struct { + uint8_t use_background_removal; + }; + struct { + uint8_t extrapolation_mode; + }; +} SurfaceFileHeader; + +#pragma pack(pop) + +#if defined(__cplusplus) +} +#endif +#endif // _SurfaceFile_h_INCLUDE