~ubuntu-branches/ubuntu/jaunty/beagle/jaunty-security

« back to all changes in this revision

Viewing changes to Util/F-Spot/Tiff.cs

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Ebner
  • Date: 2008-05-04 00:31:32 UTC
  • mfrom: (1.1.21 upstream)
  • Revision ID: james.westby@ubuntu.com-20080504003132-2tkm5o8moo5952ri
Tags: 0.3.7-2ubuntu1
 * Merge from Debian unstable. (LP: #225746) Remaining Ubuntu changes:
  - debian/control:
    + Rename ice{weasel,dove}-beagle to {mozilla,thunderbird}-beagle and
      and update the dependencies accordingly.
    + Change Maintainer to Ubuntu Mono Team.
  - debian/rules:
    + Install the mozilla-beagle and thunderbird-beagle extensions.
  - ice{dove,weasel}.dirs:
    + Renamed to {mozilla,thunderbird}-beagle.dirs.
    + Fixed paths to point to usr/lib/{firefox,thunderbird}

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// Tiff.cs
3
 
//
4
 
// Authors:
5
 
//     Larry Ewing <lewing@novell.com>
6
 
//
7
 
//
8
 
// Copyright (C) 2004 - 2006 Novell, Inc (http://www.novell.com)
9
 
//
10
 
// Permission is hereby granted, free of charge, to any person obtaining
11
 
// a copy of this software and associated documentation files (the
12
 
// "Software"), to deal in the Software without restriction, including
13
 
// without limitation the rights to use, copy, modify, merge, publish,
14
 
// distribute, sublicense, and/or sell copies of the Software, and to
15
 
// permit persons to whom the Software is furnished to do so, subject to
16
 
// the following conditions:
17
 
// 
18
 
// The above copyright notice and this permission notice shall be
19
 
// included in all copies or substantial portions of the Software.
20
 
// 
21
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22
 
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24
 
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25
 
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26
 
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27
 
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
 
//
29
 
 
30
 
using SemWeb;
31
 
using System;
32
 
 
33
 
namespace Beagle.Util.Tiff {
34
 
 
35
 
        // This is primarily to preserve the names from the specification
36
 
        // because they differ from the tiff standard names
37
 
        public enum NiffId : ushort {
38
 
                SubfileType                     = 0x00fe,
39
 
                PelPathLength                   = 0x0100,
40
 
                LineProgressionLength           = 257,
41
 
                BitsPerSample                   = 0x0101,
42
 
                PhotometricInterpretation       = 0x0106,
43
 
                DataOffset                      = 0x0111,
44
 
                SamplesPerPixel                 = 0x0115,
45
 
                DataByteCounts                  = 0x0117,
46
 
                PelPathResolution               = 0x011a,
47
 
                LineProgressionResolution       = 0x011b,
48
 
                ResolutionUnit                  = 0x0128,
49
 
                ColumnsPerPelPath               = 322,
50
 
                RowsPerLineProgression          = 323,
51
 
                Rotation                        = 33465,
52
 
                NavyCompression                 = 33466,
53
 
                TileIndex                       = 33467
54
 
        }
55
 
 
56
 
        public enum TagId : ushort {
57
 
                InteroperabilityIndex           = 0x0001,
58
 
                InteroperabilityVersion         = 0x0002,
59
 
                
60
 
                NewSubfileType                  = 0x00fe,
61
 
                SubfileType                     = 0x00ff,
62
 
                
63
 
                ImageWidth                      = 0x0100,
64
 
                ImageLength                     = 0x0101,
65
 
                BitsPerSample                   = 0x0102,
66
 
                Compression                     = 0x0103,
67
 
                PhotometricInterpretation       = 0x0106,
68
 
                FillOrder                       = 0x010a,
69
 
                DocumentName                    = 0x010d,
70
 
                ImageDescription                = 0x010e,
71
 
                Make                            = 0x010f,
72
 
                Model                           = 0x0110,
73
 
                StripOffsets                    = 0x0111,
74
 
                Orientation                     = 0x0112,
75
 
                SamplesPerPixel                 = 0x0115,
76
 
                RowsPerStrip                    = 0x0116,
77
 
                StripByteCounts                 = 0x0117,
78
 
                XResolution                     = 0x011a,
79
 
                YResolution                     = 0x011b,
80
 
                PlanarConfiguration             = 0x011c,
81
 
 
82
 
                T4Options                       = 0x0124,
83
 
                T6Options                       = 0x0125,
84
 
 
85
 
                ResolutionUnit                  = 0x0128,
86
 
                TransferFunction                = 0x012d,
87
 
                Software                        = 0x0131,
88
 
                DateTime                        = 0x0132,
89
 
                Artist                          = 0x013b,
90
 
                WhitePoint                      = 0x013e,
91
 
                PrimaryChromaticities           = 0x013f,
92
 
                        
93
 
                HalftoneHints                   = 0x0141,
94
 
                // Tiled images
95
 
                TileWidth                       = 0x0142,
96
 
                TileLength                      = 0x0143,
97
 
                TileOffsets                     = 0x0144,
98
 
                TileByteCounts                  = 0x0145,
99
 
 
100
 
                SubIFDs                         = 0x014a, // TIFF-EP
101
 
 
102
 
                // CMYK images
103
 
                InkSet                          = 0x014c,
104
 
                NumberOfInks                    = 0x014e,
105
 
                InkNames                        = 0x014d,
106
 
                DotRange                        = 0x0150,
107
 
                TargetPrinter                   = 0x0151,
108
 
                ExtraSamples                    = 0x0152,
109
 
                SampleFormat                    = 0x0153,
110
 
                SMinSampleValue                 = 0x0154,
111
 
                SMaxSampleValue                 = 0x0155,
112
 
                
113
 
                TransferRange                   = 0x0156,
114
 
                
115
 
                ClipPath                        = 0x0157, // TIFF PageMaker Technote #2.
116
 
                
117
 
                JPEGTables                      = 0x015b, // TIFF-EP
118
 
                
119
 
                JPEGProc                        = 0x0200,
120
 
                JPEGInterchangeFormat           = 0x0201,
121
 
                JPEGInterchangeFormatLength     = 0x0202,
122
 
                JPEGRestartInterval             = 0x0203,
123
 
                JPEGLosslessPredictors          = 0x0205,
124
 
                JPEGPointTransforms             = 0x0206,
125
 
                JPEGQTables                     = 0x0207,
126
 
                JPEGDCTables                    = 0x0208,
127
 
                JPEGACTables                    = 0x0209,
128
 
 
129
 
                YCbCrCoefficients               = 0x0211,
130
 
                YCbCrSubSampling                = 0x0212,
131
 
                YCbCrPositioning                = 0x0213,
132
 
 
133
 
                ReferenceBlackWhite             = 0x0214,
134
 
                RelatedImageFileFormat          = 0x1000,
135
 
                RelatedImageWidth               = 0x1001,
136
 
                RelatedImageLength              = 0x1002,
137
 
                CFARepeatPatternDim             = 0x828d,
138
 
                CFAPattern                      = 0x828e,
139
 
                BatteryLevel                    = 0x828f,
140
 
                Copyright                       = 0x8298,
141
 
                ExposureTime                    = 0x829a,
142
 
                FNumber                         = 0x829d,
143
 
 
144
 
                // These are from the NIFF spec and only really valid when the header begins with IIN1
145
 
                // see the NiffTag enum for the specifcation specific names
146
 
                        Rotation                        = 0x82b9,
147
 
                        NavyCompression                 = 0x82ba,
148
 
                        TileIndex                       = 0x82bb,
149
 
                // end NIFF specific
150
 
                        
151
 
                IPTCNAA                         = 0x83bb,
152
 
 
153
 
                PhotoshopPrivate                = 0x8649,
154
 
 
155
 
                ExifIfdPointer                  = 0x8769,
156
 
                InterColorProfile               = 0x8773,
157
 
                ExposureProgram                 = 0x8822,
158
 
                SpectralSensitivity             = 0x8824,
159
 
                GPSInfoIfdPointer               = 0x8825,
160
 
                ISOSpeedRatings                 = 0x8827,
161
 
                OECF                            = 0x8828,
162
 
                ExifVersion                     = 0x9000,
163
 
                DateTimeOriginal                = 0x9003,
164
 
                DateTimeDigitized               = 0x9004,
165
 
                ComponentsConfiguration         = 0x9101,
166
 
                CompressedBitsPerPixel          = 0x9102,
167
 
                ShutterSpeedValue               = 0x9201,
168
 
                ApertureValue                   = 0x9202,
169
 
                BrightnessValue                 = 0x9203,
170
 
                ExposureBiasValue               = 0x9204,
171
 
                MaxApertureValue                = 0x9205,
172
 
                SubjectDistance                 = 0x9206,
173
 
                MeteringMode                    = 0x9207,
174
 
                LightSource                     = 0x9208,
175
 
                Flash                           = 0x9209,
176
 
                FocalLength                     = 0x920a,
177
 
                        
178
 
                FlashEnergy_TIFFEP              = 0x920b,// TIFF-EP 
179
 
                SpacialFrequencyResponse        = 0x920c,// TIFF-EP 
180
 
                Noise                           = 0x920d,// TIFF-EP 
181
 
                FocalPlaneXResolution_TIFFEP    = 0x920e,// TIFF-EP 
182
 
                FocalPlaneYResolution_TIFFEP    = 0x920f,// TIFF-EP 
183
 
                FocalPlaneResolutionUnit_TIFFEP = 0x9210,// TIFF-EP 
184
 
                ImageName                       = 0x9211,// TIFF-EP 
185
 
                SecurityClassification          = 0x9212,// TIFF-EP 
186
 
                
187
 
                ImageHistory                    = 0x9213, // TIFF-EP null separated list
188
 
 
189
 
                SubjectArea                     = 0x9214,
190
 
 
191
 
                ExposureIndex_TIFFEP            = 0x9215, // TIFF-EP
192
 
                TIFFEPStandardID                = 0x9216, // TIFF-EP
193
 
                SensingMethod_TIFFEP            = 0x9217, // TIFF-EP
194
 
                        
195
 
                MakerNote                       = 0x927c,
196
 
                UserComment                     = 0x9286,
197
 
                SubSecTime                      = 0x9290,
198
 
                SubSecTimeOriginal              = 0x9291,
199
 
                SubSecTimeDigitized             = 0x9292,
200
 
                FlashPixVersion                 = 0xa000,
201
 
                ColorSpace                      = 0xa001,
202
 
                PixelXDimension                 = 0xa002,
203
 
                PixelYDimension                 = 0xa003,
204
 
                RelatedSoundFile                = 0xa004,
205
 
                InteroperabilityIfdPointer      = 0xa005,
206
 
                FlashEnergy                     = 0xa20b,
207
 
                SpatialFrequencyResponse        = 0xa20c,
208
 
                FocalPlaneXResolution           = 0xa20e,
209
 
                FocalPlaneYResolution           = 0xa20f,
210
 
                FocalPlaneResolutionUnit        = 0xa210,
211
 
                SubjectLocation                 = 0xa214,
212
 
                ExposureIndex                   = 0xa215,
213
 
                SensingMethod                   = 0xa217,
214
 
                FileSource                      = 0xa300,
215
 
                SceneType                       = 0xa301,
216
 
                ExifCFAPattern                  = 0xa302,
217
 
                CustomRendered                  = 0xa401,
218
 
                ExposureMode                    = 0xa402,
219
 
                WhiteBalance                    = 0xa403,
220
 
                DigitalZoomRatio                = 0xa404,
221
 
                FocalLengthIn35mmFilm           = 0xa405,
222
 
                SceneCaptureType                = 0xa406,
223
 
                GainControl                     = 0xa407,
224
 
                Contrast                        = 0xa408,
225
 
                Saturation                      = 0xa409,
226
 
                Sharpness                       = 0xa40a,
227
 
                DeviceSettingDescription        = 0xa40b,
228
 
                SubjectDistanceRange            = 0xa40c,
229
 
                ImageUniqueId                   = 0xa420,
230
 
 
231
 
                // The Following IDs are not described the EXIF spec
232
 
                Gamma                           = 0xa500,
233
 
 
234
 
                // The XMP spec declares that XMP data should live 0x2bc when
235
 
                // embedded in tiff images.
236
 
                XMP                             = 0x02bc,
237
 
                
238
 
                // from the dng spec
239
 
                DNGVersion                      = 0xc612, // Ifd0
240
 
                DNGBackwardVersion              = 0xc613, // Ifd0
241
 
                UniqueCameraModel               = 0xc614, // Ifd0
242
 
                LocalizedCameraModel            = 0xc615, // Ifd0
243
 
                CFAPlaneColor                   = 0xc616, // RawIfd
244
 
                CFALayout                       = 0xc617, // RawIfd
245
 
                LinearizationTable              = 0xc618, // RawIfd
246
 
                BlackLevelRepeatDim             = 0xc619, // RawIfd
247
 
                BlackLevel                      = 0xc61a, // RawIfd
248
 
                BlackLevelDeltaH                = 0xc61b, // RawIfd
249
 
                BlackLevelDeltaV                = 0xc61c, // RawIfd
250
 
                WhiteLevel                      = 0xc61d, // RawIfd
251
 
                DefaultScale                    = 0xc61e, // RawIfd             
252
 
                DefaultCropOrigin               = 0xc61f, // RawIfd
253
 
                DefaultCropSize                 = 0xc620, // RawIfd
254
 
                ColorMatrix1                    = 0xc621, // Ifd0
255
 
                ColorMatrix2                    = 0xc622, // Ifd0
256
 
                CameraCalibration1              = 0xc623, // Ifd0
257
 
                CameraCalibration2              = 0xc624, // Ifd0
258
 
                ReductionMatrix1                = 0xc625, // Ifd0
259
 
                ReductionMatrix2                = 0xc626, // Ifd0
260
 
                AnalogBalance                   = 0xc627, // Ifd0
261
 
                AsShotNetural                   = 0xc628, // Ifd0
262
 
                AsShotWhiteXY                   = 0xc629, // Ifd0
263
 
                BaselineExposure                = 0xc62a, // Ifd0
264
 
                BaselineNoise                   = 0xc62b, // Ifd0
265
 
                BaselineSharpness               = 0xc62c, // Ifd0
266
 
                BayerGreeSpit                   = 0xc62d, // Ifd0
267
 
                LinearResponseLimit             = 0xc62e, // Ifd0
268
 
                CameraSerialNumber              = 0xc62f, // Ifd0
269
 
                LensInfo                        = 0xc630, // Ifd0
270
 
                ChromaBlurRadius                = 0xc631, // RawIfd
271
 
                AntiAliasStrength               = 0xc632, // RawIfd
272
 
                DNGPrivateData                  = 0xc634, // Ifd0
273
 
                
274
 
                MakerNoteSafety                 = 0xc635, // Ifd0
275
 
 
276
 
                // The Spec says BestQualityScale is 0xc635 but it appears to be wrong
277
 
                //BestQualityScale                = 0xc635, // RawIfd 
278
 
                BestQualityScale                = 0xc63c, // RawIfd  this looks like the correct value
279
 
 
280
 
                CalibrationIlluminant1          = 0xc65a, // Ifd0
281
 
                CalibrationIlluminant2          = 0xc65b, // Ifd0
282
 
                
283
 
                // Print Image Matching data
284
 
                PimIfdPointer                   = 0xc4a5
285
 
        }
286
 
 
287
 
        public struct SRational {
288
 
                public int Numerator;
289
 
                public int Denominator;
290
 
                
291
 
                public SRational (byte [] raw_data, int offset, bool little)
292
 
                {
293
 
                        Numerator = BitConverter.ToInt32 (raw_data, offset, little);
294
 
                        Denominator = BitConverter.ToInt32 (raw_data, offset, little);
295
 
                }
296
 
 
297
 
                public SRational (int numerator, int denominator)
298
 
                {
299
 
                        Numerator = numerator;
300
 
                        Denominator = denominator;
301
 
                }
302
 
 
303
 
                public static SRational BitwiseCopy (Rational rational)
304
 
                {
305
 
                        SRational result;
306
 
 
307
 
                        result.Numerator = unchecked ((int) rational.Numerator);
308
 
                        result.Denominator = unchecked ((int) rational.Denominator);
309
 
                        return result;
310
 
                }
311
 
 
312
 
                public override string ToString ()
313
 
                {
314
 
                        if (Numerator == 0)
315
 
                                return "0";
316
 
                        else if (Numerator % Denominator == 0)
317
 
                                return String.Format ("{0}", Numerator / Denominator);
318
 
                        else if (Denominator % Numerator == 0)
319
 
                                return String.Format ("1/{0}", Denominator / Numerator);
320
 
 
321
 
                        return String.Format ("{0}/{1}", Numerator, Denominator);
322
 
                }
323
 
                
324
 
                public double Value {
325
 
                        get {
326
 
                                return Numerator / (double)Denominator;
327
 
                        }
328
 
                }
329
 
        }
330
 
 
331
 
        public struct Rational {
332
 
                public uint Numerator;
333
 
                public uint Denominator;
334
 
 
335
 
                public Rational (uint numerator, uint denominator)
336
 
                {
337
 
                        Numerator = numerator;
338
 
                        Denominator = denominator;
339
 
                }
340
 
                
341
 
                public Rational (string value)
342
 
                {
343
 
                        string [] vals = value.Split ('/');
344
 
                        if (vals.Length == 2) {
345
 
                                this.Numerator = UInt32.Parse (vals [0]);
346
 
                                this.Denominator = UInt32.Parse (vals [1]);
347
 
                                return;
348
 
                        } if (vals.Length == 1) {
349
 
                                double tmp = Double.Parse (value);
350
 
                                this.Numerator = (uint) (tmp * 100000);
351
 
                                this.Denominator = 100000;
352
 
                        } else
353
 
                                throw new System.Exception ("unable to parse rational value");
354
 
                }
355
 
 
356
 
                public override string ToString ()
357
 
                {
358
 
                        if (Numerator == 0)
359
 
                                return "0";
360
 
                        else if (Numerator % Denominator == 0)
361
 
                                return String.Format ("{0}", Numerator / Denominator);
362
 
                        else if (Denominator % Numerator == 0)
363
 
                                return String.Format ("1/{0}", Denominator / Numerator);
364
 
 
365
 
                        return String.Format ("{0}/{1}", Numerator, Denominator);
366
 
                }
367
 
                
368
 
                public double Value {
369
 
                        get {
370
 
                                return Numerator / (double)Denominator;
371
 
                        }
372
 
                }
373
 
        }
374
 
 
375
 
        struct UserComment {
376
 
                string Charset;
377
 
                public string Value;
378
 
 
379
 
                public UserComment (string value)
380
 
                {
381
 
                        Charset = null;
382
 
                        Value = value;
383
 
                }
384
 
 
385
 
                public UserComment (byte [] raw_data, bool little)
386
 
                {
387
 
                        if (raw_data.Length == 8 || raw_data.Length == 0) { 
388
 
                                Charset = null;
389
 
                                Value = "";
390
 
                                return;
391
 
                        } else if (raw_data.Length < 8) {
392
 
                                throw new Exception ("Invalid UserComment value, no charset found");
393
 
                        }
394
 
 
395
 
                        string charset = System.Text.Encoding.ASCII.GetString (raw_data, 0, 8);
396
 
                        System.Text.Encoding enc;
397
 
 
398
 
                        switch (charset) {
399
 
                        case "ASCII\0\0\0":
400
 
                                enc = System.Text.Encoding.ASCII;
401
 
                                break;
402
 
                        case "UNICODE\0":
403
 
                        case "Unicode\0":
404
 
                                enc = new System.Text.UnicodeEncoding (! little, true);
405
 
                                break;
406
 
                        case "JIS\0\0\0\0\0":
407
 
                                // FIXME this requires mono locale extras
408
 
                                try {
409
 
                                        enc = System.Text.Encoding.GetEncoding ("euc-jp");
410
 
                                } catch {
411
 
                                        System.Console.WriteLine ("missing jis0208 encoding");
412
 
                                        enc = System.Text.Encoding.Default;
413
 
                                }
414
 
                                break;
415
 
                        case "\0\0\0\0\0\0\0\0":
416
 
                                // FIXME the spec says to use the local encoding in this case, we could probably
417
 
                                // do something smarter, but whatever.
418
 
                                enc = System.Text.Encoding.Default;
419
 
                                break;
420
 
                        default:
421
 
                                enc = null;
422
 
                                throw new System.Exception (System.String.Format ("Invalid charset name: {0}", charset));
423
 
                        }
424
 
 
425
 
                        Charset = charset;
426
 
                        Value = enc.GetString (raw_data, 8, raw_data.Length - 8);
427
 
                }
428
 
 
429
 
                public byte [] GetBytes (bool is_little)
430
 
                {
431
 
                        bool ascii = true;
432
 
                        string description = Value;
433
 
                        System.Text.Encoding enc;
434
 
                        string heading;
435
 
 
436
 
                        for (int i = 0; i < description.Length; i++) {
437
 
                                if (description [i] > 127) {
438
 
                                        ascii = false;
439
 
                                        break;
440
 
                                }
441
 
                        }
442
 
 
443
 
                        if (ascii) {
444
 
                                heading = "ASCII\0\0\0";
445
 
                                enc = new System.Text.ASCIIEncoding ();
446
 
                        } else {
447
 
                                heading = "Unicode\0";
448
 
                                enc = new System.Text.UnicodeEncoding (! is_little, true);
449
 
                        }
450
 
                        
451
 
                        int len = enc.GetByteCount (description);
452
 
                        byte [] data = new byte [len + heading.Length];
453
 
                        System.Text.Encoding.ASCII.GetBytes (heading, 0, heading.Length, data, 0);
454
 
                        enc.GetBytes (Value, 0, Value.Length, data, heading.Length);
455
 
                        
456
 
                        UserComment c = new UserComment (data, is_little);
457
 
                        //System.Console.WriteLine ("old = \"{0}\" new = \"{1}\" heading = \"{2}\"", c.Value, description, heading);
458
 
                        return data;
459
 
                }
460
 
 
461
 
                public override string ToString ()
462
 
                {
463
 
                        return String.Format ("({0},charset={1})", Value, Charset);
464
 
                }
465
 
        }
466
 
 
467
 
        public struct CFAPattern {
468
 
                public ushort Rows;
469
 
                public ushort Columns;
470
 
                public byte [] Values;
471
 
 
472
 
                public CFAPattern (byte [] raw_data, bool little)
473
 
                {
474
 
                        Columns = BitConverter.ToUInt16 (raw_data, 0, little);
475
 
                        Rows = BitConverter.ToUInt16 (raw_data, 2, little);
476
 
 
477
 
                        Values = new byte [Rows * Columns];
478
 
                        System.Array.Copy (raw_data, 4, Values, 0, Values.Length);
479
 
                }
480
 
 
481
 
                /* 
482
 
                 * Note the Exif spec defines a CFA pattern tag that includes the row and column counts as shorts
483
 
                 * inside the first four bytes of the entry.  The Tiff-EP standard define the CFARepeatPattern tag
484
 
                 * that contains the row and column counts presumably since the Exif version wouldn't allow you to
485
 
                 * alter the endian of the file without knowing the tag layout.
486
 
                 */
487
 
                
488
 
                public CFAPattern (ushort rows, ushort cols, byte [] raw_data,  bool little)
489
 
                {
490
 
                        Columns = rows;
491
 
                        Rows = cols;
492
 
                        Values = new byte [rows * cols];
493
 
                        System.Array.Copy (raw_data, 0, Values, 0, Values.Length);
494
 
                }
495
 
        }
496
 
 
497
 
        public struct OECFTable {
498
 
                public ushort Rows;
499
 
                public ushort Columns;
500
 
                public string [] Names;
501
 
                public SRational [] Values;
502
 
                
503
 
                public OECFTable (byte [] raw_data, bool little)
504
 
                {
505
 
                        Columns = BitConverter.ToUInt16 (raw_data, 0, little);
506
 
                        Rows = BitConverter.ToUInt16 (raw_data, 2, little);
507
 
                        Names = new string [Columns];
508
 
                        Values = new SRational [Columns * Rows];
509
 
 
510
 
                        int pos = 2;
511
 
                        int i;
512
 
                        int type_size = DirectoryEntry.GetTypeSize (EntryType.SRational);
513
 
 
514
 
                        for (i = 0; i < Names.Length; i++)
515
 
                                Names [i] = ReadString (raw_data, ref pos);
516
 
                        
517
 
                        for (i = 0; i < Values.Length; i++)
518
 
                                Values [i] = new SRational (raw_data, pos + i * type_size, little);
519
 
                        
520
 
                }
521
 
 
522
 
                public string ReadString (byte [] data, ref int pos)
523
 
                {
524
 
                        int start = pos;
525
 
                        for (; pos < data.Length; pos++) {
526
 
                                if (data [pos] == 0)
527
 
                                        break;
528
 
                        }       
529
 
                        return System.Text.Encoding.ASCII.GetString (data, start, pos - start);
530
 
                }
531
 
        }
532
 
 
533
 
        public enum ExtraSamples {
534
 
                Unspecified = 0,
535
 
                AssociatedAlpha = 1,
536
 
                UnassociatedAlpa = 2
537
 
        }
538
 
 
539
 
        public enum FileSource {
540
 
                DCF = 3,
541
 
        }
542
 
 
543
 
        public enum PhotometricInterpretation : ushort {
544
 
                WhiteIsZero = 0,
545
 
                BlackIsZero = 1,
546
 
                RGB = 2,
547
 
                PaletteColor = 3,
548
 
                TransparencyMask = 4,
549
 
                Separated = 5,  // CMYK
550
 
                YCbCr = 6,
551
 
                CIELab = 8,
552
 
                ICCLab = 9,
553
 
                ITULab = 10,
554
 
                LogL = 32844, // Log Luminance
555
 
                LogLUV = 32845,
556
 
                ColorFilterArray = 32803,  // ColorFilterArray... the good stuff
557
 
                LinearRaw = 34892  // DBG LinearRaw
558
 
        }
559
 
 
560
 
        public enum PlanarConfiguration {
561
 
                Chunky = 1,
562
 
                Planar = 2
563
 
        }
564
 
        
565
 
        public enum Compression {
566
 
                Packed = 1,
567
 
                Huffman = 2,
568
 
                T4 = 3,
569
 
                T6 = 4,
570
 
                LZW = 5,
571
 
                JPEG = 6,
572
 
                JPEGStream = 7,  // TIFF-EP stores full jpeg stream 
573
 
                Deflate = 8,
574
 
                JBIG = 9,
575
 
                JBIG_MRC,
576
 
                PackBits = 32773,
577
 
                NikonCompression = 34713,
578
 
                Deflate_experimental = 0x80b2
579
 
        }
580
 
 
581
 
        public enum JPEGProc {
582
 
                BaselineSequencial = 1,
583
 
                LosslessHuffman = 14,
584
 
        }
585
 
 
586
 
        public enum SubfileType {
587
 
                FullResolution = 1,
588
 
                ReducedResolution = 2,
589
 
                PageOfMultipage = 3
590
 
        }
591
 
        
592
 
        public enum ExposureProgram {
593
 
                NotDefined = 0,
594
 
                Manual = 1,
595
 
                NormalProgram = 2,  // Normal Program
596
 
                AperturePriority = 3, // Aperture priority
597
 
                ShutterPriorty = 4, // Shutter priority
598
 
                CreativeProgram = 5, // Creative program
599
 
                ActionProgram = 6, // Action program
600
 
                PortraitMode = 7, // Portrait mode
601
 
                LandscapeMode = 8 // Landscape mode
602
 
        }
603
 
 
604
 
        public enum ExposureMode {
605
 
                Auto = 0,
606
 
                Manual = 1,
607
 
                AutoBracket = 2
608
 
        }
609
 
 
610
 
        public enum CustomRendered : ushort {
611
 
                Normal = 0,
612
 
                Custom = 1
613
 
        }
614
 
 
615
 
 
616
 
        public enum SceneType {
617
 
                DirectlyPhotographed = 1
618
 
        }
619
 
 
620
 
        public enum MeteringMode {
621
 
                Uknown = 0,
622
 
                Average = 1,
623
 
                CenterWeightedAverage = 2,
624
 
                Spot = 3,
625
 
                MulitSpot = 4,
626
 
                Pattern = 5,
627
 
                Partial = 6,
628
 
        }
629
 
 
630
 
        public enum SceneCaptureType : ushort {
631
 
                Standard = 0,
632
 
                Landscape = 1,
633
 
                Portrait = 2,
634
 
                NightScene = 3
635
 
        }
636
 
 
637
 
        public enum GainControl : ushort {
638
 
                None = 0,
639
 
                LowGainUp = 1,
640
 
                HighGainUp = 2,
641
 
                LowGainDown = 3,
642
 
                HighGainDown = 4
643
 
        }
644
 
 
645
 
        public enum Contrast : ushort {
646
 
                Normal = 0,
647
 
                Soft = 1,
648
 
                Hard = 2
649
 
        }
650
 
        
651
 
        public enum Saturation : ushort {
652
 
                Normal = 0,
653
 
                Low = 1,
654
 
                High = 2
655
 
        }
656
 
 
657
 
        public enum WhiteBalance : ushort {
658
 
                Auto = 0,
659
 
                Manual = 1
660
 
        }
661
 
 
662
 
        public enum Sharpness : ushort {
663
 
                Normal = 0,
664
 
                Soft = 1,
665
 
                Hard = 2
666
 
        }
667
 
 
668
 
        public enum LightSource {
669
 
                Unknown = 0,
670
 
                Daylight = 1,
671
 
                Fluorescent = 2,
672
 
                Tungsten = 3,
673
 
                Fash = 4,
674
 
                FineWeather = 9,
675
 
                CloudyWeather = 10,
676
 
                Shade = 11,
677
 
                DaylightFluorescent = 12,
678
 
                DaylightWhiteFluorescent = 13,
679
 
                CoolWhiteFluorescent = 14,
680
 
                WhiteFluorescent = 15,
681
 
                StandardLightA = 17,
682
 
                StandardLightB = 18,
683
 
                StandardLightC = 19,
684
 
                D55 = 20,
685
 
                D65 = 21,
686
 
                D75 = 22,
687
 
                D50 = 23,
688
 
                ISOStudioTungsten = 24,
689
 
                OtherSource = 255
690
 
        }
691
 
 
692
 
        public enum ColorSpace {
693
 
                StandardRGB = 1,  // sRGB
694
 
                AdobeRGB = 2,
695
 
                Uncalibrated = 0xffff
696
 
        }
697
 
 
698
 
        public enum ComponentsConfiguration {
699
 
                DoesNotExist = 0,
700
 
                Y = 1,
701
 
                Cb = 2,
702
 
                Cr = 3,
703
 
                R = 4,
704
 
                G = 6,
705
 
        }
706
 
 
707
 
        public enum ResolutionUnit : ushort {
708
 
                Uncalibrated = 1,
709
 
                Inch = 2,
710
 
                Centimeter = 3
711
 
        }
712
 
        
713
 
        public enum SensingMethod : short {
714
 
                NotDefined = 1,
715
 
                OneChipColorAreaSensor = 2,
716
 
                TwoChipColorAreaSensor = 3,
717
 
                ThreeChipColorAreaSensor = 4,
718
 
                ColorSequentialAreaSensor = 5,
719
 
                TrilinearSensor = 7,
720
 
                ColorSequentialLinearSensor = 8
721
 
        }
722
 
 
723
 
        [System.Flags]
724
 
        public enum NewSubfileType : uint {
725
 
                ReducedResolution = 1,
726
 
                PageOfMultipage= 1 << 1,
727
 
                TransparencyMask = 1 << 2
728
 
        }
729
 
 
730
 
        public enum EntryType {
731
 
                Byte = 1,
732
 
                Ascii,
733
 
                Short,
734
 
                Long,
735
 
                Rational,
736
 
                SByte,
737
 
                Undefined,
738
 
                SShort,
739
 
                SLong,
740
 
                SRational,
741
 
                Float,
742
 
                Double,
743
 
                Ifd // TIFF-EP - TIFF PageMaker TechnicalNote 2
744
 
        }
745
 
        
746
 
        public class Tag {
747
 
                public ushort Id;
748
 
                public EntryType Type;
749
 
                public int Count;
750
 
                public string Name;
751
 
                public string Description;
752
 
        }
753
 
 
754
 
        public class CanonTag : Tag {
755
 
                // http://www.gvsoft.homedns.org/exif/makernote-canon.html
756
 
                
757
 
                public enum CanonId {
758
 
                        Unknown1           = 0x0000,
759
 
                        CameraSettings1    = 0x0001,
760
 
                        Unknown2           = 0x0003,
761
 
                        CameraSettings2    = 0x0004,
762
 
                        ImageType          = 0x0006,
763
 
                        FirmwareVersion    = 0x0007,
764
 
                        ImageNumber        = 0x0008,
765
 
                        OwnerName          = 0x0009,
766
 
                        Unknown3           = 0x000a,
767
 
                        CameraSerialNumber = 0x000c,
768
 
                        Unknown4           = 0x000d,
769
 
                        CustomFunctions    = 0x000f
770
 
                }
771
 
                
772
 
                public CanonTag (CanonId id, EntryType type, int count, string name, string description)
773
 
                {
774
 
                        this.Id = (ushort)id;
775
 
                        this.Type = type;
776
 
                        this.Count = count;
777
 
                        this.Name = name;
778
 
                        this.Description = description;
779
 
                }
780
 
 
781
 
                public static System.Collections.Hashtable Tags;
782
 
 
783
 
                static CanonTag () {
784
 
                        CanonTag [] tags = { 
785
 
                                new CanonTag (CanonId.Unknown1, EntryType.Short, 6, null, null),
786
 
                                new CanonTag (CanonId.CameraSettings1, EntryType.Short, -1, "Camera Settings 1", "First Canon MakerNote settings section"),
787
 
                                new CanonTag (CanonId.Unknown2, EntryType.Short, 4, null, null),                                
788
 
                                new CanonTag (CanonId.CameraSettings2, EntryType.Short, -1, "Camera Settings 2", "Second Canon MakerNote settings section"),
789
 
                                new CanonTag (CanonId.ImageType, EntryType.Ascii, 32, "Image Type", null), // FIXME description
790
 
                                new CanonTag (CanonId.FirmwareVersion, EntryType.Ascii, 24, "Firmware Version", "Version of the firmware installed on the camera"),
791
 
                                new CanonTag (CanonId.ImageNumber, EntryType.Long, 1, "Image Number", null), // FIXME description
792
 
                                new CanonTag (CanonId.OwnerName, EntryType.Long, 32, "Owner Name", "Name of the Camera Owner"), // FIXME description
793
 
                                new CanonTag (CanonId.Unknown4, EntryType.Short, -1, null, null),                               
794
 
                                new CanonTag (CanonId.CameraSerialNumber, EntryType.Short, 1, "Serial Number", null), //FIXME description
795
 
                                new CanonTag (CanonId.Unknown4, EntryType.Short, -1, null, null),                               
796
 
                                new CanonTag (CanonId.CustomFunctions, EntryType.Short, -1, "Custom Functions", "Camera Custom Functions")
797
 
                        };
798
 
                                         
799
 
                        foreach (CanonTag tag in tags)
800
 
                                Tags [tag.Id] = tag;
801
 
                }
802
 
 
803
 
        }
804
 
        
805
 
        public enum Endian {
806
 
                Big,
807
 
                Little
808
 
        }
809
 
 
810
 
        public class Converter {
811
 
                public static uint ReadUInt (System.IO.Stream stream, Endian endian)
812
 
                {
813
 
                        byte [] tmp = new byte [4];
814
 
 
815
 
                        if (stream.Read (tmp, 0, tmp.Length) < 4)
816
 
                                throw new System.Exception ("Short Read");
817
 
 
818
 
                        return BitConverter.ToUInt32 (tmp, 0, endian == Endian.Little);
819
 
                }
820
 
 
821
 
                public static ushort ReadUShort (System.IO.Stream stream, Endian endian)
822
 
                {
823
 
                        byte [] tmp = new byte [2];
824
 
 
825
 
                        if (stream.Read (tmp, 0, tmp.Length) < 2)
826
 
                                throw new System.Exception ("Short Read");
827
 
 
828
 
                        return BitConverter.ToUInt16 (tmp, 0, endian == Endian.Little);
829
 
                }
830
 
        }
831
 
 
832
 
        public class Header : SemWeb.StatementSource {
833
 
                public Endian endian;
834
 
 
835
 
                private uint directory_offset;
836
 
                public ImageDirectory Directory;
837
 
 
838
 
                // false seems a safe default
839
 
                public bool Distinct {
840
 
                        get { return false; }
841
 
                }
842
 
 
843
 
                public Header (System.IO.Stream stream)
844
 
                {
845
 
                        //using (new Timer ("new Tiff.Header")) {
846
 
                        byte [] data = new byte [8];
847
 
                        stream.Read (data, 0, data.Length);
848
 
                        if (data [0] == 'M' && data [1] == 'M')
849
 
                                endian = Endian.Big;
850
 
                        else if (data [0] == 'I' && data [1] == 'I')
851
 
                                endian = Endian.Little;
852
 
 
853
 
                        ushort marker = BitConverter.ToUInt16 (data, 2, endian == Endian.Little);
854
 
                        switch (marker) {
855
 
                        case 42:
856
 
                                //System.Console.WriteLine ("Found Standard Tiff Marker {0}", marker);
857
 
                                break;
858
 
                        case 0x4f52:
859
 
                                //System.Console.WriteLine ("Found Olympus Tiff Marker {0}", marker.ToString ("x"));
860
 
                                break;
861
 
                        case 0x4e31:
862
 
                                //System.Console.WriteLine ("Found Navy Interchange File Format Tiff Marker {0}", marker.ToString ("x")); 
863
 
                                break;
864
 
                        default:
865
 
                                //System.Console.WriteLine ("Found Unknown Tiff Marker {0}", marker.ToString ("x"));
866
 
                                break;
867
 
                        }
868
 
 
869
 
                        //System.Console.WriteLine ("Converting Something");
870
 
                        directory_offset = BitConverter.ToUInt32 (data, 4, endian == Endian.Little);
871
 
                        
872
 
                        if (directory_offset < 8)
873
 
                                throw new System.Exception ("Invalid IFD0 Offset [" + directory_offset.ToString () + "]"); 
874
 
                        
875
 
#if DEBUG_LOADER
876
 
                        //System.Console.WriteLine ("Reading First IFD");
877
 
#endif
878
 
                        Directory = new ImageDirectory (stream, directory_offset, endian); 
879
 
                        //}
880
 
                }
881
 
                
882
 
                
883
 
                public void Select (SemWeb.StatementSink sink)
884
 
                {
885
 
                        //using (new Timer ("Tiff.Header.Select")) {
886
 
                                SelectDirectory (Directory, sink);
887
 
                        //}
888
 
                }
889
 
 
890
 
                public void SelectDirectory (ImageDirectory dir, StatementSink sink)
891
 
                {
892
 
                        foreach (DirectoryEntry e in dir.Entries) {
893
 
#if DEBUG_LOADER
894
 
                                //System.Console.WriteLine ("{0}", e.Id);
895
 
#endif
896
 
                                switch (e.Id) {
897
 
                                case TagId.IPTCNAA:
898
 
                                        System.IO.Stream iptcstream = new System.IO.MemoryStream (e.RawData);
899
 
                                        Iptc.IptcFile iptc = new Iptc.IptcFile (iptcstream);
900
 
                                        iptc.Select (sink);
901
 
                                        break;
902
 
                                case TagId.PhotoshopPrivate:
903
 
                                        System.IO.Stream bimstream = new System.IO.MemoryStream (e.RawData);
904
 
                                        Bim.BimFile bim = new Bim.BimFile (bimstream);
905
 
                                        bim.Select (sink);
906
 
                                        break;
907
 
                                case TagId.XMP:
908
 
                                        System.IO.Stream xmpstream = new System.IO.MemoryStream (e.RawData);
909
 
                                        Xmp.XmpFile xmp = new Xmp.XmpFile (xmpstream);
910
 
                                        xmp.Select (sink);
911
 
                                        break;
912
 
                                case TagId.ImageDescription:
913
 
                                        MetadataStore.AddLiteral (sink, "dc:description", "rdf:Alt", 
914
 
                                                                  new Literal (e.ValueAsString [0], "x-default", null));
915
 
                                        break;
916
 
                                case TagId.UserComment:
917
 
                                        MetadataStore.AddLiteral (sink, "exif:UserComment", "rdf:Alt", 
918
 
                                                                  new Literal (e.ValueAsString [0], "x-default", null));
919
 
                                        break;
920
 
                                case TagId.Copyright:
921
 
                                        MetadataStore.AddLiteral (sink, "dc:rights", "rdf:Alt", 
922
 
                                                                  new Literal (e.ValueAsString [0], "x-default", null));
923
 
                                        break;
924
 
                                case TagId.Artist:
925
 
                                        MetadataStore.Add (sink, "dc:creator", "rdf:Seq", e.ValueAsString);
926
 
                                        break;
927
 
                                case TagId.ExifIfdPointer:
928
 
                                        try {
929
 
                                                ImageDirectory sub = ((SubdirectoryEntry)e).Directory [0];
930
 
                                                SelectDirectory (sub, sink);
931
 
                                        } catch (System.Exception exc) {
932
 
                                                System.Console.WriteLine (exc);
933
 
                                        }
934
 
                                        break;
935
 
                                case TagId.Software:
936
 
                                        MetadataStore.AddLiteral (sink, "xmp:CreatorTool", e.ValueAsString [0]);
937
 
                                        break;
938
 
                                case TagId.DateTime:
939
 
                                        try {
940
 
 
941
 
                                        MetadataStore.AddLiteral (sink, "xmp:ModifyDate", 
942
 
                                                                  e.ValueAsDate.ToString ("yyyy-MM-ddThh:mm:ss"));
943
 
                                        } catch (System.Exception ex) {
944
 
                                                System.Console.WriteLine (String.Format ("error parsing {0}\n{1}", e.ValueAsString[0], ex));
945
 
                                        }
946
 
 
947
 
                                        break;
948
 
                                case TagId.DateTimeOriginal:
949
 
                                case TagId.DateTimeDigitized:
950
 
                                        // FIXME subsectime needs to be included in these values
951
 
                                        // FIXME shouldn't DateTimeOriginal be xmp:CreateDate? the spec says no but wtf?
952
 
                                        try {
953
 
                                                MetadataStore.AddLiteral (sink, "exif:" + e.Id.ToString (), 
954
 
                                                                          e.ValueAsDate.ToString ("yyyy-MM-ddThh:mm:ss"));
955
 
                                        } catch (System.Exception ex) {
956
 
                                                System.Console.WriteLine (String.Format ("error parsing {0}\n{1}", e.ValueAsString[0], ex));
957
 
                                        }
958
 
                                        break;
959
 
                                        //case TagId.SpatialFrequencyResponse
960
 
                                case TagId.ExifCFAPattern:
961
 
                                        CFAPattern pattern = new CFAPattern (e.RawData, e.IsLittle);
962
 
                                        Entity empty = new BNode ();
963
 
                                        Statement top = new Statement (MetadataStore.FSpotXMPBase, 
964
 
                                                                       (Entity)MetadataStore.Namespaces.Resolve ("exif:" + e.Id.ToString ()),
965
 
                                                                       empty);
966
 
                                        
967
 
                                        Statement cols = new Statement (empty, 
968
 
                                                                        (Entity) MetadataStore.Namespaces.Resolve ("exif:Columns"),
969
 
                                                                        new Literal (pattern.Columns.ToString (), null, null));
970
 
                                        sink.Add (cols);
971
 
                                        Statement rows = new Statement (empty, 
972
 
                                                                        (Entity) MetadataStore.Namespaces.Resolve ("exif:Rows"),
973
 
                                                                        new Literal (pattern.Rows.ToString (), null, null));
974
 
                                        sink.Add (rows);
975
 
                                        string [] vals = e.ArrayToString (pattern.Values);
976
 
                                        MetadataStore.Add (sink, empty, "exif:Values", "rdf:Seq", vals);
977
 
                                        sink.Add (top);
978
 
                                        break;
979
 
                                case TagId.ExifVersion:
980
 
                                case TagId.FlashPixVersion:
981
 
                                case TagId.ColorSpace:
982
 
                                case TagId.CompressedBitsPerPixel:
983
 
                                case TagId.PixelYDimension:
984
 
                                case TagId.PixelXDimension:
985
 
                                case TagId.RelatedSoundFile:
986
 
                                case TagId.ExposureTime:
987
 
                                case TagId.FNumber:
988
 
                                case TagId.ExposureProgram:
989
 
                                case TagId.SpectralSensitivity:
990
 
                                case TagId.ShutterSpeedValue:
991
 
                                case TagId.ApertureValue:
992
 
                                case TagId.BrightnessValue:
993
 
                                case TagId.ExposureBiasValue:
994
 
                                case TagId.MaxApertureValue:
995
 
                                case TagId.SubjectDistance:
996
 
                                case TagId.MeteringMode:
997
 
                                case TagId.LightSource:
998
 
                                case TagId.FocalLength:
999
 
                                case TagId.FlashEnergy:
1000
 
                                case TagId.FocalPlaneXResolution:
1001
 
                                case TagId.FocalPlaneYResolution:
1002
 
                                case TagId.FocalPlaneResolutionUnit:
1003
 
                                case TagId.ExposureIndex:
1004
 
                                case TagId.SensingMethod:
1005
 
                                case TagId.FileSource:
1006
 
                                case TagId.SceneType:
1007
 
                                case TagId.CustomRendered:
1008
 
                                case TagId.ExposureMode:
1009
 
                                case TagId.WhiteBalance:
1010
 
                                case TagId.DigitalZoomRatio:
1011
 
                                case TagId.FocalLengthIn35mmFilm:
1012
 
                                case TagId.SceneCaptureType:
1013
 
                                case TagId.GainControl:
1014
 
                                case TagId.Contrast:
1015
 
                                case TagId.Saturation:
1016
 
                                case TagId.Sharpness:
1017
 
                                        MetadataStore.AddLiteral (sink, "exif:" + e.Id.ToString (), e.ValueAsString [0]);
1018
 
                                        break;
1019
 
                                case TagId.ComponentsConfiguration:
1020
 
                                case TagId.ISOSpeedRatings:
1021
 
                                case TagId.SubjectArea:
1022
 
                                case TagId.SubjectLocation:
1023
 
                                        MetadataStore.Add (sink, "exif:" + e.Id.ToString (), "rdf:Seq", e.ValueAsString);
1024
 
                                        break;
1025
 
                                case TagId.TransferFunction:
1026
 
                                case TagId.YCbCrSubSampling:
1027
 
                                case TagId.WhitePoint:
1028
 
                                case TagId.PrimaryChromaticities:
1029
 
                                case TagId.YCbCrCoefficients:
1030
 
                                case TagId.ReferenceBlackWhite:
1031
 
                                case TagId.BitsPerSample:
1032
 
                                        MetadataStore.Add (sink, "tiff:" + e.Id.ToString (), "rdf:Seq", e.ValueAsString);
1033
 
                                        break;
1034
 
                                case TagId.Orientation:
1035
 
                                case TagId.Compression:
1036
 
                                case TagId.PhotometricInterpretation:                                   
1037
 
                                case TagId.SamplesPerPixel:
1038
 
                                case TagId.PlanarConfiguration:
1039
 
                                case TagId.YCbCrPositioning:
1040
 
                                case TagId.ResolutionUnit:
1041
 
                                case TagId.ImageWidth:
1042
 
                                case TagId.ImageLength:
1043
 
                                case TagId.Model:
1044
 
                                case TagId.Make:
1045
 
                                        MetadataStore.AddLiteral (sink, "tiff:" + e.Id.ToString (), e.ValueAsString [0]);
1046
 
                                        break;
1047
 
                                }
1048
 
                        }
1049
 
                }
1050
 
 
1051
 
                public void Dump (string name)
1052
 
                {
1053
 
                        ImageDirectory ifd = Directory;
1054
 
                        for (int i = 0; ifd != null; i++) {
1055
 
                                ifd.Dump (System.String.Format ("IFD[{0}]:", i));
1056
 
                                ifd = ifd.NextDirectory;
1057
 
                        }
1058
 
                }
1059
 
        }
1060
 
 
1061
 
        public class ImageDirectory {
1062
 
                protected Endian endian;
1063
 
                protected ushort num_entries;
1064
 
                protected System.Collections.ArrayList entries;
1065
 
                protected uint orig_position;
1066
 
 
1067
 
                protected uint next_directory_offset;
1068
 
                ImageDirectory next_directory;
1069
 
                
1070
 
                protected bool has_header;
1071
 
                protected bool has_footer;
1072
 
 
1073
 
                public ImageDirectory (System.IO.Stream stream, uint start_position, Endian endian)
1074
 
                {
1075
 
                        this.endian = endian;
1076
 
                        orig_position = start_position;
1077
 
                        Load (stream);
1078
 
                }
1079
 
                
1080
 
                protected void Load (System.IO.Stream stream)
1081
 
                {
1082
 
                        ReadHeader (stream);                    
1083
 
                        ReadEntries (stream);
1084
 
                        ReadFooter (stream);
1085
 
                        
1086
 
                        LoadEntries (stream);
1087
 
                        LoadNextDirectory (stream);
1088
 
                }
1089
 
 
1090
 
                public virtual bool ReadHeader (System.IO.Stream stream)
1091
 
                {
1092
 
                        stream.Seek ((long)orig_position, System.IO.SeekOrigin.Begin);
1093
 
                        return true;
1094
 
                }
1095
 
 
1096
 
                protected virtual void ReadEntries (System.IO.Stream stream) 
1097
 
                {
1098
 
                        num_entries = Converter.ReadUShort (stream, endian);
1099
 
#if DEBUG_LOADER
1100
 
                        System.Console.WriteLine ("reading {0} entries", num_entries);
1101
 
#endif                  
1102
 
                        entries = new System.Collections.ArrayList (num_entries);
1103
 
                        int entry_length = num_entries * 12;
1104
 
                        byte [] content = new byte [entry_length];
1105
 
                        
1106
 
                        if (stream.Read (content, 0, content.Length) < content.Length)
1107
 
                                throw new System.Exception ("Short Read");
1108
 
                        
1109
 
                        for (int pos = 0; pos < entry_length; pos += 12) {
1110
 
                                DirectoryEntry entry = EntryFactory.CreateEntry (this, content, pos, this.endian);
1111
 
                                entries.Add (entry);            
1112
 
#if DEBUG_LOADER
1113
 
                                System.Console.WriteLine ("Added Entry {0} {1} - {2} * {3}", entry.Id.ToString (), entry.Id.ToString ("x"), entry.Type, entry.Count);
1114
 
#endif
1115
 
                                if (entry.Id == TagId.NewSubfileType) {
1116
 
                                        
1117
 
                                }
1118
 
                        }
1119
 
                }
1120
 
 
1121
 
                protected virtual void ReadFooter (System.IO.Stream stream)
1122
 
                {
1123
 
                        next_directory_offset = Converter.ReadUInt (stream, this.endian);
1124
 
                }
1125
 
 
1126
 
                protected void LoadEntries (System.IO.Stream stream)
1127
 
                {
1128
 
                        foreach (DirectoryEntry entry in entries) {
1129
 
                                entry.LoadExternal (stream);
1130
 
                        }
1131
 
                }
1132
 
                
1133
 
                protected void LoadNextDirectory (System.IO.Stream stream)
1134
 
                {
1135
 
#if DEBUG_LOADER
1136
 
                        System.Console.WriteLine ("start_position = {1} next_directory_offset = {0}", next_directory_offset, orig_position);
1137
 
#endif
1138
 
                        next_directory = null;
1139
 
                        try {
1140
 
                                if (next_directory_offset != 0 && next_directory_offset != orig_position)
1141
 
                                        next_directory = new ImageDirectory (stream, next_directory_offset, this.endian);
1142
 
                                
1143
 
                        } catch (System.Exception) {
1144
 
                                //System.Console.WriteLine ("Error loading directory {0}", e.ToString ());
1145
 
                                next_directory = null;
1146
 
                                next_directory_offset = 0;
1147
 
                        }               
1148
 
                }
1149
 
 
1150
 
                public ImageDirectory NextDirectory {
1151
 
                        get {
1152
 
                                return next_directory;
1153
 
                        }
1154
 
                }
1155
 
 
1156
 
                public System.Collections.ArrayList Entries {
1157
 
                        get { 
1158
 
                                return entries;
1159
 
                        }
1160
 
                }
1161
 
 
1162
 
                public DirectoryEntry Lookup (TagId id) 
1163
 
                {
1164
 
                        foreach (DirectoryEntry entry in entries)
1165
 
                                if (entry.Id == id)
1166
 
                                        return entry;
1167
 
 
1168
 
                        return null;
1169
 
                }
1170
 
 
1171
 
 
1172
 
                public DirectoryEntry Lookup (uint id) 
1173
 
                {
1174
 
                        foreach (DirectoryEntry entry in entries)
1175
 
                                if ((uint)entry.Id == id)
1176
 
                                        return entry;
1177
 
 
1178
 
                        return null;
1179
 
                }
1180
 
                
1181
 
#if false // FIXME: Do we need Cms ?
1182
 
 
1183
 
                public Cms.Profile GetProfile ()
1184
 
                {
1185
 
                        Cms.ColorCIExyY whitepoint = new Cms.ColorCIExyY (0, 0, 0);
1186
 
                        Cms.ColorCIExyYTriple primaries = new Cms.ColorCIExyYTriple (whitepoint, whitepoint, whitepoint);
1187
 
                        Cms.GammaTable [] transfer = null;
1188
 
                        int bits_per_sample = 8;
1189
 
                        double gamma = 2.2;
1190
 
                        
1191
 
                        foreach (DirectoryEntry e in entries) {
1192
 
                                switch (e.Id) {
1193
 
                                case TagId.InterColorProfile:
1194
 
                                        try {
1195
 
                                                return new Cms.Profile (e.RawData);
1196
 
                                        } catch (System.Exception ex) {
1197
 
                                                System.Console.WriteLine (ex);
1198
 
                                        }
1199
 
                                        break;
1200
 
                                case TagId.ColorSpace:
1201
 
                                        switch ((ColorSpace)e.ValueAsLong [0]) {
1202
 
                                        case ColorSpace.StandardRGB:
1203
 
                                                return Cms.Profile.CreateStandardRgb ();
1204
 
                                        case ColorSpace.AdobeRGB:
1205
 
                                                return Cms.Profile.CreateAlternateRgb ();
1206
 
                                        case ColorSpace.Uncalibrated:
1207
 
                                                //System.Console.WriteLine ("Uncalibrated colorspace");
1208
 
                                                break;
1209
 
                                        }
1210
 
                                        break;
1211
 
 
1212
 
                                case TagId.WhitePoint:
1213
 
                                        Rational [] white = e.RationalValue;
1214
 
                                        whitepoint.x = white [0].Value;
1215
 
                                        whitepoint.y = white [1].Value;
1216
 
                                        whitepoint.Y = 1.0;
1217
 
                                        break;
1218
 
                                case TagId.PrimaryChromaticities:
1219
 
                                        Rational [] colors = e.RationalValue;
1220
 
                                        primaries.Red.x = colors [0].Value;
1221
 
                                        primaries.Red.y = colors [1].Value;
1222
 
                                        primaries.Red.Y = 1.0;
1223
 
 
1224
 
                                        primaries.Green.x = colors [2].Value;
1225
 
                                        primaries.Green.y = colors [3].Value;
1226
 
                                        primaries.Green.Y = 1.0;
1227
 
 
1228
 
                                        primaries.Blue.x = colors [4].Value;
1229
 
                                        primaries.Blue.y = colors [5].Value;
1230
 
                                        primaries.Blue.Y = 1.0;
1231
 
                                        break;
1232
 
                                case TagId.TransferFunction:
1233
 
                                        ushort [] trns = e.ShortValue;
1234
 
                                        ushort gamma_count = (ushort) (1 << bits_per_sample);
1235
 
                                        Cms.GammaTable [] tables = new Cms.GammaTable [3];
1236
 
                                        //System.Console.WriteLine ("Parsing transfer function: count = {0}", trns.Length);
1237
 
 
1238
 
                                        // FIXME we should use the TransferRange here
1239
 
                                        // FIXME we should use bits per sample here
1240
 
                                        for (int c = 0; c < 3; c++) {
1241
 
                                                tables [c] = new Cms.GammaTable (trns, c * gamma_count, gamma_count);
1242
 
                                        }
1243
 
 
1244
 
                                        transfer = tables;
1245
 
                                        break;
1246
 
                                case TagId.ExifIfdPointer:
1247
 
                                        SubdirectoryEntry exif = (SubdirectoryEntry) e;
1248
 
                                        DirectoryEntry ee = exif.Directory [0].Lookup ((int)TagId.Gamma);
1249
 
                                        
1250
 
                                        if (ee == null)
1251
 
                                                break;
1252
 
 
1253
 
                                        Rational rgamma = ee.RationalValue [0];
1254
 
                                        gamma = rgamma.Value;
1255
 
                                        break;
1256
 
                                }
1257
 
                        }
1258
 
 
1259
 
                        if (transfer == null) {
1260
 
                                Cms.GammaTable basic = new Cms.GammaTable (1 << bits_per_sample, gamma);
1261
 
                                transfer = new Cms.GammaTable [] { basic, basic, basic };
1262
 
                        }
1263
 
 
1264
 
                        // if we didn't get a white point or primaries, give up
1265
 
                        if (whitepoint.Y != 1.0 || primaries.Red.Y != 1.0)
1266
 
                                return null;
1267
 
                                
1268
 
                        return new Cms.Profile (whitepoint, primaries, transfer);
1269
 
                }
1270
 
 
1271
 
#endif
1272
 
                public void Dump (string name) 
1273
 
                {
1274
 
                        System.Console.WriteLine ("Starting {0}", name);
1275
 
                        foreach (DirectoryEntry e in this.Entries)
1276
 
                                e.Dump (name);
1277
 
                        System.Console.WriteLine ("Ending {0}", name);
1278
 
                }
1279
 
                
1280
 
                public string Dump2 ()
1281
 
                {
1282
 
                        System.Text.StringBuilder builder = new System.Text.StringBuilder ();
1283
 
                        builder.Append ("Dummping IFD");
1284
 
                        foreach (DirectoryEntry entry in entries) {
1285
 
                                builder.Append (entry.ToString ()+ "\n");
1286
 
 
1287
 
                                if (entry is SubdirectoryEntry)
1288
 
                                        builder.Append ("Found SUBDIRECTORYENTRY\n");
1289
 
                        }
1290
 
                        
1291
 
                        if (next_directory != null) {
1292
 
                                builder.Append ("Dummping Next IFD");
1293
 
                                builder.Append (next_directory.Dump2 ());
1294
 
                        }
1295
 
 
1296
 
                        return builder.ToString ();
1297
 
                }
1298
 
        }
1299
 
        
1300
 
        public class EntryFactory {
1301
 
                //public delegate DirectoryEntry ConstructorFunc (byte [], Endian endian);
1302
 
                //public static System.Collections.Hashtable ctors = new System.Collections.Hashtable ();
1303
 
                
1304
 
                public static DirectoryEntry CreateEntry (ImageDirectory parent, byte [] input, int start, Endian header_endian)
1305
 
                {
1306
 
                        TagId tagid;
1307
 
                        EntryType type;
1308
 
 
1309
 
                        DirectoryEntry.ParseHeader (input, start, out tagid, out type, header_endian);
1310
 
                        //ConstructorFunc ctor = ctors[tagid];                  
1311
 
                        //if (ctor == null) {
1312
 
                        //      return ctor (input, header_endian);                             
1313
 
                        //}
1314
 
                        
1315
 
                        switch (tagid) {
1316
 
                        case TagId.ExifIfdPointer:
1317
 
                        case TagId.GPSInfoIfdPointer:
1318
 
                        case TagId.InteroperabilityIfdPointer:
1319
 
                        case TagId.SubIFDs:
1320
 
                                return new SubdirectoryEntry (input, start, header_endian);
1321
 
                                //case TagId.MakerNote:
1322
 
                                //return new MakerNoteEntry (input, start, header_endian);
1323
 
                                //case TagId.PimIfdPointer:
1324
 
                                //return new 
1325
 
                                //case TagId.MakerNote:
1326
 
                                //return new MakerNoteEntry (input, start, header_endian);
1327
 
                        }
1328
 
                        
1329
 
                        switch (type) {
1330
 
                        case EntryType.Ifd:
1331
 
                                //System.Console.WriteLine ("Trying to load {0} {1}", tagid, tagid.ToString ("x"));
1332
 
                                return new SubdirectoryEntry (input, start, header_endian);
1333
 
                        case EntryType.Byte:
1334
 
                                return new ByteEntry (input, start, header_endian);
1335
 
                        case EntryType.Long:
1336
 
                                return new LongEntry (input, start, header_endian);
1337
 
                        case EntryType.Short:
1338
 
                                return new ShortEntry (input, start, header_endian);
1339
 
                        }
1340
 
 
1341
 
                        return new DirectoryEntry (input, start, header_endian);
1342
 
                }
1343
 
        }
1344
 
               
1345
 
        public class MakerNoteEntry : SubdirectoryEntry {
1346
 
                public MakerNoteEntry (byte [] data, int offset, Endian endian) : base (data, offset, endian)
1347
 
                {
1348
 
                
1349
 
                }
1350
 
 
1351
 
                public override uint GetEntryCount ()
1352
 
                {
1353
 
                        return 1;
1354
 
                }
1355
 
 
1356
 
                public override void LoadExternal (System.IO.Stream stream)
1357
 
                {
1358
 
                }
1359
 
        }
1360
 
 
1361
 
 
1362
 
        public class SubdirectoryEntry : DirectoryEntry {
1363
 
                public uint directory_offset;
1364
 
                public ImageDirectory [] Directory;
1365
 
                
1366
 
                public SubdirectoryEntry (byte [] data, int offset, Endian endian) : base (data, offset, endian)
1367
 
                {
1368
 
                        if (this.GetEntryCount () > 1) {
1369
 
                                //System.Console.WriteLine ("Count is greater than 1 ({1}) on Subdirectory {0} interesting", tagid, count);
1370
 
                        }
1371
 
                }
1372
 
 
1373
 
                public virtual uint GetEntryCount ()
1374
 
                {
1375
 
                        return count;
1376
 
                }
1377
 
 
1378
 
                public override void LoadExternal (System.IO.Stream stream)
1379
 
                {
1380
 
                        uint entry_count = GetEntryCount ();
1381
 
                        Directory = new ImageDirectory [entry_count];
1382
 
 
1383
 
                        base.LoadExternal (stream);
1384
 
 
1385
 
                        for (int i = 0; i <  entry_count; i++) {
1386
 
                                try {
1387
 
                                        directory_offset = BitConverter.ToUInt32 (raw_data, i * 4, endian == Endian.Little);
1388
 
                                        Directory [i] = new ImageDirectory (stream, directory_offset, endian);
1389
 
                                } catch (System.Exception e) {
1390
 
                                        System.Console.WriteLine ("Error loading Subdirectory {0} at {2} of {3}bytes:\n{1}", 
1391
 
                                                                  this.Id, e, directory_offset, stream.Length);
1392
 
                                }
1393
 
                                        
1394
 
                        }
1395
 
                }
1396
 
 
1397
 
                public override void Dump (string name)
1398
 
                {
1399
 
                        for (int i = 0; i < GetEntryCount (); i++) {
1400
 
                                string subdirname = System.String.Format ("{0}{1}[{2}]({3})]", name, tagid, i, directory_offset);
1401
 
 
1402
 
                                try {
1403
 
                                        if (Directory [i] != null)
1404
 
                                                Directory [i].Dump (subdirname);
1405
 
                                } catch (System.Exception e) {
1406
 
                                        System.Console.WriteLine (e);
1407
 
                                }
1408
 
                        }
1409
 
                }
1410
 
        }
1411
 
        
1412
 
        public class ShortEntry : DirectoryEntry {
1413
 
                public ShortEntry (byte [] data, int offset, Endian endian) : base (data, offset, endian)
1414
 
                {
1415
 
                }
1416
 
        }
1417
 
        
1418
 
        public class LongEntry : DirectoryEntry {
1419
 
                public LongEntry (byte [] data, int offset, Endian endian) : base (data, offset, endian)
1420
 
                {
1421
 
                        if (type != EntryType.Long)
1422
 
                                throw new System.Exception (System.String.Format ("Invalid Settings At Birth {0}", tagid));
1423
 
                }
1424
 
        }
1425
 
 
1426
 
        public class ByteEntry : DirectoryEntry {
1427
 
                public ByteEntry (byte [] data, int offset, Endian endian) : base (data, offset, endian)
1428
 
                {
1429
 
                        if (type != EntryType.Byte)
1430
 
                                throw new System.Exception ("Invalid Settings At Birth");
1431
 
                }
1432
 
        }
1433
 
        
1434
 
#if false
1435
 
        public class ImageLoader {
1436
 
                int width;
1437
 
                int length;
1438
 
                int [] bps;
1439
 
                PhotometricInterpretation interpretation;
1440
 
                Compression compression;
1441
 
                uint [] offsets;
1442
 
                uint [] strip_byte_counts;
1443
 
                uint rows_per_strip;
1444
 
                byte [] strip;
1445
 
 
1446
 
                public ImageLoader (ImageDirectory directory) 
1447
 
                {
1448
 
                        width = directory.Lookup (TagId.ImageWidth).ValueAsLong [0];
1449
 
                        length = directory.Lookup (TagId.ImageLength).ValueAsLong [0];
1450
 
                        bps = directory.Lookup (TagId.BitsPerSample).ValueAsLong;
1451
 
                        
1452
 
                        compression = (Compression) directory.Lookup (TagId.Compression).ValueAsLong [0];
1453
 
                        interpretation = (PhotometricInterpretation) directory.Lookup (TagId.PhotometricInterpretation).ValueAsLong [0];
1454
 
                        
1455
 
                        offsets = directory.Lookup (TagId.StripOffsets).ValueAsLong;
1456
 
                        strip_byte_counts = directory.Lookup (TagId.StripByteCounts).ValueAsLong;
1457
 
                        rows_per_strip = directory.Lookup (TagId.RowsPerStrip).ValueAsLong [0];
1458
 
 
1459
 
                        if (interpretation != 
1460
 
                }
1461
 
 
1462
 
 
1463
 
                public Gdk.Pixbuf LoadPixbuf (System.IO.Stream stream) 
1464
 
                {
1465
 
                        Gdk.Pixbuf dest = new Gdk.Pixbuf (Gdk.Colorspace.Rgb, false, width, height);
1466
 
                        strip = new byte [strip_byte_counts];
1467
 
                        int row;
1468
 
                        for (int i = 0; i < offsets.Length; i++) {
1469
 
                                strip = new byte [strip_byte_counts [i]];
1470
 
                                stream.Read (strip, 0, strip.Length);
1471
 
                                switch (compression) {
1472
 
                                        case Compression.Notice
1473
 
 
1474
 
                                }
1475
 
                        }
1476
 
                }
1477
 
        }
1478
 
#endif
1479
 
 
1480
 
        public class DirectoryEntry {
1481
 
                protected TagId  tagid;
1482
 
                protected EntryType type;
1483
 
                protected uint count;
1484
 
                protected uint offset_origin;
1485
 
                protected uint data_offset;
1486
 
 
1487
 
                protected byte [] raw_data;
1488
 
                protected Endian endian;
1489
 
 
1490
 
                public TagId Id {
1491
 
                        get {
1492
 
                                return tagid;
1493
 
                        }
1494
 
                }
1495
 
 
1496
 
                public EntryType Type {
1497
 
                        get {
1498
 
                                return type;
1499
 
                        }
1500
 
                }
1501
 
                
1502
 
                public uint Count {
1503
 
                        get {
1504
 
                                return count;
1505
 
                        }
1506
 
                }
1507
 
 
1508
 
                public void SetOrigin (uint pos)
1509
 
                {
1510
 
                        offset_origin = pos;
1511
 
                }
1512
 
 
1513
 
                public uint Position {
1514
 
                        get {
1515
 
                                return offset_origin + data_offset;
1516
 
                        }
1517
 
                }
1518
 
 
1519
 
                public virtual int GetTypeSize ()
1520
 
                {
1521
 
                        return GetTypeSize (type);
1522
 
                }
1523
 
 
1524
 
                public static int GetTypeSize (EntryType type)
1525
 
                {
1526
 
                        switch (type) {
1527
 
                        case EntryType.Byte:
1528
 
                        case EntryType.SByte:
1529
 
                        case EntryType.Undefined:
1530
 
                        case EntryType.Ascii:
1531
 
                                return 1;
1532
 
                        case EntryType.Short:
1533
 
                        case EntryType.SShort:
1534
 
                                return 2;
1535
 
                        case EntryType.Long:
1536
 
                        case EntryType.SLong:
1537
 
                        case EntryType.Float:
1538
 
                                return 4;
1539
 
                        case EntryType.Double:
1540
 
                        case EntryType.Rational:
1541
 
                        case EntryType.SRational:
1542
 
                                return 8;
1543
 
                        default:
1544
 
                                return 1;
1545
 
                        }
1546
 
                }
1547
 
 
1548
 
                public bool IsLittle {
1549
 
                        get {
1550
 
                                return (endian == Endian.Little);
1551
 
                        }
1552
 
                }
1553
 
 
1554
 
                public static int ParseHeader (byte [] data, int start, out TagId tagid, out EntryType type, Endian endian)
1555
 
                {
1556
 
                        tagid = (TagId) BitConverter.ToUInt16 (data, start, endian == Endian.Little);
1557
 
                        type = (EntryType) BitConverter.ToUInt16 (data, start + 2, endian == Endian.Little);
1558
 
                        return 4;
1559
 
                }
1560
 
                
1561
 
                public DirectoryEntry (byte [] data, int start, Endian endian)
1562
 
                {
1563
 
                        this.endian = endian;
1564
 
 
1565
 
                        start += ParseHeader (data, start, out this.tagid, out this.type, endian);
1566
 
                        ParseStream (data, start);
1567
 
                }
1568
 
 
1569
 
                public virtual void LoadExternal (System.IO.Stream stream)
1570
 
                {
1571
 
                        if (data_offset != 0) {
1572
 
                                stream.Seek ((long)Position, System.IO.SeekOrigin.Begin);
1573
 
                                byte [] data = new byte [count * GetTypeSize ()];
1574
 
                                if (stream.Read (data, 0, data.Length) < data.Length)
1575
 
                                        throw new System.Exception ("Short Read");
1576
 
                                raw_data = data;
1577
 
                        }
1578
 
 
1579
 
#if false
1580
 
                        switch ((int)this.Id) {
1581
 
                        case (int)TagId.NewSubfileType:
1582
 
                                //System.Console.WriteLine ("XXXXXXXXXXXXXXXXXXXXX new NewSubFileType {0}", (NewSubfileType) this.ValueAsLong [0]);
1583
 
                                break;
1584
 
                        case (int)TagId.SubfileType:
1585
 
                                //System.Console.WriteLine ("XXXXXXXXXXXXXXXXXXXXX new SubFileType {0}", (SubfileType) this.ValueAsLong [0]);
1586
 
                                break;
1587
 
                        case (int)TagId.Compression:
1588
 
                                //System.Console.WriteLine ("XXXXXXXXXXXXXXXXXXXXX new Compression {0}", (Compression) this.ValueAsLong [0]);
1589
 
                                
1590
 
                                break;
1591
 
                        case (int)TagId.JPEGProc:
1592
 
                                //System.Console.WriteLine ("XXXXXXXXXXXXXXXXXXXXX new JPEGProc {0}", (JPEGProc) this.ValueAsLong [0]);
1593
 
                                
1594
 
                                break;
1595
 
                        case (int)TagId.PhotometricInterpretation:
1596
 
                                //System.Console.WriteLine ("XXXXXXXXXXXXXXXXXXXXX new PhotometricInterpretation {0}", (PhotometricInterpretation) this.ValueAsLong [0]);
1597
 
                                break;
1598
 
                        case (int)TagId.ImageWidth:
1599
 
                        case (int)TagId.ImageLength:
1600
 
                                //System.Console.WriteLine ("XXXXXXXXXXXXXXXXXXXXX new {1} {0}", this.ValueAsLong [0], this.Id);
1601
 
                                break;
1602
 
                        case 50648:
1603
 
                        case 50656:
1604
 
                        case 50752:
1605
 
                                //System.Console.WriteLine ("XXXXXXXXXXXXXXXXXXXXX {0}({1}) - {2} {3}", this.Id, this.Id.ToString ("x"), this.type, raw_data.Length);
1606
 
                                //System.Console.WriteLine ("XXXX ", System.Text.Encoding.ASCII.GetString (raw_data));
1607
 
                                switch (this.type) {
1608
 
                                case EntryType.Long:
1609
 
                                        //foreach (uint val in ((LongEntry)this).Value)
1610
 
                                                //System.Console.Write (" {0}", val);
1611
 
                                        break;
1612
 
                                case EntryType.Short:
1613
 
                                        //foreach (ushort val in ((ShortEntry)this).ShortValue)
1614
 
                                                //System.Console.Write (" {0}", val);
1615
 
                                        break;
1616
 
                                case EntryType.Byte:
1617
 
                                        //foreach (byte val in this.RawData)
1618
 
                                                //System.Console.Write (" {0}", val);
1619
 
                                        break;
1620
 
                                }
1621
 
                                //System.Console.WriteLine ("");
1622
 
                                break;
1623
 
                        }
1624
 
#endif
1625
 
                }
1626
 
 
1627
 
                public virtual void Dump (string name)
1628
 
                {
1629
 
                        switch (this.Type) {
1630
 
                        case EntryType.Short:
1631
 
                        case EntryType.Long:
1632
 
                                uint [] vals = this.ValueAsLong;
1633
 
                                //System.Console.Write ("{3}{1}({2}) [{0}] (", vals.Length, this.Id, this.Type, name);
1634
 
                                //for (int i = 0; i < System.Math.Min (15, vals.Length); i++) {
1635
 
                                //      System.Console.Write (" {0}", vals [i]);
1636
 
                                //}
1637
 
                                //System.Console.WriteLine (")");
1638
 
                                break;
1639
 
                        case EntryType.Ascii:
1640
 
                                //System.Console.WriteLine ("{3}{1}({2}) (\"{0}\")", this.StringValue, this.Id, this.Type, name);
1641
 
                                break;
1642
 
                        default:
1643
 
                                //System.Console.WriteLine ("{3}{1}({2}) [{0}]", this.Count, this.Id, this.Type, name);
1644
 
                                break;
1645
 
                        }
1646
 
                }
1647
 
                
1648
 
                protected void ParseStream (byte [] data, int start)
1649
 
                {
1650
 
                        int i = start;
1651
 
 
1652
 
                        count = BitConverter.ToUInt32 (data, i, endian == Endian.Little); 
1653
 
                        i += 4;
1654
 
                        int size = (int)count * GetTypeSize ();
1655
 
                        if (size > 4)
1656
 
                                data_offset = BitConverter.ToUInt32 (data, i, endian == Endian.Little);
1657
 
                        else {
1658
 
                                data_offset = 0;
1659
 
                                raw_data = new byte [size];
1660
 
                                System.Array.Copy (data, i, raw_data, 0, size);
1661
 
                        }
1662
 
                }
1663
 
 
1664
 
                public void SetData (string value)
1665
 
                {
1666
 
                        int len = System.Text.Encoding.UTF8.GetByteCount (value);
1667
 
                        byte [] tmp = new byte [len + 1];
1668
 
                        System.Text.Encoding.UTF8.GetBytes (value, 0, value.Length, tmp, 0);
1669
 
                        tmp[len] = 0;
1670
 
                        //System.Console.WriteLine ("SetData: value = {0} len = {1}", value, len);
1671
 
                        SetData (tmp);
1672
 
                }
1673
 
        
1674
 
                public static System.DateTime DateTimeFromString (string dt)
1675
 
                {
1676
 
                        // Exif DateTime strings are formatted as
1677
 
                        //      "YYYY:MM:DD HH:MM:SS"
1678
 
                        
1679
 
                        string delimiters = " :";
1680
 
                        string[] dt_data = dt.Split ( delimiters.ToCharArray(), 6 );
1681
 
                        System.DateTime result;
1682
 
                        result = new System.DateTime (System.Int32.Parse(dt_data[0]), 
1683
 
                                                      System.Int32.Parse(dt_data[1]), 
1684
 
                                                      System.Int32.Parse(dt_data[2]),
1685
 
                                                      System.Int32.Parse(dt_data[3]), 
1686
 
                                                      System.Int32.Parse(dt_data[4]), 
1687
 
                                                      System.Int32.Parse(dt_data[5]));
1688
 
                        
1689
 
                        return result;
1690
 
                }
1691
 
                
1692
 
                public void SetData (byte [] data)
1693
 
                {
1694
 
                        raw_data = data;
1695
 
                        count = (uint)raw_data.Length / (uint)GetTypeSize ();
1696
 
                }
1697
 
 
1698
 
#if false               
1699
 
                public object  GetValue () {
1700
 
                        switch (Type) {
1701
 
                        case EntryType.Short:
1702
 
                                return ShortValue;
1703
 
                        case EntryType.Long:
1704
 
                                return LongValue;
1705
 
                        case  EntryType.Rational:
1706
 
                                return RationalValue;
1707
 
                        case EntryType.SRational:
1708
 
                                return SRationalValue;
1709
 
                        case EntryType.Ascii:
1710
 
                                return StringValue.Split ('\0');
1711
 
                                break;
1712
 
                        default:
1713
 
                                //System.Console.WriteLine ("{1}({2}) [{0}]", this.Count, this.Id, this.Type);
1714
 
                                break;
1715
 
 
1716
 
                                }
1717
 
                        }
1718
 
                }
1719
 
#endif
1720
 
 
1721
 
                public byte [] Value {
1722
 
                        get {
1723
 
                                return raw_data;
1724
 
                        }
1725
 
                }
1726
 
 
1727
 
                public byte [] RawData {
1728
 
                        get { 
1729
 
                                return raw_data;
1730
 
                        }
1731
 
                }
1732
 
 
1733
 
                public string [] ValueAsString {
1734
 
                        get {
1735
 
                                switch (this.Type) {
1736
 
                                case EntryType.Short:
1737
 
                                case EntryType.Long:
1738
 
                                        return ArrayToString (this.ValueAsLong);
1739
 
                                case EntryType.Rational:
1740
 
                                        return ArrayToString (this.RationalValue);
1741
 
                                case EntryType.SRational:
1742
 
                                        return ArrayToString (this.SRationalValue);
1743
 
                                case EntryType.Undefined:
1744
 
                                        switch (Id) {
1745
 
                                        case TagId.UserComment:
1746
 
                                                return new string [] { UserCommentValue };
1747
 
                                        case TagId.FlashPixVersion:
1748
 
                                        case TagId.ExifVersion:
1749
 
                                                return new string [] { StringValue };
1750
 
                                        case TagId.FileSource:
1751
 
                                        case TagId.SceneType:
1752
 
                                                return ArrayToString (this.RawData);
1753
 
                                        case TagId.ComponentsConfiguration:
1754
 
                                                return ArrayToString (ValueAsLong);
1755
 
                                        default:
1756
 
                                                //System.Console.WriteLine ("Cannot convert type \"{0}\" to string", Id);
1757
 
                                                break;
1758
 
                                        }
1759
 
                                        break;
1760
 
                                case EntryType.Ascii:
1761
 
                                        return StringValue.Split ('\0');
1762
 
                                }
1763
 
                                return null;
1764
 
                        }
1765
 
                }
1766
 
 
1767
 
                public string [] ArrayToString (System.Array array)
1768
 
                {
1769
 
                        string [] vals = new string [array.Length];
1770
 
                        for (int i = 0; i < array.Length; i++)
1771
 
                                vals [i] = array.GetValue (i).ToString ();
1772
 
 
1773
 
                        return vals;
1774
 
                }
1775
 
 
1776
 
                public uint [] ValueAsLong {
1777
 
                        get {
1778
 
                                uint [] data = new uint [this.Count];
1779
 
                                for (int i = 0; i < this.Count; i++) {
1780
 
                                        switch (this.Type) {
1781
 
                                        case EntryType.Long:
1782
 
                                                data [i] = BitConverter.ToUInt32 (raw_data, i * GetTypeSize (), endian == Endian.Little);
1783
 
                                                break;
1784
 
                                        case EntryType.Short:
1785
 
                                                data [i] = BitConverter.ToUInt16 (raw_data, i * GetTypeSize (), endian == Endian.Little);
1786
 
                                                break;
1787
 
                                        case EntryType.Undefined:
1788
 
                                        case EntryType.Byte:
1789
 
                                                data [i] = raw_data [i];
1790
 
                                                break;
1791
 
                                        default:
1792
 
                                                throw new System.Exception ("Invalid conversion");
1793
 
                                        }
1794
 
                                }
1795
 
                                return data;
1796
 
                        }
1797
 
                }
1798
 
                
1799
 
                // The following methods are usded to convert the data 
1800
 
                // to the various type regardless of the entry
1801
 
                // type, they are used internally in processing the data
1802
 
                // Use at your own risk.
1803
 
 
1804
 
                public string StringValue {
1805
 
                        get {
1806
 
                                return System.Text.Encoding.ASCII.GetString (raw_data);
1807
 
                        }
1808
 
                }
1809
 
 
1810
 
                public System.DateTime ValueAsDate {
1811
 
                        get {
1812
 
                                return DirectoryEntry.DateTimeFromString (StringValue);
1813
 
                        }
1814
 
                }
1815
 
 
1816
 
                public string UserCommentValue {
1817
 
                        get {
1818
 
                                UserComment comment = new UserComment (raw_data, IsLittle);
1819
 
                                return comment.Value;
1820
 
                        }
1821
 
                }
1822
 
 
1823
 
                public SRational [] SRationalValue {
1824
 
                        get {
1825
 
                                Rational [] vals = RationalValue;
1826
 
                                SRational [] data = new SRational [vals.Length];
1827
 
                                
1828
 
                                for (int i = 0; i < vals.Length; i++)
1829
 
                                        data [i] = SRational.BitwiseCopy (vals [i]);
1830
 
 
1831
 
                                return data;
1832
 
                        }
1833
 
                }
1834
 
 
1835
 
                public Rational [] RationalValue {
1836
 
                        get {
1837
 
                                uint [] vals = LongValue;
1838
 
                                Rational [] data = new Rational [vals.Length / 2];
1839
 
 
1840
 
                                for (int i = 0; i < vals.Length; i += 2)
1841
 
                                        data [i/2] = new Rational (vals [i], vals [i + 1]);
1842
 
                                
1843
 
                                return data;
1844
 
                        }
1845
 
                        
1846
 
                }
1847
 
 
1848
 
                public uint [] LongValue {
1849
 
                        get {
1850
 
                                uint [] data = new uint [raw_data.Length / 4];
1851
 
                                for (int i = 0; i < raw_data.Length; i+= 4)
1852
 
                                        data [i/4] = BitConverter.ToUInt32 (raw_data, i, endian == Endian.Little);
1853
 
 
1854
 
                                return data;
1855
 
                        }
1856
 
                }
1857
 
 
1858
 
                public ushort [] ShortValue {
1859
 
                        get {
1860
 
                                ushort [] data = new ushort [raw_data.Length];
1861
 
                                for (int i = 0; i < raw_data.Length; i+= 2) {
1862
 
                                        data [i] = BitConverter.ToUInt16 (raw_data, i, endian == Endian.Little);
1863
 
                                }
1864
 
                                return data;
1865
 
                        }
1866
 
                }
1867
 
        }
1868
 
 
1869
 
 
1870
 
#if false
1871
 
        public class TiffFile : ImageFile, SemWeb.StatementSource {
1872
 
                public Header Header;
1873
 
 
1874
 
                // false seems a safe default
1875
 
                public bool Distinct {
1876
 
                        get { return false; }
1877
 
                }
1878
 
 
1879
 
                public TiffFile (string path) : base (path)
1880
 
                {
1881
 
                        try {
1882
 
                                using (System.IO.Stream input = Open ()) {
1883
 
                                        this.Header = new Header (input);
1884
 
                                }
1885
 
 
1886
 
#if DEBUG_LOADER
1887
 
                                Header.Dump (this.ToString () + ":");
1888
 
#endif
1889
 
                        } catch (System.Exception e) {
1890
 
                                System.Console.WriteLine (e.ToString ());
1891
 
                        }
1892
 
                }
1893
 
 
1894
 
                public TiffFile (Uri uri) : base (uri)
1895
 
                {
1896
 
                        try {
1897
 
                                using (System.IO.Stream input = Open ()) {
1898
 
                                        this.Header = new Header (input);
1899
 
                                }
1900
 
 
1901
 
#if DEBUG_LOADER
1902
 
                                Header.Dump (this.ToString () + ":");
1903
 
#endif
1904
 
                        } catch (System.Exception e) {
1905
 
                                System.Console.WriteLine (e.ToString ());
1906
 
                        }
1907
 
                }
1908
 
 
1909
 
                public virtual void Select (SemWeb.StatementSink sink)
1910
 
                {
1911
 
                        Header.SelectDirectory (Header.Directory, sink);
1912
 
                }
1913
 
 
1914
 
                public override System.DateTime Date {
1915
 
                        get {
1916
 
                                SubdirectoryEntry sub = (SubdirectoryEntry) this.Header.Directory.Lookup (TagId.ExifIfdPointer);
1917
 
                                DirectoryEntry e;
1918
 
 
1919
 
                                if (sub != null) {
1920
 
                                        e = sub.Directory [0].Lookup (TagId.DateTimeOriginal);
1921
 
                                        
1922
 
                                        if (e != null)
1923
 
                                                return DirectoryEntry.DateTimeFromString (e.StringValue).ToUniversalTime ();
1924
 
                                }
1925
 
 
1926
 
                                e = this.Header.Directory.Lookup (TagId.DateTime);
1927
 
 
1928
 
                                if (e != null)
1929
 
                                        return DirectoryEntry.DateTimeFromString (e.StringValue).ToUniversalTime ();
1930
 
                                else
1931
 
                                        return base.Date;
1932
 
                        }
1933
 
                }
1934
 
                
1935
 
                public override System.IO.Stream PixbufStream ()
1936
 
                {
1937
 
                        return Open ();
1938
 
                }
1939
 
 
1940
 
                public override PixbufOrientation GetOrientation ()
1941
 
                {
1942
 
                        ShortEntry e = (ShortEntry)(this.Header.Directory.Lookup (TagId.Orientation));
1943
 
                        if (e != null) 
1944
 
                                return (PixbufOrientation)(e.ShortValue[0]);
1945
 
                        else
1946
 
                                return PixbufOrientation.TopLeft;
1947
 
                }
1948
 
 
1949
 
                public System.IO.Stream LookupJpegSubstream (ImageDirectory directory)
1950
 
                {
1951
 
                        uint offset = directory.Lookup (TagId.JPEGInterchangeFormat).ValueAsLong [0];
1952
 
                        
1953
 
                        System.IO.Stream file = Open ();
1954
 
                        file.Position = offset;
1955
 
                        return file;
1956
 
                }
1957
 
 
1958
 
                public Gdk.Pixbuf LoadJpegInterchangeFormat (ImageDirectory directory)
1959
 
                {
1960
 
                        uint offset = directory.Lookup (TagId.JPEGInterchangeFormat).ValueAsLong [0];
1961
 
                        uint length = directory.Lookup (TagId.JPEGInterchangeFormatLength).ValueAsLong [0];
1962
 
                           
1963
 
                        using (System.IO.Stream file = Open ()) {
1964
 
                                file.Position = offset;
1965
 
                                
1966
 
                                byte [] data = new byte [32768];
1967
 
                                int read;
1968
 
 
1969
 
                                Gdk.PixbufLoader loader = new Gdk.PixbufLoader ();
1970
 
                                
1971
 
                                while (length > 0) {
1972
 
                                        read = file.Read (data, 0, (int)System.Math.Min ((int)data.Length, length));
1973
 
                                        if (read <= 0)
1974
 
                                                break;
1975
 
 
1976
 
                                        loader.Write (data, (ulong)read);
1977
 
                                        length -= (uint) read;
1978
 
                                }
1979
 
                                Gdk.Pixbuf result = loader.Pixbuf;
1980
 
                                loader.Close ();
1981
 
                                return result; 
1982
 
                        }
1983
 
                }
1984
 
        }
1985
 
 
1986
 
        public class DngFile : TiffFile {
1987
 
                public DngFile (string path) : base (path) 
1988
 
                {
1989
 
                }
1990
 
 
1991
 
                public DngFile (System.Uri uri) : base (uri) 
1992
 
                {
1993
 
                }
1994
 
 
1995
 
                public override System.IO.Stream PixbufStream ()
1996
 
                {
1997
 
                        try {
1998
 
                                SubdirectoryEntry sub = (SubdirectoryEntry) Header.Directory.Lookup (TagId.SubIFDs);
1999
 
                                ImageDirectory directory = sub.Directory [sub.Directory.Length - 1];
2000
 
 
2001
 
                                uint offset = directory.Lookup (TagId.StripOffsets).ValueAsLong [0];
2002
 
                                System.IO.Stream file = Open ();
2003
 
                                file.Position = offset;
2004
 
                                return file;
2005
 
                        } catch {
2006
 
                                return DCRawFile.RawPixbufStream (uri);
2007
 
                        }
2008
 
                }
2009
 
 
2010
 
                public override void Select (SemWeb.StatementSink sink)
2011
 
                {
2012
 
                        
2013
 
                        /* this is just a sanity pass, if the first ifd is not a subfile use the normal
2014
 
                         * tiff path 
2015
 
                         */
2016
 
                        DirectoryEntry e = Header.Directory.Lookup (TagId.NewSubfileType);
2017
 
                        if (e == null) {
2018
 
                                base.Select (sink);
2019
 
                                return;
2020
 
                        }
2021
 
 
2022
 
                        /*
2023
 
                         * Even though Ifd0 doesn't have the full resolution image
2024
 
                         * it would have the XMP data so we look for it
2025
 
                         */
2026
 
                        e = Header.Directory.Lookup (TagId.XMP);
2027
 
                        if (e != null) {
2028
 
                                System.IO.Stream xmpstream = new System.IO.MemoryStream (e.RawData);
2029
 
                                Xmp.XmpFile xmp = new Xmp.XmpFile (xmpstream);
2030
 
                                xmp.Select (sink);
2031
 
                        }
2032
 
 
2033
 
                        /* 
2034
 
                         * Ifd0 will also have the exif directory
2035
 
                         */
2036
 
                        ImageDirectory dir = Header.Directory;
2037
 
                        SubdirectoryEntry sub = (SubdirectoryEntry) dir.Lookup (TagId.ExifIfdPointer);
2038
 
                        if (sub != null)
2039
 
                                Header.SelectDirectory (sub.Directory [0], sink);
2040
 
                        
2041
 
                        /*
2042
 
                         * now we lookup subifd0 (we should probably scan the newsubfile types here)
2043
 
                         * and load the metadata we are interested in from it.
2044
 
                         */
2045
 
                        sub = (SubdirectoryEntry) Header.Directory.Lookup (TagId.SubIFDs);      
2046
 
 
2047
 
                        int i = 0;
2048
 
                        do {
2049
 
                                uint dirtype = e.ValueAsLong [0];
2050
 
                                if (dirtype == 0) {
2051
 
                                        Header.SelectDirectory (dir, sink);
2052
 
                                        break;
2053
 
                                }
2054
 
                                        
2055
 
                                if (sub == null)
2056
 
                                        break;
2057
 
 
2058
 
                                dir = sub.Directory [i];
2059
 
                                e = dir.Lookup (TagId.NewSubfileType);
2060
 
                                i++;
2061
 
                        } while (i < sub.Directory.Length);
2062
 
 
2063
 
                        
2064
 
                }
2065
 
        }       
2066
 
        
2067
 
        public class NefFile : TiffFile, IThumbnailContainer {
2068
 
                public NefFile (string path) : base (path) 
2069
 
                {
2070
 
                }
2071
 
 
2072
 
                public NefFile (Uri uri) : base (uri)
2073
 
                {
2074
 
                }
2075
 
 
2076
 
                public override void Select (SemWeb.StatementSink sink)
2077
 
                {
2078
 
                        DirectoryEntry e = Header.Directory.Lookup (TagId.NewSubfileType);
2079
 
 
2080
 
                        if (e == null) {
2081
 
                                base.Select (sink);
2082
 
                                return;
2083
 
                        }
2084
 
 
2085
 
                        ImageDirectory dir = Header.Directory;
2086
 
                        SubdirectoryEntry sub = (SubdirectoryEntry) dir.Lookup (TagId.ExifIfdPointer);
2087
 
                        
2088
 
                        if (sub != null)
2089
 
                                Header.SelectDirectory (sub.Directory [0], sink);
2090
 
                        
2091
 
                        sub = (SubdirectoryEntry) Header.Directory.Lookup (TagId.SubIFDs);      
2092
 
 
2093
 
                        int i = 0;
2094
 
                        do {
2095
 
                                uint dirtype = e.ValueAsLong [0];
2096
 
                                if (dirtype == 0) {
2097
 
                                        Header.SelectDirectory (dir, sink);
2098
 
                                        break;
2099
 
                                }
2100
 
                                        
2101
 
                                if (sub == null)
2102
 
                                        break;
2103
 
 
2104
 
                                dir = sub.Directory [i];
2105
 
                                e = dir.Lookup (TagId.NewSubfileType);
2106
 
                                i++;
2107
 
                        } while (i < sub.Directory.Length);
2108
 
                }
2109
 
 
2110
 
                public Gdk.Pixbuf GetEmbeddedThumbnail ()
2111
 
                {
2112
 
                        using (System.IO.Stream stream = Open ()) {
2113
 
                                return TransformAndDispose (new Gdk.Pixbuf (stream));
2114
 
                        }
2115
 
                }
2116
 
 
2117
 
                public override System.IO.Stream PixbufStream ()
2118
 
                {
2119
 
                        try {
2120
 
                                SubdirectoryEntry sub = (SubdirectoryEntry) Header.Directory.Lookup (TagId.SubIFDs);
2121
 
                                ImageDirectory jpeg_directory = sub.Directory [0];
2122
 
                                return LookupJpegSubstream (jpeg_directory);
2123
 
                        } catch (System.Exception) {
2124
 
                                return DCRawFile.RawPixbufStream (uri);
2125
 
                        }
2126
 
                }
2127
 
        }
2128
 
                
2129
 
 
2130
 
        public class Cr2File : TiffFile, IThumbnailContainer {
2131
 
                public Cr2File (string path) : base (path) 
2132
 
                {
2133
 
                }
2134
 
 
2135
 
                public Cr2File (Uri uri) : base (uri)
2136
 
                {
2137
 
                }
2138
 
 
2139
 
                /*
2140
 
                public override PixbufOrientation GetOrientation ()
2141
 
                {
2142
 
                        return PixbufOrientation.TopLeft;
2143
 
                }
2144
 
                */
2145
 
 
2146
 
                public Gdk.Pixbuf GetEmbeddedThumbnail ()
2147
 
                {
2148
 
                        ImageDirectory directory;
2149
 
                        directory = Header.Directory.NextDirectory;
2150
 
                        return TransformAndDispose (LoadJpegInterchangeFormat (directory));
2151
 
                }
2152
 
 
2153
 
 
2154
 
                public override System.IO.Stream PixbufStream ()
2155
 
                {
2156
 
                        uint offset = Header.Directory.Lookup (TagId.StripOffsets).ValueAsLong [0];
2157
 
                        System.IO.Stream file = Open ();
2158
 
                        file.Position = offset;
2159
 
                        return file;
2160
 
                }
2161
 
        }
2162
 
#endif
2163
 
}
2164