aboutsummaryrefslogblamecommitdiffstats
path: root/src/libpyexiv2.cpp
blob: 22c40633b91ae7baa064e153c24e3ee8f7714f4f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11



                                                                                
                                                 





                                                                 
                                                             




                                                                    
                                                         




                                                                              




                                                                                

                                          



                          
 






                                          

                                                             






                                            

                                                              




                                  



                                               





                                   


                                                       
                 
                    
                                                              













                                                                                                             
                                                              

         











                                                                                     

                                                               

                             


                                                                                     
                         

                                                                                                             
                         
                            
                                                                       

                    
                                                              





                                                              


                                                                                     
                         



                                                                            
                         
                            
                                                                       

                    
                                                              






                                                                                  


                                                                                     
                         





                                                                                                                    
                         
                            
                         
                                                        
                                                                                                          
                         

                                               

                    
                                                              






                                                                  


                                                                                     
                         


                                                                                                                    
                                                   
                         
                            
                                                                       

                    
                                                              

         






                                                                                                             



                                                                                           



                                    
                                                              

         











                                                                                     
                                                              


                             

                                                         
                                                                     

                                                                                            
                         




                                                                                                                                         
                         

                                                  
                            
                                                                       

                    
                                                              

         
                                                                                                        
         

                             

                                                          
                                                                     

                                                                                                
                         








                                                                                                                            
                         
                            
                         


                                                                                                
                                                                                                          




                                                                           
                         
                                           

                    
                                                              

         
                                                                                        
         

                             

                                                          
                                                                     

                                                                                                
                         








                                                                                                                            
                                                   
                         
                            
                                                                       

                    
                                                              

         

                                                      














                                                                                               


                                                                                    

                                                                 
                                                              



                                                                               
                                                                 
                 

                                                              

         
                                                      
         



                                                                                       

                    
                                                              

         


                                     
                                                   
                    
                                                              

         
                                                               


                             
                                                                    

                                                                 

                    
                                                              

         
                                                                    


                             
                                                         

                    
                                                              

         

























































                                                                                        
 

                                               

                                                                                                       


                                                                                         








                                                                                                             
 




                                                                             
                                
// *****************************************************************************
/*
 * Copyright (C) 2006 Olivier Tilloy <olivier@tilloy.net>
 *
 * This file is part of the pyexiv2 distribution.
 *
 * pyexiv2 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.
 *
 * pyexiv2 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 pyexiv2; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
 */
/*
  File:      libpyexiv2.cpp
  Author(s): Olivier Tilloy <olivier@tilloy.net>
 */
// *****************************************************************************

#include "libpyexiv2.hpp"

// Custom error codes for Exiv2 exceptions
#define METADATA_NOT_READ 101
#define NON_REPEATABLE 102
#define KEY_NOT_FOUND 103
#define THUMB_ACCESS 104
#define NO_THUMBNAIL 105

namespace LibPyExiv2
{

	// Base constructor
	Image::Image(std::string filename)
	{
		_filename = filename;
		_image = Exiv2::ImageFactory::open(filename);
		assert(_image.get() != 0);
		_dataRead = false;
	}

	// Copy constructor
	Image::Image(const Image & image)
	{
		_filename = image._filename;
		_image = Exiv2::ImageFactory::open(_filename);
		assert(_image.get() != 0);
		_dataRead = false;
	}

	void Image::readMetadata()
	{
		_image->readMetadata();
		_exifData = _image->exifData();
		_iptcData = _image->iptcData();
		_dataRead = true;
	}

