File: exifdata.cpp

package info (click to toggle)
luminance-hdr 2.6.1.1%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 34,860 kB
  • sloc: cpp: 43,967; ansic: 4,122; xml: 116; makefile: 20; sh: 7
file content (220 lines) | stat: -rw-r--r-- 7,486 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/*
 * This file is a part of Luminance HDR package.
 * ----------------------------------------------------------------------
 * Copyright (C) 2012 Davide Anastasia
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * ----------------------------------------------------------------------
 */

#include "exifdata.hpp"

#include <cmath>
#include <exiv2/exiv2.hpp>
#include <iostream>

#if EXIV2_TEST_VERSION(0,28,0)
typedef Exiv2::Error Exiv2Error;
typedef Exiv2::Image::UniquePtr ImagePtr;
#define EXIV2_TO_INT toInt64
#else
typedef Exiv2::AnyError Exiv2Error;
typedef Exiv2::Image::AutoPtr ImagePtr;
#define EXIV2_TO_INT toLong
#endif

namespace pfs {
namespace exif {

namespace {
// reflected-light meter calibration constant
const float K = 12.07488f;
// default ISO value for camera that do not report io
const float DEFAULT_ISO = 100.f;
// invalid value
const float INVALID_VALUE = -1.f;
// invalid value
const float INVALID_EV_VALUE = -100000.f;
// default EVCOMP value
const float DEFAULT_EVCOMP = 0.0f;

float log_base(float value, float base) {
    return (std::log(value) / std::log(base));
}
}

ExifData::ExifData() { reset(); }

ExifData::ExifData(const std::string &filename) { fromFile(filename); }

void ExifData::fromFile(const std::string &filename) {
    reset();
    try {
        ::ImagePtr image = Exiv2::ImageFactory::open(filename);
        image->readMetadata();
        ::Exiv2::ExifData &exifData = image->exifData();

        // if data is empty
        if (exifData.empty()) return;

        // Exiv2 iterator in read-only
        ::Exiv2::ExifData::const_iterator it = exifData.end();
        if ((it = exifData.findKey(Exiv2::ExifKey(
                 "Exif.Photo.ExposureTime"))) != exifData.end()) {
            m_exposureTime = it->toFloat();
        } else if ((it = exifData.findKey(Exiv2::ExifKey(
                        "Exif.Photo.ShutterSpeedValue"))) != exifData.end()) {
            long num = 1;
            long div = 1;
            float tmp = std::exp(std::log(2.0f) * it->toFloat());
            if (tmp > 1) {
                div = static_cast<long>(tmp + 0.5f);
            } else {
                num = static_cast<long>(1.0f / tmp + 0.5f);
            }
            m_exposureTime = static_cast<float>(num) / div;
        }

        if ((it = exifData.findKey(Exiv2::ExifKey("Exif.Photo.FNumber"))) !=
            exifData.end()) {
            m_FNumber = it->toFloat();
        } else if ((it = exifData.findKey(Exiv2::ExifKey(
                        "Exif.Photo.ApertureValue"))) != exifData.end()) {
            m_FNumber =
                static_cast<float>(expf(logf(2.0f) * it->toFloat() / 2.f));
        }
        // some cameras/lens DO print the fnum but with value 0, and this is not
        // allowed for ev computation purposes.
        if (m_FNumber == 0.0f) {
            m_FNumber = INVALID_VALUE;
        }

        // if iso is found use that value, otherwise assume a value of iso=100.
        // (again, some cameras do not print iso in exif).
        if ((it = exifData.findKey(Exiv2::ExifKey(
                 "Exif.Photo.ISOSpeedRatings"))) != exifData.end()) {
            m_isoSpeed = it->toFloat();
        }

        if ((it = exifData.findKey(Exiv2::ExifKey(
                 "Exif.Photo.ExposureBiasValue"))) != exifData.end()) {
            m_EVCompensation = it->toFloat();
        }

        // exif orientation --------
        /*
         *           http://jpegclub.org/exif_orientation.html
         *
         *
         *       Value   0th Row     0th Column
         *           1   top         left side
         *           2   top         right side
         *           3   bottom      right side
         *           4   bottom      left side
         *           5   left side   top
         *           6   right side  top
         *           7   right side  bottom
         *           8   left side   bottom
         *
         */
        if ((it = exifData.findKey(Exiv2::ExifKey("Exif.Image.Orientation"))) !=
            exifData.end()) {
            long rotation = it->EXIV2_TO_INT();
            switch (rotation) {
                case 3:
                    m_orientation = 180;
                    break;
                case 6:
                    m_orientation = 90;
                    break;
                case 8:
                    m_orientation = 270;
                    break;
            }
        }
    } catch (Exiv2Error &e) {
        return;
    }
}

const float &ExifData::getExposureTime() const { return m_exposureTime; }
bool ExifData::hasExposureTime() const {
    return (m_exposureTime != INVALID_VALUE);
}
void ExifData::setExposureTime(float et) { m_exposureTime = et; }

const float &ExifData::getIsoSpeed() const { return m_isoSpeed; }
bool ExifData::hasIsoSpeed() const { return true; }
void ExifData::setIsoSpeed(float iso) { m_isoSpeed = iso; }

const float &ExifData::getFNumber() const { return m_FNumber; }
bool ExifData::hasFNumber() const { return (m_FNumber != INVALID_VALUE); }
void ExifData::setFNumber(float fnum) { m_FNumber = fnum; }

float ExifData::getExposureValue() const {
    if (hasFNumber() && hasExposureTime()) {
        return log_base((m_FNumber * m_FNumber) / m_exposureTime, 2.0f);
    }
    return INVALID_EV_VALUE;
}
bool ExifData::hasExposureValue() const {
    return (getExposureValue() != INVALID_EV_VALUE);
}

const float &ExifData::getExposureValueCompensation() const {
    return m_EVCompensation;
}
bool ExifData::hasExposureValueCompensation() const {
    return (m_EVCompensation != 0.0f);
}
void ExifData::setExposureValueCompensation(float evcomp) {
    m_EVCompensation = evcomp;
}

float ExifData::getAverageSceneLuminance() const {
    if (hasIsoSpeed() && hasFNumber() && hasExposureTime()) {
        return ((m_exposureTime * m_isoSpeed) / (m_FNumber * m_FNumber * K));
    }
    return INVALID_VALUE;
}

short ExifData::getOrientationDegree() const { return m_orientation; }

void ExifData::reset() {
    // reset internal value
    m_exposureTime = INVALID_VALUE;
    m_isoSpeed = DEFAULT_ISO;
    m_FNumber = INVALID_VALUE;
    m_EVCompensation = DEFAULT_EVCOMP;
    m_orientation = 0;
}

bool ExifData::isValid() const {
    return (hasIsoSpeed() && hasFNumber() && hasExposureTime());
}

std::ostream &operator<<(std::ostream &out, const ExifData &exifData) {
    out << "Exposure time = " << exifData.m_exposureTime << ", ";
    out << "F value = " << exifData.m_FNumber << ", ";
    out << "ISO = " << exifData.m_isoSpeed << ", ";
    out << "Exposure value = " << exifData.getExposureValue() << " ("
        << exifData.m_EVCompensation << "), ";
    out << "Average Scene Luminance = " << exifData.getAverageSceneLuminance();

    return out;
}

}  // namespace exif
}  // namespace LibHDR