forked from ImpulseAdventure/JPEGsnoop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
JfifDecode.cpp
8021 lines (6853 loc) · 262 KB
/
JfifDecode.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// JPEGsnoop - JPEG Image Decoder & Analysis Utility
// Copyright (C) 2017 - Calvin Hass
// http://www.impulseadventure.com/photo/jpeg-snoop.html
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include "stdafx.h"
#include "JfifDecode.h"
#include "snoop.h"
#include "JPEGsnoop.h" // for m_pAppConfig get
#include "WindowBuf.h"
#include "Md5.h"
#include "afxinet.h"
#include "windows.h"
#include "UrlString.h"
#include "DbSigs.h"
#include "General.h"
// Maximum number of component values to extract into array for display
#define MAX_anValues 64
// Clear out internal members
void CjfifDecode::Reset()
{
// File handling
m_nPos = 0;
m_nPosSos = 0;
m_nPosEoi = 0;
m_nPosEmbedStart = 0;
m_nPosEmbedEnd = 0;
m_nPosFileEnd = 0;
// SOS / SOF handling
m_nSofNumLines_Y = 0;
m_nSofSampsPerLine_X = 0;
m_nSofNumComps_Nf = 0;
// Quantization tables
ClearDQT();
// Photoshop
m_nImgQualPhotoshopSfw = 0;
m_nImgQualPhotoshopSa = 0;
m_nApp14ColTransform = -1;
// Restart marker
m_nImgRstEn = false;
m_nImgRstInterval = 0;
// Basic metadata
m_strImgExifMake = _T("???");
m_nImgExifMakeSubtype = 0;
m_strImgExifModel = _T("???");
m_bImgExifMakernotes = false;
m_strImgExtras = _T("");
m_strComment = _T("");
m_strSoftware = _T("");
m_bImgProgressive = false;
m_bImgSofUnsupported = false;
_tcscpy_s(m_acApp0Identifier,_T(""));
// Derived metadata
m_strHash = _T("NONE");
m_strHashRot = _T("NONE");
m_eImgLandscape = ENUM_LANDSCAPE_UNSET;
m_strImgQualExif = _T("");
m_bAvi = false;
m_bAviMjpeg = false;
m_bPsd = false;
// Misc
m_bImgOK = false; // Set during SOF to indicate further proc OK
m_bBufFakeDHT = false; // Start in normal Buf mode
m_eImgEdited = EDITED_UNSET;
m_eDbReqSuggest = DB_ADD_SUGGEST_UNSET;
m_bSigExactInDB = false;
// Embedded thumbnail
m_nImgExifThumbComp = 0;
m_nImgExifThumbOffset = 0;
m_nImgExifThumbLen = 0;
m_strHashThumb = _T("NONE"); // Will go into DB to say NONE!
m_strHashThumbRot = _T("NONE"); // Will go into DB to say NONE!
m_nImgThumbNumLines = 0;
m_nImgThumbSampsPerLine = 0;
// Now clear out any previously generated bitmaps
// or image decoding parameters
if (m_pImgDec) {
if (m_pImgSrcDirty) {
m_pImgDec->Reset();
}
}
// Reset the decoding state checks
// These are to help ensure we don't start decoding SOS
// if we haven't seen other valid markers yet! Otherwise
// we could run into very bad loops (e.g. .PSD files)
// just because we saw FFD8FF first then JFIF_SOS
m_bStateAbort = false;
m_bStateSoi = false;
m_bStateDht = false;
m_bStateDhtOk = false;
m_bStateDhtFake = false;
m_bStateDqt = false;
m_bStateDqtOk = false;
m_bStateSof = false;
m_bStateSofOk = false;
m_bStateSos = false;
m_bStateSosOk = false;
m_bStateEoi = false;
}
// Initialize the JFIF decoder. Several class pointers are provided
// as parameters, so that we can directly access the output log, the
// file buffer and the image scan decoder.
// Loads up the signature database.
//
// INPUT:
// - pLog Ptr to log file class
// - pWBuf Ptr to Window Buf class
// - pImgDec Ptr to Image Decoder class
//
// PRE:
// - Requires that CDocLog, CwindowBuf and CimgDecode classes
// are already initialized
//
CjfifDecode::CjfifDecode(CDocLog* pLog,CwindowBuf* pWBuf,CimgDecode* pImgDec)
{
// Ideally this would be passed by constructor, but simply access
// directly for now.
CJPEGsnoopApp* pApp;
pApp = (CJPEGsnoopApp*)AfxGetApp();
m_pAppConfig = pApp->m_pAppConfig;
ASSERT(m_pAppConfig);
if (DEBUG_EN) m_pAppConfig->DebugLogAdd(_T("CjfifDecode::CjfifDecode() Begin"));
ASSERT(pLog);
ASSERT(pWBuf);
ASSERT(pImgDec);
// Need to zero out the private members
m_bOutputDB = FALSE; // mySQL output for web
// Enable verbose reporting
m_bVerbose = FALSE;
m_pImgSrcDirty = TRUE;
// Generate lookup tables for Huffman codes
GenLookupHuffMask();
if (DEBUG_EN) m_pAppConfig->DebugLogAdd(_T("CjfifDecode::CjfifDecode() Checkpoint 1"));
// Window status bar is not ready yet, wait for call to SetStatusBar()
m_pStatBar = NULL;
// Save copies of other class pointers
m_pLog = pLog;
m_pWBuf = pWBuf;
m_pImgDec = pImgDec;
// Reset decoding state
Reset();
if (DEBUG_EN) m_pAppConfig->DebugLogAdd(_T("CjfifDecode::CjfifDecode() Checkpoint 2"));
// Load the local database (if it exists)
theApp.m_pDbSigs->DatabaseExtraLoad();
if (DEBUG_EN) m_pAppConfig->DebugLogAdd(_T("CjfifDecode::CjfifDecode() Checkpoint 3"));
// Allocate the Photoshop decoder
m_pPsDec = new CDecodePs(pWBuf,pLog);
if (!m_pPsDec) {
ASSERT(false);
return;
}
if (DEBUG_EN) m_pAppConfig->DebugLogAdd(_T("CjfifDecode::CjfifDecode() Checkpoint 4"));
#ifdef SUPPORT_DICOM
// Allocate the DICOM decoder
m_pDecDicom = new CDecodeDicom(pWBuf,pLog);
if (!m_pDecDicom) {
ASSERT(false);
return;
}
if (DEBUG_EN) m_pAppConfig->DebugLogAdd(_T("CjfifDecode::CjfifDecode() Checkpoint 5"));
#endif
if (DEBUG_EN) m_pAppConfig->DebugLogAdd(_T("CjfifDecode::CjfifDecode() End"));
}
// Destructor
CjfifDecode::~CjfifDecode()
{
// Free the Photoshop decoder
if (m_pPsDec) {
delete m_pPsDec;
m_pPsDec = NULL;
}
#ifdef SUPPORT_DICOM
// Free the DICOM decoder
if (m_pDecDicom) {
delete m_pDecDicom;
m_pDecDicom = NULL;
}
#endif
}
// Asynchronously update a local pointer to the status bar once
// it becomes available. Note that the status bar is not ready by
// the time of the CjfifDecode class constructor call.
//
// INPUT:
// - pStatBar Ptr to status bar
//
// POST:
// - m_pStatBar
//
void CjfifDecode::SetStatusBar(CStatusBar* pStatBar)
{
m_pStatBar = pStatBar;
}
// Indicate that the source of the image scan data
// has been dirtied. Either the source has changed
// or some of the View2 options have changed.
//
// POST:
// - m_pImgSrcDirty
//
void CjfifDecode::ImgSrcChanged()
{
m_pImgSrcDirty = true;
}
// Set the AVI mode flag for this file
//
// POST:
// - m_bAvi
// - m_bAviMjpeg
//
void CjfifDecode::SetAviMode(bool bIsAvi,bool bIsMjpeg)
{
m_bAvi = bIsAvi;
m_bAviMjpeg = bIsMjpeg;
}
// Fetch the AVI mode flag for this file
//
// PRE:
// - m_bAvi
// - m_bAviMjpeg
//
// OUTPUT:
// - bIsAvi
// - bIsMjpeg
//
void CjfifDecode::GetAviMode(bool &bIsAvi,bool &bIsMjpeg)
{
bIsAvi = m_bAvi;
bIsMjpeg = m_bAviMjpeg;
}
// Fetch the starting file position of the embedded thumbnail
//
// PRE:
// - m_nPosEmbedStart
//
// RETURN:
// - File position
//
unsigned long CjfifDecode::GetPosEmbedStart()
{
return m_nPosEmbedStart;
}
// Fetch the ending file position of the embedded thumbnail
//
// PRE:
// - m_nPosEmbedEnd
//
// RETURN:
// - File position
//
unsigned long CjfifDecode::GetPosEmbedEnd()
{
return m_nPosEmbedEnd;
}
// Determine if the last analysis revealed a JFIF with known markers
//
// RETURN:
// - TRUE if file (at position during analysis) appeared to decode OK
//
bool CjfifDecode::GetDecodeStatus()
{
return m_bImgOK;
}
// Fetch a summary of the JFIF decoder results
// These details are used in preparation of signature submission to the DB
//
// PRE:
// - m_strHash
// - m_strHashRot
// - m_strImgExifMake
// - m_strImgExifModel
// - m_strImgQualExif
// - m_strSoftware
// - m_eDbReqSuggest
//
// OUTPUT:
// - strHash
// - strHashRot
// - strImgExifMake
// - strImgExifModel
// - strImgQualExif
// - strSoftware
// - nDbReqSuggest
//
void CjfifDecode::GetDecodeSummary(CString &strHash,CString &strHashRot,CString &strImgExifMake,CString &strImgExifModel,
CString &strImgQualExif,CString &strSoftware,teDbAdd &eDbReqSuggest)
{
strHash = m_strHash;
strHashRot = m_strHashRot;
strImgExifMake = m_strImgExifMake;
strImgExifModel = m_strImgExifModel;
strImgQualExif = m_strImgQualExif;
strSoftware = m_strSoftware;
eDbReqSuggest = m_eDbReqSuggest;
}
// Fetch an element from the "standard" luminance quantization table
//
// PRE:
// - glb_anStdQuantLum[]
//
// RETURN:
// - DQT matrix element
//
unsigned CjfifDecode::GetDqtQuantStd(unsigned nInd)
{
if (nInd < MAX_DQT_COEFF) {
return glb_anStdQuantLum[nInd];
} else {
#ifdef DEBUG_LOG
CString strTmp;
CString strDebug;
strTmp.Format(_T("GetDqtQuantStd() with nInd out of range. nInd=[%u]"),nInd);
strDebug.Format(_T("## File=[%-100s] Block=[%-10s] Error=[%s]\n"),(LPCTSTR)m_pAppConfig->strCurFname,
_T("JfifDecode"),(LPCTSTR)strTmp);
OutputDebugString(strDebug);
#else
ASSERT(false);
#endif
return 0;
}
}
// Fetch the DQT ordering index (with optional zigzag sequence)
//
// INPUT:
// - nInd Coefficient index
// - bZigZag Use zig-zag ordering
//
// RETURN:
// - Sequence index
//
unsigned CjfifDecode::GetDqtZigZagIndex(unsigned nInd,bool bZigZag)
{
if (nInd < MAX_DQT_COEFF) {
if (bZigZag) {
return nInd;
} else {
return glb_anZigZag[nInd];
}
} else {
#ifdef DEBUG_LOG
CString strTmp;
CString strDebug;
strTmp.Format(_T("GetDqtZigZagIndex() with nInd out of range. nInd=[%u]"),nInd);
strDebug.Format(_T("## File=[%-100s] Block=[%-10s] Error=[%s]\n"),(LPCTSTR)m_pAppConfig->strCurFname,
_T("JfifDecode"),(LPCTSTR)strTmp);
OutputDebugString(strDebug);
#else
ASSERT(false);
#endif
return 0;
}
}
// Reset the DQT tables
//
// POST:
// - m_anImgDqtTbl[][]
// - m_anImgThumbDqt[][]
// - m_adImgDqtQual[]
// - m_abImgDqtSet[]
// - m_abImgDqtThumbSet[]
//
void CjfifDecode::ClearDQT()
{
for (unsigned nTblInd=0;nTblInd<MAX_DQT_DEST_ID;nTblInd++)
{
for (unsigned nCoeffInd=0;nCoeffInd<MAX_DQT_COEFF;nCoeffInd++)
{
m_anImgDqtTbl[nTblInd][nCoeffInd] = 0;
m_anImgThumbDqt[nTblInd][nCoeffInd] = 0;
}
m_adImgDqtQual[nTblInd] = 0;
m_abImgDqtSet[nTblInd] = false;
m_abImgDqtThumbSet[nTblInd] = false;
}
}
// Set the DQT matrix element
//
// INPUT:
// - dqt0[] Matrix array for table 0
// - dqt1[] Matrix array for table 1
//
// POST:
// - m_anImgDqtTbl[][]
// - m_eImgLandscape
// - m_abImgDqtSet[]
// - m_strImgQuantCss
//
void CjfifDecode::SetDQTQuick(unsigned short anDqt0[64],unsigned short anDqt1[64])
{
m_eImgLandscape = ENUM_LANDSCAPE_YES;
for (unsigned ind=0;ind<MAX_DQT_COEFF;ind++)
{
m_anImgDqtTbl[0][ind] = anDqt0[ind];
m_anImgDqtTbl[1][ind] = anDqt1[ind];
}
m_abImgDqtSet[0] = true;
m_abImgDqtSet[1] = true;
m_strImgQuantCss = _T("NA");
}
// Construct a lookup table for the Huffman code masks
// The result is a simple bit sequence of zeros followed by
// an increasing number of 1 bits.
// 00000000...00000001
// 00000000...00000011
// 00000000...00000111
// ...
// 01111111...11111111
// 11111111...11111111
//
// POST:
// - m_anMaskLookup[]
//
void CjfifDecode::GenLookupHuffMask()
{
unsigned int mask;
for (unsigned len=0;len<32;len++)
{
mask = (1 << (len))-1;
mask <<= 32-len;
m_anMaskLookup[len] = mask;
}
}
// Provide a short-hand alias for the m_pWBuf buffer
// Also support redirection to a local table in case we are
// faking out the DHT (eg. for MotionJPEG files).
//
// PRE:
// - m_bBufFakeDHT Flag to include Fake DHT table
// - m_abMJPGDHTSeg[] DHT table used if m_bBufFakeDHT=true
//
// INPUT:
// - nOffset File offset to read from
// - bClean Forcibly disables any redirection to Fake DHT table
//
// POST:
// - m_pLog
//
// RETURN:
// - Byte from file (or local table)
//
BYTE CjfifDecode::Buf(unsigned long nOffset,bool bClean=false)
{
// Buffer can be redirected to internal array for AVI DHT
// tables, so check for it here.
if (m_bBufFakeDHT) {
return m_abMJPGDHTSeg[nOffset];
} else {
return m_pWBuf->Buf(nOffset,bClean);
}
}
// Write out a line to the log buffer if we are in verbose mode
//
// PRE:
// - m_bVerbose Verbose mode
//
// INPUT:
// - strLine String to output
//
// OUTPUT:
// - none
//
// POST:
// - m_pLog
//
// RETURN:
// - none
//
void CjfifDecode::DbgAddLine(LPCTSTR strLine)
{
if (m_bVerbose)
{
m_pLog->AddLine(strLine);
}
}
// Convert a UINT32 and decompose into 4 bytes, but support
// either endian byte-swap mode
//
// PRE:
// - m_nImgExifEndian Byte swap mode (0=little, 1=big)
//
// INPUT:
// - nVal Input UINT32
//
// OUTPUT:
// - nByte0 Byte #1
// - nByte1 Byte #2
// - nByte2 Byte #3
// - nByte3 Byte #4
//
// RETURN:
// - none
//
void CjfifDecode::UnByteSwap4(unsigned nVal,unsigned &nByte0,unsigned &nByte1,unsigned &nByte2,unsigned &nByte3)
{
if (m_nImgExifEndian == 0) {
// Little Endian
nByte3 = (nVal & 0xFF000000) >> 24;
nByte2 = (nVal & 0x00FF0000) >> 16;
nByte1 = (nVal & 0x0000FF00) >> 8;
nByte0 = (nVal & 0x000000FF);
} else {
// Big Endian
nByte0 = (nVal & 0xFF000000) >> 24;
nByte1 = (nVal & 0x00FF0000) >> 16;
nByte2 = (nVal & 0x0000FF00) >> 8;
nByte3 = (nVal & 0x000000FF);
}
}
// Perform conversion from 4 bytes into UINT32 with
// endian byte-swapping support
//
// PRE:
// - m_nImgExifEndian Byte swap mode (0=little, 1=big)
//
// INPUT:
// - nByte0 Byte #1
// - nByte1 Byte #2
// - nByte2 Byte #3
// - nByte3 Byte #4
//
// RETURN:
// - UINT32
//
unsigned CjfifDecode::ByteSwap4(unsigned nByte0,unsigned nByte1, unsigned nByte2, unsigned nByte3)
{
unsigned nVal;
if (m_nImgExifEndian == 0) {
// Little endian, byte swap required
nVal = (nByte3<<24) + (nByte2<<16) + (nByte1<<8) + nByte0;
} else {
// Big endian, no swap required
nVal = (nByte0<<24) + (nByte1<<16) + (nByte2<<8) + nByte3;
}
return nVal;
}
// Perform conversion from 2 bytes into half-word with
// endian byte-swapping support
//
// PRE:
// - m_nImgExifEndian Byte swap mode (0=little, 1=big)
//
// INPUT:
// - nByte0 Byte #1
// - nByte1 Byte #2
//
// RETURN:
// - UINT16
//
unsigned CjfifDecode::ByteSwap2(unsigned nByte0,unsigned nByte1)
{
unsigned nVal;
if (m_nImgExifEndian == 0) {
// Little endian, byte swap required
nVal = (nByte1<<8) + nByte0;
} else {
// Big endian, no swap required
nVal = (nByte0<<8) + nByte1;
}
return nVal;
}
// Decode Canon Makernotes
// Only the most common makernotes are supported; there are a large
// number of makernotes that have not been documented anywhere.
CStr2 CjfifDecode::LookupMakerCanonTag(unsigned nMainTag,unsigned nSubTag,unsigned nVal)
{
CString strTmp;
CStr2 sRetVal;
sRetVal.strTag = _T("???");
sRetVal.bUnknown = false; // Set to true in default clauses
sRetVal.strVal.Format(_T("%u"),nVal); // Provide default value
unsigned nValHi,nValLo;
nValHi = (nVal & 0xff00) >> 8;
nValLo = (nVal & 0x00ff);
switch(nMainTag)
{
case 0x0001:
switch(nSubTag)
{
case 0x0001: sRetVal.strTag = _T("Canon.Cs1.Macro");break; // Short Macro mode
case 0x0002: sRetVal.strTag = _T("Canon.Cs1.Selftimer");break; // Short Self timer
case 0x0003: sRetVal.strTag = _T("Canon.Cs1.Quality");
if (nVal == 2) { sRetVal.strVal = _T("norm"); }
else if (nVal == 3) { sRetVal.strVal = _T("fine"); }
else if (nVal == 5) { sRetVal.strVal = _T("superfine"); }
else {
sRetVal.strVal = _T("?");
}
// Save the quality string for later
m_strImgQualExif = sRetVal.strVal;
break; // Short Quality
case 0x0004: sRetVal.strTag = _T("Canon.Cs1.FlashMode");break; // Short Flash mode setting
case 0x0005: sRetVal.strTag = _T("Canon.Cs1.DriveMode");break; // Short Drive mode setting
case 0x0007: sRetVal.strTag = _T("Canon.Cs1.FocusMode"); // Short Focus mode setting
switch(nVal) {
case 0 : sRetVal.strVal = _T("One-shot");break;
case 1 : sRetVal.strVal = _T("AI Servo");break;
case 2 : sRetVal.strVal = _T("AI Focus");break;
case 3 : sRetVal.strVal = _T("Manual Focus");break;
case 4 : sRetVal.strVal = _T("Single");break;
case 5 : sRetVal.strVal = _T("Continuous");break;
case 6 : sRetVal.strVal = _T("Manual Focus");break;
default : sRetVal.strVal = _T("?");break;
}
break;
case 0x000a: sRetVal.strTag = _T("Canon.Cs1.ImageSize"); // Short Image size
if (nVal == 0) { sRetVal.strVal = _T("Large"); }
else if (nVal == 1) { sRetVal.strVal = _T("Medium"); }
else if (nVal == 2) { sRetVal.strVal = _T("Small"); }
else {
sRetVal.strVal = _T("?");
}
break;
case 0x000b: sRetVal.strTag = _T("Canon.Cs1.EasyMode");break; // Short Easy shooting mode
case 0x000c: sRetVal.strTag = _T("Canon.Cs1.DigitalZoom");break; // Short Digital zoom
case 0x000d: sRetVal.strTag = _T("Canon.Cs1.Contrast");break; // Short Contrast setting
case 0x000e: sRetVal.strTag = _T("Canon.Cs1.Saturation");break; // Short Saturation setting
case 0x000f: sRetVal.strTag = _T("Canon.Cs1.Sharpness");break; // Short Sharpness setting
case 0x0010: sRetVal.strTag = _T("Canon.Cs1.ISOSpeed");break; // Short ISO speed setting
case 0x0011: sRetVal.strTag = _T("Canon.Cs1.MeteringMode");break; // Short Metering mode setting
case 0x0012: sRetVal.strTag = _T("Canon.Cs1.FocusType");break; // Short Focus type setting
case 0x0013: sRetVal.strTag = _T("Canon.Cs1.AFPoint");break; // Short AF point selected
case 0x0014: sRetVal.strTag = _T("Canon.Cs1.ExposureProgram");break; // Short Exposure mode setting
case 0x0016: sRetVal.strTag = _T("Canon.Cs1.LensType");break; //
case 0x0017: sRetVal.strTag = _T("Canon.Cs1.Lens");break; // Short 'long' and 'short' focal length of lens (in 'focal m_nImgUnits') and 'focal m_nImgUnits' per mm
case 0x001a: sRetVal.strTag = _T("Canon.Cs1.MaxAperture");break; //
case 0x001b: sRetVal.strTag = _T("Canon.Cs1.MinAperture");break; //
case 0x001c: sRetVal.strTag = _T("Canon.Cs1.FlashActivity");break; // Short Flash activity
case 0x001d: sRetVal.strTag = _T("Canon.Cs1.FlashDetails");break; // Short Flash details
case 0x0020: sRetVal.strTag = _T("Canon.Cs1.FocusMode");break; // Short Focus mode setting
default:
sRetVal.strTag.Format(_T("Canon.Cs1.x%04X"),nSubTag);
sRetVal.bUnknown = true;
break;
} // switch nSubTag
break;
case 0x0004:
switch(nSubTag)
{
case 0x0002: sRetVal.strTag = _T("Canon.Cs2.ISOSpeed");break; // Short ISO speed used
case 0x0004: sRetVal.strTag = _T("Canon.Cs2.TargetAperture");break; // Short Target Aperture
case 0x0005: sRetVal.strTag = _T("Canon.Cs2.TargetShutterSpeed");break; // Short Target shutter speed
case 0x0007: sRetVal.strTag = _T("Canon.Cs2.WhiteBalance");break; // Short White balance setting
case 0x0009: sRetVal.strTag = _T("Canon.Cs2.Sequence");break; // Short Sequence number (if in a continuous burst)
case 0x000e: sRetVal.strTag = _T("Canon.Cs2.AFPointUsed");break; // Short AF point used
case 0x000f: sRetVal.strTag = _T("Canon.Cs2.FlashBias");break; // Short Flash bias
case 0x0013: sRetVal.strTag = _T("Canon.Cs2.SubjectDistance");break; // Short Subject distance (m_nImgUnits are not clear)
case 0x0015: sRetVal.strTag = _T("Canon.Cs2.ApertureValue");break; // Short Aperture
case 0x0016: sRetVal.strTag = _T("Canon.Cs2.ShutterSpeedValue");break; // Short Shutter speed
default:
sRetVal.strTag.Format(_T("Canon.Cs2.x%04X"),nSubTag);
sRetVal.bUnknown = true;
break;
} // switch nSubTag
break;
case 0x000F:
// CustomFunctions are different! Tag given by high byte, value by low
// Index order (usually the nSubTag) is not used.
sRetVal.strVal.Format(_T("%u"),nValLo); // Provide default value
switch(nValHi)
{
case 0x0001: sRetVal.strTag = _T("Canon.Cf.NoiseReduction");break; // Short Long exposure noise reduction
case 0x0002: sRetVal.strTag = _T("Canon.Cf.ShutterAeLock");break; // Short Shutter/AE lock buttons
case 0x0003: sRetVal.strTag = _T("Canon.Cf.MirrorLockup");break; // Short Mirror lockup
case 0x0004: sRetVal.strTag = _T("Canon.Cf.ExposureLevelIncrements");break; // Short Tv/Av and exposure level
case 0x0005: sRetVal.strTag = _T("Canon.Cf.AFAssist");break; // Short AF assist light
case 0x0006: sRetVal.strTag = _T("Canon.Cf.FlashSyncSpeedAv");break; // Short Shutter speed in Av mode
case 0x0007: sRetVal.strTag = _T("Canon.Cf.AEBSequence");break; // Short AEB sequence/auto cancellation
case 0x0008: sRetVal.strTag = _T("Canon.Cf.ShutterCurtainSync");break; // Short Shutter curtain sync
case 0x0009: sRetVal.strTag = _T("Canon.Cf.LensAFStopButton");break; // Short Lens AF stop button Fn. Switch
case 0x000a: sRetVal.strTag = _T("Canon.Cf.FillFlashAutoReduction");break; // Short Auto reduction of fill flash
case 0x000b: sRetVal.strTag = _T("Canon.Cf.MenuButtonReturn");break; // Short Menu button return position
case 0x000c: sRetVal.strTag = _T("Canon.Cf.SetButtonFunction");break; // Short SET button func. when shooting
case 0x000d: sRetVal.strTag = _T("Canon.Cf.SensorCleaning");break; // Short Sensor cleaning
case 0x000e: sRetVal.strTag = _T("Canon.Cf.SuperimposedDisplay");break; // Short Superimposed display
case 0x000f: sRetVal.strTag = _T("Canon.Cf.ShutterReleaseNoCFCard");break; // Short Shutter Release W/O CF Card
default:
sRetVal.strTag.Format(_T("Canon.Cf.x%04X"),nValHi);
sRetVal.bUnknown = true;
break;
} // switch nSubTag
break;
/*
// Other ones assumed to use high-byte/low-byte method:
case 0x00C0:
sRetVal.strVal.Format(_T("%u"),nValLo); // Provide default value
switch(nValHi)
{
//case 0x0001: sRetVal.strTag = _T("Canon.x00C0.???");break; //
default:
sRetVal.strTag.Format(_T("Canon.x00C0.x%04X"),nValHi);
break;
}
break;
case 0x00C1:
sRetVal.strVal.Format(_T("%u"),nValLo); // Provide default value
switch(nValHi)
{
//case 0x0001: sRetVal.strTag = _T("Canon.x00C1.???");break; //
default:
sRetVal.strTag.Format(_T("Canon.x00C1.x%04X"),nValHi);
break;
}
break;
*/
case 0x0012:
switch(nSubTag)
{
case 0x0002: sRetVal.strTag = _T("Canon.Pi.ImageWidth");break; //
case 0x0003: sRetVal.strTag = _T("Canon.Pi.ImageHeight");break; //
case 0x0004: sRetVal.strTag = _T("Canon.Pi.ImageWidthAsShot");break; //
case 0x0005: sRetVal.strTag = _T("Canon.Pi.ImageHeightAsShot");break; //
case 0x0016: sRetVal.strTag = _T("Canon.Pi.AFPointsUsed");break; //
case 0x001a: sRetVal.strTag = _T("Canon.Pi.AFPointsUsed20D");break; //
default:
sRetVal.strTag.Format(_T("Canon.Pi.x%04X"),nSubTag);
sRetVal.bUnknown = true;
break;
} // switch nSubTag
break;
default:
sRetVal.strTag.Format(_T("Canon.x%04X.x%04X"),nMainTag,nSubTag);
sRetVal.bUnknown = true;
break;
} // switch mainTag
return sRetVal;
}
// Perform decode of EXIF IFD tags including MakerNote tags
//
// PRE:
// - m_strImgExifMake Used for MakerNote decode
//
// INPUT:
// - strSect IFD section
// - nTag Tag code value
//
// OUTPUT:
// - bUnknown Was the tag unknown?
//
// RETURN:
// - Formatted string
//
CString CjfifDecode::LookupExifTag(CString strSect,unsigned nTag,bool &bUnknown)
{
CString strTmp;
bUnknown = false;
if (strSect == _T("IFD0"))
{
switch(nTag)
{
case 0x010E: return _T("ImageDescription");break; // ascii string Describes image
case 0x010F: return _T("Make");break; // ascii string Shows manufacturer of digicam
case 0x0110: return _T("Model");break; // ascii string Shows model number of digicam
case 0x0112: return _T("Orientation");break; // unsigned short 1 The orientation of the camera relative to the scene, when the image was captured. The start point of stored data is, '1' means upper left, '3' lower right, '6' upper right, '8' lower left, '9' undefined.
case 0x011A: return _T("XResolution");break; // unsigned rational 1 Display/Print resolution of image. Large number of digicam uses 1/72inch, but it has no mean because personal computer doesn't use this value to display/print out.
case 0x011B: return _T("YResolution");break; // unsigned rational 1
case 0x0128: return _T("ResolutionUnit");break; // unsigned short 1 Unit of XResolution(0x011a)/YResolution(0x011b). '1' means no-unit, '2' means inch, '3' means centimeter.
case 0x0131: return _T("Software");break; // ascii string Shows firmware(internal software of digicam) version number.
case 0x0132: return _T("DateTime");break; // ascii string 20 Date/Time of image was last modified. Data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20bytes. In usual, it has the same value of DateTimeOriginal(0x9003)
case 0x013B: return _T("Artist");break; // Seems to be here and not only in SubIFD (maybe instead of SubIFD)
case 0x013E: return _T("WhitePoint");break; // unsigned rational 2 Defines chromaticity of white point of the image. If the image uses CIE Standard Illumination D65(known as international standard of 'daylight'), the values are '3127/10000,3290/10000'.
case 0x013F: return _T("PrimChromaticities");break; // unsigned rational 6 Defines chromaticity of the primaries of the image. If the image uses CCIR Recommendation 709 primearies, values are '640/1000,330/1000,300/1000,600/1000,150/1000,0/1000'.
case 0x0211: return _T("YCbCrCoefficients");break; // unsigned rational 3 When image format is YCbCr, this value shows a constant to translate it to RGB format. In usual, values are '0.299/0.587/0.114'.
case 0x0213: return _T("YCbCrPositioning");break; // unsigned short 1 When image format is YCbCr and uses 'Subsampling'(cropping of chroma data, all the digicam do that), defines the chroma sample point of subsampling pixel array. '1' means the center of pixel array, '2' means the datum point.
case 0x0214: return _T("ReferenceBlackWhite");break; // unsigned rational 6 Shows reference value of black point/white point. In case of YCbCr format, first 2 show black/white of Y, next 2 are Cb, last 2 are Cr. In case of RGB format, first 2 show black/white of R, next 2 are G, last 2 are B.
case 0x8298: return _T("Copyright");break; // ascii string Shows copyright information
case 0x8769: return _T("ExifOffset");break; //unsigned long 1 Offset to Exif Sub IFD
case 0x8825: return _T("GPSOffset");break; //unsigned long 1 Offset to Exif GPS IFD
//NEW:
case 0x9C9B: return _T("XPTitle");break;
case 0x9C9C: return _T("XPComment");break;
case 0x9C9D: return _T("XPAuthor");break;
case 0x9C9e: return _T("XPKeywords");break;
case 0x9C9f: return _T("XPSubject");break;
//NEW: The following were found in IFD0 even though they should just be SubIFD?
case 0xA401: return _T("CustomRendered");break;
case 0xA402: return _T("ExposureMode");break;
case 0xA403: return _T("WhiteBalance");break;
case 0xA406: return _T("SceneCaptureType");break;
default:
strTmp.Format(_T("IFD0.0x%04X"),nTag);
bUnknown = true;
return strTmp;
break;
}
} else if (strSect == _T("SubIFD")) {
switch(nTag)
{
case 0x00fe: return _T("NewSubfileType");break; // unsigned long 1
case 0x00ff: return _T("SubfileType");break; // unsigned short 1
case 0x012d: return _T("TransferFunction");break; // unsigned short 3
case 0x013b: return _T("Artist");break; // ascii string
case 0x013d: return _T("Predictor");break; // unsigned short 1
case 0x0142: return _T("TileWidth");break; // unsigned short 1
case 0x0143: return _T("TileLength");break; // unsigned short 1
case 0x0144: return _T("TileOffsets");break; // unsigned long
case 0x0145: return _T("TileByteCounts");break; // unsigned short
case 0x014a: return _T("SubIFDs");break; // unsigned long
case 0x015b: return _T("JPEGTables");break; // undefined
case 0x828d: return _T("CFARepeatPatternDim");break; // unsigned short 2
case 0x828e: return _T("CFAPattern");break; // unsigned byte
case 0x828f: return _T("BatteryLevel");break; // unsigned rational 1
case 0x829A: return _T("ExposureTime");break;
case 0x829D: return _T("FNumber");break;
case 0x83bb: return _T("IPTC/NAA");break; // unsigned long
case 0x8773: return _T("InterColorProfile");break; // undefined
case 0x8822: return _T("ExposureProgram");break;
case 0x8824: return _T("SpectralSensitivity");break; // ascii string
case 0x8825: return _T("GPSInfo");break; // unsigned long 1
case 0x8827: return _T("ISOSpeedRatings");break;
case 0x8828: return _T("OECF");break; // undefined
case 0x8829: return _T("Interlace");break; // unsigned short 1
case 0x882a: return _T("TimeZoneOffset");break; // signed short 1
case 0x882b: return _T("SelfTimerMode");break; // unsigned short 1
case 0x9000: return _T("ExifVersion");break;
case 0x9003: return _T("DateTimeOriginal");break;
case 0x9004: return _T("DateTimeDigitized");break;
case 0x9101: return _T("ComponentsConfiguration");break;
case 0x9102: return _T("CompressedBitsPerPixel");break;
case 0x9201: return _T("ShutterSpeedValue");break;
case 0x9202: return _T("ApertureValue");break;
case 0x9203: return _T("BrightnessValue");break;
case 0x9204: return _T("ExposureBiasValue");break;
case 0x9205: return _T("MaxApertureValue");break;
case 0x9206: return _T("SubjectDistance");break;
case 0x9207: return _T("MeteringMode");break;
case 0x9208: return _T("LightSource");break;
case 0x9209: return _T("Flash");break;
case 0x920A: return _T("FocalLength");break;
case 0x920b: return _T("FlashEnergy");break; // unsigned rational 1
case 0x920c: return _T("SpatialFrequencyResponse");break; // undefined
case 0x920d: return _T("Noise");break; // undefined
case 0x9211: return _T("ImageNumber");break; // unsigned long 1
case 0x9212: return _T("SecurityClassification");break; // ascii string 1
case 0x9213: return _T("ImageHistory");break; // ascii string
case 0x9214: return _T("SubjectLocation");break; // unsigned short 4
case 0x9215: return _T("ExposureIndex");break; // unsigned rational 1
case 0x9216: return _T("TIFF/EPStandardID");break; // unsigned byte 4
case 0x927C: return _T("MakerNote");break;
case 0x9286: return _T("UserComment");break;
case 0x9290: return _T("SubSecTime");break; // ascii string
case 0x9291: return _T("SubSecTimeOriginal");break; // ascii string
case 0x9292: return _T("SubSecTimeDigitized");break; // ascii string
case 0xA000: return _T("FlashPixVersion");break;
case 0xA001: return _T("ColorSpace");break;
case 0xA002: return _T("ExifImageWidth");break;
case 0xA003: return _T("ExifImageHeight");break;
case 0xA004: return _T("RelatedSoundFile");break;
case 0xA005: return _T("ExifInteroperabilityOffset");break;
case 0xa20b: return _T("FlashEnergy unsigned");break; // rational 1
case 0xa20c: return _T("SpatialFrequencyResponse");break; // unsigned short 1
case 0xA20E: return _T("FocalPlaneXResolution");break;
case 0xA20F: return _T("FocalPlaneYResolution");break;
case 0xA210: return _T("FocalPlaneResolutionUnit");break;
case 0xa214: return _T("SubjectLocation");break; // unsigned short 1
case 0xa215: return _T("ExposureIndex");break; // unsigned rational 1
case 0xA217: return _T("SensingMethod");break;
case 0xA300: return _T("FileSource");break;
case 0xA301: return _T("SceneType");break;
case 0xa302: return _T("CFAPattern");break; // undefined 1
case 0xa401: return _T("CustomRendered");break; // Short Custom image processing
case 0xa402: return _T("ExposureMode");break; // Short Exposure mode
case 0xa403: return _T("WhiteBalance");break; // Short White balance
case 0xa404: return _T("DigitalZoomRatio");break; // Rational Digital zoom ratio
case 0xa405: return _T("FocalLengthIn35mmFilm");break; // Short Focal length in 35 mm film
case 0xa406: return _T("SceneCaptureType");break; // Short Scene capture type
case 0xa407: return _T("GainControl");break; // Rational Gain control
case 0xa408: return _T("Contrast");break; // Short Contrast
case 0xa409: return _T("Saturation");break; // Short Saturation
case 0xa40a: return _T("Sharpness");break; // Short Sharpness
case 0xa40b: return _T("DeviceSettingDescription");break; // Undefined Device settings description
case 0xa40c: return _T("SubjectDistanceRange");break; // Short Subject distance range
case 0xa420: return _T("ImageUniqueID");break; // Ascii Unique image ID
default:
strTmp.Format(_T("SubIFD.0x%04X"),nTag);
bUnknown = true;
return strTmp;
break;
}
} else if (strSect == _T("IFD1")) {
switch(nTag)
{
case 0x0100: return _T("ImageWidth");break; // unsigned short/long 1 Shows size of thumbnail image.
case 0x0101: return _T("ImageLength");break; // unsigned short/long 1
case 0x0102: return _T("BitsPerSample");break; // unsigned short 3 When image format is no compression, this value shows the number of bits per component for each pixel. Usually this value is '8,8,8'
case 0x0103: return _T("Compression");break; // unsigned short 1 Shows compression method. '1' means no compression, '6' means JPEG compression.
case 0x0106: return _T("PhotometricInterpretation");break; // unsigned short 1 Shows the color space of the image data components. '1' means monochrome, '2' means RGB, '6' means YCbCr.
case 0x0111: return _T("StripOffsets");break; // unsigned short/long When image format is no compression, this value shows offset to image data. In some case image data is striped and this value is plural.
case 0x0115: return _T("SamplesPerPixel");break; // unsigned short 1 When image format is no compression, this value shows the number of components stored for each pixel. At color image, this value is '3'.
case 0x0116: return _T("RowsPerStrip");break; // unsigned short/long 1 When image format is no compression and image has stored as strip, this value shows how many rows stored to each strip. If image has not striped, this value is the same as ImageLength(0x0101).
case 0x0117: return _T("StripByteConunts");break; // unsigned short/long When image format is no compression and stored as strip, this value shows how many bytes used for each strip and this value is plural. If image has not stripped, this value is single and means whole data size of image.
case 0x011a: return _T("XResolution");break; // unsigned rational 1 Display/Print resolution of image. Large number of digicam uses 1/72inch, but it has no mean because personal computer doesn't use this value to display/print out.
case 0x011b: return _T("YResolution");break; // unsigned rational 1
case 0x011c: return _T("PlanarConfiguration");break; // unsigned short 1 When image format is no compression YCbCr, this value shows byte aligns of YCbCr data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for each subsampling pixel. If value is '2', Y/Cb/Cr value is separated and stored to Y plane/Cb plane/Cr plane format.