	void Image::writeMetadata()
	{
		if(_dataRead)
		{
			_image->setExifData(_exifData);
			_image->setIptcData(_iptcData);
			_image->writeMetadata();
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	boost::python::list Image::getAvailableExifTags()
	{
		boost::python::list list;
		if(_dataRead)
		{
			for(Exiv2::ExifMetadata::iterator i = _exifData.begin() ; i != _exifData.end() ; ++i)
			{
				list.append(i->key());
			}
			return list;
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	bool Image::isExifTagSet(std::string key)
	{
		if(_dataRead)
		{
			Exiv2::ExifKey exifKey = Exiv2::ExifKey(key);
			Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey);
			return (i != _exifData.end());
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	boost::python::tuple Image::getExifTag(std::string key)
	{
		if(_dataRead)
		{
			Exiv2::ExifKey exifKey = Exiv2::ExifKey(key);
			Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey);
			if(i != _exifData.end())
			{
				Exiv2::Exifdatum exifDatum = _exifData[key];
				return boost::python::make_tuple(exifDatum.typeName(), exifDatum.toString());
			}
			else
				throw Exiv2::Error(KEY_NOT_FOUND, key);
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	std::string Image::getExifTagToString(std::string key)
	{
		if(_dataRead)
		{
			Exiv2::ExifKey exifKey = Exiv2::ExifKey(key);
			Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey);
			if(i != _exifData.end())
			{
				Exiv2::Exifdatum exifDatum = _exifData[key];
				std::ostringstream buffer;
				buffer << exifDatum;
				return buffer.str();
			}
			else
				throw Exiv2::Error(KEY_NOT_FOUND, key);
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	boost::python::tuple Image::setExifTag(std::string key, std::string value)
	{
		boost::python::tuple returnValue;
		if(_dataRead)
		{
			Exiv2::ExifKey exifKey = Exiv2::ExifKey(key);
			Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey);
			if(i != _exifData.end())
			{
				Exiv2::Exifdatum exifDatum = _exifData[key];
				returnValue = boost::python::make_tuple(exifDatum.typeName(), exifDatum.toString());
				// First erase the existing tag: in some case (and
				// I don't know why), the new value won't replace
				// the old one if not previously erased...
				_exifData.erase(i);
			}
			else
			{
				// The key was not found
				returnValue = boost::python::make_tuple(std::string(""), std::string(""));
			}
			_exifData[key] = value;
			return returnValue;
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	boost::python::tuple Image::deleteExifTag(std::string key)
	{
		boost::python::tuple returnValue;
		if(_dataRead)
		{
			Exiv2::ExifKey exifKey = Exiv2::ExifKey(key);
			Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey);
			if(i != _exifData.end())
			{
				Exiv2::Exifdatum exifDatum = _exifData[key];
				returnValue = boost::python::make_tuple(exifDatum.typeName(), exifDatum.toString());
				_exifData.erase(i);
				return returnValue;
			}
			else
				throw Exiv2::Error(KEY_NOT_FOUND, key);
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	boost::python::list Image::getAvailableIptcTags()
	{
		boost::python::list list;
		if(_dataRead)
		{
			for(Exiv2::IptcMetadata::iterator i = _iptcData.begin() ; i != _iptcData.end() ; i++)
			{
				// The key is appended to the list if and only if it is not
				// already present.
				if (list.count(i->key()) == 0)
					list.append(i->key());
			}
			return list;
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	bool Image::isIptcTagSet(std::string key)
	{
		if(_dataRead)
		{
			Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key);
			Exiv2::IptcMetadata::iterator i = _iptcData.findKey(iptcKey);
			return (i != _iptcData.end());
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	boost::python::list Image::getIptcTag(std::string key)
	{
		if(_dataRead)
		{
			boost::python::list valuesList;
			unsigned int valueOccurences = 0;
			Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key);
			for (Exiv2::IptcMetadata::iterator dataIterator = _iptcData.begin();
				dataIterator != _iptcData.end(); ++dataIterator)
			{
				if (dataIterator->key() == key)
				{
					valuesList.append(boost::python::make_tuple(dataIterator->typeName(), dataIterator->toString()));
					++valueOccurences;
				}
			}
			if (valueOccurences > 0)
				return valuesList;
			else
				throw Exiv2::Error(KEY_NOT_FOUND, key);
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	boost::python::tuple Image::setIptcTag(std::string key, std::string value, unsigned int index=0)
	{
		if(_dataRead)
		{
			boost::python::tuple returnValue;
			unsigned int indexCounter = index;
			Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key);
			Exiv2::IptcMetadata::iterator dataIterator = _iptcData.findKey(iptcKey);
			while ((indexCounter > 0) && (dataIterator != _iptcData.end()))
			{
				dataIterator = std::find_if(++dataIterator, _iptcData.end(),
					Exiv2::FindMetadatumById::FindMetadatumById(iptcKey.tag(), iptcKey.record()));
				--indexCounter;
			}
			if (dataIterator != _iptcData.end())
			{
				// The tag at given index already exists, override it
				returnValue = boost::python::make_tuple(dataIterator->typeName(), dataIterator->toString());
				dataIterator->setValue(value);
			}
			else
			{
				// Either index is greater than the index of the last repetition
				// of the tag, or the tag does not exist yet.
				// In both cases, it is created.
				returnValue = boost::python::make_tuple(std::string(""), std::string(""));
				Exiv2::Iptcdatum iptcDatum(iptcKey);
				iptcDatum.setValue(value);
				int state = _iptcData.add(iptcDatum);
				if (state == 6)
					throw Exiv2::Error(NON_REPEATABLE);
			}
			return returnValue;
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	boost::python::tuple Image::deleteIptcTag(std::string key, unsigned int index=0)
	{
		if(_dataRead)
		{
			boost::python::tuple returnValue;
			unsigned int indexCounter = index;
			Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key);
			Exiv2::IptcMetadata::iterator dataIterator = _iptcData.findKey(iptcKey);
			while ((indexCounter > 0) && (dataIterator != _iptcData.end()))
			{
				dataIterator = std::find_if(++dataIterator, _iptcData.end(),
					Exiv2::FindMetadatumById::FindMetadatumById(iptcKey.tag(), iptcKey.record()));
				--indexCounter;
			}
			if (dataIterator != _iptcData.end())
			{
				// The tag at given index already exists, delete it
				returnValue = boost::python::make_tuple(dataIterator->typeName(), dataIterator->toString());
				_iptcData.erase(dataIterator);
				return returnValue;
			}
			else
				throw Exiv2::Error(KEY_NOT_FOUND, key);
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	boost::python::tuple Image::getThumbnailData()
	{
		if(_dataRead)
		{
			Exiv2::Thumbnail::AutoPtr thumbnail = _exifData.getThumbnail();
			if (thumbnail.get() != 0)
			{
				std::string format(_exifData.thumbnailFormat());
				// Copy the data buffer in a string. Since the data buffer can
				// contain null char ('\x00'), the string cannot be simply
				// constructed like that:
				//     std::string data((char*) dataBuffer.pData_);
				// because it would be truncated after the first occurence of a
				// null char. Therefore, it has to be copied char by char.
				Exiv2::DataBuf dataBuffer = _exifData.copyThumbnail();
				char* charData = (char*) dataBuffer.pData_;
				long dataLen = dataBuffer.size_;
				// First allocate the memory for the whole string...
				std::string data(dataLen, ' ');
				// ... then fill it with the raw jpeg data.
				for(long i = 0; i < dataLen; ++i)
				{
					data[i] = charData[i];
				}
				return boost::python::make_tuple(format, data);
			}
			else
				throw Exiv2::Error(THUMB_ACCESS);
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	void Image::setThumbnailData(std::string data)
	{
		if(_dataRead)
		{
			const Exiv2::byte* dataBuf = (const Exiv2::byte*) data.c_str();
			_exifData.setJpegThumbnail(dataBuf, data.size());
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	void Image::deleteThumbnail()
	{
		if(_dataRead)
			_exifData.eraseThumbnail();
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	void Image::dumpThumbnailToFile(const std::string path)
	{
		if(_dataRead)
		{
			int result = _exifData.writeThumbnail(path);
			if (result == 8)
				throw Exiv2::Error(NO_THUMBNAIL);
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	void Image::setThumbnailFromJpegFile(const std::string path)
	{
		if(_dataRead)
		{
			_exifData.setJpegThumbnail(path);
		}
		else
			throw Exiv2::Error(METADATA_NOT_READ);
	}

	void translateExiv2Error(Exiv2::Error const& e)
	{
		// Use the Python 'C' API to set up an exception object
		const char* message = e.what().c_str();
		// The type of the Python exception depends on the error code
		// Warning: this piece of code should be updated in case the error codes
		// defined by Exiv2 (file 'src/error.cpp') are changed
		switch (e.code())
		{
			case -2:
			case -1:
			case 1:
			case 2:
				PyErr_SetString(PyExc_RuntimeError, message);
				break;
			case 3:
			case 9:
			case 10:
			case 11:
			case 12:
			case 13:
			case 14:
			case 15:
			case 17:
			case 18:
			case 20:
			case 21:
			case 23:
			case 31:
			case 32:
			case 33:
			case 36:
			case 37:
				PyErr_SetString(PyExc_IOError, message);
				break;
			case 6:
			case 7:
				PyErr_SetString(PyExc_KeyError, message);
				break;
			case 4:
			case 5:
			case 8:
			case 22:
			case 24:
			case 25:
			case 26:
			case 27:
			case 28:
			case 29:
			case 30:
			case 34:
				PyErr_SetString(PyExc_ValueError, message);
				break;
			case 16:
			case 19:
			case 35:
				PyErr_SetString(PyExc_MemoryError, message);
				break;

			// custom error codes
			case METADATA_NOT_READ:
				PyErr_SetString(PyExc_IOError, "Image metadata has not been read yet");
				break;
			case NON_REPEATABLE:
				PyErr_SetString(PyExc_KeyError, "Tag is not repeatable");
				break;
			case KEY_NOT_FOUND:
				PyErr_SetString(PyExc_ValueError, "Tag not set");
				break;
			case THUMB_ACCESS:
				PyErr_SetString(PyExc_IOError, "Cannot access image thumbnail");
				break;
			case NO_THUMBNAIL:
				PyErr_SetString(PyExc_IOError, "The EXIF data does not contain a thumbnail");
				break;

			default:
				PyErr_SetString(PyExc_RuntimeError, message);
		}
	}

} // End of namespace LibPyExiv2