// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2017 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "utils.hpp" #include "toexv.hpp" static size_t exifMetadataCount(Exiv2::Image::AutoPtr& image) { size_t result = 0 ; Exiv2::ExifData& exif = image->exifData(); Exiv2::ExifData::const_iterator end = exif.end(); for (Exiv2::ExifData::const_iterator i = exif.begin(); i != end; ++i) result++; return result; } // ***************************************************************************** // Main int main(int argc, char* const argv[]) { Exiv2::XmpParser::initialize(); ::atexit(Exiv2::XmpParser::terminate); #ifdef EXV_ENABLE_BMFF Exiv2::enableBMFF(); #endif try { // Handle command line arguments Params params(":iecCahsx"); if (params.getopt(argc, argv)) return params.usage(); if (params.help_ ) return params.help(); Exiv2::Image::AutoPtr readImage = Exiv2::ImageFactory::open(params.read_); assert(readImage.get() != 0); readImage->readMetadata(); if ( params.write_ == "+" ) { std::cout << "exifMetadataCount = " << exifMetadataCount(readImage) << std::endl; // create an in-memory file and write the metadata Exiv2::BasicIo::AutoPtr memIo (new Exiv2::MemIo()); Exiv2::Image::AutoPtr memImage(new Exiv2::ExvImage(memIo,true)); memImage->setMetadata (*readImage); memImage->writeMetadata(); // serialize the in-memory file into buff size_t size = memImage->io().size(); Exiv2::byte buff[size]; memImage->io().seek(0,Exiv2::BasicIo::beg); memImage->io().read(buff,size); std::cout << "size = " << size << std::endl; // create an in-memory file with buff and read the metadata into buffImage Exiv2::BasicIo::AutoPtr buffIo (new Exiv2::MemIo(buff,size)); Exiv2::Image::AutoPtr buffImage(new Exiv2::ExvImage(buffIo,false)); assert(buffImage.get() != 0); buffImage->readMetadata(); std::cout << "exifMetadataCount = " << exifMetadataCount(buffImage) << std::endl; } else if ( params.write_ != "-" ) { // create a file and write the metadata Exiv2::Image::AutoPtr writeImage = Exiv2::ImageFactory::create(Exiv2::ImageType::exv,params.write_); params.copyMetadata(readImage,writeImage); } else { // create an in-memory file Exiv2::BasicIo::AutoPtr memIo (new Exiv2::MemIo()); Exiv2::Image::AutoPtr memImage(new Exiv2::ExvImage(memIo,true)); params.copyMetadata(readImage,memImage); // read a few bytes from the in-memory file size_t size = memImage->io().size(); if (size>32) size = 32; Exiv2::byte data[size]; memImage->io().seek(0,Exiv2::BasicIo::beg); memImage->io().read(data,size); // dump the bytes for ( size_t i = 0 ; i < size ; i++ ) { char c = (char) data[i] ; if ( !isascii(c) ) c = '.' ; std::cout << c ; } std::cout << std::endl; } return 0; } catch (Exiv2::AnyError& e) { std::cerr << "Caught Exiv2 exception '" << e << "'\n"; return 3; } } Params::Params( const char* opts) : optstring_(opts) , first_(true) , help_(false) , iptc_(false) , exif_(false) , ICC_(false) , all_(false) , comment_(false) , xmp_(false) , size_(false) , usage_(false) {} void Params::copyMetadata(Exiv2::Image::AutoPtr& readImage,Exiv2::Image::AutoPtr& writeImage) { if (all_ ) writeImage->setMetadata (*readImage); if (iptc_ ) writeImage->setIptcData ( readImage->iptcData()); if (exif_ ) writeImage->setExifData ( readImage->exifData()); if (ICC_ ) writeImage->setIccProfile(*readImage->iccProfile()); if (comment_) writeImage->setComment ( readImage->comment()); if (xmp_ ) writeImage->setXmpData ( readImage->xmpData()); writeImage->writeMetadata(); if ( size_ ) std::cout << write_ << " " << writeImage->io().size() << std::endl; } int Params::option(int opt, const std::string& /*optarg*/, int optopt) { int rc = 0; switch (opt) { case 'h': help_ = true ; break; case 'i': iptc_ = true ; break; case 'e': exif_ = true ; break; case 'c': comment_ = true ; break; case 'C': ICC_ = true ; break; case 'x': xmp_ = true ; break; case 'a': all_ = true ; break; case 's': size_ = true ; break; case 'p': /* ignore for backwards compatibility */ ; break; case ':': std::cerr << progname() << ": Option -" << static_cast(optopt) << " requires an argument\n"; rc = 1; break; case '?': std::cerr << progname() << ": Unrecognized option -" << static_cast(optopt) << "\n"; rc = 1; break; default: std::cerr << progname() << ": getopt returned unexpected character code " << (char) opt << " 0x" << std::hex << opt << "\n"; rc = 1; break; } return rc; } int Params::nonoption(const std::string& argv) { if (!write_.empty()) { std::cerr << progname() << ": Unexpected extra argument (" << argv << ")\n"; return 1; } if (first_) read_ = argv; else write_ = argv; first_ = false; return 0; } int Params::getopt(int argc, char* const argv[]) { int rc = Util::Getopt::getopt(argc, argv, optstring_); if ( argc == 1 ) usage_ = true; // Further consistency checks if ( !help_ && !usage_ ) { if (rc==0 && read_.empty() ) { std::cerr << progname() << ": Read and write files must be specified\n"; rc = 1; } if (rc==0 && write_.empty() ) { std::cerr << progname() << ": Write file must be specified\n"; rc = 1; } } if ( argc == 3 ) { all_ = true; size_ = true; } if ( usage_ ) return 2 ; return rc; } int Params::usage(std::ostream& os) const { os << "Reads and writes raw metadata. Use -h option for help.\n" << "Usage: " << progname() << " [-" << optstring_ << "]" << " readfile {-|+|writefile}\n"; return 2; } int Params::help(std::ostream& os) const { usage(os); os << "\nOptions:\n" " -i Read Iptc data from readfile and write to writefile.\n" " -e Read Exif data from readfile and write to writefile.\n" " -c Read Jpeg comment from readfile and write to writefile.\n" " -C Read ICC profile from readfile and write to writefile.\n" " -x Read XMP data from readfile and write to writefile.\n" " -a Read all metadata from readfile and write to writefile.\n" " -s Print size of writefile.\n" " -h Display this help and exit.\n"; return 1; }