Commit e249bc3e authored by Wescoeur's avatar Wescoeur

fix(QExifImageHeader): use app indentation

parent 8d46bcb1
...@@ -56,153 +56,136 @@ ...@@ -56,153 +56,136 @@
A synonym for \c QPair<qint32,qint32> representing a signed rational number as stored in EXIF A synonym for \c QPair<qint32,qint32> representing a signed rational number as stored in EXIF
headers. The first integer in the pair is the numerator and the second the denominator. headers. The first integer in the pair is the numerator and the second the denominator.
*/ */
/*! /*!
\typedef QExifURational \typedef QExifURational
A synonym for \c QPair<qint32,qint32> representing an unsigned rational number as stored in A synonym for \c QPair<qint32,qint32> representing an unsigned rational number as stored in
EXIF headers. The first integer in the pair is the numerator and the second the denominator. EXIF headers. The first integer in the pair is the numerator and the second the denominator.
*/ */
struct ExifIfdHeader struct ExifIfdHeader {
{ quint16 tag;
quint16 tag; quint16 type;
quint16 type; quint32 count;
quint32 count; union {
union quint32 offset;
{ quint8 offsetBytes[4];
quint32 offset; char offsetAscii[4];
quint8 offsetBytes[ 4 ]; quint16 offsetShorts[2];
char offsetAscii[ 4 ]; };
quint16 offsetShorts[ 2 ];
};
}; };
QDataStream &operator >>( QDataStream &stream, ExifIfdHeader &header ) QDataStream &operator>> (QDataStream &stream, ExifIfdHeader &header) {
{ stream >> header.tag;
stream >> header.tag; stream >> header.type;
stream >> header.type; stream >> header.count;
stream >> header.count;
if( header.type == QExifValue::Byte && header.count <= 4 ) if (header.type == QExifValue::Byte && header.count <= 4) {
{ stream.readRawData(header.offsetAscii, 4);
stream.readRawData( header.offsetAscii, 4 ); } else if (header.type == QExifValue::Ascii && header.count <= 4) {
} stream.readRawData(header.offsetAscii, 4);
else if( header.type == QExifValue::Ascii && header.count <= 4 ) } else if (header.type == QExifValue::Short && header.count <= 2) {
{ stream >> header.offsetShorts[0];
stream.readRawData( header.offsetAscii, 4 ); stream >> header.offsetShorts[1];
} } else {
else if( header.type == QExifValue::Short && header.count <= 2 ) stream >> header.offset;
{ }
stream >> header.offsetShorts[ 0 ];
stream >> header.offsetShorts[ 1 ];
}
else
{
stream >> header.offset;
}
return stream; return stream;
} }
class QExifValuePrivate : public QSharedData {
class QExifValuePrivate : public QSharedData
{
public: public:
QExifValuePrivate( quint16 t, int c ) QExifValuePrivate (quint16 t, int c)
: type( t ), count( c ) : type(t), count(c)
{} {}
virtual ~QExifValuePrivate(){}
virtual ~QExifValuePrivate () {}
quint16 type; quint16 type;
int count; int count;
}; };
class QExifByteValuePrivate : public QExifValuePrivate class QExifByteValuePrivate : public QExifValuePrivate {
{
public: public:
QExifByteValuePrivate() QExifByteValuePrivate ()
: QExifValuePrivate(QExifValue::Byte, 0) : QExifValuePrivate(QExifValue::Byte, 0) {
{ ref.ref(); } ref.ref();
QExifByteValuePrivate( const QVector< quint8 > &v ) }
: QExifValuePrivate( QExifValue::Byte, v.size() ), value( v )
{} QExifByteValuePrivate (const QVector<quint8> &v)
: QExifValuePrivate(QExifValue::Byte, v.size()), value(v)
QVector< quint8 > value; {}
QVector<quint8> value;
}; };
class QExifUndefinedValuePrivate : public QExifValuePrivate class QExifUndefinedValuePrivate : public QExifValuePrivate {
{
public: public:
QExifUndefinedValuePrivate( const QByteArray &v ) QExifUndefinedValuePrivate (const QByteArray &v)
: QExifValuePrivate( QExifValue::Undefined, v.size() ), value( v ) : QExifValuePrivate(QExifValue::Undefined, v.size()), value(v)
{} {}
QByteArray value; QByteArray value;
}; };
class QExifAsciiValuePrivate : public QExifValuePrivate class QExifAsciiValuePrivate : public QExifValuePrivate {
{
public: public:
QExifAsciiValuePrivate( const QString &v ) QExifAsciiValuePrivate (const QString &v)
: QExifValuePrivate( QExifValue::Ascii, v.size() + 1 ), value( v ) : QExifValuePrivate(QExifValue::Ascii, v.size() + 1), value(v)
{} {}
QString value; QString value;
}; };
class QExifShortValuePrivate : public QExifValuePrivate class QExifShortValuePrivate : public QExifValuePrivate {
{
public: public:
QExifShortValuePrivate( const QVector< quint16 > &v ) QExifShortValuePrivate (const QVector<quint16> &v)
: QExifValuePrivate( QExifValue::Short, v.size() ), value( v ) : QExifValuePrivate(QExifValue::Short, v.size()), value(v)
{} {}
QVector< quint16 > value; QVector<quint16> value;
}; };
class QExifLongValuePrivate : public QExifValuePrivate class QExifLongValuePrivate : public QExifValuePrivate {
{
public: public:
QExifLongValuePrivate( const QVector< quint32 > &v ) QExifLongValuePrivate (const QVector<quint32> &v)
: QExifValuePrivate( QExifValue::Long, v.size() ), value( v ) : QExifValuePrivate(QExifValue::Long, v.size()), value(v)
{} {}
QVector< quint32 > value; QVector<quint32> value;
}; };
class QExifSignedLongValuePrivate : public QExifValuePrivate class QExifSignedLongValuePrivate : public QExifValuePrivate {
{
public: public:
QExifSignedLongValuePrivate( const QVector< qint32 > &v ) QExifSignedLongValuePrivate (const QVector<qint32> &v)
: QExifValuePrivate( QExifValue::SignedLong, v.size() ), value( v ) : QExifValuePrivate(QExifValue::SignedLong, v.size()), value(v)
{} {}
QVector< qint32 > value; QVector<qint32> value;
}; };
class QExifRationalValuePrivate : public QExifValuePrivate class QExifRationalValuePrivate : public QExifValuePrivate {
{
public: public:
QExifRationalValuePrivate( const QVector< QExifURational > &v ) QExifRationalValuePrivate (const QVector<QExifURational> &v)
: QExifValuePrivate( QExifValue::Rational, v.size() ), value( v ) : QExifValuePrivate(QExifValue::Rational, v.size()), value(v)
{} {}
QVector< QExifURational > value; QVector<QExifURational> value;
}; };
class QExifSignedRationalValuePrivate : public QExifValuePrivate class QExifSignedRationalValuePrivate : public QExifValuePrivate {
{
public: public:
QExifSignedRationalValuePrivate( const QVector< QExifSRational > &v ) QExifSignedRationalValuePrivate (const QVector<QExifSRational> &v)
: QExifValuePrivate( QExifValue::SignedRational, v.size() ), value( v ) : QExifValuePrivate(QExifValue::SignedRational, v.size()), value(v)
{} {}
QVector< QExifSRational > value; QVector<QExifSRational> value;
}; };
Q_GLOBAL_STATIC(QExifByteValuePrivate,qExifValuePrivateSharedNull) Q_GLOBAL_STATIC(QExifByteValuePrivate, qExifValuePrivateSharedNull)
/*! /*!
\class QExifValue \class QExifValue
...@@ -228,7 +211,7 @@ Q_GLOBAL_STATIC(QExifByteValuePrivate,qExifValuePrivateSharedNull) ...@@ -228,7 +211,7 @@ Q_GLOBAL_STATIC(QExifByteValuePrivate,qExifValuePrivateSharedNull)
\sa QExifImageHeader \sa QExifImageHeader
\preliminary \preliminary
*/ */
/*! /*!
\enum QExifValue::Type \enum QExifValue::Type
...@@ -243,7 +226,7 @@ Q_GLOBAL_STATIC(QExifByteValuePrivate,qExifValuePrivateSharedNull) ...@@ -243,7 +226,7 @@ Q_GLOBAL_STATIC(QExifByteValuePrivate,qExifValuePrivateSharedNull)
\value Undefined An array of 8 bit integers. \value Undefined An array of 8 bit integers.
\value SignedLong A signed 32 bit integer. \value SignedLong A signed 32 bit integer.
\value SignedRational Two signed 32 bit integers representing the numerator and denominator of a signed rational number. \value SignedRational Two signed 32 bit integers representing the numerator and denominator of a signed rational number.
*/ */
/*! /*!
\enum QExifValue::TextEncoding \enum QExifValue::TextEncoding
...@@ -255,481 +238,425 @@ Q_GLOBAL_STATIC(QExifByteValuePrivate,qExifValuePrivateSharedNull) ...@@ -255,481 +238,425 @@ Q_GLOBAL_STATIC(QExifByteValuePrivate,qExifValuePrivateSharedNull)
\value JisEncoding A JIS X208-1990 string of Undefined type. \value JisEncoding A JIS X208-1990 string of Undefined type.
\value UnicodeEncoding A Unicode string of Undefined type. \value UnicodeEncoding A Unicode string of Undefined type.
\value UndefinedEncoding An unspecified string encoding of Undefined type. Assumed to be the local 8-bit encoding. \value UndefinedEncoding An unspecified string encoding of Undefined type. Assumed to be the local 8-bit encoding.
*/ */
/*! /*!
Constructs a null QExifValue. Constructs a null QExifValue.
*/ */
QExifValue::QExifValue() QExifValue::QExifValue ()
: d( qExifValuePrivateSharedNull() ) : d(qExifValuePrivateSharedNull())
{ {}
}
/*! /*!
Constructs a QExifValue with a \a value of type Byte. Constructs a QExifValue with a \a value of type Byte.
*/ */
QExifValue::QExifValue( quint8 value ) QExifValue::QExifValue (quint8 value)
: d( new QExifByteValuePrivate( QVector< quint8 >( 1, value ) ) ) : d(new QExifByteValuePrivate(QVector<quint8>(1, value)))
{ {}
}
/*! /*!
Constructs a QExifValue with an array of \a values of type Byte. Constructs a QExifValue with an array of \a values of type Byte.
*/ */
QExifValue::QExifValue( const QVector< quint8 > &values ) QExifValue::QExifValue (const QVector<quint8> &values)
: d( new QExifByteValuePrivate( values ) ) : d(new QExifByteValuePrivate(values))
{ {}
}
/*! /*!
Constructs a QExifValue with a \a value of type Ascii or Undefined. Constructs a QExifValue with a \a value of type Ascii or Undefined.
If the \a encoding is NoEncoding the value will be of type Ascii, otherwise it will be Undefined and the string If the \a encoding is NoEncoding the value will be of type Ascii, otherwise it will be Undefined and the string
encoded using the given \a encoding. encoded using the given \a encoding.
*/ */
QExifValue::QExifValue( const QString &value, TextEncoding encoding ) QExifValue::QExifValue (const QString &value, TextEncoding encoding)
: d( qExifValuePrivateSharedNull() ) : d(qExifValuePrivateSharedNull()) {
{ switch (encoding) {
switch( encoding )
{
case AsciiEncoding: case AsciiEncoding:
d = new QExifUndefinedValuePrivate( QByteArray::fromRawData( "ASCII\0\0\0", 8 ) + value.toUtf8() ); d = new QExifUndefinedValuePrivate(QByteArray::fromRawData("ASCII\0\0\0", 8) + value.toUtf8());
break; break;
case JisEncoding: case JisEncoding: {
{ QTextCodec *codec = QTextCodec::codecForName("JIS X 0208");
QTextCodec *codec = QTextCodec::codecForName( "JIS X 0208" ); if (codec)
if( codec ) d = new QExifUndefinedValuePrivate(QByteArray::fromRawData("JIS\0\0\0\0\0", 8) + codec->fromUnicode(value));
d = new QExifUndefinedValuePrivate( QByteArray::fromRawData( "JIS\0\0\0\0\0", 8 ) + codec->fromUnicode( value ) ); }
} break;
break; case UnicodeEncoding: {
case UnicodeEncoding: QTextCodec *codec = QTextCodec::codecForName("UTF-16");
{ if (codec)
QTextCodec *codec = QTextCodec::codecForName( "UTF-16" ); d = new QExifUndefinedValuePrivate(QByteArray::fromRawData("UNICODE\0", 8) + codec->fromUnicode(value));
if( codec ) }
d = new QExifUndefinedValuePrivate( QByteArray::fromRawData( "UNICODE\0", 8 ) + codec->fromUnicode( value ) ); break;
}
break;
case UndefinedEncoding: case UndefinedEncoding:
d = new QExifUndefinedValuePrivate( QByteArray::fromRawData( "\0\0\0\0\0\0\0\\0", 8 ) + value.toLocal8Bit() ); d = new QExifUndefinedValuePrivate(QByteArray::fromRawData("\0\0\0\0\0\0\0\\0", 8) + value.toLocal8Bit());
break; break;
default: default:
d = new QExifAsciiValuePrivate( value ); d = new QExifAsciiValuePrivate(value);
} }
} }
/*! /*!
Constructs a QExifValue with a \a value of type Short. Constructs a QExifValue with a \a value of type Short.
*/ */
QExifValue::QExifValue( quint16 value ) QExifValue::QExifValue (quint16 value)
: d( new QExifShortValuePrivate( QVector< quint16 >( 1, value ) ) ) : d(new QExifShortValuePrivate(QVector<quint16>(1, value)))
{ {}
}
/*! /*!
Constructs a QExifValue with an array of \a values of type Short. Constructs a QExifValue with an array of \a values of type Short.
*/ */
QExifValue::QExifValue( const QVector< quint16 > &values ) QExifValue::QExifValue (const QVector<quint16> &values)
: d( new QExifShortValuePrivate( values ) ) : d(new QExifShortValuePrivate(values))
{ {}
}
/*! /*!
Constructs a QExifValue with a \a value of type Long. Constructs a QExifValue with a \a value of type Long.
*/ */
QExifValue::QExifValue( quint32 value ) QExifValue::QExifValue (quint32 value)
: d( new QExifLongValuePrivate( QVector< quint32 >( 1, value ) ) ) : d(new QExifLongValuePrivate(QVector<quint32>(1, value)))
{ {}
}
/*! /*!
Constructs a QExifValue with an array of \a values of type Long. Constructs a QExifValue with an array of \a values of type Long.
*/ */
QExifValue::QExifValue( const QVector< quint32 > &values ) QExifValue::QExifValue (const QVector<quint32> &values)
: d( new QExifLongValuePrivate( values ) ) : d(new QExifLongValuePrivate(values))
{ {}
}
/*! /*!
Constructs a QExifValue with a \a value of type Rational. Constructs a QExifValue with a \a value of type Rational.
*/ */
QExifValue::QExifValue( const QExifURational &value ) QExifValue::QExifValue (const QExifURational &value)
: d( new QExifRationalValuePrivate( QVector< QExifURational >( 1, value ) ) ) : d(new QExifRationalValuePrivate(QVector<QExifURational>(1, value)))
{ {}
}
/*! /*!
Constructs a QExifValue with an array of \a values of type Rational. Constructs a QExifValue with an array of \a values of type Rational.
*/ */
QExifValue::QExifValue( const QVector< QExifURational > &values ) QExifValue::QExifValue (const QVector<QExifURational> &values)
: d( new QExifRationalValuePrivate( values ) ) : d(new QExifRationalValuePrivate(values))
{ {}
}
/*! /*!
Constructs a QExifValue with a \a value of type Undefined. Constructs a QExifValue with a \a value of type Undefined.
*/ */
QExifValue::QExifValue( const QByteArray &value ) QExifValue::QExifValue (const QByteArray &value)
: d( new QExifUndefinedValuePrivate( value ) ) : d(new QExifUndefinedValuePrivate(value))
{ {}
}
/*! /*!
Constructs a QExifValue with a \a value of type SignedLong. Constructs a QExifValue with a \a value of type SignedLong.
*/ */
QExifValue::QExifValue( qint32 value ) QExifValue::QExifValue (qint32 value)
: d( new QExifSignedLongValuePrivate( QVector< qint32 >( 1, value ) ) ) : d(new QExifSignedLongValuePrivate(QVector<qint32>(1, value)))
{ {}
}
/*! /*!
Constructs a QExifValue with an array of \a values of type SignedLong. Constructs a QExifValue with an array of \a values of type SignedLong.
*/ */
QExifValue::QExifValue( const QVector< qint32 > &values ) QExifValue::QExifValue (const QVector<qint32> &values)
: d( new QExifSignedLongValuePrivate( values ) ) : d(new QExifSignedLongValuePrivate(values))
{ {}
}
/*! /*!
Constructs a QExifValue with a \a value of type SignedRational. Constructs a QExifValue with a \a value of type SignedRational.
*/ */
QExifValue::QExifValue( const QExifSRational &value ) QExifValue::QExifValue (const QExifSRational &value)
: d( new QExifSignedRationalValuePrivate( QVector< QExifSRational >( 1, value ) ) ) : d(new QExifSignedRationalValuePrivate(QVector<QExifSRational>(1, value)))
{ {}
}
/*! /*!
Constructs a QExifValue with an array of \a values of type SignedRational. Constructs a QExifValue with an array of \a values of type SignedRational.
*/ */
QExifValue::QExifValue( const QVector< QExifSRational > &values ) QExifValue::QExifValue (const QVector<QExifSRational> &values)
: d( new QExifSignedRationalValuePrivate( values ) ) : d(new QExifSignedRationalValuePrivate(values))
{ {}
}
/*! /*!
Constructs a QExifValue of type Ascii with an ascii string formatted from a date-time \a value. Constructs a QExifValue of type Ascii with an ascii string formatted from a date-time \a value.
Date-times are stored as strings in the format \c {yyyy:MM:dd HH:mm:ss}. Date-times are stored as strings in the format \c {yyyy:MM:dd HH:mm:ss}.
*/ */
QExifValue::QExifValue( const QDateTime &value ) QExifValue::QExifValue (const QDateTime &value)
: d( new QExifAsciiValuePrivate( value.toString( QLatin1String( "yyyy:MM:dd HH:mm:ss" ) ) ) ) : d(new QExifAsciiValuePrivate(value.toString(QLatin1String("yyyy:MM:dd HH:mm:ss"))))
{ {}
}
/*! /*!
Constructs a copy of the QExifValue \a other. Constructs a copy of the QExifValue \a other.
*/ */
QExifValue::QExifValue( const QExifValue &other ) QExifValue::QExifValue (const QExifValue &other)
: d( other.d ) : d(other.d)
{ {}
}
/*! /*!
Assigns the value of \a other to a QExifValue. Assigns the value of \a other to a QExifValue.
*/ */
QExifValue &QExifValue::operator =( const QExifValue &other ) QExifValue &QExifValue::operator= (const QExifValue &other) {
{ d = other.d;
d = other.d;
return *this; return *this;
} }
/*! /*!
Destroys a QExifValue. Destroys a QExifValue.
*/ */
QExifValue::~QExifValue() QExifValue::~QExifValue ()
{ {}
}
/*! /*!
Compares a QExifValue to \a other. Returns true if they are the same value and false otherwise. Compares a QExifValue to \a other. Returns true if they are the same value and false otherwise.
*/ */
bool QExifValue::operator ==( const QExifValue &other ) const bool QExifValue::operator== (const QExifValue &other) const {
{ return d == other.d;
return d == other.d;
} }
/*! /*!
Returns true if a QExifValue has a null value and false otherwise. Returns true if a QExifValue has a null value and false otherwise.
*/ */
bool QExifValue::isNull() const bool QExifValue::isNull () const {
{ return d == qExifValuePrivateSharedNull();
return d == qExifValuePrivateSharedNull();
} }
/*! /*!
Returns the type of a QExifValue. Returns the type of a QExifValue.
*/ */
int QExifValue::type() const int QExifValue::type () const {
{ return d->type;
return d->type;
} }
/*! /*!
Returns the number of elements in a QExifValue. For ascii strings this is the length of the string Returns the number of elements in a QExifValue. For ascii strings this is the length of the string
including the terminating null. including the terminating null.
*/ */
int QExifValue::count() const int QExifValue::count () const {
{ return d->count;
return d->count;
} }
/*! /*!
Returns the encoding of strings stored in Undefined values. Returns the encoding of strings stored in Undefined values.
*/ */
QExifValue::TextEncoding QExifValue::encoding() const QExifValue::TextEncoding QExifValue::encoding () const {
{ if (d->type == Undefined && d->count > 8) {
if( d->type == Undefined && d->count > 8 ) QByteArray value = static_cast<const QExifUndefinedValuePrivate *>(d.constData())->value;
{
QByteArray value = static_cast< const QExifUndefinedValuePrivate * >( d.constData() )->value; if (value.startsWith(QByteArray::fromRawData("ASCII\0\0\0", 8)))
return AsciiEncoding;
if( value.startsWith( QByteArray::fromRawData( "ASCII\0\0\0", 8 ) ) ) else if (value.startsWith(QByteArray::fromRawData("JIS\0\0\0\0\0", 8)))
return AsciiEncoding; return JisEncoding;
else if( value.startsWith( QByteArray::fromRawData( "JIS\0\0\0\0\0", 8 ) ) ) else if (value.startsWith(QByteArray::fromRawData("UNICODE\0", 8)))
return JisEncoding; return UnicodeEncoding;
else if( value.startsWith( QByteArray::fromRawData( "UNICODE\0", 8 ) ) ) else if (value.startsWith(QByteArray::fromRawData("\0\0\0\0\0\0\0\0", 8)))
return UnicodeEncoding; return UndefinedEncoding;
else if( value.startsWith( QByteArray::fromRawData( "\0\0\0\0\0\0\0\0", 8 ) ) ) }
return UndefinedEncoding; return NoEncoding;
}
return NoEncoding;
} }
/*! /*!
Returns the value of a single element QExifValue of type Byte. Returns the value of a single element QExifValue of type Byte.
*/ */
quint8 QExifValue::toByte() const quint8 QExifValue::toByte () const {
{ return d->type == Byte && d->count == 1
return d->type == Byte && d->count == 1 ? static_cast<const QExifByteValuePrivate *>(d.constData())->value.at(0)
? static_cast< const QExifByteValuePrivate * >( d.constData() )->value.at( 0 ) : 0;
: 0;
} }
/*! /*!
Returns the value of a multiple element QExifValue of type Byte. Returns the value of a multiple element QExifValue of type Byte.
*/ */
QVector< quint8 > QExifValue::toByteVector() const QVector<quint8> QExifValue::toByteVector () const {
{ return d->type == Byte
return d->type == Byte ? static_cast<const QExifByteValuePrivate *>(d.constData())->value
? static_cast< const QExifByteValuePrivate * >( d.constData() )->value : QVector<quint8>();
: QVector< quint8 >();
} }
/*! /*!
Returns the value of a QExifValue of type Ascii. Returns the value of a QExifValue of type Ascii.
*/ */
QString QExifValue::toString() const QString QExifValue::toString () const {
{ switch (d->type) {
switch( d->type )
{
case Ascii: case Ascii:
return static_cast< const QExifAsciiValuePrivate * >( d.constData() )->value; return static_cast<const QExifAsciiValuePrivate *>(d.constData())->value;
case Undefined: case Undefined: {
{ QByteArray string = static_cast<const QExifUndefinedValuePrivate *>(d.constData())->value.mid(8);
QByteArray string = static_cast< const QExifUndefinedValuePrivate * >( d.constData() )->value.mid( 8 );
switch (encoding()) {
switch( encoding() ) case AsciiEncoding:
{ return QString::fromUtf8(string.constData(), string.length());
case AsciiEncoding: case JisEncoding: {
return QString::fromUtf8( string.constData(), string.length() ); QTextCodec *codec = QTextCodec::codecForName("JIS X 0208");
case JisEncoding: if (codec)
{ return codec->toUnicode(string);
QTextCodec *codec = QTextCodec::codecForName( "JIS X 0208" );
if( codec )
return codec->toUnicode( string );
}
break;
case UnicodeEncoding:
{
QTextCodec *codec = QTextCodec::codecForName( "UTF-16" );
if( codec )
return codec->toUnicode( string );
}
case UndefinedEncoding:
return QString::fromLocal8Bit( string.constData(), string.length() );
default:
break;
}
} }
default: break;
return QString(); case UnicodeEncoding: {
QTextCodec *codec = QTextCodec::codecForName("UTF-16");
if (codec)
return codec->toUnicode(string);
}
case UndefinedEncoding:
return QString::fromLocal8Bit(string.constData(), string.length());
default:
break;
}
} }
default:
return QString();
}
} }
/*! /*!
Returns the value of a single element QExifValue of type Byte or Short. Returns the value of a single element QExifValue of type Byte or Short.
*/ */
quint16 QExifValue::toShort() const quint16 QExifValue::toShort () const {
{ if (d->count == 1) {
if( d->count == 1 ) switch (d->type) {
{ case Byte:
switch( d->type ) return static_cast<const QExifByteValuePrivate *>(d.constData())->value.at(0);
{ case Short:
case Byte: return static_cast<const QExifShortValuePrivate *>(d.constData())->value.at(0);
return static_cast< const QExifByteValuePrivate * >( d.constData() )->value.at( 0 );
case Short:
return static_cast< const QExifShortValuePrivate * >( d.constData() )->value.at( 0 );
}
} }
return 0; }
return 0;
} }
/*! /*!
Returns the value of a single element QExifValue of type Short. Returns the value of a single element QExifValue of type Short.
*/ */
QVector< quint16 > QExifValue::toShortVector() const QVector<quint16> QExifValue::toShortVector () const {
{ return d->type == Short
return d->type == Short ? static_cast<const QExifShortValuePrivate *>(d.constData())->value
? static_cast< const QExifShortValuePrivate * >( d.constData() )->value : QVector<quint16>();
: QVector< quint16 >();
} }
/*! /*!
Returns the value of a single element QExifValue of type Byte, Short, Long, or SignedLong. Returns the value of a single element QExifValue of type Byte, Short, Long, or SignedLong.
*/ */
quint32 QExifValue::toLong() const quint32 QExifValue::toLong () const {
{ if (d->count == 1) {
if( d->count == 1 ) switch (d->type) {
{ case Byte:
switch( d->type ) return static_cast<const QExifByteValuePrivate *>(d.constData())->value.at(0);
{ case Short:
case Byte: return static_cast<const QExifShortValuePrivate *>(d.constData())->value.at(0);
return static_cast< const QExifByteValuePrivate * >( d.constData() )->value.at( 0 ); case Long:
case Short: return static_cast<const QExifLongValuePrivate *>(d.constData())->value.at(0);
return static_cast< const QExifShortValuePrivate * >( d.constData() )->value.at( 0 ); case SignedLong:
case Long: return static_cast<const QExifSignedLongValuePrivate *>(d.constData())->value.at(0);
return static_cast< const QExifLongValuePrivate * >( d.constData() )->value.at( 0 );
case SignedLong:
return static_cast< const QExifSignedLongValuePrivate * >( d.constData() )->value.at( 0 );
}
} }
return 0; }
return 0;
} }
/*! /*!
Returns the value of a multiple element QExifValue of type Long. Returns the value of a multiple element QExifValue of type Long.
*/ */
QVector< quint32 > QExifValue::toLongVector() const QVector<quint32> QExifValue::toLongVector () const {
{ return d->type == Long
return d->type == Long ? static_cast<const QExifLongValuePrivate *>(d.constData())->value
? static_cast< const QExifLongValuePrivate * >( d.constData() )->value : QVector<quint32>();
: QVector< quint32 >();
} }
/*! /*!
Returns the value of a multiple element QExifValue of type Rational. Returns the value of a multiple element QExifValue of type Rational.
*/ */
QExifURational QExifValue::toRational() const QExifURational QExifValue::toRational () const {
{ return d->type == Rational && d->count == 1
return d->type == Rational && d->count == 1 ? static_cast<const QExifRationalValuePrivate *>(d.constData())->value.at(0)
? static_cast< const QExifRationalValuePrivate * >( d.constData() )->value.at( 0 ) : QExifURational();
: QExifURational();
} }
/*! /*!
Returns the value of a multiple element QExifValue of type Rational. Returns the value of a multiple element QExifValue of type Rational.
*/ */
QVector< QExifURational > QExifValue::toRationalVector() const QVector<QExifURational> QExifValue::toRationalVector () const {
{ return d->type == Rational
return d->type == Rational ? static_cast<const QExifRationalValuePrivate *>(d.constData())->value
? static_cast< const QExifRationalValuePrivate * >( d.constData() )->value : QVector<QExifURational>();
: QVector< QExifURational >();
} }
/*! /*!
Returns the value of a QExifValue of type Undefined. Returns the value of a QExifValue of type Undefined.
*/ */
QByteArray QExifValue::toByteArray() const QByteArray QExifValue::toByteArray () const {
{ switch (d->type) {
switch( d->type )
{
case Ascii: case Ascii:
return static_cast< const QExifAsciiValuePrivate * >( d.constData() )->value.toUtf8(); return static_cast<const QExifAsciiValuePrivate *>(d.constData())->value.toUtf8();
case Undefined: case Undefined:
return static_cast< const QExifUndefinedValuePrivate * >( d.constData() )->value; return static_cast<const QExifUndefinedValuePrivate *>(d.constData())->value;
default: default:
return QByteArray(); return QByteArray();
} }
} }
/*! /*!
Returns the value of a single element QExifValue of type Byte, Short, Long, or SignedLong. Returns the value of a single element QExifValue of type Byte, Short, Long, or SignedLong.
*/ */
qint32 QExifValue::toSignedLong() const qint32 QExifValue::toSignedLong () const {
{ if (d->count == 1) {
if( d->count == 1 ) switch (d->type) {
{ case Byte:
switch( d->type ) return static_cast<const QExifByteValuePrivate *>(d.constData())->value.at(0);
{ case Short:
case Byte: return static_cast<const QExifShortValuePrivate *>(d.constData())->value.at(0);
return static_cast< const QExifByteValuePrivate * >( d.constData() )->value.at( 0 ); case Long:
case Short: return static_cast<const QExifLongValuePrivate *>(d.constData())->value.at(0);
return static_cast< const QExifShortValuePrivate * >( d.constData() )->value.at( 0 ); case SignedLong:
case Long: return static_cast<const QExifSignedLongValuePrivate *>(d.constData())->value.at(0);
return static_cast< const QExifLongValuePrivate * >( d.constData() )->value.at( 0 );
case SignedLong:
return static_cast< const QExifSignedLongValuePrivate * >( d.constData() )->value.at( 0 );
}
} }
return 0; }
return 0;
} }
/*! /*!
Returns the value of a multiple element QExifValue of type SignedLong. Returns the value of a multiple element QExifValue of type SignedLong.
*/ */
QVector< qint32 > QExifValue::toSignedLongVector() const QVector<qint32> QExifValue::toSignedLongVector () const {
{ return d->type == SignedLong
return d->type == SignedLong ? static_cast<const QExifSignedLongValuePrivate *>(d.constData())->value
? static_cast< const QExifSignedLongValuePrivate * >( d.constData() )->value : QVector<qint32>();
: QVector< qint32 >();
} }
/*! /*!
Returns the value of a single element QExifValue of type SignedRational. Returns the value of a single element QExifValue of type SignedRational.
*/ */
QExifSRational QExifValue::toSignedRational() const QExifSRational QExifValue::toSignedRational () const {
{ return d->type == SignedRational && d->count == 1
return d->type == SignedRational && d->count == 1 ? static_cast<const QExifSignedRationalValuePrivate *>(d.constData())->value.at(0)
? static_cast< const QExifSignedRationalValuePrivate * >( d.constData() )->value.at( 0 ) : QExifSRational();
: QExifSRational();
} }
/*! /*!
Returns the value of a multiple element QExifValue of type SignedRational. Returns the value of a multiple element QExifValue of type SignedRational.
*/ */
QVector< QExifSRational > QExifValue::toSignedRationalVector() const QVector<QExifSRational> QExifValue::toSignedRationalVector () const {
{ return d->type == SignedRational
return d->type == SignedRational ? static_cast<const QExifSignedRationalValuePrivate *>(d.constData())->value
? static_cast< const QExifSignedRationalValuePrivate * >( d.constData() )->value : QVector<QExifSRational>();
: QVector< QExifSRational >();
} }
/*! /*!
Returns the value of QExifValue storing a date-time. Returns the value of QExifValue storing a date-time.
Date-times are stored as ascii strings in the format \c {yyyy:MM:dd HH:mm:ss}. Date-times are stored as ascii strings in the format \c {yyyy:MM:dd HH:mm:ss}.
*/ */
QDateTime QExifValue::toDateTime() const QDateTime QExifValue::toDateTime () const {
{ return d->type == Ascii && d->count == 20
return d->type == Ascii && d->count == 20 ? QDateTime::fromString(static_cast<const QExifAsciiValuePrivate *>(d.constData())->value, QLatin1String("yyyy:MM:dd HH:mm:ss"))
? QDateTime::fromString( static_cast< const QExifAsciiValuePrivate * >( d.constData() )->value, QLatin1String( "yyyy:MM:dd HH:mm:ss" ) ) : QDateTime();
: QDateTime();
} }
class QExifImageHeaderPrivate class QExifImageHeaderPrivate {
{
public: public:
QSysInfo::Endian byteOrder; QSysInfo::Endian byteOrder;
mutable qint64 size; mutable qint64 size;
QMap<QExifImageHeader::ImageTag, QExifValue > imageIfdValues; QMap<QExifImageHeader::ImageTag, QExifValue> imageIfdValues;
QMap<QExifImageHeader::ExifExtendedTag, QExifValue > exifIfdValues; QMap<QExifImageHeader::ExifExtendedTag, QExifValue> exifIfdValues;
QMap<QExifImageHeader::GpsTag, QExifValue > gpsIfdValues; QMap<QExifImageHeader::GpsTag, QExifValue> gpsIfdValues;
QSize thumbnailSize; QSize thumbnailSize;
QByteArray thumbnailData; QByteArray thumbnailData;
QExifValue thumbnailXResolution; QExifValue thumbnailXResolution;
QExifValue thumbnailYResolution; QExifValue thumbnailYResolution;
QExifValue thumbnailResolutionUnit; QExifValue thumbnailResolutionUnit;
QExifValue thumbnailOrientation; QExifValue thumbnailOrientation;
}; };
/*! /*!
...@@ -752,7 +679,7 @@ public: ...@@ -752,7 +679,7 @@ public:
EXIF header data itself. EXIF header data itself.
\preliminary \preliminary
*/ */
/*! /*!
\enum QExifImageHeader::ImageTag \enum QExifImageHeader::ImageTag
...@@ -785,7 +712,7 @@ public: ...@@ -785,7 +712,7 @@ public:
\value Software \value Software
\value Artist \value Artist
\value Copyright \value Copyright
*/ */
/*! /*!
\enum QExifImageHeader::ExifExtendedTag \enum QExifImageHeader::ExifExtendedTag
...@@ -847,7 +774,7 @@ public: ...@@ -847,7 +774,7 @@ public:
\value Sharpness \value Sharpness
\value DeviceSettingDescription \value DeviceSettingDescription
\value SubjectDistanceRange \value SubjectDistanceRange
*/ */
/*! /*!
\enum QExifImageHeader::GpsTag \enum QExifImageHeader::GpsTag
...@@ -884,88 +811,82 @@ public: ...@@ -884,88 +811,82 @@ public:
\value GpsAreaInformation \value GpsAreaInformation
\value GpsDateStamp \value GpsDateStamp
\value GpsDifferential \value GpsDifferential
*/ */
/*! /*!
Constructs a new EXIF image data editor. Constructs a new EXIF image data editor.
*/ */
QExifImageHeader::QExifImageHeader() QExifImageHeader::QExifImageHeader ()
: d( new QExifImageHeaderPrivate ) : d(new QExifImageHeaderPrivate) {
{ d->byteOrder = QSysInfo::ByteOrder;
d->byteOrder = QSysInfo::ByteOrder; d->size = -1;
d->size = -1;
} }
/*! /*!
Constructs a new EXIF image data editor and reads the meta-data from a JPEG image with the given \a fileName. Constructs a new EXIF image data editor and reads the meta-data from a JPEG image with the given \a fileName.
*/ */
QExifImageHeader::QExifImageHeader(const QString &fileName) QExifImageHeader::QExifImageHeader (const QString &fileName)
: d(new QExifImageHeaderPrivate) : d(new QExifImageHeaderPrivate) {
{ d->byteOrder = QSysInfo::ByteOrder;
d->byteOrder = QSysInfo::ByteOrder; d->size = -1;
d->size = -1;
loadFromJpeg(fileName);
loadFromJpeg(fileName);
} }
/*! /*!
Destroys an EXIF image data editor. Destroys an EXIF image data editor.
*/ */
QExifImageHeader::~QExifImageHeader() QExifImageHeader::~QExifImageHeader () {
{ clear();
clear();
delete d; delete d;
} }
/*! /*!
Reads meta-data from a JPEG image with the given \a fileName. Reads meta-data from a JPEG image with the given \a fileName.
Returns true if the data was successfully parsed and false otherwise. Returns true if the data was successfully parsed and false otherwise.
*/ */
bool QExifImageHeader::loadFromJpeg(const QString &fileName) bool QExifImageHeader::loadFromJpeg (const QString &fileName) {
{ QFile file(fileName);
QFile file(fileName);
if (file.open(QIODevice::ReadOnly))
if(file.open(QIODevice::ReadOnly)) return loadFromJpeg(&file);
return loadFromJpeg(&file); else
else return false;
return false;
} }
/*! /*!
Reads meta-data from an I/O \a device containing a JPEG image. Reads meta-data from an I/O \a device containing a JPEG image.
Returns true if the data was successfully parsed and false otherwise. Returns true if the data was successfully parsed and false otherwise.
*/ */
bool QExifImageHeader::loadFromJpeg(QIODevice *device) bool QExifImageHeader::loadFromJpeg (QIODevice *device) {
{ clear();
clear();
QByteArray exifData = extractExif(device); QByteArray exifData = extractExif(device);
if (!exifData.isEmpty()) { if (!exifData.isEmpty()) {
QBuffer buffer(&exifData); QBuffer buffer(&exifData);
return buffer.open(QIODevice::ReadOnly) && read(&buffer); return buffer.open(QIODevice::ReadOnly) && read(&buffer);
} }
return false; return false;
} }
/*! /*!
Saves meta-data to a JPEG image with the given \a fileName. Saves meta-data to a JPEG image with the given \a fileName.
Returns true if the data was successfully written. Returns true if the data was successfully written.
*/ */
bool QExifImageHeader::saveToJpeg(const QString &fileName) const bool QExifImageHeader::saveToJpeg (const QString &fileName) const {
{ QFile file(fileName);
QFile file(fileName);
if (file.open(QIODevice::ReadWrite))
if (file.open(QIODevice::ReadWrite)) return saveToJpeg(&file);
return saveToJpeg(&file); else
else return false;
return false;
} }
/*! /*!
...@@ -974,997 +895,953 @@ bool QExifImageHeader::saveToJpeg(const QString &fileName) const ...@@ -974,997 +895,953 @@ bool QExifImageHeader::saveToJpeg(const QString &fileName) const
The device must be non-sequential and already contain a valid JPEG image. The device must be non-sequential and already contain a valid JPEG image.
Returns true if the data was successfully written. Returns true if the data was successfully written.
*/ */
bool QExifImageHeader::saveToJpeg(QIODevice *device) const bool QExifImageHeader::saveToJpeg (QIODevice *device) const {
{ if (device->isSequential())
if( device->isSequential() ) return false;
return false;
QByteArray exif; QByteArray exif;
{ {
QBuffer buffer( &exif ); QBuffer buffer(&exif);
if( !buffer.open( QIODevice::WriteOnly ) ) if (!buffer.open(QIODevice::WriteOnly))
return false; return false;
write( &buffer ); write(&buffer);
buffer.close(); buffer.close();
exif = QByteArray::fromRawData( "Exif\0\0", 6 ) + exif; exif = QByteArray::fromRawData("Exif\0\0", 6) + exif;
} }
QDataStream stream( device ); QDataStream stream(device);
stream.setByteOrder( QDataStream::BigEndian ); stream.setByteOrder(QDataStream::BigEndian);
if( device->read( 2 ) != "\xFF\xD8" ) // Not a valid JPEG image. if (device->read(2) != "\xFF\xD8") // Not a valid JPEG image.
return false; return false;
quint16 segmentId; quint16 segmentId;
quint16 segmentLength; quint16 segmentLength;
stream >> segmentId; stream >> segmentId;
stream >> segmentLength; stream >> segmentLength;
if( segmentId == 0xFFE0 ) if (segmentId == 0xFFE0) {
{ QByteArray jfif = device->read(segmentLength - 2);
QByteArray jfif = device->read( segmentLength - 2 );
if( !jfif.startsWith( "JFIF" ) ) if (!jfif.startsWith("JFIF"))
return false; return false;
stream >> segmentId; stream >> segmentId;
stream >> segmentLength; stream >> segmentLength;
if( segmentId == 0xFFE1 ) if (segmentId == 0xFFE1) {
{ QByteArray oldExif = device->read(segmentLength - 2);
QByteArray oldExif = device->read( segmentLength - 2 );
if( !oldExif.startsWith( "Exif" ) ) if (!oldExif.startsWith("Exif"))
return false; return false;
int dSize = oldExif.size() - exif.size(); int dSize = oldExif.size() - exif.size();
if( dSize > 0 ) if (dSize > 0)
exif += QByteArray( dSize, '\0' ); exif += QByteArray(dSize, '\0');
QByteArray remainder = device->readAll(); QByteArray remainder = device->readAll();
device->seek( 0 ); device->seek(0);
stream << quint16( 0xFFD8 ); // SOI stream << quint16(0xFFD8); // SOI
stream << quint16( 0xFFE0 ); // APP0 stream << quint16(0xFFE0); // APP0
stream << quint16( jfif.size() + 2 ); stream << quint16(jfif.size() + 2);
device->write( jfif ); device->write(jfif);
stream << quint16( 0xFFE1 ); //APP1 stream << quint16(0xFFE1); // APP1
stream << quint16( exif.size() + 2 ); stream << quint16(exif.size() + 2);
device->write( exif ); device->write(exif);
device->write( remainder ); device->write(remainder);
} } else {
else QByteArray remainder = device->readAll();
{
QByteArray remainder = device->readAll(); device->seek(0);
device->seek( 0 ); stream << quint16(0xFFD8); // SOI
stream << quint16(0xFFE0); // APP0
stream << quint16( 0xFFD8 ); // SOI stream << quint16(jfif.size() + 2);
stream << quint16( 0xFFE0 ); // APP0 device->write(jfif);
stream << quint16( jfif.size() + 2 ); stream << quint16(0xFFE1); // APP1
device->write( jfif ); stream << quint16(exif.size() + 2);
stream << quint16( 0xFFE1 ); //APP1 device->write(exif);
stream << quint16( exif.size() + 2 ); stream << quint16(0xFFE0); // APP0
device->write( exif ); stream << segmentId;
stream << quint16( 0xFFE0 ); // APP0 stream << segmentLength;
stream << segmentId; device->write(remainder);
stream << segmentLength;
device->write( remainder );
}
} }
else if( segmentId == 0xFFE1 ) } else if (segmentId == 0xFFE1) {
{ QByteArray oldExif = device->read(segmentLength - 2);
QByteArray oldExif = device->read( segmentLength - 2 );
if( !oldExif.startsWith( "Exif" ) ) if (!oldExif.startsWith("Exif"))
return false; return false;
int dSize = oldExif.size() - exif.size(); int dSize = oldExif.size() - exif.size();
if( dSize > 0 ) if (dSize > 0)
exif += QByteArray( dSize, '\0' ); exif += QByteArray(dSize, '\0');
QByteArray remainder = device->readAll(); QByteArray remainder = device->readAll();
device->seek( 0 ); device->seek(0);
stream << quint16( 0xFFD8 ); // SOI stream << quint16(0xFFD8); // SOI
stream << quint16( 0xFFE1 ); //APP1 stream << quint16(0xFFE1); // APP1
stream << quint16( exif.size() + 2 ); stream << quint16(exif.size() + 2);
device->write( exif ); device->write(exif);
device->write( remainder ); device->write(remainder);
} } else {
else QByteArray remainder = device->readAll();
{
QByteArray remainder = device->readAll(); device->seek(0);
device->seek( 0 );
stream << quint16( 0xFFD8 ); // SOI
stream << quint16( 0xFFE1 ); //APP1
stream << quint16( exif.size() + 2 );
device->write( exif );
stream << segmentId;
stream << segmentLength;
device->write( remainder );
}
return true; stream << quint16(0xFFD8); // SOI
stream << quint16(0xFFE1); // APP1
stream << quint16(exif.size() + 2);
device->write(exif);
stream << segmentId;
stream << segmentLength;
device->write(remainder);
}
return true;
} }
/*! /*!
Returns the byte order of EXIF file. Returns the byte order of EXIF file.
*/ */
QSysInfo::Endian QExifImageHeader::byteOrder() const QSysInfo::Endian QExifImageHeader::byteOrder () const {
{ return d->byteOrder;
return d->byteOrder;
} }
quint32 QExifImageHeader::sizeOf (const QExifValue &value) const {
quint32 QExifImageHeader::sizeOf(const QExifValue &value) const switch (value.type()) {
{
switch (value.type()) {
case QExifValue::Byte: case QExifValue::Byte:
case QExifValue::Undefined: case QExifValue::Undefined:
return value.count() > 4 return value.count() > 4
? 12 + value.count() ? 12 + value.count()
: 12; : 12;
case QExifValue::Ascii: case QExifValue::Ascii:
return value.count() > 4 return value.count() > 4
? 12 + value.count() ? 12 + value.count()
: 12; : 12;
case QExifValue::Short: case QExifValue::Short:
return value.count() > 2 return value.count() > 2
? 12 + value.count() * sizeof(quint16) ? 12 + value.count() * sizeof(quint16)
: 12; : 12;
case QExifValue::Long: case QExifValue::Long:
case QExifValue::SignedLong: case QExifValue::SignedLong:
return value.count() > 1 return value.count() > 1
? 12 + value.count() * sizeof(quint32) ? 12 + value.count() * sizeof(quint32)
: 12; : 12;
case QExifValue::Rational: case QExifValue::Rational:
case QExifValue::SignedRational: case QExifValue::SignedRational:
return value.count() > 0 return value.count() > 0
? 12 + value.count() * sizeof(quint32) * 2 ? 12 + value.count() * sizeof(quint32) * 2
: 12; : 12;
default: default:
return 0; return 0;
} }
} }
template <typename T> template<typename T>
quint32 QExifImageHeader::calculateSize(const QMap<T, QExifValue> &values) const quint32 QExifImageHeader::calculateSize (const QMap<T, QExifValue> &values) const {
{ quint32 size = sizeof(quint16);
quint32 size = sizeof(quint16);
foreach (const QExifValue &value, values) foreach(const QExifValue &value, values)
size += sizeOf(value); size += sizeOf(value);
return size; return size;
} }
/*! /*!
Returns the size of EXIF data in bytes. Returns the size of EXIF data in bytes.
*/ */
qint64 QExifImageHeader::size() const qint64 QExifImageHeader::size () const {
{ if (d->size == -1) {
if (d->size == -1) { d->size = 2 + // Byte Order
d->size 2 + // Marker
= 2 // Byte Order 4 + // Image Ifd offset
+ 2 // Marker 12 + // ExifIfdPointer Ifd
+ 4 // Image Ifd offset 4 + // Thumbnail Ifd offset
+ 12 // ExifIfdPointer Ifd calculateSize(d->imageIfdValues) + // Image headers and values.
+ 4 // Thumbnail Ifd offset calculateSize(d->exifIfdValues); // Exif headers and values.
+ calculateSize(d->imageIfdValues) // Image headers and values.
+ calculateSize(d->exifIfdValues); // Exif headers and values.
if (!d->gpsIfdValues.isEmpty()) {
d->size
+= 12 // GpsInfoIfdPointer Ifd
+ calculateSize(d->gpsIfdValues); // Gps headers and values.
}
if (!d->thumbnailData.isEmpty()) { if (!d->gpsIfdValues.isEmpty()) {
d->size d->size += 12 + // GpsInfoIfdPointer Ifd
+= 2 // Thumbnail Ifd count calculateSize(d->gpsIfdValues); // Gps headers and values.
+ 12 // Compression Ifd
+ 20 // XResolution Ifd
+ 20 // YResolution Ifd
+ 12 // ResolutionUnit Ifd
+ 12 // JpegInterchangeFormat Ifd
+ 12 // JpegInterchangeFormatLength Ifd
+ d->thumbnailData.size(); // Thumbnail data size.
}
} }
return d->size; if (!d->thumbnailData.isEmpty()) {
d->size += 2 + // Thumbnail Ifd count
12 + // Compression Ifd
20 + // XResolution Ifd
20 + // YResolution Ifd
12 + // ResolutionUnit Ifd
12 + // JpegInterchangeFormat Ifd
12 + // JpegInterchangeFormatLength Ifd
d->thumbnailData.size(); // Thumbnail data size.
}
}
return d->size;
} }
/*! /*!
Clears all image meta-data. Clears all image meta-data.
*/ */
void QExifImageHeader::clear() void QExifImageHeader::clear () {
{ d->imageIfdValues.clear();
d->imageIfdValues.clear(); d->exifIfdValues.clear();
d->exifIfdValues.clear(); d->gpsIfdValues.clear();
d->gpsIfdValues.clear(); d->thumbnailData.clear();
d->thumbnailData.clear();
d->size = -1;
d->size = -1;
} }
/*! /*!
Returns a list of all image tags in an EXIF header. Returns a list of all image tags in an EXIF header.
*/ */
QList<QExifImageHeader::ImageTag> QExifImageHeader::imageTags() const QList<QExifImageHeader::ImageTag> QExifImageHeader::imageTags () const {
{ return d->imageIfdValues.keys();
return d->imageIfdValues.keys();
} }
/*! /*!
Returns a list of all extended EXIF tags in a header. Returns a list of all extended EXIF tags in a header.
*/ */
QList<QExifImageHeader::ExifExtendedTag> QExifImageHeader::extendedTags() const QList<QExifImageHeader::ExifExtendedTag> QExifImageHeader::extendedTags () const {
{ return d->exifIfdValues.keys();
return d->exifIfdValues.keys();
} }
/*! /*!
Returns a list of all GPS tags in an EXIF header. Returns a list of all GPS tags in an EXIF header.
*/ */
QList<QExifImageHeader::GpsTag> QExifImageHeader::gpsTags() const QList<QExifImageHeader::GpsTag> QExifImageHeader::gpsTags () const {
{ return d->gpsIfdValues.keys();
return d->gpsIfdValues.keys();
} }
/*! /*!
Returns true if an EXIf header contains a value for an image \a tag and false otherwise. Returns true if an EXIf header contains a value for an image \a tag and false otherwise.
*/ */
bool QExifImageHeader::contains(ImageTag tag) const bool QExifImageHeader::contains (ImageTag tag) const {
{ return d->imageIfdValues.contains(tag);
return d->imageIfdValues.contains(tag);
} }
/*! /*!
Returns true if a header contains a a value for an extended EXIF \a tag and false otherwise. Returns true if a header contains a a value for an extended EXIF \a tag and false otherwise.
*/ */
bool QExifImageHeader::contains(ExifExtendedTag tag) const bool QExifImageHeader::contains (ExifExtendedTag tag) const {
{ return d->exifIfdValues.contains(tag);
return d->exifIfdValues.contains(tag);
} }
/*! /*!
Returns true if an EXIf header contains a value for a GPS \a tag and false otherwise. Returns true if an EXIf header contains a value for a GPS \a tag and false otherwise.
*/ */
bool QExifImageHeader::contains(GpsTag tag) const bool QExifImageHeader::contains (GpsTag tag) const {
{ return d->gpsIfdValues.contains(tag);
return d->gpsIfdValues.contains(tag);
} }
/*! /*!
Removes the value for an image \a tag. Removes the value for an image \a tag.
*/ */
void QExifImageHeader::remove(ImageTag tag) void QExifImageHeader::remove (ImageTag tag) {
{ d->imageIfdValues.remove(tag);
d->imageIfdValues.remove(tag);
d->size = -1; d->size = -1;
} }
/*! /*!
Removes the value for an extended EXIF \a tag. Removes the value for an extended EXIF \a tag.
*/ */
void QExifImageHeader::remove(ExifExtendedTag tag) void QExifImageHeader::remove (ExifExtendedTag tag) {
{ d->exifIfdValues.remove(tag);
d->exifIfdValues.remove(tag);
d->size = -1; d->size = -1;
} }
/*! /*!
Removes the value for a GPS \a tag. Removes the value for a GPS \a tag.
*/ */
void QExifImageHeader::remove(GpsTag tag) void QExifImageHeader::remove (GpsTag tag) {
{ d->gpsIfdValues.remove(tag);
d->gpsIfdValues.remove(tag);
d->size = -1; d->size = -1;
} }
/*! /*!
Returns the value for an image \a tag. Returns the value for an image \a tag.
*/ */
QExifValue QExifImageHeader::value(ImageTag tag) const QExifValue QExifImageHeader::value (ImageTag tag) const {
{ return d->imageIfdValues.value(tag);
return d->imageIfdValues.value(tag);
} }
/*! /*!
Returns the value for an extended EXIF \a tag. Returns the value for an extended EXIF \a tag.
*/ */
QExifValue QExifImageHeader::value(ExifExtendedTag tag) const QExifValue QExifImageHeader::value (ExifExtendedTag tag) const {
{ return d->exifIfdValues.value(tag);
return d->exifIfdValues.value(tag);
} }
/*! /*!
Returns the value for a GPS tag. Returns the value for a GPS tag.
*/ */
QExifValue QExifImageHeader::value(GpsTag tag) const QExifValue QExifImageHeader::value (GpsTag tag) const {
{ return d->gpsIfdValues.value(tag);
return d->gpsIfdValues.value(tag);
} }
/*! /*!
Sets the \a value for an image \a tag. Sets the \a value for an image \a tag.
*/ */
void QExifImageHeader::setValue(ImageTag tag, const QExifValue &value) void QExifImageHeader::setValue (ImageTag tag, const QExifValue &value) {
{ d->imageIfdValues[tag] = value;
d->imageIfdValues[tag] = value;
d->size = -1; d->size = -1;
} }
/*! /*!
Sets the \a value for an extended EXIF \a tag. Sets the \a value for an extended EXIF \a tag.
*/ */
void QExifImageHeader::setValue(ExifExtendedTag tag, const QExifValue &value) void QExifImageHeader::setValue (ExifExtendedTag tag, const QExifValue &value) {
{ d->exifIfdValues[tag] = value;
d->exifIfdValues[tag] = value;
d->size = -1; d->size = -1;
} }
/*! /*!
Sets the \a value for an GPS \a tag. Sets the \a value for an GPS \a tag.
*/ */
void QExifImageHeader::setValue(GpsTag tag, const QExifValue &value) void QExifImageHeader::setValue (GpsTag tag, const QExifValue &value) {
{ d->gpsIfdValues[tag] = value;
d->gpsIfdValues[tag] = value;
d->size = -1; d->size = -1;
} }
/*! /*!
Returns the image thumbnail. Returns the image thumbnail.
*/ */
QImage QExifImageHeader::thumbnail() const QImage QExifImageHeader::thumbnail () const {
{ QImage image;
QImage image;
image.loadFromData(d->thumbnailData, "JPG");
image.loadFromData(d->thumbnailData, "JPG");
if (!d->thumbnailOrientation.isNull()) {
if (!d->thumbnailOrientation.isNull()) { switch (d->thumbnailOrientation.toShort()) {
switch (d->thumbnailOrientation.toShort()) { case 1:
case 1: return image;
return image; case 2:
case 2: return image.transformed(QTransform().rotate(180, Qt::YAxis));
return image.transformed(QTransform().rotate(180, Qt::YAxis)); case 3:
case 3: return image.transformed(QTransform().rotate(180, Qt::ZAxis));
return image.transformed(QTransform().rotate(180, Qt::ZAxis)); case 4:
case 4: return image.transformed(QTransform().rotate(180, Qt::XAxis));
return image.transformed(QTransform().rotate(180, Qt::XAxis)); case 5:
case 5: return image.transformed(QTransform().rotate(180, Qt::YAxis).rotate(90, Qt::ZAxis));
return image.transformed(QTransform().rotate(180, Qt::YAxis).rotate(90, Qt::ZAxis)); case 6:
case 6: return image.transformed(QTransform().rotate(90, Qt::ZAxis));
return image.transformed(QTransform().rotate(90, Qt::ZAxis)); case 7:
case 7: return image.transformed(QTransform().rotate(180, Qt::XAxis).rotate(90, Qt::ZAxis));
return image.transformed(QTransform().rotate(180, Qt::XAxis).rotate(90, Qt::ZAxis)); case 8:
case 8: return image.transformed(QTransform().rotate(270, Qt::ZAxis));
return image.transformed(QTransform().rotate(270, Qt::ZAxis));
}
} }
}
return image; return image;
} }
/*! /*!
Sets the image \a thumbnail. Sets the image \a thumbnail.
*/ */
void QExifImageHeader::setThumbnail( const QImage &thumbnail ) void QExifImageHeader::setThumbnail (const QImage &thumbnail) {
{ if (!thumbnail.isNull()) {
if (!thumbnail.isNull()) { QBuffer buffer;
QBuffer buffer;
if (buffer.open(QIODevice::WriteOnly) && thumbnail.save(&buffer, "JPG")) {
if (buffer.open(QIODevice::WriteOnly) && thumbnail.save(&buffer, "JPG")) { buffer.close();
buffer.close();
d->thumbnailSize = thumbnail.size();
d->thumbnailSize = thumbnail.size(); d->thumbnailData = buffer.data();
d->thumbnailData = buffer.data(); d->thumbnailOrientation = QExifValue();
d->thumbnailOrientation = QExifValue();
}
} else {
d->thumbnailSize = QSize();
d->thumbnailData = QByteArray();
} }
} else {
d->thumbnailSize = QSize();
d->thumbnailData = QByteArray();
}
d->size = -1; d->size = -1;
} }
QByteArray QExifImageHeader::extractExif( QIODevice *device ) const QByteArray QExifImageHeader::extractExif (QIODevice *device) const {
{ QDataStream stream(device);
QDataStream stream( device );
stream.setByteOrder( QDataStream::BigEndian ); stream.setByteOrder(QDataStream::BigEndian);
if( device->read( 2 ) != "\xFF\xD8" ) if (device->read(2) != "\xFF\xD8")
return QByteArray(); return QByteArray();
while( device->read( 2 ) != "\xFF\xE1" ) while (device->read(2) != "\xFF\xE1") {
{ if (device->atEnd())
if( device->atEnd() ) return QByteArray();
return QByteArray();
quint16 length; quint16 length;
stream >> length; stream >> length;
device->seek( device->pos() + length - 2 ); device->seek(device->pos() + length - 2);
} }
quint16 length; quint16 length;
stream >> length; stream >> length;
if( device->read( 4 ) != "Exif" ) if (device->read(4) != "Exif")
return QByteArray(); return QByteArray();
device->read( 2 ); device->read(2);
return device->read( length - 8 ); return device->read(length - 8);
} }
QList<ExifIfdHeader> QExifImageHeader::readIfdHeaders (QDataStream &stream) const {
QList<ExifIfdHeader> headers;
QList<ExifIfdHeader> QExifImageHeader::readIfdHeaders(QDataStream &stream) const quint16 count;
{
QList<ExifIfdHeader> headers;
quint16 count; stream >> count;
stream >> count; for (quint16 i = 0; i < count; i++) {
ExifIfdHeader header;
for (quint16 i = 0; i < count; i++) { stream >> header;
ExifIfdHeader header;
stream >> header; headers.append(header);
}
headers.append(header); return headers;
}
return headers;
} }
QExifValue QExifImageHeader::readIfdValue(QDataStream &stream, int startPos, const ExifIfdHeader &header) const QExifValue QExifImageHeader::readIfdValue (QDataStream &stream, int startPos, const ExifIfdHeader &header) const {
{ switch (header.type) {
switch (header.type) { case QExifValue::Byte: {
case QExifValue::Byte: QVector<quint8> value(header.count);
{
QVector<quint8> value( header.count );
if (header.count > 4) {
stream.device()->seek(startPos + header.offset);
for (quint32 i = 0; i < header.count; i++) if (header.count > 4) {
stream >> value[i]; stream.device()->seek(startPos + header.offset);
} else {
for( quint32 i = 0; i < header.count; i++ )
value[ i ] = header.offsetBytes[ i ];
} for (quint32 i = 0; i < header.count; i++)
return QExifValue(value); stream >> value[i];
} } else {
for (quint32 i = 0; i < header.count; i++)
value[i] = header.offsetBytes[i];
}
return QExifValue(value);
}
case QExifValue::Undefined: case QExifValue::Undefined:
if (header.count > 4) { if (header.count > 4) {
stream.device()->seek(startPos + header.offset); stream.device()->seek(startPos + header.offset);
return QExifValue(stream.device()->read(header.count)); return QExifValue(stream.device()->read(header.count));
} else { } else {
return QExifValue(QByteArray::fromRawData(header.offsetAscii, header.count)); return QExifValue(QByteArray::fromRawData(header.offsetAscii, header.count));
} }
case QExifValue::Ascii: case QExifValue::Ascii:
if (header.count > 4) { if (header.count > 4) {
stream.device()->seek(startPos + header.offset); stream.device()->seek(startPos + header.offset);
QByteArray ascii = stream.device()->read(header.count); QByteArray ascii = stream.device()->read(header.count);
return QExifValue(QString::fromUtf8(ascii.constData(), ascii.size() - 1)); return QExifValue(QString::fromUtf8(ascii.constData(), ascii.size() - 1));
} else { } else {
return QExifValue(QString::fromUtf8(header.offsetAscii, header.count - 1)); return QExifValue(QString::fromUtf8(header.offsetAscii, header.count - 1));
} }
case QExifValue::Short: case QExifValue::Short: {
{ QVector<quint16> value(header.count);
QVector<quint16> value(header.count);
if (header.count > 2) {
if (header.count > 2) { stream.device()->seek(startPos + header.offset);
stream.device()->seek(startPos + header.offset);
for (quint32 i = 0; i < header.count; i++)
for (quint32 i = 0; i < header.count; i++) stream >> value[i];
stream >> value[i]; } else {
} else { for (quint32 i = 0; i < header.count; i++)
for (quint32 i = 0; i < header.count; i++) value[i] = header.offsetShorts[i];
value[i] = header.offsetShorts[i]; }
return QExifValue(value);
} }
return QExifValue(value); case QExifValue::Long: {
} QVector<quint32> value(header.count);
case QExifValue::Long:
{ if (header.count > 1) {
QVector<quint32> value(header.count); stream.device()->seek(startPos + header.offset);
if (header.count > 1) { for (quint32 i = 0; i < header.count; i++)
stream.device()->seek(startPos + header.offset); stream >> value[i];
} else if (header.count == 1) {
for (quint32 i = 0; i < header.count; i++) value[0] = header.offset;
stream >> value[i]; }
} else if(header.count == 1) { return QExifValue(value);
value[0] = header.offset; }
} case QExifValue::SignedLong: {
return QExifValue(value); QVector<qint32> value(header.count);
}
case QExifValue::SignedLong: if (header.count > 1) {
{ stream.device()->seek(startPos + header.offset);
QVector<qint32> value(header.count);
for (quint32 i = 0; i < header.count; i++)
if (header.count > 1) { stream >> value[i];
stream.device()->seek(startPos + header.offset); } else if (header.count == 1) {
value[0] = header.offset;
for (quint32 i = 0; i < header.count; i++) }
stream >> value[i]; return QExifValue(value);
} else if (header.count == 1) { }
value[0] = header.offset; break;
} case QExifValue::Rational: {
return QExifValue(value); QVector<QExifURational> value(header.count);
}
break;
case QExifValue::Rational:
{
QVector<QExifURational> value(header.count);
stream.device()->seek(startPos + header.offset); stream.device()->seek(startPos + header.offset);
for (quint32 i = 0; i < header.count; i++) for (quint32 i = 0; i < header.count; i++)
stream >> value[i]; stream >> value[i];
return QExifValue(value); return QExifValue(value);
} }
case QExifValue::SignedRational: case QExifValue::SignedRational: {
{ QVector<QExifSRational> value(header.count);
QVector<QExifSRational> value(header.count);
stream.device()->seek(startPos + header.offset); stream.device()->seek(startPos + header.offset);
for(quint32 i = 0; i < header.count; i++) for (quint32 i = 0; i < header.count; i++)
stream >> value[i]; stream >> value[i];
return QExifValue(value); return QExifValue(value);
} }
default: default:
qWarning() << "Invalid Ifd Type" << header.type; qWarning() << "Invalid Ifd Type" << header.type;
return QExifValue(); return QExifValue();
} }
} }
template <typename T> QMap<T, QExifValue> QExifImageHeader::readIfdValues( template<typename T>
QDataStream &stream, int startPos, const QList<ExifIfdHeader> &headers) const QMap<T, QExifValue> QExifImageHeader::readIfdValues (
{ QDataStream &stream,
QMap<T, QExifValue> values; int startPos,
const QList<ExifIfdHeader> &headers
) const {
QMap<T, QExifValue> values;
// This needs to be non-const so it works with gcc3 // This needs to be non-const so it works with gcc3
QList<ExifIfdHeader> headers_ = headers; QList<ExifIfdHeader> headers_ = headers;
foreach (const ExifIfdHeader &header, headers_) foreach(const ExifIfdHeader &header, headers_)
values[T(header.tag)] = readIfdValue(stream, startPos, header); values[T(header.tag)] = readIfdValue(stream, startPos, header);
return values; return values;
} }
template <typename T> template<typename T>
QMap<T, QExifValue> QExifImageHeader::readIfdValues( QMap<T, QExifValue> QExifImageHeader::readIfdValues (
QDataStream &stream, int startPos, const QExifValue &pointer) const QDataStream &stream,
{ int startPos,
if (pointer.type() == QExifValue::Long && pointer.count() == 1) { const QExifValue &pointer
stream.device()->seek(startPos + pointer.toLong()); ) const {
if (pointer.type() == QExifValue::Long && pointer.count() == 1) {
stream.device()->seek(startPos + pointer.toLong());
QList<ExifIfdHeader> headers = readIfdHeaders(stream); QList<ExifIfdHeader> headers = readIfdHeaders(stream);
return readIfdValues<T>(stream, startPos, headers); return readIfdValues<T>(stream, startPos, headers);
} else { } else {
return QMap<T, QExifValue >(); return QMap<T, QExifValue>();
} }
} }
/*! /*!
Reads the contents of an EXIF header from an I/O \a device. Reads the contents of an EXIF header from an I/O \a device.
Returns true if the header was read and false otherwise. Returns true if the header was read and false otherwise.
\sa loadFromJpeg(), write() \sa loadFromJpeg(), write()
*/ */
bool QExifImageHeader::read(QIODevice *device) bool QExifImageHeader::read (QIODevice *device) {
{ clear();
clear();
int startPos = device->pos(); int startPos = device->pos();
QDataStream stream(device); QDataStream stream(device);
QByteArray byteOrder = device->read(2); QByteArray byteOrder = device->read(2);
if (byteOrder == "II") { if (byteOrder == "II") {
d->byteOrder = QSysInfo::LittleEndian; d->byteOrder = QSysInfo::LittleEndian;
stream.setByteOrder( QDataStream::LittleEndian ); stream.setByteOrder(QDataStream::LittleEndian);
} else if (byteOrder == "MM") { } else if (byteOrder == "MM") {
d->byteOrder = QSysInfo::BigEndian; d->byteOrder = QSysInfo::BigEndian;
stream.setByteOrder( QDataStream::BigEndian ); stream.setByteOrder(QDataStream::BigEndian);
} else { } else {
return false; return false;
} }
quint16 id; quint16 id;
quint32 offset; quint32 offset;
stream >> id; stream >> id;
stream >> offset; stream >> offset;
if (id != 0x002A) if (id != 0x002A)
return false; return false;
device->seek(startPos + offset); device->seek(startPos + offset);
QList<ExifIfdHeader> headers = readIfdHeaders(stream); QList<ExifIfdHeader> headers = readIfdHeaders(stream);
stream >> offset; stream >> offset;
d->imageIfdValues = readIfdValues<ImageTag>(stream, startPos, headers); d->imageIfdValues = readIfdValues<ImageTag>(stream, startPos, headers);
QExifValue exifIfdPointer = d->imageIfdValues.take(ImageTag(ExifIfdPointer)); QExifValue exifIfdPointer = d->imageIfdValues.take(ImageTag(ExifIfdPointer));
QExifValue gpsIfdPointer = d->imageIfdValues.take(ImageTag(GpsInfoIfdPointer)); QExifValue gpsIfdPointer = d->imageIfdValues.take(ImageTag(GpsInfoIfdPointer));
d->exifIfdValues = readIfdValues<ExifExtendedTag>(stream, startPos, exifIfdPointer); d->exifIfdValues = readIfdValues<ExifExtendedTag>(stream, startPos, exifIfdPointer);
d->gpsIfdValues = readIfdValues<GpsTag>(stream, startPos, gpsIfdPointer); d->gpsIfdValues = readIfdValues<GpsTag>(stream, startPos, gpsIfdPointer);
d->exifIfdValues.remove(ExifExtendedTag(InteroperabilityIfdPointer)); d->exifIfdValues.remove(ExifExtendedTag(InteroperabilityIfdPointer));
if (offset) { if (offset) {
device->seek(startPos + offset); device->seek(startPos + offset);
QMap<quint16, QExifValue> thumbnailIfdValues = readIfdValues<quint16>( QMap<quint16, QExifValue> thumbnailIfdValues = readIfdValues<quint16>(
stream, startPos, readIfdHeaders( stream)); stream, startPos, readIfdHeaders(stream));
QExifValue jpegOffset = thumbnailIfdValues.value(JpegInterchangeFormat); QExifValue jpegOffset = thumbnailIfdValues.value(JpegInterchangeFormat);
QExifValue jpegLength = thumbnailIfdValues.value(JpegInterchangeFormatLength); QExifValue jpegLength = thumbnailIfdValues.value(JpegInterchangeFormatLength);
if (jpegOffset.type() == QExifValue::Long && jpegOffset.count() == 1 if (jpegOffset.type() == QExifValue::Long && jpegOffset.count() == 1 &&
&& jpegLength.type() == QExifValue::Long && jpegLength.count() == 1) jpegLength.type() == QExifValue::Long && jpegLength.count() == 1) {
{ device->seek(startPos + jpegOffset.toLong());
device->seek(startPos + jpegOffset.toLong());
d->thumbnailData = device->read( jpegLength.toLong() ); d->thumbnailData = device->read(jpegLength.toLong());
d->thumbnailXResolution = thumbnailIfdValues.value(XResolution); d->thumbnailXResolution = thumbnailIfdValues.value(XResolution);
d->thumbnailYResolution = thumbnailIfdValues.value(YResolution); d->thumbnailYResolution = thumbnailIfdValues.value(YResolution);
d->thumbnailResolutionUnit = thumbnailIfdValues.value(ResolutionUnit); d->thumbnailResolutionUnit = thumbnailIfdValues.value(ResolutionUnit);
d->thumbnailOrientation = thumbnailIfdValues.value(Orientation); d->thumbnailOrientation = thumbnailIfdValues.value(Orientation);
}
} }
return true; }
return true;
} }
quint32 QExifImageHeader::writeExifHeader(QDataStream &stream, quint16 tag, const QExifValue &value, quint32 offset) const quint32 QExifImageHeader::writeExifHeader (QDataStream &stream, quint16 tag, const QExifValue &value, quint32 offset) const {
{ stream << tag;
stream << tag; stream << quint16(value.type());
stream << quint16(value.type()); stream << quint32(value.count());
stream << quint32(value.count());
switch (value.type()) { switch (value.type()) {
case QExifValue::Byte: case QExifValue::Byte:
if (value.count() <= 4) { if (value.count() <= 4) {
foreach (quint8 byte, value.toByteVector()) foreach(quint8 byte, value.toByteVector())
stream << byte; stream << byte;
for (int j = value.count(); j < 4; j++) for (int j = value.count(); j < 4; j++)
stream << quint8(0); stream << quint8(0);
} else { } else {
stream << offset; stream << offset;
offset += value.count(); offset += value.count();
} }
break; break;
case QExifValue::Undefined: case QExifValue::Undefined:
if (value.count() <= 4) { if (value.count() <= 4) {
stream.device()->write(value.toByteArray()); stream.device()->write(value.toByteArray());
if ( value.count() < 4) if (value.count() < 4)
stream.writeRawData("\0\0\0\0", 4 - value.count()); stream.writeRawData("\0\0\0\0", 4 - value.count());
} else { } else {
stream << offset; stream << offset;
offset += value.count(); offset += value.count();
} }
break; break;
case QExifValue::Ascii: case QExifValue::Ascii:
if (value.count() <= 4) { if (value.count() <= 4) {
QByteArray bytes = value.toByteArray(); QByteArray bytes = value.toByteArray();
stream.writeRawData(bytes.constData(), value.count()); stream.writeRawData(bytes.constData(), value.count());
if (value.count() < 4) if (value.count() < 4)
stream.writeRawData("\0\0\0\0", 4 - value.count()); stream.writeRawData("\0\0\0\0", 4 - value.count());
} else { } else {
stream << offset; stream << offset;
offset += value.count(); offset += value.count();
} }
break; break;
case QExifValue::Short: case QExifValue::Short:
if (value.count() <= 2) { if (value.count() <= 2) {
foreach (quint16 shrt, value.toShortVector()) foreach(quint16 shrt, value.toShortVector())
stream << shrt; stream << shrt;
for (int j = value.count(); j < 2; j++) for (int j = value.count(); j < 2; j++)
stream << quint16(0); stream << quint16(0);
} else { } else {
stream << offset; stream << offset;
offset += value.count() * sizeof(quint16); offset += value.count() * sizeof(quint16);
} }
break; break;
case QExifValue::Long: case QExifValue::Long:
if(value.count() == 0) { if (value.count() == 0) {
stream << quint32(0); stream << quint32(0);
} else if(value.count() == 1) { } else if (value.count() == 1) {
stream << value.toLong(); stream << value.toLong();
} else { } else {
stream << offset; stream << offset;
offset += value.count() * sizeof(quint32); offset += value.count() * sizeof(quint32);
} }
break; break;
case QExifValue::SignedLong: case QExifValue::SignedLong:
if (value.count() == 0) { if (value.count() == 0) {
stream << quint32( 0 ); stream << quint32(0);
} else if (value.count() == 1) { } else if (value.count() == 1) {
stream << value.toSignedLong(); stream << value.toSignedLong();
} else { } else {
stream << offset; stream << offset;
offset += value.count() * sizeof(qint32); offset += value.count() * sizeof(qint32);
} }
break; break;
case QExifValue::Rational: case QExifValue::Rational:
if(value.count() == 0) { if (value.count() == 0) {
stream << quint32(0); stream << quint32(0);
} else { } else {
stream << offset; stream << offset;
offset += value.count() * sizeof(quint32) * 2; offset += value.count() * sizeof(quint32) * 2;
} }
break; break;
case QExifValue::SignedRational: case QExifValue::SignedRational:
if (value.count() == 0) { if (value.count() == 0) {
stream << quint32(0); stream << quint32(0);
} else { } else {
stream << offset; stream << offset;
offset += value.count() * sizeof(qint32) * 2; offset += value.count() * sizeof(qint32) * 2;
} }
break; break;
default: default:
qWarning() << "Invalid Ifd Type" << value.type(); qWarning() << "Invalid Ifd Type" << value.type();
stream << quint32(0); stream << quint32(0);
} }
return offset; return offset;
} }
void QExifImageHeader::writeExifValue(QDataStream &stream, const QExifValue &value) const void QExifImageHeader::writeExifValue (QDataStream &stream, const QExifValue &value) const {
{ switch (value.type()) {
switch (value.type()) {
case QExifValue::Byte: case QExifValue::Byte:
if (value.count() > 4) if (value.count() > 4)
foreach (quint8 byte, value.toByteVector()) foreach(quint8 byte, value.toByteVector())
stream << byte; stream << byte;
break; break;
case QExifValue::Undefined: case QExifValue::Undefined:
if (value.count() > 4) if (value.count() > 4)
stream.device()->write(value.toByteArray()); stream.device()->write(value.toByteArray());
break; break;
case QExifValue::Ascii: case QExifValue::Ascii:
if (value.count() > 4) { if (value.count() > 4) {
QByteArray bytes = value.toByteArray(); QByteArray bytes = value.toByteArray();
stream.writeRawData(bytes.constData(), bytes.size() + 1); stream.writeRawData(bytes.constData(), bytes.size() + 1);
} }
break; break;
case QExifValue::Short: case QExifValue::Short:
if (value.count() > 2) if (value.count() > 2)
foreach(quint16 shrt, value.toShortVector()) foreach(quint16 shrt, value.toShortVector())
stream << shrt; stream << shrt;
break; break;
case QExifValue::Long: case QExifValue::Long:
if(value.count() > 1) if (value.count() > 1)
foreach (quint32 lng, value.toLongVector()) foreach(quint32 lng, value.toLongVector())
stream << lng; stream << lng;
break; break;
case QExifValue::SignedLong: case QExifValue::SignedLong:
if (value.count() > 1) if (value.count() > 1)
foreach(qint32 lng, value.toSignedLongVector()) foreach(qint32 lng, value.toSignedLongVector())
stream << lng; stream << lng;
break; break;
case QExifValue::Rational: case QExifValue::Rational:
if (value.count() > 0) if (value.count() > 0)
foreach (QExifURational rational, value.toRationalVector()) foreach(QExifURational rational, value.toRationalVector())
stream << rational; stream << rational;
break; break;
case QExifValue::SignedRational: case QExifValue::SignedRational:
if (value.count() > 0) if (value.count() > 0)
foreach (QExifSRational rational, value.toSignedRationalVector()) foreach(QExifSRational rational, value.toSignedRationalVector())
stream << rational; stream << rational;
break; break;
default: default:
qWarning() << "Invalid Ifd Type" << value.type(); qWarning() << "Invalid Ifd Type" << value.type();
break; break;
} }
} }
template <typename T> quint32 QExifImageHeader::writeExifHeaders( template<typename T>
QDataStream &stream, const QMap<T, QExifValue> &values, quint32 offset) const quint32 QExifImageHeader::writeExifHeaders (
{ QDataStream &stream,
offset += values.count() * 12; const QMap<T, QExifValue> &values,
quint32 offset
) const {
offset += values.count() * 12;
for (typename QMap<T, QExifValue>::const_iterator i = values.constBegin(); i != values.constEnd(); i++) for (typename QMap<T, QExifValue>::const_iterator i = values.constBegin(); i != values.constEnd(); i++)
offset = writeExifHeader(stream, i.key(), i.value(), offset); offset = writeExifHeader(stream, i.key(), i.value(), offset);
return offset; return offset;
} }
template <typename T> void QExifImageHeader::writeExifValues( template<typename T>
QDataStream &stream, const QMap<T, QExifValue> &values) const void QExifImageHeader::writeExifValues (
{ QDataStream &stream,
for (typename QMap<T, QExifValue>::const_iterator i = values.constBegin(); i != values.constEnd(); i++) const QMap<T, QExifValue> &values
writeExifValue(stream, i.value()); ) const {
for (typename QMap<T, QExifValue>::const_iterator i = values.constBegin(); i != values.constEnd(); i++)
writeExifValue(stream, i.value());
} }
/*! /*!
Writes an EXIF header to an I/O \a device. Writes an EXIF header to an I/O \a device.
Returns the total number of bytes written. Returns the total number of bytes written.
*/ */
qint64 QExifImageHeader::write(QIODevice *device) const qint64 QExifImageHeader::write (QIODevice *device) const {
{ // #ifndef QT_NO_DEBUG
//#ifndef QT_NO_DEBUG qint64 startPos = device->pos();
qint64 startPos = device->pos(); // #endif
//#endif
QDataStream stream( device );
if (d->byteOrder == QSysInfo::LittleEndian) {
stream.setByteOrder( QDataStream::LittleEndian );
device->write("II", 2);
device->write("\x2A\x00", 2);
device->write("\x08\x00\x00\x00", 4);
} else if (d->byteOrder == QSysInfo::BigEndian) {
stream.setByteOrder(QDataStream::BigEndian);
device->write("MM", 2);
device->write("\x00\x2A", 2);
device->write("\x00\x00\x00\x08", 4);
}
quint16 count = d->imageIfdValues.count() + 1; QDataStream stream(device);
quint32 offset = 26;
if (!d->gpsIfdValues.isEmpty()) { if (d->byteOrder == QSysInfo::LittleEndian) {
count++; stream.setByteOrder(QDataStream::LittleEndian);
offset += 12;
}
stream << count; device->write("II", 2);
device->write("\x2A\x00", 2);
device->write("\x08\x00\x00\x00", 4);
} else if (d->byteOrder == QSysInfo::BigEndian) {
stream.setByteOrder(QDataStream::BigEndian);
offset = writeExifHeaders(stream, d->imageIfdValues, offset); device->write("MM", 2);
device->write("\x00\x2A", 2);
device->write("\x00\x00\x00\x08", 4);
}
quint32 exifIfdOffset = offset; quint16 count = d->imageIfdValues.count() + 1;
quint32 offset = 26;
stream << quint16( ExifIfdPointer ); if (!d->gpsIfdValues.isEmpty()) {
stream << quint16( QExifValue::Long ); count++;
stream << quint32( 1 ); offset += 12;
stream << exifIfdOffset; }
offset += calculateSize(d->exifIfdValues);
quint32 gpsIfdOffset = offset; stream << count;
if (!d->gpsIfdValues.isEmpty()) { offset = writeExifHeaders(stream, d->imageIfdValues, offset);
stream << quint16(GpsInfoIfdPointer);
stream << quint16(QExifValue::Long);
stream << quint32(1);
stream << gpsIfdOffset;
d->imageIfdValues.insert(ImageTag(GpsInfoIfdPointer), QExifValue(offset)); quint32 exifIfdOffset = offset;
offset += calculateSize(d->gpsIfdValues); stream << quint16(ExifIfdPointer);
} stream << quint16(QExifValue::Long);
stream << quint32(1);
stream << exifIfdOffset;
offset += calculateSize(d->exifIfdValues);
if (!d->thumbnailData.isEmpty()) quint32 gpsIfdOffset = offset;
stream << offset; // Write offset to thumbnail Ifd.
else
stream << quint32(0);
writeExifValues( stream, d->imageIfdValues ); if (!d->gpsIfdValues.isEmpty()) {
stream << quint16(GpsInfoIfdPointer);
stream << quint16(QExifValue::Long);
stream << quint32(1);
stream << gpsIfdOffset;
Q_ASSERT(startPos + exifIfdOffset == device->pos()); d->imageIfdValues.insert(ImageTag(GpsInfoIfdPointer), QExifValue(offset));
stream << quint16(d->exifIfdValues.count()); offset += calculateSize(d->gpsIfdValues);
}
writeExifHeaders(stream, d->exifIfdValues, exifIfdOffset); if (!d->thumbnailData.isEmpty())
writeExifValues(stream, d->exifIfdValues); stream << offset; // Write offset to thumbnail Ifd.
else
stream << quint32(0);
Q_ASSERT(startPos + gpsIfdOffset == device->pos()); writeExifValues(stream, d->imageIfdValues);
if (!d->gpsIfdValues.isEmpty()) { Q_ASSERT(startPos + exifIfdOffset == device->pos());
stream << quint16(d->gpsIfdValues.count());
writeExifHeaders(stream, d->gpsIfdValues, gpsIfdOffset); stream << quint16(d->exifIfdValues.count());
writeExifValues(stream, d->gpsIfdValues);
}
Q_ASSERT(startPos + offset == device->pos()); writeExifHeaders(stream, d->exifIfdValues, exifIfdOffset);
writeExifValues(stream, d->exifIfdValues);
if (!d->thumbnailData.isEmpty()) { Q_ASSERT(startPos + gpsIfdOffset == device->pos());
offset += 86;
stream << quint16(7); if (!d->gpsIfdValues.isEmpty()) {
stream << quint16(d->gpsIfdValues.count());
QExifValue xResolution = d->thumbnailXResolution.isNull() writeExifHeaders(stream, d->gpsIfdValues, gpsIfdOffset);
? QExifValue(QExifURational(72, 1)) writeExifValues(stream, d->gpsIfdValues);
: d->thumbnailXResolution; }
QExifValue yResolution = d->thumbnailYResolution.isNull() Q_ASSERT(startPos + offset == device->pos());
? QExifValue(QExifURational(72, 1))
: d->thumbnailYResolution;
QExifValue resolutionUnit = d->thumbnailResolutionUnit.isNull() if (!d->thumbnailData.isEmpty()) {
? QExifValue(quint16(2)) offset += 86;
: d->thumbnailResolutionUnit;
QExifValue orientation = d->thumbnailOrientation.isNull() stream << quint16(7);
? QExifValue(quint16(0))
: d->thumbnailOrientation;
writeExifHeader(stream, Compression, QExifValue(quint16(6)), offset); QExifValue xResolution = d->thumbnailXResolution.isNull()
? QExifValue(QExifURational(72, 1))
: d->thumbnailXResolution;
offset = writeExifHeader(stream, XResolution, xResolution, offset); QExifValue yResolution = d->thumbnailYResolution.isNull()
offset = writeExifHeader(stream, YResolution, yResolution, offset); ? QExifValue(QExifURational(72, 1))
: d->thumbnailYResolution;
writeExifHeader(stream, ResolutionUnit, resolutionUnit, offset); QExifValue resolutionUnit = d->thumbnailResolutionUnit.isNull()
writeExifHeader(stream, Orientation, orientation, offset); ? QExifValue(quint16(2))
writeExifHeader(stream, JpegInterchangeFormat, QExifValue(offset), offset); : d->thumbnailResolutionUnit;
writeExifHeader(stream, JpegInterchangeFormatLength,
QExifValue(quint32(d->thumbnailData.size())), offset);
writeExifValue(stream, xResolution); QExifValue orientation = d->thumbnailOrientation.isNull()
writeExifValue(stream, yResolution); ? QExifValue(quint16(0))
: d->thumbnailOrientation;
Q_ASSERT(startPos + offset == device->pos()); writeExifHeader(stream, Compression, QExifValue(quint16(6)), offset);
device->write(d->thumbnailData); offset = writeExifHeader(stream, XResolution, xResolution, offset);
offset = writeExifHeader(stream, YResolution, yResolution, offset);
offset += d->thumbnailData.size(); writeExifHeader(stream, ResolutionUnit, resolutionUnit, offset);
} writeExifHeader(stream, Orientation, orientation, offset);
writeExifHeader(stream, JpegInterchangeFormat, QExifValue(offset), offset);
writeExifHeader(stream, JpegInterchangeFormatLength,
QExifValue(quint32(d->thumbnailData.size())), offset);
writeExifValue(stream, xResolution);
writeExifValue(stream, yResolution);
Q_ASSERT(startPos + offset == device->pos()); Q_ASSERT(startPos + offset == device->pos());
d->size = offset; device->write(d->thumbnailData);
offset += d->thumbnailData.size();
}
Q_ASSERT(startPos + offset == device->pos());
d->size = offset;
return offset; return offset;
} }
...@@ -51,298 +51,286 @@ ...@@ -51,298 +51,286 @@
#include <QSysInfo> #include <QSysInfo>
#include <QIODevice> #include <QIODevice>
typedef QPair< quint32, quint32 > QExifURational; typedef QPair<quint32, quint32> QExifURational;
typedef QPair< qint32, qint32 > QExifSRational; typedef QPair<qint32, qint32> QExifSRational;
//Q_DECLARE_METATYPE(QExifURational)
//Q_DECLARE_METATYPE(QExifSRational)
class QExifValuePrivate; class QExifValuePrivate;
class QExifValue class QExifValue {
{
public: public:
enum Type enum Type {
{ Byte = 1,
Byte = 1, Ascii = 2,
Ascii = 2, Short = 3,
Short = 3, Long = 4,
Long = 4, Rational = 5,
Rational = 5, Undefined = 7,
Undefined = 7, SignedLong = 9,
SignedLong = 9, SignedRational = 10
SignedRational = 10 };
};
enum TextEncoding {
enum TextEncoding NoEncoding,
{ AsciiEncoding,
NoEncoding, JisEncoding,
AsciiEncoding, UnicodeEncoding,
JisEncoding, UndefinedEncoding
UnicodeEncoding, };
UndefinedEncoding
}; QExifValue ();
QExifValue (quint8 value);
QExifValue(); QExifValue (const QVector<quint8> &value);
QExifValue( quint8 value ); QExifValue (const QString &value, TextEncoding encoding = NoEncoding);
QExifValue( const QVector< quint8 > &value ); QExifValue (quint16 value);
QExifValue( const QString &value, TextEncoding encoding = NoEncoding ); QExifValue (const QVector<quint16> &value);
QExifValue( quint16 value ); QExifValue (quint32 value);
QExifValue( const QVector< quint16 > &value ); QExifValue (const QVector<quint32> &value);
QExifValue( quint32 value ); QExifValue (const QExifURational &value);
QExifValue( const QVector< quint32 > &value ); QExifValue (const QVector<QExifURational> &value);
QExifValue( const QExifURational &value ); QExifValue (const QByteArray &value);
QExifValue( const QVector< QExifURational > &value ); QExifValue (qint32 value);
QExifValue( const QByteArray &value ); QExifValue (const QVector<qint32> &value);
QExifValue( qint32 value ); QExifValue (const QExifSRational &value);
QExifValue( const QVector< qint32 > &value ); QExifValue (const QVector<QExifSRational> &value);
QExifValue( const QExifSRational &value ); QExifValue (const QDateTime &value);
QExifValue( const QVector< QExifSRational > &value ); QExifValue (const QExifValue &other);
QExifValue( const QDateTime &value ); QExifValue &operator= (const QExifValue &other);
QExifValue( const QExifValue &other ); ~QExifValue ();
QExifValue &operator =( const QExifValue &other );
~QExifValue(); bool operator== (const QExifValue &other) const;
bool operator ==( const QExifValue &other ) const; bool isNull () const;
bool isNull() const; int type () const;
int count () const;
int type() const;
int count() const; TextEncoding encoding () const;
TextEncoding encoding() const; quint8 toByte () const;
QVector<quint8> toByteVector () const;
quint8 toByte() const; QString toString () const;
QVector< quint8 > toByteVector() const; quint16 toShort () const;
QString toString() const; QVector<quint16> toShortVector () const;
quint16 toShort() const; quint32 toLong () const;
QVector< quint16 > toShortVector() const; QVector<quint32> toLongVector () const;
quint32 toLong() const; QExifURational toRational () const;
QVector< quint32 > toLongVector() const; QVector<QExifURational> toRationalVector () const;
QExifURational toRational() const; QByteArray toByteArray () const;
QVector< QExifURational > toRationalVector() const; qint32 toSignedLong () const;
QByteArray toByteArray() const; QVector<qint32> toSignedLongVector () const;
qint32 toSignedLong() const; QExifSRational toSignedRational () const;
QVector< qint32 > toSignedLongVector() const; QVector<QExifSRational> toSignedRationalVector () const;
QExifSRational toSignedRational() const; QDateTime toDateTime () const;
QVector< QExifSRational > toSignedRationalVector() const;
QDateTime toDateTime() const;
private: private:
QExplicitlySharedDataPointer< QExifValuePrivate > d; QExplicitlySharedDataPointer<QExifValuePrivate> d;
}; };
struct ExifIfdHeader; struct ExifIfdHeader;
class QExifImageHeaderPrivate; class QExifImageHeaderPrivate;
class QExifImageHeader class QExifImageHeader {
{ Q_DISABLE_COPY(QExifImageHeader)
Q_DISABLE_COPY(QExifImageHeader)
public: public:
enum ImageTag enum ImageTag {
{ ImageWidth = 0x0100,
ImageLength = 0x0101,
ImageWidth = 0x0100, BitsPerSample = 0x0102,
ImageLength = 0x0101, Compression = 0x0103,
BitsPerSample = 0x0102, PhotometricInterpretation = 0x0106,
Compression = 0x0103, Orientation = 0x0112,
PhotometricInterpretation = 0x0106, SamplesPerPixel = 0x0115,
Orientation = 0x0112, PlanarConfiguration = 0x011C,
SamplesPerPixel = 0x0115, YCbCrSubSampling = 0x0212,
PlanarConfiguration = 0x011C, XResolution = 0x011A,
YCbCrSubSampling = 0x0212, YResolution = 0x011B,
XResolution = 0x011A, ResolutionUnit = 0x0128,
YResolution = 0x011B, StripOffsets = 0x0111,
ResolutionUnit = 0x0128, RowsPerStrip = 0x0116,
StripOffsets = 0x0111, StripByteCounts = 0x0117,
RowsPerStrip = 0x0116, TransferFunction = 0x012D,
StripByteCounts = 0x0117, WhitePoint = 0x013E,
TransferFunction = 0x012D, PrimaryChromaciticies = 0x013F,
WhitePoint = 0x013E, YCbCrCoefficients = 0x0211,
PrimaryChromaciticies = 0x013F, ReferenceBlackWhite = 0x0214,
YCbCrCoefficients = 0x0211, DateTime = 0x0132,
ReferenceBlackWhite = 0x0214, ImageDescription = 0x010E,
DateTime = 0x0132, Make = 0x010F,
ImageDescription = 0x010E, Model = 0x0110,
Make = 0x010F, Software = 0x0131,
Model = 0x0110, Artist = 0x013B,
Software = 0x0131, Copyright = 0x8298
Artist = 0x013B, };
Copyright = 0x8298
}; enum ExifExtendedTag {
ExifVersion = 0x9000,
enum ExifExtendedTag FlashPixVersion = 0xA000,
{ ColorSpace = 0xA001,
ExifVersion = 0x9000, ComponentsConfiguration = 0x9101,
FlashPixVersion = 0xA000, CompressedBitsPerPixel = 0x9102,
ColorSpace = 0xA001, PixelXDimension = 0xA002,
ComponentsConfiguration = 0x9101, PixelYDimension = 0xA003,
CompressedBitsPerPixel = 0x9102, MakerNote = 0x927C,
PixelXDimension = 0xA002, UserComment = 0x9286,
PixelYDimension = 0xA003, RelatedSoundFile = 0xA004,
MakerNote = 0x927C, DateTimeOriginal = 0x9003,
UserComment = 0x9286, DateTimeDigitized = 0x9004,
RelatedSoundFile = 0xA004, SubSecTime = 0x9290,
DateTimeOriginal = 0x9003, SubSecTimeOriginal = 0x9291,
DateTimeDigitized = 0x9004, SubSecTimeDigitized = 0x9292,
SubSecTime = 0x9290, ImageUniqueId = 0xA420,
SubSecTimeOriginal = 0x9291, ExposureTime = 0x829A,
SubSecTimeDigitized = 0x9292, FNumber = 0x829D,
ImageUniqueId = 0xA420, ExposureProgram = 0x8822,
SpectralSensitivity = 0x8824,
ExposureTime = 0x829A, ISOSpeedRatings = 0x8827,
FNumber = 0x829D, Oecf = 0x8828,
ExposureProgram = 0x8822, ShutterSpeedValue = 0x9201,
SpectralSensitivity = 0x8824, ApertureValue = 0x9202,
ISOSpeedRatings = 0x8827, BrightnessValue = 0x9203,
Oecf = 0x8828, ExposureBiasValue = 0x9204,
ShutterSpeedValue = 0x9201, MaxApertureValue = 0x9205,
ApertureValue = 0x9202, SubjectDistance = 0x9206,
BrightnessValue = 0x9203, MeteringMode = 0x9207,
ExposureBiasValue = 0x9204, LightSource = 0x9208,
MaxApertureValue = 0x9205, Flash = 0x9209,
SubjectDistance = 0x9206, FocalLength = 0x920A,
MeteringMode = 0x9207, SubjectArea = 0x9214,
LightSource = 0x9208, FlashEnergy = 0xA20B,
Flash = 0x9209, SpatialFrequencyResponse = 0xA20C,
FocalLength = 0x920A, FocalPlaneXResolution = 0xA20E,
SubjectArea = 0x9214, FocalPlaneYResolution = 0xA20F,
FlashEnergy = 0xA20B, FocalPlaneResolutionUnit = 0xA210,
SpatialFrequencyResponse = 0xA20C, SubjectLocation = 0xA214,
FocalPlaneXResolution = 0xA20E, ExposureIndex = 0xA215,
FocalPlaneYResolution = 0xA20F, SensingMethod = 0xA217,
FocalPlaneResolutionUnit = 0xA210, FileSource = 0xA300,
SubjectLocation = 0xA214, SceneType = 0xA301,
ExposureIndex = 0xA215, CfaPattern = 0xA302,
SensingMethod = 0xA217, CustomRendered = 0xA401,
FileSource = 0xA300, ExposureMode = 0xA402,
SceneType = 0xA301, WhiteBalance = 0xA403,
CfaPattern = 0xA302, DigitalZoomRatio = 0xA404,
CustomRendered = 0xA401, FocalLengthIn35mmFilm = 0xA405,
ExposureMode = 0xA402, SceneCaptureType = 0xA406,
WhiteBalance = 0xA403, GainControl = 0xA407,
DigitalZoomRatio = 0xA404, Contrast = 0xA408,
FocalLengthIn35mmFilm = 0xA405, Saturation = 0xA409,
SceneCaptureType = 0xA406, Sharpness = 0xA40A,
GainControl = 0xA407, DeviceSettingDescription = 0xA40B,
Contrast = 0xA408, SubjectDistanceRange = 0x40C
Saturation = 0xA409, };
Sharpness = 0xA40A,
DeviceSettingDescription = 0xA40B, enum GpsTag {
SubjectDistanceRange = 0x40C GpsVersionId = 0x0000,
}; GpsLatitudeRef = 0x0001,
GpsLatitude = 0x0002,
enum GpsTag GpsLongitudeRef = 0x0003,
{ GpsLongitude = 0x0004,
GpsVersionId = 0x0000, GpsAltitudeRef = 0x0005,
GpsLatitudeRef = 0x0001, GpsAltitude = 0x0006,
GpsLatitude = 0x0002, GpsTimeStamp = 0x0007,
GpsLongitudeRef = 0x0003, GpsSatellites = 0x0008,
GpsLongitude = 0x0004, GpsStatus = 0x0009,
GpsAltitudeRef = 0x0005, GpsMeasureMode = 0x000A,
GpsAltitude = 0x0006, GpsDop = 0x000B,
GpsTimeStamp = 0x0007, GpsSpeedRef = 0x000C,
GpsSatellites = 0x0008, GpsSpeed = 0x000D,
GpsStatus = 0x0009, GpsTrackRef = 0x000E,
GpsMeasureMode = 0x000A, GpsTrack = 0x000F,
GpsDop = 0x000B, GpsImageDirectionRef = 0x0010,
GpsSpeedRef = 0x000C, GpsImageDirection = 0x0011,
GpsSpeed = 0x000D, GpsMapDatum = 0x0012,
GpsTrackRef = 0x000E, GpsDestLatitudeRef = 0x0013,
GpsTrack = 0x000F, GpsDestLatitude = 0x0014,
GpsImageDirectionRef = 0x0010, GpsDestLongitudeRef = 0x0015,
GpsImageDirection = 0x0011, GpsDestLongitude = 0x0016,
GpsMapDatum = 0x0012, GpsDestBearingRef = 0x0017,
GpsDestLatitudeRef = 0x0013, GpsDestBearing = 0x0018,
GpsDestLatitude = 0x0014, GpsDestDistanceRef = 0x0019,
GpsDestLongitudeRef = 0x0015, GpsDestDistance = 0x001A,
GpsDestLongitude = 0x0016, GpsProcessingMethod = 0x001B,
GpsDestBearingRef = 0x0017, GpsAreaInformation = 0x001C,
GpsDestBearing = 0x0018, GpsDateStamp = 0x001D,
GpsDestDistanceRef = 0x0019, GpsDifferential = 0x001E
GpsDestDistance = 0x001A, };
GpsProcessingMethod = 0x001B,
GpsAreaInformation = 0x001C, QExifImageHeader ();
GpsDateStamp = 0x001D, explicit QExifImageHeader (const QString &fileName);
GpsDifferential = 0x001E ~QExifImageHeader ();
};
bool loadFromJpeg (const QString &fileName);
QExifImageHeader(); bool loadFromJpeg (QIODevice *device);
explicit QExifImageHeader(const QString &fileName); bool saveToJpeg (const QString &fileName) const;
~QExifImageHeader(); bool saveToJpeg (QIODevice *device) const;
bool loadFromJpeg(const QString &fileName); bool read (QIODevice *device);
bool loadFromJpeg(QIODevice *device); qint64 write (QIODevice *device) const;
bool saveToJpeg(const QString &fileName) const;
bool saveToJpeg(QIODevice *device) const; qint64 size () const;
bool read(QIODevice *device); QSysInfo::Endian byteOrder () const;
qint64 write(QIODevice *device) const;
void clear ();
qint64 size() const;
QList<ImageTag> imageTags () const;
QSysInfo::Endian byteOrder() const; QList<ExifExtendedTag> extendedTags () const;
QList<GpsTag> gpsTags () const;
void clear();
bool contains (ImageTag tag) const;
QList<ImageTag> imageTags() const; bool contains (ExifExtendedTag tag) const;
QList<ExifExtendedTag> extendedTags() const; bool contains (GpsTag tag) const;
QList<GpsTag> gpsTags() const;
void remove (ImageTag tag);
bool contains(ImageTag tag) const; void remove (ExifExtendedTag tag);
bool contains(ExifExtendedTag tag) const; void remove (GpsTag tag);
bool contains(GpsTag tag) const;
QExifValue value (ImageTag tag) const;
void remove(ImageTag tag); QExifValue value (ExifExtendedTag tag) const;
void remove(ExifExtendedTag tag); QExifValue value (GpsTag tag) const;
void remove(GpsTag tag);
void setValue (ImageTag tag, const QExifValue &value);
QExifValue value(ImageTag tag) const; void setValue (ExifExtendedTag tag, const QExifValue &value);
QExifValue value(ExifExtendedTag tag) const; void setValue (GpsTag tag, const QExifValue &value);
QExifValue value(GpsTag tag) const;
QImage thumbnail () const;
void setValue(ImageTag tag, const QExifValue &value); void setThumbnail (const QImage &thumbnail);
void setValue(ExifExtendedTag tag, const QExifValue &value);
void setValue(GpsTag tag, const QExifValue &value);
QImage thumbnail() const;
void setThumbnail( const QImage &thumbnail );
private: private:
enum PrivateTag enum PrivateTag {
{ ExifIfdPointer = 0x8769,
ExifIfdPointer = 0x8769, GpsInfoIfdPointer = 0x8825,
GpsInfoIfdPointer = 0x8825, InteroperabilityIfdPointer = 0xA005,
InteroperabilityIfdPointer = 0xA005, JpegInterchangeFormat = 0x0201,
JpegInterchangeFormat = 0x0201, JpegInterchangeFormatLength = 0x0202
JpegInterchangeFormatLength = 0x0202 };
};
QByteArray extractExif( QIODevice *device ) const; QByteArray extractExif (QIODevice *device) const;
QList< ExifIfdHeader > readIfdHeaders( QDataStream &stream ) const; QList<ExifIfdHeader> readIfdHeaders (QDataStream &stream) const;
QExifValue readIfdValue(QDataStream &stream, int startPos, const ExifIfdHeader &header) const; QExifValue readIfdValue (QDataStream &stream, int startPos, const ExifIfdHeader &header) const;
template <typename T> QMap<T, QExifValue> readIfdValues( template<typename T>
QDataStream &stream, int startPos, const QList<ExifIfdHeader> &headers) const; QMap<T, QExifValue> readIfdValues (QDataStream &stream, int startPos, const QList<ExifIfdHeader> &headers) const;
template <typename T> QMap<T, QExifValue> readIfdValues( template<typename T>
QDataStream &stream, int startPos, const QExifValue &pointer) const; QMap<T, QExifValue> readIfdValues (QDataStream &stream, int startPos, const QExifValue &pointer) const;
quint32 writeExifHeader(QDataStream &stream, quint16 tag, const QExifValue &value, quint32 offset) const; quint32 writeExifHeader (QDataStream &stream, quint16 tag, const QExifValue &value, quint32 offset) const;
void writeExifValue(QDataStream &stream, const QExifValue &value) const; void writeExifValue (QDataStream &stream, const QExifValue &value) const;
template <typename T> quint32 writeExifHeaders( template<typename T>
QDataStream &stream, const QMap<T, QExifValue > &values, quint32 offset) const; quint32 writeExifHeaders (QDataStream &stream, const QMap<T, QExifValue> &values, quint32 offset) const;
template <typename T> void writeExifValues( template<typename T>
QDataStream &target, const QMap<T, QExifValue> &values) const; void writeExifValues (QDataStream &target, const QMap<T, QExifValue> &values) const;
quint32 sizeOf(const QExifValue &value) const; quint32 sizeOf (const QExifValue &value) const;
template <typename T> quint32 calculateSize( template<typename T>
const QMap<T, QExifValue> &values) const; quint32 calculateSize (const QMap<T, QExifValue> &values) const;
QExifImageHeaderPrivate *d; QExifImageHeaderPrivate *d;
}; };
#endif #endif // ifndef QEXIFIMAGEHEADER_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment