Project

General

Profile

Feature #1199 » exiv2.patch

Ben Touchette, 31 Jul 2016 20:36

View differences:

2/src/CMakeLists.txt 2016-07-30 09:11:31.321580114 -0400
79 79
                          ${CMAKE_CURRENT_LIST_DIR}/../include/exiv2/xmp.hpp
80 80
                          ${CMAKE_CURRENT_LIST_DIR}/../include/exiv2/xmpsidecar.hpp
81 81
                          ${CMAKE_CURRENT_LIST_DIR}/../include/exiv2/utilsvideo.hpp
82
                          ${CMAKE_CURRENT_LIST_DIR}/../include/exiv2/webpimage.hpp
82 83
   )
83 84
# Add library C++ source files to this list
......
137 138
                          xmp.cpp
138 139
                          xmpsidecar.cpp
139 140
                          utilsvideo.cpp
141
                          webpimage.cpp
140 142
   )
141 143
IF( EXIV2_ENABLE_WEBREADY )
2/src/image.cpp 2016-07-30 09:25:24.186965712 -0400
64 64
#endif // EXV_ENABLE_VIDEO
65 65
#include "rw2image.hpp"
66 66
#include "pgfimage.hpp"
67
#include "webpimage.hpp"
67 68
#include "xmpsidecar.hpp"
68 69
// + standard includes
......
106 107
    const Registry registry[] = {
107 108
        //image type       creation fct     type check  Exif mode    IPTC mode    XMP mode     Comment mode
108 109
        //---------------  ---------------  ----------  -----------  -----------  -----------  ------------
110
        { ImageType::webp, newWebPInstance, isWebPType, amReadWrite, amNone,      amReadWrite, amNone      },
109 111
        { ImageType::jpeg, newJpegInstance, isJpegType, amReadWrite, amReadWrite, amReadWrite, amReadWrite },
110 112
        { ImageType::exv,  newExvInstance,  isExvType,  amReadWrite, amReadWrite, amReadWrite, amReadWrite },
111 113
        { ImageType::cr2,  newCr2Instance,  isCr2Type,  amReadWrite, amReadWrite, amReadWrite, amNone      },
2/src/Makefile 2016-07-30 09:12:01.465924217 -0400
119 119
	 types.cpp             \
120 120
	 value.cpp             \
121 121
	 version.cpp           \
122
	 webpimage.cpp         \
122 123
	 xmp.cpp               \
123 124
	 xmpsidecar.cpp
124 125
ifdef ENABLE_VIDEO
2/src/svn_version.h 2016-07-30 09:13:57.367242726 -0400
1
#ifndef SVN_VERSION
2
#define SVN_VERSION 0
3
#endif
2/src/webpimage.cpp 2016-07-31 12:01:49.726236093 -0400
1
// ***************************************************************** -*- C++ -*-
2
/*
3
 * Copyright (C) 2004-2015 Andreas Huggel <ahuggel@gmx.net>
4
 *
5
 * This program is part of the Exiv2 distribution.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20
 */
21
/*
22
  File:      webpimage.cpp
23
  Version:   $Rev: 3845 $
24
  Author(s): Ben Touchette <draekko.software+exiv2@gmail.com>
25
  History:   29-Jul-16
26
  Credits:   See header file
27
 */
28
// *****************************************************************************
29
#include "rcsid_int.hpp"
30

  
31
// *****************************************************************************
32
// included header files
33
#include "config.h"
34

  
35
#include "webpimage.hpp"
36
#include "futils.hpp"
37
#include "basicio.hpp"
38
#include "tags.hpp"
39
#include "tags_int.hpp"
40
#include "types.hpp"
41
#include "tiffimage.hpp"
42
#include "tiffimage_int.hpp"
43
#include "exiv2/convert.hpp"
44
#include <cmath>
45
#include <sstream>
46
#include <iomanip>
47
#include <string>
48
#include <cstring>
49
#include <iostream>
50
#include <cassert>
51
#include <cstdio>
52

  
53
#include <zlib.h>     // To uncompress or compress text chunk
54

  
55
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
56

  
57
// *****************************************************************************
58
// class member definitions
59
namespace Exiv2 {
60
    namespace Internal {
61

  
62

  
63
}}                                      // namespace Internal, Exiv2
64

  
65
namespace Exiv2 {
66
    using namespace Exiv2::Internal;
67

  
68
    WebPImage::WebPImage(BasicIo::AutoPtr io)
69
            : Image(ImageType::webp, mdNone, io)
70
    {
71
    } // WebPImage::WebPImage
72

  
73
    std::string WebPImage::mimeType() const
74
    {
75
        return "image/webp";
76
    }
77

  
78
    /* =========================================== */
79

  
80
    void WebPImage::setIptcData(const IptcData& /*iptcData*/)
81
    {
82
        // not supported
83
        throw(Error(32, "IPTC metadata", "WebP"));
84
    }
85

  
86
    void WebPImage::setComment(const std::string& /*comment*/)
87
    {
88
        // not supported
89
        throw(Error(32, "Image comment", "WebP"));
90
    }
91

  
92
    /* =========================================== */
93

  
94
    void WebPImage::writeMetadata()
95
    {
96
        if (io_->open() != 0) {
97
            throw Error(9, io_->path(), strError());
98
        }
99
        IoCloser closer(*io_);
100
        BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
101
        assert (tempIo.get() != 0);
102

  
103
        doWriteMetadata(*tempIo); // may throw
104
        io_->close();
105
        io_->transfer(*tempIo); // may throw
106
    } // WebPImage::writeMetadata
107

  
108

  
109
    void WebPImage::doWriteMetadata(BasicIo& outIo)
110
    {
111
        if (!io_->isopen()) throw Error(20);
112
        if (!outIo.isopen()) throw Error(21);
113

  
114
        byte data[12];
115
        DataBuf chunkId(5);
116
        const int TAG_SIZE = 4;
117
        chunkId.pData_[4] = '\0' ;
118

  
119
        io_->read(data, TAG_SIZE * 3);
120
        uint64_t filesize = Exiv2::getULong(data + 4, littleEndian);
121
        uint64_t endoffile = 12;
122

  
123
        /* Set up header */
124
        if (outIo.write(data, TAG_SIZE * 3) != TAG_SIZE * 3)
125
            throw Error(21);
126

  
127
        /* Parse Chunks */
128
        bool has_xmp = false;
129
        bool has_exif = false;
130
        byte size_buff[4];
131
        std::string xmpData;
132
        Blob blob;
133

  
134
        if (iptcData_.count() > 0) {
135
            std::cout << "Found iptc data\n";
136
        }
137

  
138
        if (exifData_.count() > 0) {
139
            ExifParser::encode(blob, littleEndian, exifData_);
140
            if (blob.size() > 0) {
141
                has_exif = true;
142
            }
143
        }
144

  
145
        if (xmpData_.count() > 0) {
146
            copyIptcToXmp(iptcData_, xmpData_);
147
            copyExifToXmp(exifData_, xmpData_);
148
            XmpParser::encode(xmpPacket_, xmpData_,
149
                              XmpParser::useCompactFormat |
150
                              XmpParser::omitAllFormatting);
151
            if (xmpPacket_.size() > 0) {
152
                has_xmp = true;
153
                xmpData = xmpPacket_.data();
154
            }
155
        }
156

  
157
        while (!io_->eof()) {
158
            io_->read(chunkId.pData_, 4);
159
            io_->read(size_buff, 4);
160

  
161
            if (endoffile >= filesize) {
162
                break;
163
            }
164

  
165
            uint64_t size = Exiv2::getULong(size_buff, littleEndian);
166

  
167
            DataBuf payload(size);
168
            io_->read(payload.pData_, payload.size_);
169

  
170
            if (equalsWebPTag(chunkId, "VP8X")) {
171
              if (has_xmp){
172
                payload.pData_[0] |= 0x4;
173
              } else {
174
                payload.pData_[0] &= ~0x4;
175
              }
176
              if (has_exif) {
177
                payload.pData_[0] |= 0x8;
178
              } else {
179
                payload.pData_[0] &= ~0x8;
180
              }
181
              if (outIo.write(chunkId.pData_, TAG_SIZE) != TAG_SIZE)
182
                  throw Error(21);
183
              if (outIo.write(size_buff, 4) != 4)
184
                  throw Error(21);
185
              if (outIo.write(payload.pData_, payload.size_) != payload.size_)
186
                  throw Error(21);
187
            } else if (equalsWebPTag(chunkId, "EXIF")) {
188
              // Skip and add new data afterwards
189
            } else if (equalsWebPTag(chunkId, "XMP ")) {
190
              // Skip and add new data afterwards
191
            } else {
192
              if (outIo.write(chunkId.pData_, TAG_SIZE) != TAG_SIZE)
193
                  throw Error(21);
194
              if (outIo.write(size_buff, 4) != 4)
195
                  throw Error(21);
196
              if (outIo.write(payload.pData_, payload.size_) != payload.size_)
197
                  throw Error(21);
198
            }
199

  
200
            endoffile = io_->tell();
201
            if (endoffile >= filesize) {
202
                break;
203
            }
204
        }
205

  
206
        if (has_exif) {
207
            std::string header = "EXIF";
208
            if (outIo.write((const byte*)header.data(), 4) != 4)
209
                throw Error(21);
210

  
211
            us2Data(data, blob.size()+10, bigEndian);
212
            static const char exifHeader[] = { 0xff, 0x1, 0xFF, 0xE1, data[0], data[1], 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
213
            std::string rawExif =   std::string(exifHeader, 12)
214
                                  + std::string((const char*)&blob[0], blob.size());
215
            ul2Data(data, rawExif.size(), littleEndian);
216
            if (outIo.write(data, 4) != 4) throw Error(21);
217
            if (outIo.write((const byte*)rawExif.data(), static_cast<long>(rawExif.size())) != (long)rawExif.size())
218
            {
219
                throw Error(21);
220
            }
221
        }
222

  
223
        if (has_xmp) {
224
            std::string header = "XMP ";
225
            if (outIo.write((const byte*)header.data(), TAG_SIZE) != TAG_SIZE) throw Error(21);
226
            ul2Data(data, xmpData.size(), littleEndian);
227
            if (outIo.write(data, 4) != 4) throw Error(21);
228
            if (outIo.write((const byte*)xmpData.data(), static_cast<long>(xmpData.size())) != (long)xmpData.size()) {
229
                throw Error(21);
230
            }
231
            for (int lp=0; lp<12; lp++)
232
                data[0] = 0;
233
            if (outIo.write(data, 1) != 1) throw Error(21);
234
        }
235

  
236
        // Fix File Size Payload Data
237
        if (has_xmp || has_exif) {
238
          outIo.seek(0, BasicIo::beg);
239
          filesize = outIo.size() - 8;
240
          outIo.seek(4, BasicIo::beg);
241
          ul2Data(data, filesize, littleEndian);
242
          if (outIo.write(data, 4) != 4) throw Error(21);
243
        }
244

  
245
    } // WebPImage::writeMetadata
246

  
247
    /* =========================================== */
248

  
249
    void WebPImage::readMetadata()
250
    {
251
        if (io_->open() != 0) throw Error(9, io_->path(), strError());
252
        IoCloser closer(*io_);
253
        // Ensure that this is the correct image type
254
        if (!isWebPType(*io_, true)) {
255
            if (io_->error() || io_->eof()) throw Error(14);
256
            throw Error(15);
257
        }
258
        clearMetadata();
259

  
260
        byte data[12];
261
        DataBuf chunkId(5);
262
        const int TAG_SIZE = 4;
263
        chunkId.pData_[4] = '\0' ;
264

  
265
        io_->read(data, TAG_SIZE * 3);
266

  
267
        WebPImage::decodeChunks(Exiv2::getULong(data + 4, littleEndian) + 12);
268

  
269
    } // WebPImage::readMetadata
270

  
271
    void WebPImage::decodeChunks(uint64_t filesize)
272
    {
273
        DataBuf  chunkId(5);
274
        byte     size_buff[4];
275
        uint64_t size;
276
        uint64_t endoffile = 12;
277

  
278
        chunkId.pData_[4] = '\0' ;
279

  
280
        while (!io_->eof()) {
281
            io_->read(chunkId.pData_, 4);
282
            io_->read(size_buff, 4);
283
            size = Exiv2::getULong(size_buff, littleEndian);
284

  
285
            DataBuf payload(size);
286

  
287
            if (equalsWebPTag(chunkId, "VP8X")) {
288
                io_->read(payload.pData_, payload.size_);
289
                byte size_buf[4];
290
                memcpy(&size_buf, &payload.pData_[4], 3);
291
                size_buf[3] = 0;
292
                pixelWidth_ = Exiv2::getULong(size_buf, littleEndian) + 1;
293
                memcpy(&size_buf, &payload.pData_[7], 3);
294
                size_buf[3] = 0;
295
                pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
296
            } else if (equalsWebPTag(chunkId, "ICCP")) {
297
#ifdef __SVN__ /* COULD BE ENABLED FOR SVN VERSION */
298
                io_->read(payload.pData_, payload.size_);
299
                this->setIccProfile(payload);
300
#else
301
                io_->seek(size, BasicIo::cur);
302
#endif
303
            } else if (equalsWebPTag(chunkId, "EXIF")) {
304
                io_->read(payload.pData_, payload.size_);
305

  
306
                const byte exifHeader[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
307
                long pos = -1;
308

  
309
                for (long i=0 ; i < payload.size_-(long)sizeof(exifHeader) ; i++)
310
                {
311
                    if (memcmp(exifHeader, &payload.pData_[i], sizeof(exifHeader)) == 0)
312
                    {
313
                        pos = i;
314
                        break;
315
                    }
316
                }
317

  
318
                if (pos != -1)
319
                {
320
                    IptcData iptcData;
321
                    XmpData  xmpData;
322
                    pos = pos + sizeof(exifHeader);
323
                    ByteOrder bo = ExifParser::decode(exifData_,
324
                                                      payload.pData_ + pos,
325
                                                      payload.size_ - pos);
326
                    setByteOrder(bo);
327
                }
328
                else
329
                {
330
#ifndef SUPPRESS_WARNINGS
331
                    EXV_WARNING << "Failed to decode Exif metadata.\n";
332
#endif
333
                    exifData_.clear();
334
                }
335
            } else if (equalsWebPTag(chunkId, "XMP ")) {
336
                io_->read(payload.pData_, payload.size_);
337
                xmpPacket_.assign(reinterpret_cast<char*>(payload.pData_), payload.size_);
338
                if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) {
339
#ifndef SUPPRESS_WARNINGS
340
                    EXV_WARNING << "Failed to decode XMP metadata.\n";
341
#endif
342
                } else {
343
                    copyXmpToIptc(xmpData_, iptcData_);
344
                    copyXmpToExif(xmpData_, exifData_);
345
                }
346
            } else {
347
                io_->seek(size, BasicIo::cur);
348
            }
349

  
350
            endoffile = io_->tell();
351
            if (endoffile >= filesize) {
352
                break;
353
            }
354
        }
355
    }
356

  
357
    /* =========================================== */
358

  
359
    Image::AutoPtr newWebPInstance(BasicIo::AutoPtr io, bool /*create*/)
360
    {
361
        Image::AutoPtr image(new WebPImage(io));
362
        if (!image->good()) {
363
            image.reset();
364
        }
365
        return image;
366
    }
367

  
368
    bool isWebPType(BasicIo& iIo, bool advance)
369
    {
370
        const int32_t len = 4;
371
        const unsigned char RiffImageId[4] = { 'R', 'I', 'F' ,'F'};
372
        const unsigned char WebPImageId[4] = { 'W', 'E', 'B' ,'P'};
373
        byte webp[len];
374
        byte data[len];
375
        byte riff[len];
376
        iIo.read(riff, len);
377
        iIo.read(data, len);
378
        iIo.read(webp, len);
379
        bool matched_riff = (memcmp(riff, RiffImageId, len) == 0);
380
        bool matched_webp = (memcmp(webp, WebPImageId, len) == 0);
381
        iIo.seek(-12, BasicIo::cur);
382
        return matched_riff && matched_webp;
383
    }
384

  
385
    /*!
386
      @brief Function used to check equality of a Tags with a
387
          particular string (ignores case while comparing).
388
      @param buf Data buffer that will contain Tag to compare
389
      @param str char* Pointer to string
390
      @return Returns true if the buffer value is equal to string.
391
     */
392
    bool WebPImage::equalsWebPTag(Exiv2::DataBuf& buf, const char* str) {
393
        for(int i = 0; i < 4; i++ )
394
            if(toupper(buf.pData_[i]) != str[i])
395
                return false;
396
        return true;
397
    }
398

  
399
} // namespace Exiv2
exiv2/include/exiv2/webpimage.hpp 2016-07-31 11:20:16.897652938 -0400
1
// ***************************************************************** -*- C++ -*-
2
/*
3
 * Copyright (C) 2004-2015 Andreas Huggel <ahuggel@gmx.net>
4
 *
5
 * This program is part of the Exiv2 distribution.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20
 */
21
/*!
22
  @file    webpimage.hpp
23
  @brief   An Image subclass to support WEBP image files
24
  @version $Rev$
25
  @author  Ben Touchette
26
           <a href="mailto:draekko.software+exiv2@gmail.com">draekko.software+exiv2@gmail.com</a>
27
  @date    29-Jul-16
28
 */
29
#ifndef WEBPIMAGE_HPP
30
#define WEBPIMAGE_HPP
31

  
32
// *****************************************************************************
33
// included header files
34
#include "exif.hpp"
35
#include "image.hpp"
36
#include "tags_int.hpp"
37

  
38
// *****************************************************************************
39
// namespace extensions
40
namespace Exiv2 {
41

  
42
// *****************************************************************************
43
// class definitions
44

  
45
    // Add WEBP to the supported image formats
46
    namespace ImageType {
47
        const int webp = 23; //!< Treating webp as an image type>
48
    }
49

  
50
    /*!
51
      @brief Class to access WEBP video files.
52
     */
53
    class EXIV2API WebPImage:public Image
54
    {
55
    public:
56
        //! @name Creators
57
        //@{
58
        /*!
59
          @brief Constructor for a WebP video. Since the constructor
60
              can not return a result, callers should check the good() method
61
              after object construction to determine success or failure.
62
          @param io An auto-pointer that owns a BasicIo instance used for
63
              reading and writing image metadata. \b Important: The constructor
64
              takes ownership of the passed in BasicIo instance through the
65
              auto-pointer. Callers should not continue to use the BasicIo
66
              instance after it is passed to this method. Use the Image::io()
67
              method to get a temporary reference.
68
         */
69
        WebPImage(BasicIo::AutoPtr io);
70
        //@}
71

  
72
        //! @name Manipulators
73
        //@{
74
        void readMetadata();
75
        void writeMetadata();
76
        //@}
77

  
78
        /*!
79
          @brief Not supported. Calling this function will throw an Error(32).
80
         */
81
        void setComment(const std::string& comment);
82
        void setIptcData(const IptcData& iptcData);
83

  
84
        //! @name Accessors
85
        //@{
86
        std::string mimeType() const;
87
        //@}
88

  
89
    private:
90
        EXV_DLLLOCAL void doWriteMetadata(BasicIo& outIo);
91
        //! @name NOT Implemented
92
        //@{
93
        bool equalsWebPTag(Exiv2::DataBuf& buf ,const char* str);
94
        void decodeChunks(uint64_t filesize);
95
        //! Copy constructor
96
        WebPImage(const WebPImage& rhs);
97
        //! Assignment operator
98
        WebPImage& operator=(const WebPImage& rhs);
99
        //@}
100

  
101
    private:
102
        int streamType_;
103

  
104
    }; //Class WebPImage
105

  
106
// *****************************************************************************
107
// template, inline and free functions
108

  
109
    // These could be static private functions on Image subclasses but then
110
    // ImageFactory needs to be made a friend.
111
    /*!
112
      @brief Create a new WebPImage instance and return an auto-pointer to it.
113
          Caller owns the returned object and the auto-pointer ensures that
114
          it will be deleted.
115
     */
116
    EXIV2API Image::AutoPtr newWebPInstance(BasicIo::AutoPtr io, bool create);
117

  
118
    //! Check if the file iIo is a WebP Video.
119
    EXIV2API bool isWebPType(BasicIo& iIo, bool advance);
120

  
121
}                                       // namespace Exiv2
122

  
123
#endif                                  // WEBPIMAGE_HPP
(1-1/12)