canvas-resize-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,959 @@
1
+
2
+ /*
3
+ * Javascript EXIF Reader - jQuery plugin 0.1.3
4
+ * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/
5
+ * Licensed under the MPL License [http://www.nihilogic.dk/licenses/mpl-license.txt]
6
+ */
7
+
8
+ /*
9
+ * I added three functions for read EXIF from dataURL
10
+ * - getImageDataFromDataURL
11
+ * - getDataFromDataURL
12
+ * - jQuery.fn.exifLoadFromDataURL
13
+ *
14
+ * http://orientation.gokercebeci.com
15
+ * @gokercebeci
16
+ */
17
+
18
+ (function() {
19
+
20
+
21
+ var BinaryFile = function(strData, iDataOffset, iDataLength) {
22
+ var data = strData;
23
+ var dataOffset = iDataOffset || 0;
24
+ var dataLength = 0;
25
+
26
+ this.getRawData = function() {
27
+ return data;
28
+ }
29
+
30
+ if (typeof strData == "string") {
31
+ dataLength = iDataLength || data.length;
32
+
33
+ this.getByteAt = function(iOffset) {
34
+ return data.charCodeAt(iOffset + dataOffset) & 0xFF;
35
+ }
36
+ } else if (typeof strData == "unknown") {
37
+ dataLength = iDataLength || IEBinary_getLength(data);
38
+
39
+ this.getByteAt = function(iOffset) {
40
+ return IEBinary_getByteAt(data, iOffset + dataOffset);
41
+ }
42
+ }
43
+
44
+ this.getLength = function() {
45
+ return dataLength;
46
+ }
47
+
48
+ this.getSByteAt = function(iOffset) {
49
+ var iByte = this.getByteAt(iOffset);
50
+ if (iByte > 127)
51
+ return iByte - 256;
52
+ else
53
+ return iByte;
54
+ }
55
+
56
+ this.getShortAt = function(iOffset, bBigEndian) {
57
+ var iShort = bBigEndian ?
58
+ (this.getByteAt(iOffset) << 8) + this.getByteAt(iOffset + 1)
59
+ : (this.getByteAt(iOffset + 1) << 8) + this.getByteAt(iOffset)
60
+ if (iShort < 0)
61
+ iShort += 65536;
62
+ return iShort;
63
+ }
64
+ this.getSShortAt = function(iOffset, bBigEndian) {
65
+ var iUShort = this.getShortAt(iOffset, bBigEndian);
66
+ if (iUShort > 32767)
67
+ return iUShort - 65536;
68
+ else
69
+ return iUShort;
70
+ }
71
+ this.getLongAt = function(iOffset, bBigEndian) {
72
+ var iByte1 = this.getByteAt(iOffset),
73
+ iByte2 = this.getByteAt(iOffset + 1),
74
+ iByte3 = this.getByteAt(iOffset + 2),
75
+ iByte4 = this.getByteAt(iOffset + 3);
76
+
77
+ var iLong = bBigEndian ?
78
+ (((((iByte1 << 8) + iByte2) << 8) + iByte3) << 8) + iByte4
79
+ : (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1;
80
+ if (iLong < 0)
81
+ iLong += 4294967296;
82
+ return iLong;
83
+ }
84
+ this.getSLongAt = function(iOffset, bBigEndian) {
85
+ var iULong = this.getLongAt(iOffset, bBigEndian);
86
+ if (iULong > 2147483647)
87
+ return iULong - 4294967296;
88
+ else
89
+ return iULong;
90
+ }
91
+ this.getStringAt = function(iOffset, iLength) {
92
+ var aStr = [];
93
+ for (var i = iOffset, j = 0; i < iOffset + iLength; i++, j++) {
94
+ aStr[j] = String.fromCharCode(this.getByteAt(i));
95
+ }
96
+ return aStr.join("");
97
+ }
98
+
99
+ this.getCharAt = function(iOffset) {
100
+ return String.fromCharCode(this.getByteAt(iOffset));
101
+ }
102
+ this.toBase64 = function() {
103
+ return window.btoa(data);
104
+ }
105
+ this.fromBase64 = function(strBase64) {
106
+ data = window.atob(strBase64);
107
+ }
108
+ }
109
+
110
+
111
+ var BinaryAjax = (function() {
112
+
113
+ function createRequest() {
114
+ var oHTTP = null;
115
+ if (window.XMLHttpRequest) {
116
+ oHTTP = new XMLHttpRequest();
117
+ } else if (window.ActiveXObject) {
118
+ oHTTP = new ActiveXObject("Microsoft.XMLHTTP");
119
+ }
120
+ return oHTTP;
121
+ }
122
+
123
+ function getHead(strURL, fncCallback, fncError) {
124
+ var oHTTP = createRequest();
125
+ if (oHTTP) {
126
+ if (fncCallback) {
127
+ if (typeof(oHTTP.onload) != "undefined") {
128
+ oHTTP.onload = function() {
129
+ if (oHTTP.status == "200") {
130
+ fncCallback(this);
131
+ } else {
132
+ if (fncError)
133
+ fncError();
134
+ }
135
+ oHTTP = null;
136
+ };
137
+ } else {
138
+ oHTTP.onreadystatechange = function() {
139
+ if (oHTTP.readyState == 4) {
140
+ if (oHTTP.status == "200") {
141
+ fncCallback(this);
142
+ } else {
143
+ if (fncError)
144
+ fncError();
145
+ }
146
+ oHTTP = null;
147
+ }
148
+ };
149
+ }
150
+ }
151
+ oHTTP.open("HEAD", strURL, true);
152
+ oHTTP.send(null);
153
+ } else {
154
+ if (fncError)
155
+ fncError();
156
+ }
157
+ }
158
+
159
+ function sendRequest(strURL, fncCallback, fncError, aRange, bAcceptRanges, iFileSize) {
160
+ var oHTTP = createRequest();
161
+ if (oHTTP) {
162
+
163
+ var iDataOffset = 0;
164
+ if (aRange && !bAcceptRanges) {
165
+ iDataOffset = aRange[0];
166
+ }
167
+ var iDataLen = 0;
168
+ if (aRange) {
169
+ iDataLen = aRange[1] - aRange[0] + 1;
170
+ }
171
+
172
+ if (fncCallback) {
173
+ if (typeof(oHTTP.onload) != "undefined") {
174
+ oHTTP.onload = function() {
175
+
176
+ if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") {
177
+ this.binaryResponse = new BinaryFile(this.responseText, iDataOffset, iDataLen);
178
+ this.fileSize = iFileSize || this.getResponseHeader("Content-Length");
179
+ fncCallback(this);
180
+ } else {
181
+ if (fncError)
182
+ fncError();
183
+ }
184
+ oHTTP = null;
185
+ };
186
+ } else {
187
+ oHTTP.onreadystatechange = function() {
188
+ if (oHTTP.readyState == 4) {
189
+ if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") {
190
+ this.binaryResponse = new BinaryFile(oHTTP.responseBody, iDataOffset, iDataLen);
191
+ this.fileSize = iFileSize || this.getResponseHeader("Content-Length");
192
+ fncCallback(this);
193
+ } else {
194
+ if (fncError)
195
+ fncError();
196
+ }
197
+ oHTTP = null;
198
+ }
199
+ };
200
+ }
201
+ }
202
+ oHTTP.open("GET", strURL, true);
203
+
204
+ if (oHTTP.overrideMimeType)
205
+ oHTTP.overrideMimeType('text/plain; charset=x-user-defined');
206
+
207
+ if (aRange && bAcceptRanges) {
208
+ oHTTP.setRequestHeader("Range", "bytes=" + aRange[0] + "-" + aRange[1]);
209
+ }
210
+
211
+ oHTTP.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 1970 00:00:00 GMT");
212
+
213
+ oHTTP.send(null);
214
+ } else {
215
+ if (fncError)
216
+ fncError();
217
+ }
218
+ }
219
+
220
+ return function(strURL, fncCallback, fncError, aRange) {
221
+
222
+ if (aRange) {
223
+ getHead(
224
+ strURL,
225
+ function(oHTTP) {
226
+ var iLength = parseInt(oHTTP.getResponseHeader("Content-Length"), 10);
227
+ var strAcceptRanges = oHTTP.getResponseHeader("Accept-Ranges");
228
+
229
+ var iStart, iEnd;
230
+ iStart = aRange[0];
231
+ if (aRange[0] < 0)
232
+ iStart += iLength;
233
+ iEnd = iStart + aRange[1] - 1;
234
+
235
+ sendRequest(strURL, fncCallback, fncError, [iStart, iEnd], (strAcceptRanges == "bytes"), iLength);
236
+ }
237
+ );
238
+
239
+ } else {
240
+ sendRequest(strURL, fncCallback, fncError);
241
+ }
242
+ }
243
+
244
+ }());
245
+
246
+
247
+ document.write(
248
+ "<script type='text/vbscript'>\r\n"
249
+ + "Function IEBinary_getByteAt(strBinary, iOffset)\r\n"
250
+ + " IEBinary_getByteAt = AscB(MidB(strBinary,iOffset+1,1))\r\n"
251
+ + "End Function\r\n"
252
+ + "Function IEBinary_getLength(strBinary)\r\n"
253
+ + " IEBinary_getLength = LenB(strBinary)\r\n"
254
+ + "End Function\r\n"
255
+ + "</script>\r\n"
256
+ );
257
+
258
+
259
+ var EXIF = {};
260
+
261
+ (function() {
262
+
263
+ var bDebug = false;
264
+
265
+ EXIF.Tags = {
266
+
267
+ // version tags
268
+ 0x9000: "ExifVersion", // EXIF version
269
+ 0xA000: "FlashpixVersion", // Flashpix format version
270
+
271
+ // colorspace tags
272
+ 0xA001: "ColorSpace", // Color space information tag
273
+
274
+ // image configuration
275
+ 0xA002: "PixelXDimension", // Valid width of meaningful image
276
+ 0xA003: "PixelYDimension", // Valid height of meaningful image
277
+ 0x9101: "ComponentsConfiguration", // Information about channels
278
+ 0x9102: "CompressedBitsPerPixel", // Compressed bits per pixel
279
+
280
+ // user information
281
+ 0x927C: "MakerNote", // Any desired information written by the manufacturer
282
+ 0x9286: "UserComment", // Comments by user
283
+
284
+ // related file
285
+ 0xA004: "RelatedSoundFile", // Name of related sound file
286
+
287
+ // date and time
288
+ 0x9003: "DateTimeOriginal", // Date and time when the original image was generated
289
+ 0x9004: "DateTimeDigitized", // Date and time when the image was stored digitally
290
+ 0x9290: "SubsecTime", // Fractions of seconds for DateTime
291
+ 0x9291: "SubsecTimeOriginal", // Fractions of seconds for DateTimeOriginal
292
+ 0x9292: "SubsecTimeDigitized", // Fractions of seconds for DateTimeDigitized
293
+
294
+ // picture-taking conditions
295
+ 0x829A: "ExposureTime", // Exposure time (in seconds)
296
+ 0x829D: "FNumber", // F number
297
+ 0x8822: "ExposureProgram", // Exposure program
298
+ 0x8824: "SpectralSensitivity", // Spectral sensitivity
299
+ 0x8827: "ISOSpeedRatings", // ISO speed rating
300
+ 0x8828: "OECF", // Optoelectric conversion factor
301
+ 0x9201: "ShutterSpeedValue", // Shutter speed
302
+ 0x9202: "ApertureValue", // Lens aperture
303
+ 0x9203: "BrightnessValue", // Value of brightness
304
+ 0x9204: "ExposureBias", // Exposure bias
305
+ 0x9205: "MaxApertureValue", // Smallest F number of lens
306
+ 0x9206: "SubjectDistance", // Distance to subject in meters
307
+ 0x9207: "MeteringMode", // Metering mode
308
+ 0x9208: "LightSource", // Kind of light source
309
+ 0x9209: "Flash", // Flash status
310
+ 0x9214: "SubjectArea", // Location and area of main subject
311
+ 0x920A: "FocalLength", // Focal length of the lens in mm
312
+ 0xA20B: "FlashEnergy", // Strobe energy in BCPS
313
+ 0xA20C: "SpatialFrequencyResponse", //
314
+ 0xA20E: "FocalPlaneXResolution", // Number of pixels in width direction per FocalPlaneResolutionUnit
315
+ 0xA20F: "FocalPlaneYResolution", // Number of pixels in height direction per FocalPlaneResolutionUnit
316
+ 0xA210: "FocalPlaneResolutionUnit", // Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution
317
+ 0xA214: "SubjectLocation", // Location of subject in image
318
+ 0xA215: "ExposureIndex", // Exposure index selected on camera
319
+ 0xA217: "SensingMethod", // Image sensor type
320
+ 0xA300: "FileSource", // Image source (3 == DSC)
321
+ 0xA301: "SceneType", // Scene type (1 == directly photographed)
322
+ 0xA302: "CFAPattern", // Color filter array geometric pattern
323
+ 0xA401: "CustomRendered", // Special processing
324
+ 0xA402: "ExposureMode", // Exposure mode
325
+ 0xA403: "WhiteBalance", // 1 = auto white balance, 2 = manual
326
+ 0xA404: "DigitalZoomRation", // Digital zoom ratio
327
+ 0xA405: "FocalLengthIn35mmFilm", // Equivalent foacl length assuming 35mm film camera (in mm)
328
+ 0xA406: "SceneCaptureType", // Type of scene
329
+ 0xA407: "GainControl", // Degree of overall image gain adjustment
330
+ 0xA408: "Contrast", // Direction of contrast processing applied by camera
331
+ 0xA409: "Saturation", // Direction of saturation processing applied by camera
332
+ 0xA40A: "Sharpness", // Direction of sharpness processing applied by camera
333
+ 0xA40B: "DeviceSettingDescription", //
334
+ 0xA40C: "SubjectDistanceRange", // Distance to subject
335
+
336
+ // other tags
337
+ 0xA005: "InteroperabilityIFDPointer",
338
+ 0xA420: "ImageUniqueID" // Identifier assigned uniquely to each image
339
+ };
340
+
341
+ EXIF.TiffTags = {
342
+ 0x0100: "ImageWidth",
343
+ 0x0101: "ImageHeight",
344
+ 0x8769: "ExifIFDPointer",
345
+ 0x8825: "GPSInfoIFDPointer",
346
+ 0xA005: "InteroperabilityIFDPointer",
347
+ 0x0102: "BitsPerSample",
348
+ 0x0103: "Compression",
349
+ 0x0106: "PhotometricInterpretation",
350
+ 0x0112: "Orientation",
351
+ 0x0115: "SamplesPerPixel",
352
+ 0x011C: "PlanarConfiguration",
353
+ 0x0212: "YCbCrSubSampling",
354
+ 0x0213: "YCbCrPositioning",
355
+ 0x011A: "XResolution",
356
+ 0x011B: "YResolution",
357
+ 0x0128: "ResolutionUnit",
358
+ 0x0111: "StripOffsets",
359
+ 0x0116: "RowsPerStrip",
360
+ 0x0117: "StripByteCounts",
361
+ 0x0201: "JPEGInterchangeFormat",
362
+ 0x0202: "JPEGInterchangeFormatLength",
363
+ 0x012D: "TransferFunction",
364
+ 0x013E: "WhitePoint",
365
+ 0x013F: "PrimaryChromaticities",
366
+ 0x0211: "YCbCrCoefficients",
367
+ 0x0214: "ReferenceBlackWhite",
368
+ 0x0132: "DateTime",
369
+ 0x010E: "ImageDescription",
370
+ 0x010F: "Make",
371
+ 0x0110: "Model",
372
+ 0x0131: "Software",
373
+ 0x013B: "Artist",
374
+ 0x8298: "Copyright"
375
+ }
376
+
377
+ EXIF.GPSTags = {
378
+ 0x0000: "GPSVersionID",
379
+ 0x0001: "GPSLatitudeRef",
380
+ 0x0002: "GPSLatitude",
381
+ 0x0003: "GPSLongitudeRef",
382
+ 0x0004: "GPSLongitude",
383
+ 0x0005: "GPSAltitudeRef",
384
+ 0x0006: "GPSAltitude",
385
+ 0x0007: "GPSTimeStamp",
386
+ 0x0008: "GPSSatellites",
387
+ 0x0009: "GPSStatus",
388
+ 0x000A: "GPSMeasureMode",
389
+ 0x000B: "GPSDOP",
390
+ 0x000C: "GPSSpeedRef",
391
+ 0x000D: "GPSSpeed",
392
+ 0x000E: "GPSTrackRef",
393
+ 0x000F: "GPSTrack",
394
+ 0x0010: "GPSImgDirectionRef",
395
+ 0x0011: "GPSImgDirection",
396
+ 0x0012: "GPSMapDatum",
397
+ 0x0013: "GPSDestLatitudeRef",
398
+ 0x0014: "GPSDestLatitude",
399
+ 0x0015: "GPSDestLongitudeRef",
400
+ 0x0016: "GPSDestLongitude",
401
+ 0x0017: "GPSDestBearingRef",
402
+ 0x0018: "GPSDestBearing",
403
+ 0x0019: "GPSDestDistanceRef",
404
+ 0x001A: "GPSDestDistance",
405
+ 0x001B: "GPSProcessingMethod",
406
+ 0x001C: "GPSAreaInformation",
407
+ 0x001D: "GPSDateStamp",
408
+ 0x001E: "GPSDifferential"
409
+ }
410
+
411
+ EXIF.StringValues = {
412
+ ExposureProgram: {
413
+ 0: "Not defined",
414
+ 1: "Manual",
415
+ 2: "Normal program",
416
+ 3: "Aperture priority",
417
+ 4: "Shutter priority",
418
+ 5: "Creative program",
419
+ 6: "Action program",
420
+ 7: "Portrait mode",
421
+ 8: "Landscape mode"
422
+ },
423
+ MeteringMode: {
424
+ 0: "Unknown",
425
+ 1: "Average",
426
+ 2: "CenterWeightedAverage",
427
+ 3: "Spot",
428
+ 4: "MultiSpot",
429
+ 5: "Pattern",
430
+ 6: "Partial",
431
+ 255: "Other"
432
+ },
433
+ LightSource: {
434
+ 0: "Unknown",
435
+ 1: "Daylight",
436
+ 2: "Fluorescent",
437
+ 3: "Tungsten (incandescent light)",
438
+ 4: "Flash",
439
+ 9: "Fine weather",
440
+ 10: "Cloudy weather",
441
+ 11: "Shade",
442
+ 12: "Daylight fluorescent (D 5700 - 7100K)",
443
+ 13: "Day white fluorescent (N 4600 - 5400K)",
444
+ 14: "Cool white fluorescent (W 3900 - 4500K)",
445
+ 15: "White fluorescent (WW 3200 - 3700K)",
446
+ 17: "Standard light A",
447
+ 18: "Standard light B",
448
+ 19: "Standard light C",
449
+ 20: "D55",
450
+ 21: "D65",
451
+ 22: "D75",
452
+ 23: "D50",
453
+ 24: "ISO studio tungsten",
454
+ 255: "Other"
455
+ },
456
+ Flash: {
457
+ 0x0000: "Flash did not fire",
458
+ 0x0001: "Flash fired",
459
+ 0x0005: "Strobe return light not detected",
460
+ 0x0007: "Strobe return light detected",
461
+ 0x0009: "Flash fired, compulsory flash mode",
462
+ 0x000D: "Flash fired, compulsory flash mode, return light not detected",
463
+ 0x000F: "Flash fired, compulsory flash mode, return light detected",
464
+ 0x0010: "Flash did not fire, compulsory flash mode",
465
+ 0x0018: "Flash did not fire, auto mode",
466
+ 0x0019: "Flash fired, auto mode",
467
+ 0x001D: "Flash fired, auto mode, return light not detected",
468
+ 0x001F: "Flash fired, auto mode, return light detected",
469
+ 0x0020: "No flash function",
470
+ 0x0041: "Flash fired, red-eye reduction mode",
471
+ 0x0045: "Flash fired, red-eye reduction mode, return light not detected",
472
+ 0x0047: "Flash fired, red-eye reduction mode, return light detected",
473
+ 0x0049: "Flash fired, compulsory flash mode, red-eye reduction mode",
474
+ 0x004D: "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",
475
+ 0x004F: "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",
476
+ 0x0059: "Flash fired, auto mode, red-eye reduction mode",
477
+ 0x005D: "Flash fired, auto mode, return light not detected, red-eye reduction mode",
478
+ 0x005F: "Flash fired, auto mode, return light detected, red-eye reduction mode"
479
+ },
480
+ SensingMethod: {
481
+ 1: "Not defined",
482
+ 2: "One-chip color area sensor",
483
+ 3: "Two-chip color area sensor",
484
+ 4: "Three-chip color area sensor",
485
+ 5: "Color sequential area sensor",
486
+ 7: "Trilinear sensor",
487
+ 8: "Color sequential linear sensor"
488
+ },
489
+ SceneCaptureType: {
490
+ 0: "Standard",
491
+ 1: "Landscape",
492
+ 2: "Portrait",
493
+ 3: "Night scene"
494
+ },
495
+ SceneType: {
496
+ 1: "Directly photographed"
497
+ },
498
+ CustomRendered: {
499
+ 0: "Normal process",
500
+ 1: "Custom process"
501
+ },
502
+ WhiteBalance: {
503
+ 0: "Auto white balance",
504
+ 1: "Manual white balance"
505
+ },
506
+ GainControl: {
507
+ 0: "None",
508
+ 1: "Low gain up",
509
+ 2: "High gain up",
510
+ 3: "Low gain down",
511
+ 4: "High gain down"
512
+ },
513
+ Contrast: {
514
+ 0: "Normal",
515
+ 1: "Soft",
516
+ 2: "Hard"
517
+ },
518
+ Saturation: {
519
+ 0: "Normal",
520
+ 1: "Low saturation",
521
+ 2: "High saturation"
522
+ },
523
+ Sharpness: {
524
+ 0: "Normal",
525
+ 1: "Soft",
526
+ 2: "Hard"
527
+ },
528
+ SubjectDistanceRange: {
529
+ 0: "Unknown",
530
+ 1: "Macro",
531
+ 2: "Close view",
532
+ 3: "Distant view"
533
+ },
534
+ FileSource: {
535
+ 3: "DSC"
536
+ },
537
+ Components: {
538
+ 0: "",
539
+ 1: "Y",
540
+ 2: "Cb",
541
+ 3: "Cr",
542
+ 4: "R",
543
+ 5: "G",
544
+ 6: "B"
545
+ }
546
+ }
547
+
548
+ function addEvent(oElement, strEvent, fncHandler)
549
+ {
550
+ if (oElement.addEventListener) {
551
+ oElement.addEventListener(strEvent, fncHandler, false);
552
+ } else if (oElement.attachEvent) {
553
+ oElement.attachEvent("on" + strEvent, fncHandler);
554
+ }
555
+ }
556
+
557
+
558
+ function imageHasData(oImg)
559
+ {
560
+ return !!(oImg.exifdata);
561
+ }
562
+
563
+ function getImageData(oImg, fncCallback)
564
+ {
565
+ BinaryAjax(
566
+ oImg.src,
567
+ function(oHTTP) {
568
+ console.log('BINARY', oHTTP.binaryResponse);
569
+ var oEXIF = findEXIFinJPEG(oHTTP.binaryResponse);
570
+ oImg.exifdata = oEXIF || {};
571
+ if (fncCallback)
572
+ fncCallback();
573
+ }
574
+ )
575
+ }
576
+
577
+ function getImageDataFromDataURL(oImg, fncCallback)
578
+ {
579
+ var byteString = atob(oImg.src.split(',')[1]);
580
+ var f = new BinaryFile(byteString, 0, byteString.length)
581
+ var oEXIF = findEXIFinJPEG(f);
582
+ oImg.exifdata = oEXIF || {};
583
+ if (fncCallback)
584
+ fncCallback();
585
+ }
586
+
587
+ function findEXIFinJPEG(oFile) {
588
+ var aMarkers = [];
589
+
590
+ if (oFile.getByteAt(0) != 0xFF || oFile.getByteAt(1) != 0xD8) {
591
+ return false; // not a valid jpeg
592
+ }
593
+
594
+ var iOffset = 2;
595
+ var iLength = oFile.getLength();
596
+ while (iOffset < iLength) {
597
+ if (oFile.getByteAt(iOffset) != 0xFF) {
598
+ if (bDebug)
599
+ console.log("Not a valid marker at offset " + iOffset + ", found: " + oFile.getByteAt(iOffset));
600
+ return false; // not a valid marker, something is wrong
601
+ }
602
+
603
+ var iMarker = oFile.getByteAt(iOffset + 1);
604
+
605
+ // we could implement handling for other markers here,
606
+ // but we're only looking for 0xFFE1 for EXIF data
607
+
608
+ if (iMarker == 22400) {
609
+ if (bDebug)
610
+ console.log("Found 0xFFE1 marker");
611
+ return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset + 2, true) - 2);
612
+ iOffset += 2 + oFile.getShortAt(iOffset + 2, true);
613
+
614
+ } else if (iMarker == 225) {
615
+ // 0xE1 = Application-specific 1 (for EXIF)
616
+ if (bDebug)
617
+ console.log("Found 0xFFE1 marker");
618
+ return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset + 2, true) - 2);
619
+
620
+ } else {
621
+ iOffset += 2 + oFile.getShortAt(iOffset + 2, true);
622
+ }
623
+
624
+ }
625
+
626
+ }
627
+
628
+
629
+ function readTags(oFile, iTIFFStart, iDirStart, oStrings, bBigEnd)
630
+ {
631
+ var iEntries = oFile.getShortAt(iDirStart, bBigEnd);
632
+ var oTags = {};
633
+ for (var i = 0; i < iEntries; i++) {
634
+ var iEntryOffset = iDirStart + i * 12 + 2;
635
+ var strTag = oStrings[oFile.getShortAt(iEntryOffset, bBigEnd)];
636
+ if (!strTag && bDebug)
637
+ console.log("Unknown tag: " + oFile.getShortAt(iEntryOffset, bBigEnd));
638
+ oTags[strTag] = readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd);
639
+ }
640
+ return oTags;
641
+ }
642
+
643
+
644
+ function readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd)
645
+ {
646
+ var iType = oFile.getShortAt(iEntryOffset + 2, bBigEnd);
647
+ var iNumValues = oFile.getLongAt(iEntryOffset + 4, bBigEnd);
648
+ var iValueOffset = oFile.getLongAt(iEntryOffset + 8, bBigEnd) + iTIFFStart;
649
+
650
+ switch (iType) {
651
+ case 1: // byte, 8-bit unsigned int
652
+ case 7: // undefined, 8-bit byte, value depending on field
653
+ if (iNumValues == 1) {
654
+ return oFile.getByteAt(iEntryOffset + 8, bBigEnd);
655
+ } else {
656
+ var iValOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);
657
+ var aVals = [];
658
+ for (var n = 0; n < iNumValues; n++) {
659
+ aVals[n] = oFile.getByteAt(iValOffset + n);
660
+ }
661
+ return aVals;
662
+ }
663
+ break;
664
+
665
+ case 2: // ascii, 8-bit byte
666
+ var iStringOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);
667
+ return oFile.getStringAt(iStringOffset, iNumValues - 1);
668
+ break;
669
+
670
+ case 3: // short, 16 bit int
671
+ if (iNumValues == 1) {
672
+ return oFile.getShortAt(iEntryOffset + 8, bBigEnd);
673
+ } else {
674
+ var iValOffset = iNumValues > 2 ? iValueOffset : (iEntryOffset + 8);
675
+ var aVals = [];
676
+ for (var n = 0; n < iNumValues; n++) {
677
+ aVals[n] = oFile.getShortAt(iValOffset + 2 * n, bBigEnd);
678
+ }
679
+ return aVals;
680
+ }
681
+ break;
682
+
683
+ case 4: // long, 32 bit int
684
+ if (iNumValues == 1) {
685
+ return oFile.getLongAt(iEntryOffset + 8, bBigEnd);
686
+ } else {
687
+ var aVals = [];
688
+ for (var n = 0; n < iNumValues; n++) {
689
+ aVals[n] = oFile.getLongAt(iValueOffset + 4 * n, bBigEnd);
690
+ }
691
+ return aVals;
692
+ }
693
+ break;
694
+ case 5: // rational = two long values, first is numerator, second is denominator
695
+ if (iNumValues == 1) {
696
+ return oFile.getLongAt(iValueOffset, bBigEnd) / oFile.getLongAt(iValueOffset + 4, bBigEnd);
697
+ } else {
698
+ var aVals = [];
699
+ for (var n = 0; n < iNumValues; n++) {
700
+ aVals[n] = oFile.getLongAt(iValueOffset + 8 * n, bBigEnd) / oFile.getLongAt(iValueOffset + 4 + 8 * n, bBigEnd);
701
+ }
702
+ return aVals;
703
+ }
704
+ break;
705
+ case 9: // slong, 32 bit signed int
706
+ if (iNumValues == 1) {
707
+ return oFile.getSLongAt(iEntryOffset + 8, bBigEnd);
708
+ } else {
709
+ var aVals = [];
710
+ for (var n = 0; n < iNumValues; n++) {
711
+ aVals[n] = oFile.getSLongAt(iValueOffset + 4 * n, bBigEnd);
712
+ }
713
+ return aVals;
714
+ }
715
+ break;
716
+ case 10: // signed rational, two slongs, first is numerator, second is denominator
717
+ if (iNumValues == 1) {
718
+ return oFile.getSLongAt(iValueOffset, bBigEnd) / oFile.getSLongAt(iValueOffset + 4, bBigEnd);
719
+ } else {
720
+ var aVals = [];
721
+ for (var n = 0; n < iNumValues; n++) {
722
+ aVals[n] = oFile.getSLongAt(iValueOffset + 8 * n, bBigEnd) / oFile.getSLongAt(iValueOffset + 4 + 8 * n, bBigEnd);
723
+ }
724
+ return aVals;
725
+ }
726
+ break;
727
+ }
728
+ }
729
+
730
+
731
+ function readEXIFData(oFile, iStart, iLength)
732
+ {
733
+ if (oFile.getStringAt(iStart, 4) != "Exif") {
734
+ if (bDebug)
735
+ console.log("Not valid EXIF data! " + oFile.getStringAt(iStart, 4));
736
+ return false;
737
+ }
738
+
739
+ var bBigEnd;
740
+
741
+ var iTIFFOffset = iStart + 6;
742
+
743
+ // test for TIFF validity and endianness
744
+ if (oFile.getShortAt(iTIFFOffset) == 0x4949) {
745
+ bBigEnd = false;
746
+ } else if (oFile.getShortAt(iTIFFOffset) == 0x4D4D) {
747
+ bBigEnd = true;
748
+ } else {
749
+ if (bDebug)
750
+ console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)");
751
+ return false;
752
+ }
753
+
754
+ if (oFile.getShortAt(iTIFFOffset + 2, bBigEnd) != 0x002A) {
755
+ if (bDebug)
756
+ console.log("Not valid TIFF data! (no 0x002A)");
757
+ return false;
758
+ }
759
+
760
+ if (oFile.getLongAt(iTIFFOffset + 4, bBigEnd) != 0x00000008) {
761
+ if (bDebug)
762
+ console.log("Not valid TIFF data! (First offset not 8)", oFile.getShortAt(iTIFFOffset + 4, bBigEnd));
763
+ return false;
764
+ }
765
+
766
+ var oTags = readTags(oFile, iTIFFOffset, iTIFFOffset + 8, EXIF.TiffTags, bBigEnd);
767
+
768
+ if (oTags.ExifIFDPointer) {
769
+ var oEXIFTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.ExifIFDPointer, EXIF.Tags, bBigEnd);
770
+ for (var strTag in oEXIFTags) {
771
+ switch (strTag) {
772
+ case "LightSource" :
773
+ case "Flash" :
774
+ case "MeteringMode" :
775
+ case "ExposureProgram" :
776
+ case "SensingMethod" :
777
+ case "SceneCaptureType" :
778
+ case "SceneType" :
779
+ case "CustomRendered" :
780
+ case "WhiteBalance" :
781
+ case "GainControl" :
782
+ case "Contrast" :
783
+ case "Saturation" :
784
+ case "Sharpness" :
785
+ case "SubjectDistanceRange" :
786
+ case "FileSource" :
787
+ oEXIFTags[strTag] = EXIF.StringValues[strTag][oEXIFTags[strTag]];
788
+ break;
789
+
790
+ case "ExifVersion" :
791
+ case "FlashpixVersion" :
792
+ oEXIFTags[strTag] = String.fromCharCode(oEXIFTags[strTag][0], oEXIFTags[strTag][1], oEXIFTags[strTag][2], oEXIFTags[strTag][3]);
793
+ break;
794
+
795
+ case "ComponentsConfiguration" :
796
+ oEXIFTags[strTag] =
797
+ EXIF.StringValues.Components[oEXIFTags[strTag][0]]
798
+ + EXIF.StringValues.Components[oEXIFTags[strTag][1]]
799
+ + EXIF.StringValues.Components[oEXIFTags[strTag][2]]
800
+ + EXIF.StringValues.Components[oEXIFTags[strTag][3]];
801
+ break;
802
+ }
803
+ oTags[strTag] = oEXIFTags[strTag];
804
+ }
805
+ }
806
+
807
+ if (oTags.GPSInfoIFDPointer) {
808
+ var oGPSTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.GPSInfoIFDPointer, EXIF.GPSTags, bBigEnd);
809
+ for (var strTag in oGPSTags) {
810
+ switch (strTag) {
811
+ case "GPSVersionID" :
812
+ oGPSTags[strTag] = oGPSTags[strTag][0]
813
+ + "." + oGPSTags[strTag][1]
814
+ + "." + oGPSTags[strTag][2]
815
+ + "." + oGPSTags[strTag][3];
816
+ break;
817
+ }
818
+ oTags[strTag] = oGPSTags[strTag];
819
+ }
820
+ }
821
+
822
+ return oTags;
823
+ }
824
+
825
+
826
+ EXIF.getData = function(oImg, fncCallback)
827
+ {
828
+ if (!oImg.complete)
829
+ return false;
830
+ if (!imageHasData(oImg)) {
831
+ getImageData(oImg, fncCallback);
832
+ } else {
833
+ if (fncCallback)
834
+ fncCallback();
835
+ }
836
+ return true;
837
+ }
838
+
839
+ EXIF.getDataFromDataURL = function(oImg, fncCallback)
840
+ {
841
+ if (!oImg.complete)
842
+ return false;
843
+ if (!imageHasData(oImg)) {
844
+ getImageDataFromDataURL(oImg, fncCallback);
845
+ } else {
846
+ if (fncCallback)
847
+ fncCallback();
848
+ }
849
+ return true;
850
+ }
851
+
852
+ EXIF.getTag = function(oImg, strTag)
853
+ {
854
+ if (!imageHasData(oImg))
855
+ return;
856
+ return oImg.exifdata[strTag];
857
+ }
858
+
859
+ EXIF.getAllTags = function(oImg)
860
+ {
861
+ if (!imageHasData(oImg))
862
+ return {};
863
+ var oData = oImg.exifdata;
864
+ var oAllTags = {};
865
+ for (var a in oData) {
866
+ if (oData.hasOwnProperty(a)) {
867
+ oAllTags[a] = oData[a];
868
+ }
869
+ }
870
+ return oAllTags;
871
+ }
872
+
873
+ EXIF.pretty = function(oImg)
874
+ {
875
+ if (!imageHasData(oImg))
876
+ return "";
877
+ var oData = oImg.exifdata;
878
+ var strPretty = "";
879
+ for (var a in oData) {
880
+ if (oData.hasOwnProperty(a)) {
881
+ if (typeof oData[a] == "object") {
882
+ strPretty += a + " : [" + oData[a].length + " values]\r\n";
883
+ } else {
884
+ strPretty += a + " : " + oData[a] + "\r\n";
885
+ }
886
+ }
887
+ }
888
+ return strPretty;
889
+ }
890
+
891
+ EXIF.readFromBinaryFile = function(oFile) {
892
+ return findEXIFinJPEG(oFile);
893
+ }
894
+
895
+ function loadAllImages()
896
+ {
897
+ var aImages = document.getElementsByTagName("img");
898
+ for (var i = 0; i < aImages.length; i++) {
899
+ if (aImages[i].getAttribute("exif") == "true") {
900
+ if (!aImages[i].complete) {
901
+ addEvent(aImages[i], "load",
902
+ function() {
903
+ EXIF.getData(this);
904
+ }
905
+ );
906
+ } else {
907
+ EXIF.getData(aImages[i]);
908
+ }
909
+ }
910
+ }
911
+ }
912
+
913
+ // automatically load exif data for all images with exif=true when doc is ready
914
+ jQuery(document).ready(loadAllImages);
915
+
916
+ // load data for images manually
917
+ jQuery.fn.exifLoad = function(fncCallback) {
918
+ return this.each(function() {
919
+ EXIF.getData(this, fncCallback)
920
+ });
921
+ }
922
+
923
+ // load data for images manually
924
+ jQuery.fn.exifLoadFromDataURL = function(fncCallback) {
925
+ return this.each(function() {
926
+ EXIF.getDataFromDataURL(this, fncCallback)
927
+ return true;
928
+ });
929
+ }
930
+
931
+ jQuery.fn.exif = function(strTag) {
932
+ var aStrings = [];
933
+ this.each(function() {
934
+ aStrings.push(EXIF.getTag(this, strTag));
935
+ });
936
+ return aStrings;
937
+ }
938
+
939
+ jQuery.fn.exifAll = function() {
940
+ var aStrings = [];
941
+ this.each(function() {
942
+ aStrings.push(EXIF.getAllTags(this));
943
+ });
944
+ return aStrings;
945
+ }
946
+
947
+ jQuery.fn.exifPretty = function() {
948
+ var aStrings = [];
949
+ this.each(function() {
950
+ aStrings.push(EXIF.pretty(this));
951
+ });
952
+ return aStrings;
953
+ }
954
+
955
+
956
+ })();
957
+
958
+
959
+ })();