1 /***************************************************
2 nikon_curve.c - read Nikon NTC/NCV files
3
4 Copyright 2004-2007 by Shawn Freeman, Udi Fuchs
5
6 This program reads in a Nikon NTC/NCV file,
7 interperates it's tone curve, and writes out a
8 simple ASCII file containing a table of interpolation
9 values. See the header file for more information.
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License version 2
13 as published by the Free Software Foundation. You should have received
14 a copy of the license along with this program.
15
16 ****************************************************/
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <math.h>
22 #include <errno.h>
23 #include <stdarg.h> /* For variable argument lists */
24 #include "SimpleNikonCurve.h"
25
26 #ifdef __WITH_UFRAW__
27 #include "uf_glib.h"
28 #include "ufraw.h"
29 #else
30 #define MAX(a,b) ((a) > (b) ? (a) : (b))
31 #define MIN(a,b) ((a) < (b) ? (a) : (b))
32 #define g_fopen fopen
33 #endif
34
35 /*************************************************
36 * Internal static data
37 *************************************************/
38
39 //file offsets for the different data in different file types
40 static const int FileOffsets[2][4] = {
41 {NTC_PATCH_OFFSET,NTC_BOX_DATA, NTC_NUM_ANCHOR_POINTS, NTC_ANCHOR_DATA_START},
42 {NCV_PATCH_OFFSET,NCV_BOX_DATA, NCV_NUM_ANCHOR_POINTS, NCV_ANCHOR_DATA_START},
43 };
44
45 //file header indicating ntc file
46 static const unsigned char NTCFileHeader[] = {0x9d,0xdc,0x7d,0x00,0x65,0xd4,
47 0x11,0xd1,0x91,0x94,0x44,0x45,0x53,0x54,0x00,0x00};
48
49 //file header indicating an ncv file
50 static const unsigned char NCVFileHeader[] = {0x40,0xa9,0x86,0x7a,0x1b,0xe9,
51 0xd2,0x11,0xa9,0x0a,0x00,0xaa,0x00,0xb1,0xc1,0xb7};
52
53 //This is an additional header chunk at the beginning of the file
54 //There are some similarities between the headers, but not enough to fully crack.
55 //This does not appear to change.
56 static const unsigned char NCVSecondFileHeader[] = {0x01,0x32,0xa4,0x76,0xa2,
57 0x17,0xd4,0x11,0xa9,0x0a,0x00,0xaa,0x00,0xb1,0xc1,
58 0xb7,0x01,0x00,0x05,0x00,0x00,0x00,0x01};
59
60 //This is the terminator of an NCV file. Again there are some similarites
61 //to other sections, but not enough for to crack what it means. However,
62 //it does not appear to change.
63 static const unsigned char NCVFileTerminator[] = {0x45,0xd3,0x0d,0x77,0xa3,0x6e,
64 0x1e,0x4e,0xa4,0xbe,0xcf,0xc1,0x8e,0xb5,0xb7,0x47,
65 0x01,0x00,0x05,0x00,0x00,0x00,0x01 };
66
67 //File section header. Only a one byte difference between this and an NTC file header
68 static const unsigned char FileSectionHeader[] = {0x9d,0xdc,0x7d,0x03,0x65,0xd4,
69 0x11,0xd1,0x91,0x94,0x44,0x45,0x53,0x54,0x00,0x00};
70 //file type header array
71 static const unsigned char *FileTypeHeaders[NUM_FILE_TYPES] = {
72 NTCFileHeader,
73 NCVFileHeader,
74 };
75
76 /**STANDALONE**/
77 #ifdef _STAND_ALONE_
78
79 //filenames
80 char exportFilename[1024];
81 char nikonFilename[1024];
82
83 unsigned int standalone_samplingRes = 65536;
84 unsigned int standalone_outputRes = 256;
85 unsigned int program_mode = CURVE_MODE;
86
87 /*******************************************
88 ProcessArgs:
89 Convenient function for processing the args
90 for the test runner.
91 ********************************************/
ProcessArgs(int num_args,char * args[])92 int ProcessArgs(int num_args, char *args[])
93 {
94 exportFilename[0] = '\0';
95 nikonFilename[0] = '\0';
96
97 int i;
98 for(i = 0; i < num_args; i++)
99 {
100 if (strcmp(args[i],"-h") == 0 || strcmp(args[i],"-H") == 0 || num_args <= 1)
101 {
102 printf("NikonCurveGenerator %s %s\n",NC_VERSION, NC_DATE);
103 printf("Written by Shawn Freeman\n");
104 printf("Thanks go out to Udi Fuchs, UFRaw, and GIMP :)\n\n");
105 printf("Usage:\n");
106 printf("-nef Specify an NEF file to get tone curve data from.\n\n");
107
108 //signal that processing cannot occur
109 return NC_ERROR;
110 }
111 else if (strcmp(args[i],"-nef") == 0)
112 {
113 i++;
114 program_mode = NEF_MODE;
115 strncpy(nikonFilename, args[i], 1023);
116 nikonFilename[1023] = '\0';
117 }
118 //don't load argument 0
119 else if (i != 0)
120 {
121 //consider this the file name to load
122 strncpy(nikonFilename, args[i], 1023);
123 nikonFilename[1023] = '\0';
124 }
125 }
126
127 if (strlen(exportFilename) == 0)
128 {
129 //set it to have a default output file name
130 strncpy(exportFilename, nikonFilename, 1023);
131 exportFilename[1023] = '\0';
132 int StrLen = strlen(exportFilename);
133 for (short i=strlen(exportFilename);exportFilename[i] != '.'; i--) {
134 exportFilename[i]=0;
135 }
136 strncat(exportFilename, "anchors", 1023);
137 exportFilename[1023] = '\0';
138 }
139
140 return NC_SUCCESS;
141 }
142 #endif //End STAND_ALONE
143
144 /************************************************************
145 nc_message_handler:
146 The Nikon Curve message handler. Udi Fuchs created this
147 to make the error hanpting consistent acros the code.
148
149 code - Message code
150 message - The message
151 **************************************************************/
nc_message(int code,char * format,...)152 void nc_message(int code, char *format, ...)
153 {
154 char message[256];
155 va_list ap;
156 va_start(ap, format);
157
158 vsnprintf(message, 255, format, ap);
159 message[255] = '\0';
160 va_end(ap);
161
162 #ifdef _STAND_ALONE_ //if we're running standalone mode
163
164 code = code;
165 fprintf(stderr, message);
166 fflush(stderr);
167
168 #else
169
170 #ifdef __WITH_UFRAW__ //and if compiling with UFRAW
171
172 if (code==NC_SET_ERROR)
173 {
174 ufraw_message(UFRAW_SET_ERROR, message);
175 }
176 else
177 {
178 ufraw_message(code, message);
179 }
180
181 #else //else, just print out the errors normally
182
183 code = code;
184 g_printerr("%s", message);
185
186 #endif //End WITH_UFRAW
187
188 #endif //End STAND_ALONE
189 }
190
191 // #define _DEBUG
DEBUG_PRINT(char * format,...)192 void DEBUG_PRINT(char *format, ...)
193 {
194 #ifdef _DEBUG
195 va_list ap;
196 va_start(ap, format);
197 vfprintf(stderr, format, ap);
198 fflush(stderr);
199 va_end(ap);
200 #else
201 format = format;
202 #endif
203 }
204
205 /* nc_merror(): Handle memory allocaltion errors */
nc_merror(void * ptr,char * where)206 void nc_merror(void *ptr, char *where)
207 {
208 if (ptr) return;
209 #ifdef __WITH_UFRAW__
210 g_error("Out of memory in %s\n", where);
211 #else
212 fprintf(stderr, "Out of memory in %s\n", where);
213 exit(1);
214 #endif
215 }
216
217 // Assert something at compile time (must use this inside a function);
218 // works because compilers won't let us declare negative-length arrays.
219 #define STATIC_ASSERT(cond) \
220 { (void)((int (*)(char failed_static_assertion[(cond)?1:-1]))0); }
221
222 /***********************************************************************
223 isBigEndian:
224 Determines if the machine we are running on is big endian or not.
225 ************************************************************************/
isBigEndian()226 int isBigEndian()
227 {
228 STATIC_ASSERT(sizeof(short)==2);
229 short x;
230 unsigned char EndianTest[2] = { 1, 0 };
231
232 x = *(short *) EndianTest;
233
234 return (x!=1);
235 }
236
237 /***********************************************************************
238 ShortVal:
239 Convert short int (16 bit) from little endian to machine endianess.
240 ************************************************************************/
ShortVal(short s)241 short ShortVal(short s)
242 {
243 STATIC_ASSERT(sizeof(short)==2);
244 if (isBigEndian()) {
245 unsigned char b1, b2;
246
247 b1 = s & 255;
248 b2 = (s >> 8) & 255;
249
250 return (b1 << 8) + b2;
251 } else
252 return s;
253 }
254
255 /***********************************************************************
256 LongVal:
257 Convert long int (32 bit) from little endian to machine endianess.
258 ************************************************************************/
LongVal(int i)259 int LongVal(int i)
260 {
261 STATIC_ASSERT(sizeof(int)==4);
262 if (isBigEndian()) {
263 unsigned char b1, b2, b3, b4;
264
265 b1 = i & 255;
266 b2 = ( i >> 8 ) & 255;
267 b3 = ( i>>16 ) & 255;
268 b4 = ( i>>24 ) & 255;
269
270 return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4;
271 } else
272 return i;
273 }
274
275 /***********************************************************************
276 FloatVal:
277 Convert float from little endian to machine endianess.
278 ************************************************************************/
FloatVal(float f)279 float FloatVal(float f)
280 {
281 STATIC_ASSERT(sizeof(float)==4);
282 if (isBigEndian()) {
283 union {
284 float f;
285 unsigned char b[4];
286 } dat1, dat2;
287
288 dat1.f = f;
289 dat2.b[0] = dat1.b[3];
290 dat2.b[1] = dat1.b[2];
291 dat2.b[2] = dat1.b[1];
292 dat2.b[3] = dat1.b[0];
293 return dat2.f;
294 } else
295 return f;
296 }
297
298 /***********************************************************************
299 DoubleVal:
300 Convert double from little endian to machine endianess.
301 ************************************************************************/
DoubleVal(double d)302 double DoubleVal(double d)
303 {
304 STATIC_ASSERT(sizeof(double)==8);
305 if (isBigEndian()) {
306 union {
307 double d;
308 unsigned char b[8];
309 } dat1, dat2;
310
311 dat1.d = d;
312 dat2.b[0] = dat1.b[7];
313 dat2.b[1] = dat1.b[6];
314 dat2.b[2] = dat1.b[5];
315 dat2.b[3] = dat1.b[4];
316 dat2.b[4] = dat1.b[3];
317 dat2.b[5] = dat1.b[2];
318 dat2.b[6] = dat1.b[1];
319 dat2.b[7] = dat1.b[0];
320 return dat2.d;
321 } else
322 return d;
323 }
324
325 /*********************************************
326 GetNikonFileType:
327 Gets the nikon file type by comparing file
328 headers.
329
330 file - The file to check.
331 **********************************************/
GetNikonFileType(FILE * file)332 int GetNikonFileType(FILE *file)
333 {
334 unsigned char buff[HEADER_SIZE];
335 int i = 0, j = 0;
336 int found = 1;
337
338 fread(buff,HEADER_SIZE,1,file);
339
340 for(i = 0; i < NUM_FILE_TYPES; i++)
341 {
342 found = 1;
343 for(j = 0; j < HEADER_SIZE; j++)
344 {
345 if (buff[j] != FileTypeHeaders[i][j])
346 {
347 found = 0;
348 break;
349 }
350 }
351
352 if (found)
353 {
354 //return the file type
355 return i;
356 }
357 }
358 nc_message(NC_SET_ERROR, "Error, no compatible file types found!\n");
359 return -1;
360 }
361
362 /*********************************************
363 LoadNikonCurve:
364 Loads all curves from a Nikon ntc or ncv file.
365
366 fileName - The filename.
367 curve - Pointer to curve struct to hold the data.
368 resolution - How many data points to sample from the curve.
369 **********************************************/
LoadNikonData(char * fileName,NikonData * data)370 int LoadNikonData(char *fileName, NikonData *data)
371 {
372 FILE *input = NULL;
373 int offset = 0;
374 CurveData *curve = NULL;
375
376 if (fileName == NULL || strlen(fileName) == 0)
377 {
378 nc_message(NC_SET_ERROR,
379 "Error, input filename cannot be NULL or empty!\n");
380 return NC_ERROR;
381 }
382
383 DEBUG_PRINT("DEBUG: OPENING FILE: %s\n",fileName);
384
385 //open file for reading only!
386 input = g_fopen(fileName,"rb");
387
388 //make sure we have a valid file
389 if (input == NULL)
390 {
391 nc_message(NC_SET_ERROR, "Error opening '%s': %s\n",
392 fileName, strerror(errno));
393 return NC_ERROR;
394 }
395
396 //init the curve;
397 memset(data,0,sizeof(NikonData));
398
399 //get the file type
400 data->m_fileType = GetNikonFileType(input);
401 // set file seek positions for curve tones depending of file type
402 // todo: is it possible to find one common rule?
403 long curveFilePos[4][4] = {
404 {FileOffsets[data->m_fileType][BOX_DATA], SEEK_SET, FileOffsets[data->m_fileType][ANCHOR_DATA], SEEK_SET},
405 {NEXT_SECTION_BOX_DATA_OFFSET, SEEK_CUR, NUM_POINTS_TO_ANCHOR_OFFSET, SEEK_CUR},
406 {NEXT_SECTION_BOX_DATA_OFFSET, SEEK_CUR, NUM_POINTS_TO_ANCHOR_OFFSET, SEEK_CUR},
407 {NEXT_SECTION_BOX_DATA_OFFSET, SEEK_CUR, NUM_POINTS_TO_ANCHOR_OFFSET, SEEK_CUR}
408 };
409
410 //make sure we have a good file type
411 if (data->m_fileType == -1)
412 return NC_ERROR;
413
414 //advance file pointer to necessary data section
415 fseek(input,offset,SEEK_SET);
416
417 //Conevenience and opt if compiler doesn't already do it
418 curve = &data->curves[0];
419
420 //set curve type
421 curve->m_curveType = TONE_CURVE;
422
423 //read patch version
424 fseek(input,FileOffsets[data->m_fileType][PATCH_DATA],SEEK_SET);
425 fread(&data->m_patch_version,sizeof(unsigned short),1,input);
426 data->m_patch_version = ShortVal(data->m_patch_version);
427
428 // read all tone curves data follow from here
429 int i;
430 for(i = 0; i < NUM_CURVE_TYPES; i++)
431 {
432 curve = &data->curves[i];
433
434 //set curve type
435 curve->m_curveType = i;
436
437 //get box data
438 fseek(input, curveFilePos[i][0], curveFilePos[i][1]);
439
440 fread(&curve->m_min_x,sizeof(double),1,input);
441 curve->m_min_x = DoubleVal(curve->m_min_x);
442
443 fread(&curve->m_max_x,sizeof(double),1,input);
444 curve->m_max_x = DoubleVal(curve->m_max_x);
445
446 fread(&curve->m_gamma,sizeof(double),1,input);
447 curve->m_gamma = DoubleVal(curve->m_gamma);
448
449 fread(&curve->m_min_y,sizeof(double),1,input);
450 curve->m_min_y = DoubleVal(curve->m_min_y);
451
452 fread(&curve->m_max_y,sizeof(double),1,input);
453 curve->m_max_y = DoubleVal(curve->m_max_y);
454
455 //get number of anchors (always located after box data)
456 fread(&curve->m_numAnchors,1,1,input);
457
458 // It seems that if there is no curve then the 62 bytes in the buffer
459 // are either all 0x00 (D70) or 0xFF (D2H).
460 // We therefore switch these values with the default values.
461 if (curve->m_min_x==1.0) {
462 curve->m_min_x = 0.0;
463 DEBUG_PRINT("DEBUG: NEF X MIN -> %e (changed)\n",curve->m_min_x);
464 }
465 if (curve->m_max_x==0.0) {
466 curve->m_max_x = 1.0;
467 DEBUG_PRINT("DEBUG: NEF X MAX -> %e (changed)\n",curve->m_max_x);
468 }
469 if (curve->m_min_y==1.0) {
470 curve->m_min_y = 0.0;
471 DEBUG_PRINT("DEBUG: NEF Y MIN -> %e (changed)\n",curve->m_min_y);
472 }
473 if (curve->m_max_y==0.0) {
474 curve->m_max_y = 1.0;
475 DEBUG_PRINT("DEBUG: NEF Y MAX -> %e (changed)\n",curve->m_max_y);
476 }
477 if (curve->m_gamma==0.0 || curve->m_gamma==255.0+255.0/256.0) {
478 curve->m_gamma = 1.0;
479 DEBUG_PRINT("DEBUG: NEF GAMMA -> %e (changed)\n",curve->m_gamma);
480 }
481 if (curve->m_numAnchors==255) {
482 curve->m_numAnchors = 0;
483 DEBUG_PRINT("DEBUG: NEF NUMBER OF ANCHORS -> %u (changed)\n",
484 curve->m_numAnchors);
485 }
486 if (curve->m_numAnchors > NIKON_MAX_ANCHORS) {
487 curve->m_numAnchors = NIKON_MAX_ANCHORS;
488 DEBUG_PRINT("DEBUG: NEF NUMBER OF ANCHORS -> %u (changed)\n",
489 curve->m_numAnchors);
490 }
491 //Move to start of the anchor data
492 fseek(input, curveFilePos[i][2], curveFilePos[i][3]);
493
494 //read in the anchor points
495 int rs = fread(curve->m_anchors, sizeof(CurveAnchorPoint),
496 curve->m_numAnchors, input);
497 if (curve->m_numAnchors != rs) {
498 nc_message(NC_SET_ERROR, "Error reading all anchor points\n");
499 return NC_ERROR;
500 }
501
502 int j;
503 for (j = 0; j < curve->m_numAnchors; j++)
504 {
505 curve->m_anchors[j].x = DoubleVal(curve->m_anchors[j].x);
506 curve->m_anchors[j].y = DoubleVal(curve->m_anchors[j].y);
507 }
508
509 DEBUG_PRINT("DEBUG: Loading Data:\n");
510 DEBUG_PRINT("DEBUG: CURVE_TYPE: %u \n",curve->m_curveType);
511 DEBUG_PRINT("DEBUG: BOX->MIN_X: %f\n",curve->m_min_x);
512 DEBUG_PRINT("DEBUG: BOX->MAX_X: %f\n",curve->m_max_x);
513 DEBUG_PRINT("DEBUG: BOX->GAMMA: %f\n",curve->m_gamma);
514 DEBUG_PRINT("DEBUG: BOX->MIN_Y: %f\n",curve->m_min_y);
515 DEBUG_PRINT("DEBUG: BOX->MAX_Y: %f\n",curve->m_max_x);
516
517 #ifdef _DEBUG
518 int i_dbg;
519 for(i_dbg = 0; i_dbg < curve->m_numAnchors; i_dbg++)
520 {
521 DEBUG_PRINT("DEBUG: ANCHOR X,Y: %f,%f\n",
522 curve->m_anchors[i_dbg].x,curve->m_anchors[i_dbg].y);
523 }
524 DEBUG_PRINT("\n");
525 #endif
526
527 // We expect only tone curves, no R,G,B
528 if (i) {
529 if (curve->m_numAnchors != 2) {
530 printf("XXX JDLA : Not foreseen at %d processing %s\n",
531 __LINE__,nikonFilename);
532 exit(EXIT_FAILURE);
533 }
534 if (curve->m_anchors[0].x != 0.0 || curve->m_anchors[0].y != 0.0) {
535 printf("XXX JDLA : Not foreseen at %d processing %s\n",
536 __LINE__,nikonFilename);
537 exit(EXIT_FAILURE);
538 }
539 if (curve->m_anchors[1].x != 1.0 || curve->m_anchors[1].y != 1.0) {
540 printf("XXX JDLA : Not foreseen at %d processing %s\n",
541 __LINE__,nikonFilename);
542 exit(EXIT_FAILURE);
543 }
544 } else {
545 if (curve->m_min_x < 0.0 || curve->m_max_x > 1.0) {
546 printf("XXX JDLA : Not foreseen at %d processing %s\n"
547 "=> m_min_x : %f m_max_x : %f\n",
548 __LINE__,nikonFilename,curve->m_min_x,curve->m_max_x);
549 exit(EXIT_FAILURE);
550 }
551 if (curve->m_min_y < 0.0 || curve->m_max_y > 1.0) {
552 printf("XXX JDLA : Not foreseen at %d processing %s\n",
553 __LINE__,nikonFilename);
554 exit(EXIT_FAILURE);
555 }
556 // Write the output, gammaing the anchor points.
557 FILE *OutFile = fopen(exportFilename,"w");
558 for(short k = 0; k < curve->m_numAnchors; k++) {
559 fprintf(OutFile,
560 "%f %f\n",
561 curve->m_anchors[k].x,
562 pow(curve->m_anchors[k].y,1/curve->m_gamma));
563 }
564 fclose(OutFile);
565 }
566
567 }
568 fclose(input);
569 return NC_SUCCESS;
570 }
571
572 /****************************************
573 ConvertNikonCurveData:
574 The main driver. Takes a filename and
575 processes the curve, if possible.
576
577 fileName - The file to process.
578 *****************************************/
ConvertNikonCurveData(char * inFileName,char * outFileName,unsigned int samplingRes,unsigned int outputRes)579 int ConvertNikonCurveData(char *inFileName, char *outFileName,
580 unsigned int samplingRes, unsigned int outputRes)
581 {
582 //Load the curve data from the ncv/ntc file
583 NikonData data;
584 char tmpstr[1024];
585
586 if ( samplingRes <= 1 || outputRes <= 1 || samplingRes > MAX_RESOLUTION
587 || outputRes > MAX_RESOLUTION )
588 {
589 nc_message(NC_SET_ERROR, "Error, sampling and output resolution"
590 "must be 1 <= res <= %u\n", MAX_RESOLUTION);
591 return NC_ERROR;
592 }
593
594 //loads all the curve data. Does not allocate sample arrays.
595 if (LoadNikonData(inFileName, &data) != NC_SUCCESS)
596 {
597 return NC_ERROR;
598 }
599
600 return NC_SUCCESS;
601 }
602
603 /*****************************************************
604 FindTIFFOffset:
605 Moves the file pointer to the location
606 indicated by the TAG-TYPE pairing. This is meant just
607 as a helper function for this code. Uses elsewhere
608 may be limited.
609
610 file - Nikon File ptr
611 num_entries - Number of entries to search through
612 tiff_tag - The tiff tag to match.
613 tiff_type - The tiff type to match.
614 *******************************************************/
FindTIFFOffset(FILE * file,unsigned short num_entries,unsigned short tiff_tag,unsigned short tiff_type)615 int FindTIFFOffset(FILE *file, unsigned short num_entries, unsigned short tiff_tag, unsigned short tiff_type)
616 {
617 unsigned short tag = 0;
618 unsigned short type = 0;
619 unsigned int offset = 0;
620
621 int i;
622 for(i = 0; i < num_entries; i++)
623 {
624 //get tag 2 bytes
625 tag = (fgetc(file)<<8)|fgetc(file);
626 if (tag == tiff_tag)
627 {
628 //get type 2 bytes
629 type = (fgetc(file)<<8)|fgetc(file);
630 if (type == tiff_type) //Type for length of field
631 {
632 //get length (4 bytes)
633 offset = (fgetc(file)<<24)|(fgetc(file)<<16)|(fgetc(file)<<8)|fgetc(file);
634 //get value\offset 4 bytes
635 offset = (fgetc(file)<<24)|(fgetc(file)<<16)|(fgetc(file)<<8)|fgetc(file);
636 fseek(file,offset,SEEK_SET);
637 return 1; //true;
638 }
639 }
640 else
641 {
642 //advance to next entry
643 fseek(file,10,SEEK_CUR);
644 }
645 }
646 return 0; //false;
647 }
648
649 /*******************************************************
650 RipNikonNEFData:
651 Gets Nikon NEF data. For now, this is just the tone
652 curve data.
653
654 infile - The input file
655 curve - data structure to hold data in.
656 sample_p - pointer to the curve sample reference.
657 can be NULL if curve sample is not needed.
658 ********************************************************/
RipNikonNEFData(char * infile,CurveData * data,CurveSample ** sample_p)659 int RipNikonNEFData(char *infile, CurveData *data, CurveSample **sample_p)
660 {
661 unsigned short byte_order = 0;
662 unsigned short num_entries = 0;
663 unsigned short version = 0;
664 unsigned int offset = 0;
665
666 //open the file
667 FILE *file = g_fopen(infile,"rb");
668
669 //make sure we have a valid file
670 if (file == NULL)
671 {
672 nc_message(NC_SET_ERROR, "Error opening '%s': %s\n",
673 infile, strerror(errno));
674 return NC_ERROR;
675 }
676
677 //gets the byte order
678 fread(&byte_order,2,1,file);
679 byte_order = ShortVal(byte_order);
680 if (byte_order != 0x4d4d)
681 {
682 //Must be in motorola format if it came from a NIKON
683 nc_message(NC_SET_ERROR,
684 "NEF file data format is Intel. Data format should be Motorola.\n");
685 return NC_ERROR;
686 }
687
688 //get the version
689 //fread(&version,2,1,file);
690 version = (fgetc(file)<<8)|fgetc(file);
691 if (version != 0x002a)
692 {
693 //must be 42 or not a valid TIFF
694 nc_message(NC_SET_ERROR,
695 "NEF file version is %u. Version should be 42.\n",version);
696 return NC_ERROR;
697 }
698
699 //get offset to first IFD
700 offset = (fgetc(file)<<24)|(fgetc(file)<<16)|(fgetc(file)<<8)|fgetc(file);
701 //go to the IFD
702 fseek(file,offset,SEEK_SET);
703 //get number of entries
704 num_entries = (fgetc(file)<<8)|fgetc(file);
705
706 //move file pointer to exif offset
707 if (!FindTIFFOffset(file,num_entries,TIFF_TAG_EXIF_OFFSET,TIFF_TYPE_LONG))
708 {
709 nc_message(NC_SET_ERROR,
710 "NEF data entry could not be found with tag %u and type %u.\n",
711 TIFF_TAG_EXIF_OFFSET, TIFF_TYPE_LONG);
712 return NC_ERROR;
713 }
714
715 //get number of entries
716 num_entries = (fgetc(file)<<8)|fgetc(file);
717
718 //move file pointer to maker note offset
719 if (!FindTIFFOffset(file,num_entries,TIFF_TAG_MAKER_NOTE_OFFSET,TIFF_TYPE_UNDEFINED))
720 {
721 nc_message(NC_SET_ERROR,
722 "NEF data entry could not be found with tag %u and type %u.\n",
723 TIFF_TAG_MAKER_NOTE_OFFSET, TIFF_TYPE_UNDEFINED);
724 return NC_ERROR;
725 }
726
727 //////////////////////////////////////////////////////////////////////////
728 //NOTE: At this point, this section of the file acts almost like another
729 // file header. Skip the first bytes, (which just say nikon with a
730 // few bytes at the end. Offsets from here on in are from the start
731 // of this section, not the start of the file.
732 //////////////////////////////////////////////////////////////////////////
733
734 //Check the name. If it isn't Nikon then we can't do anything with this file.
735 char name[6];
736 fread(name,6,1,file);
737 if (strcmp(name,"Nikon") != 0)
738 {
739 nc_message(NC_SET_ERROR,
740 "NEF string identifier is %s. Should be: Nikon.\n",name);
741 return NC_ERROR;
742 }
743 fseek(file,4,SEEK_CUR);
744
745 //save the current file location, as all other offsets for this section run off this.
746 unsigned long pos = ftell(file);
747
748 //get byte order (use a regular fread)
749 fread(&byte_order,2,1,file);
750 byte_order = ShortVal(byte_order);
751 if (byte_order != 0x4d4d)
752 {
753 //Must be in motorola format or not from a Nikon
754 nc_message(NC_SET_ERROR,
755 "NEF secondary file data format is Intel. "
756 "Data format should be Motorola.\n");
757 return NC_ERROR;
758 }
759
760 //get version
761 version = (fgetc(file)<<8)|fgetc(file);
762 if (version != 0x002a)
763 {
764 nc_message(NC_SET_ERROR,
765 "NEF secondary file version is %u. Version should be 42.\n",
766 version);
767 return NC_ERROR;
768 }
769
770 //get offset to first IFD
771 offset = (fgetc(file)<<24)| (fgetc(file)<<16)|(fgetc(file)<<8)|fgetc(file);
772 //go to the IFD (these offsets are NOT from the start of the file,
773 //just the start of the section).
774 fseek(file,pos+offset,SEEK_SET);
775 //get number of entries
776 num_entries = (fgetc(file)<<8)|fgetc(file);
777
778 //move file position to tone curve data
779 if (!FindTIFFOffset(file,num_entries,TIFF_TAG_CURVE_OFFSET,TIFF_TYPE_UNDEFINED))
780 {
781 nc_message(NC_SET_ERROR,
782 "NEF data entry could not be found with tag %u and type %u.\n",
783 TIFF_TAG_CURVE_OFFSET, TIFF_TYPE_UNDEFINED);
784 return NC_ERROR;
785 }
786
787 offset = ftell(file);
788 return RipNikonNEFCurve(file, offset+pos, data, sample_p);
789 }
790
791
792 /*******************************************************
793 RipNikonNEFCurve:
794 The actual retriever for the curve data from the NEF
795 file.
796
797 file - The input file.
798 infile - Offset to retrieve the data
799 curve - data structure to hold curve in.
800 sample_p - pointer to the curve sample reference.
801 can be NULL if curve sample is not needed.
802 ********************************************************/
RipNikonNEFCurve(FILE * file,int offset,CurveData * data,CurveSample ** sample_p)803 int RipNikonNEFCurve(FILE *file, int offset, CurveData *data,
804 CurveSample **sample_p)
805 {
806 int i;
807
808 //seek to the offset of the data. Skip first two bytes (section isn't needed).
809 fseek(file, offset+2, SEEK_SET);
810
811 memset(data,0,sizeof(CurveData));
812 /////////////////////////////////////////////////
813 //GET CURVE DATA
814 /////////////////////////////////////////////////
815 //get box data and gamma
816 data->m_min_x = (double)fgetc(file)/255.0;
817 data->m_max_x = (double)fgetc(file)/255.0;
818 data->m_min_y = (double)fgetc(file)/255.0;
819 data->m_max_y = (double)fgetc(file)/255.0;
820 //16-bit fixed point.
821 data->m_gamma = (double)fgetc(file) + ((double)fgetc(file)/256.0);
822
823 //DEBUG_PRINT("DEBUG: NEF SECTION SIZE -> %u\n",data->section_size);
824 DEBUG_PRINT("DEBUG: NEF X MIN -> %e\n",data->m_min_x);
825 DEBUG_PRINT("DEBUG: NEF X MAX -> %e\n",data->m_max_x);
826 DEBUG_PRINT("DEBUG: NEF Y MIN -> %e\n",data->m_min_y);
827 DEBUG_PRINT("DEBUG: NEF Y MAX -> %e\n",data->m_max_y);
828 //DEBUG_PRINT("DEBUG: NEF GAMMA (16-bit fixed point) -> %e\n",(data->m_gamma>>8)+(data->m_gamma&0x00ff)/256.0);
829 DEBUG_PRINT("DEBUG: NEF GAMMA -> %e\n",data->m_gamma);
830 // It seems that if there is no curve then the 62 bytes in the buffer
831 // are either all 0x00 (D70) or 0xFF (D2H).
832 // We therefore switch these values with the default values.
833 if (data->m_min_x==1.0) {
834 data->m_min_x = 0.0;
835 DEBUG_PRINT("DEBUG: NEF X MIN -> %e (changed)\n",data->m_min_x);
836 }
837 if (data->m_max_x==0.0) {
838 data->m_max_x = 1.0;
839 DEBUG_PRINT("DEBUG: NEF X MAX -> %e (changed)\n",data->m_max_x);
840 }
841 if (data->m_min_y==1.0) {
842 data->m_min_y = 0.0;
843 DEBUG_PRINT("DEBUG: NEF Y MIN -> %e (changed)\n",data->m_min_y);
844 }
845 if (data->m_max_y==0.0) {
846 data->m_max_y = 1.0;
847 DEBUG_PRINT("DEBUG: NEF Y MAX -> %e (changed)\n",data->m_max_y);
848 }
849 if (data->m_gamma==0.0 || data->m_gamma==255.0+255.0/256.0) {
850 data->m_gamma = 1.0;
851 DEBUG_PRINT("DEBUG: NEF GAMMA -> %e (changed)\n",data->m_gamma);
852 }
853
854 //get number of anchor points (there should be at least 2
855 fread(&data->m_numAnchors,1,1,file);
856 DEBUG_PRINT("DEBUG: NEF NUMBER OF ANCHORS -> %u\n",data->m_numAnchors);
857 if (data->m_numAnchors==255) {
858 data->m_numAnchors = 0;
859 DEBUG_PRINT("DEBUG: NEF NUMBER OF ANCHORS -> %u (changed)\n",
860 data->m_numAnchors);
861 }
862 if (data->m_numAnchors > NIKON_MAX_ANCHORS) {
863 data->m_numAnchors = NIKON_MAX_ANCHORS;
864 DEBUG_PRINT("DEBUG: NEF NUMBER OF ANCHORS -> %u (changed)\n",
865 data->m_numAnchors);
866 }
867
868 //convert data to doubles
869 for(i = 0; i < data->m_numAnchors; i++)
870 {
871 //get anchor points
872 data->m_anchors[i].x = (double)fgetc(file)/255.0;
873 data->m_anchors[i].y = (double)fgetc(file)/255.0;
874 }
875
876 //The total number of points possible is 25 (50 bytes).
877 //At this point we subtract the number of bytes read for points from the max (50+1)
878 fseek(file,(51 - data->m_numAnchors*2),SEEK_CUR);
879
880 //get data (always 4096 entries, 1 byte apiece)
881 DEBUG_PRINT("DEBUG: NEF data OFFSET -> %ld\n",ftell(file));
882
883 return NC_SUCCESS;
884 }
885
886 /*******************************
887 main:
888 Uh....no comment. :)
889 ********************************/
890 #ifdef _STAND_ALONE_
891
main(int argc,char * argv[])892 int main(int argc, char* argv[])
893 {
894 //make sure we can continue processing
895 if (ProcessArgs(argc,argv) == NC_SUCCESS)
896 {
897
898 //if we are in NEF mode, rip the curve out of the RAW file
899 if (program_mode == NEF_MODE)
900 {
901 NikonData data;
902
903 //intiialze the structure to zero
904 memset(&data,0,sizeof(NikonData));
905
906 if (RipNikonNEFData(nikonFilename, &data.curves[TONE_CURVE], NULL)
907 != NC_SUCCESS)
908 {
909 return NC_ERROR;
910 }
911
912 }
913 //else, process a nikon curve file
914 else
915 {
916 //do the deed
917 ConvertNikonCurveData(nikonFilename,exportFilename,
918 standalone_samplingRes, standalone_outputRes);
919 }
920 }
921 return NC_SUCCESS;
922 }
923 #endif
924