如何使用 LibTiff 从头开始生成 Adobe DNG 图像
How to produce an Adobe DNG image from scratch with LibTiff
我正在尝试使用 libTiff 从头开始为我的特定相机 RAW 文件生成 Adobe DNG 文件。为此,我写了一个例子来生成一个应该是全黑的 DNG。但是,我无法打开我的结果,我怀疑我的代码有问题或遗漏了什么。
#include <stdlib.h>
#include <string.h>
#include <sys\stat.h>
#include <time.h>
#include <math.h>
#include <errno.h>
#include <tiffio.h>
#define HPIXELS 2048 // number of horizontal pixels on PointGrey Grasshopper3 GS3-U3-41C6C sensor
#define VPIXELS 2048 // number of vertical pixels on PointGrey Grasshopper3 GS3-U3-41C6C sensor
int main(int argc, char **argv) {
static const short CFARepeatPatternDim[] = { 2,2 }; // 2x2 CFA
static const float cam_xyz[] = {
2.005, -0.771, -0.269,
-0.752, 1.688, 0.064,
-0.149, 0.283, 0.745 }; // xyz
static const double sRGB[] = {
3.6156, -0.8100, -0.0837,
-0.3094, 1.5500, -0.5439,
0.0967, -0.4700, 1.9805 }; // sRGB profile
static const float neutral[] = { 0.807133, 1.0, 0.913289 };
const int bpp = 8;
const char* fname = "C:\tmp\dngTest\output.DNG";
long sub_offset = 0;
long white = 0xffff;
struct stat st;
struct tm tm;
char datetime[64];
FILE *ifp;
TIFF *tif;
// ============================================================================
stat(fname, &st);
gmtime_s(&tm, &st.st_mtime);
sprintf(datetime, "%04d:%02d:%02d %02d:%02d:%02d",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
if (!(tif = TIFFOpen("C:\tmp\dngTest\output.dng", "w"))) {
fclose(ifp);
exit(-1);
}
// Set meta data
TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 1);
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, HPIXELS >> 4);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, VPIXELS >> 4);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(tif, TIFFTAG_MAKE, "PointGrey");
TIFFSetField(tif, TIFFTAG_MODEL, "Grasshopper3 GS3-U3-41C6C");
TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_SOFTWARE, "primus_dng");
TIFFSetField(tif, TIFFTAG_DATETIME, datetime);
TIFFSetField(tif, TIFFTAG_SUBIFD, 1, &sub_offset);
TIFFSetField(tif, TIFFTAG_DNGVERSION, "[=10=]1[=10=]1[=10=][=10=]");
TIFFSetField(tif, TIFFTAG_DNGBACKWARDVERSION, "[=10=]1[=10=][=10=][=10=]");
TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, "PointGrey Grasshopper3 GS3-U3-41C6C");
TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, cam_xyz);
TIFFSetField(tif, TIFFTAG_ASSHOTNEUTRAL, 3, neutral);
TIFFSetField(tif, TIFFTAG_CALIBRATIONILLUMINANT1, 21);
// TIFFSetField(tif, TIFFTAG_ORIGINALRAWFILENAME, fname); TODO enable when clear not to crash
// All Black Thumbnail
{
unsigned char *buf = (unsigned char *)malloc((int)HPIXELS >> 4);
memset(buf, 0, (int)HPIXELS >> 4);
for (int row = 0; row < (int)VPIXELS>> 4; row++)
TIFFWriteScanline(tif, buf, row, 0); // just leave it black, no software uses the built-in preview, builds off real image.
}
TIFFWriteDirectory(tif);
// fprintf(stderr, "Writing TIFF header for main image...\n");
TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0); // image
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, HPIXELS); // in pixels
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, VPIXELS); // in pixels
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); // int
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, bpp);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, CFARepeatPatternDim);
TIFFSetField(tif, TIFFTAG_CFAPATTERN, "[=10=]0[=10=]1[=10=]1[=10=]2"); // RGGB // 0 = Red, 1 = Green, 2 = Blue, 3 = Cyan, 4 = Magenta, 5 = Yellow, 6 = White
//TIFFSetField(tif, TIFFTAG_LINEARIZATIONTABLE, 256, curve); set it off for now
TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, &white);
fprintf(stderr, "Processing RAW data...\n");
// bit depth
unsigned char *pLine = (unsigned char*)malloc(sizeof(unsigned char) * HPIXELS);
memset(pLine, 0, sizeof(unsigned char) * HPIXELS);
for (int row = 0; row < VPIXELS; row++)
{
TIFFWriteScanline(tif, pLine, row, 0); // this writes a single complete row
}
free(pLine);
TIFFClose(tif);
return 0;
}
最小的完整示例是leaned on this.我正在使用 RGGB 拜耳电池。切换到 Adobe DNG SDK 是我真正想避免的事情,因为使用 VS2015 或更高版本构建库是一团糟。
示例程序按预期运行。我在实际上是 GRGB 和
的拜耳模式上犯了一个错误
TIFFSetField(tif, TIFFTAG_CFAPATTERN, "[=10=]1[=10=]0[=10=]1[=10=]2");
我正在尝试使用 libTiff 从头开始为我的特定相机 RAW 文件生成 Adobe DNG 文件。为此,我写了一个例子来生成一个应该是全黑的 DNG。但是,我无法打开我的结果,我怀疑我的代码有问题或遗漏了什么。
#include <stdlib.h>
#include <string.h>
#include <sys\stat.h>
#include <time.h>
#include <math.h>
#include <errno.h>
#include <tiffio.h>
#define HPIXELS 2048 // number of horizontal pixels on PointGrey Grasshopper3 GS3-U3-41C6C sensor
#define VPIXELS 2048 // number of vertical pixels on PointGrey Grasshopper3 GS3-U3-41C6C sensor
int main(int argc, char **argv) {
static const short CFARepeatPatternDim[] = { 2,2 }; // 2x2 CFA
static const float cam_xyz[] = {
2.005, -0.771, -0.269,
-0.752, 1.688, 0.064,
-0.149, 0.283, 0.745 }; // xyz
static const double sRGB[] = {
3.6156, -0.8100, -0.0837,
-0.3094, 1.5500, -0.5439,
0.0967, -0.4700, 1.9805 }; // sRGB profile
static const float neutral[] = { 0.807133, 1.0, 0.913289 };
const int bpp = 8;
const char* fname = "C:\tmp\dngTest\output.DNG";
long sub_offset = 0;
long white = 0xffff;
struct stat st;
struct tm tm;
char datetime[64];
FILE *ifp;
TIFF *tif;
// ============================================================================
stat(fname, &st);
gmtime_s(&tm, &st.st_mtime);
sprintf(datetime, "%04d:%02d:%02d %02d:%02d:%02d",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
if (!(tif = TIFFOpen("C:\tmp\dngTest\output.dng", "w"))) {
fclose(ifp);
exit(-1);
}
// Set meta data
TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 1);
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, HPIXELS >> 4);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, VPIXELS >> 4);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(tif, TIFFTAG_MAKE, "PointGrey");
TIFFSetField(tif, TIFFTAG_MODEL, "Grasshopper3 GS3-U3-41C6C");
TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_SOFTWARE, "primus_dng");
TIFFSetField(tif, TIFFTAG_DATETIME, datetime);
TIFFSetField(tif, TIFFTAG_SUBIFD, 1, &sub_offset);
TIFFSetField(tif, TIFFTAG_DNGVERSION, "[=10=]1[=10=]1[=10=][=10=]");
TIFFSetField(tif, TIFFTAG_DNGBACKWARDVERSION, "[=10=]1[=10=][=10=][=10=]");
TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, "PointGrey Grasshopper3 GS3-U3-41C6C");
TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, cam_xyz);
TIFFSetField(tif, TIFFTAG_ASSHOTNEUTRAL, 3, neutral);
TIFFSetField(tif, TIFFTAG_CALIBRATIONILLUMINANT1, 21);
// TIFFSetField(tif, TIFFTAG_ORIGINALRAWFILENAME, fname); TODO enable when clear not to crash
// All Black Thumbnail
{
unsigned char *buf = (unsigned char *)malloc((int)HPIXELS >> 4);
memset(buf, 0, (int)HPIXELS >> 4);
for (int row = 0; row < (int)VPIXELS>> 4; row++)
TIFFWriteScanline(tif, buf, row, 0); // just leave it black, no software uses the built-in preview, builds off real image.
}
TIFFWriteDirectory(tif);
// fprintf(stderr, "Writing TIFF header for main image...\n");
TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0); // image
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, HPIXELS); // in pixels
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, VPIXELS); // in pixels
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); // int
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, bpp);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, CFARepeatPatternDim);
TIFFSetField(tif, TIFFTAG_CFAPATTERN, "[=10=]0[=10=]1[=10=]1[=10=]2"); // RGGB // 0 = Red, 1 = Green, 2 = Blue, 3 = Cyan, 4 = Magenta, 5 = Yellow, 6 = White
//TIFFSetField(tif, TIFFTAG_LINEARIZATIONTABLE, 256, curve); set it off for now
TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, &white);
fprintf(stderr, "Processing RAW data...\n");
// bit depth
unsigned char *pLine = (unsigned char*)malloc(sizeof(unsigned char) * HPIXELS);
memset(pLine, 0, sizeof(unsigned char) * HPIXELS);
for (int row = 0; row < VPIXELS; row++)
{
TIFFWriteScanline(tif, pLine, row, 0); // this writes a single complete row
}
free(pLine);
TIFFClose(tif);
return 0;
}
最小的完整示例是leaned on this.我正在使用 RGGB 拜耳电池。切换到 Adobe DNG SDK 是我真正想避免的事情,因为使用 VS2015 或更高版本构建库是一团糟。
示例程序按预期运行。我在实际上是 GRGB 和
的拜耳模式上犯了一个错误TIFFSetField(tif, TIFFTAG_CFAPATTERN, "[=10=]1[=10=]0[=10=]1[=10=]2");