Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
make
.swp
.git
.user
1 change: 1 addition & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This project depends on the following dynamically linked libraries:

* qt5
* libexif
* libheif

### OSX

Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ all: build

.PHONY: install-deps-deb
install-deps-deb:
apt install qt5-qmake libexif12 qt5-default libexif-dev qt5-image-formats-plugins
apt install qt5-qmake libexif12 qt5-default libexif-dev qt5-image-formats-plugins libheif1 libheif-dev cmake

check-deps-deb:
dpkg -l | grep qt5-qmake
dpkg -l | grep libexif12
dpkg -l | grep libexif-dev
dpkg -l | grep qt5-default
dpkg -l | grep qt5-image-formats-plugins
dpkg -l | grep libheif1
dpkg -l | grep libheif-dev
dpkg -l | grep cmake

.PHONY: clean
clean:
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ slide [-t rotation_seconds] [-o background_opacity(0..255)] [-b blur_radius] -p
* qt5-image-formats-plugins
* libexif

## if *.heic support wanted
* libheif
* qt-heif-image-plugin (alas is not a part of Qt jet, have to be compiled, see instuctions below)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* qt-heif-image-plugin (alas is not a part of Qt jet, have to be compiled, see instuctions below)
* qt-heif-image-plugin (alas is not a part of Qt yet, have to be compiled, see instuctions below)

* cmake

Ubuntu/Raspbian:

```
Expand All @@ -75,6 +80,18 @@ Install binaries
```
sudo make install
```
Build Qt plugin for *.heic (Iphone) files

```
git clone https://github.com/jakar/qt-heif-image-plugin.git
cd qt-heif-image-plugin
mkdir -p build
cd build
cmake ..
make
sudo make install
```

Comment on lines +83 to +94
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary only to compile from source or as well to just run it? Can I use slide without heic support if I leave this out?


### macOS

Expand Down
249 changes: 249 additions & 0 deletions src/exifhelper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
#include "exifhelper.h"
#include <QVariant>
#include <QDateTime>
#include <QLocale>
#include <QFileInfo>
#include <stdlib.h>
#include <iostream>
#include <libheif/heif_cxx.h>

ExifHelper::ExifHelper():
m_exifData(NULL),
m_isHeif(false)
{

}
ExifHelper::~ExifHelper(){
if(m_exifData)
exif_data_free(m_exifData);
}

void ExifHelper::setImage(const std::string path){
m_path=path.c_str();
if(m_exifData){
exif_data_free(m_exifData);
}
if(isHeif(path)){
m_exifData=getExifDataFromHeif(path);
m_isHeif=true;
}else{
m_exifData=exif_data_new_from_file(path.c_str());
m_isHeif=false;
}

if(m_exifData){
m_byteOrder=exif_data_get_byte_order(m_exifData);
}
}

ExifData *ExifHelper::getExifData(){
return(m_exifData);
}

int ExifHelper::getImageRotation()
{
if(m_isHeif) return 0; //if not, heic image will be rotated 2 times, courtesy of libheif?
int orientation = 0;
if (m_exifData)
{
ExifEntry *exifEntry = exif_data_get_entry(m_exifData, EXIF_TAG_ORIENTATION);

if (exifEntry)
{
orientation = exif_get_short(exifEntry->data, m_byteOrder);
// std::cout << m_path.toStdString() << " orientation " << orientation<< "\n";
}
}

int degrees = 0;
switch(orientation) {
case 8:
degrees = 270;
break;
case 3:
degrees = 180;
break;
case 6:
degrees = 90;
break;
}

return degrees;
}



const QString ExifHelper::getImageInfo(){
QString txt("Path: ");
txt=txt+m_path+"\n";
if (m_exifData)
{

txt=txt+"XxY: "+getExifXDimension()+"x"+getExifYDimension()+"\n";
txt=txt+"XxY resolution: "+getExifXResolution()+"x"+getExifYResolution()+"\n";
txt=txt+"date: "+getExifDate()+"\n";
txt=txt+"camera: "+getExifCamera()+"\n";
txt=txt+getExifGPS();

}else{
txt=txt+"No exif data found :(";
}

return(txt);
}

const QString ExifHelper::getExifXResolution(){
QString txt("");
if(m_exifData){
ExifEntry *exifEntry = exif_data_get_entry(m_exifData, EXIF_TAG_X_RESOLUTION);
if (exifEntry)
{
txt=txt+QString::number(exif_get_long(exifEntry->data, m_byteOrder));
}
}
return txt;
}


const QString ExifHelper::getExifYResolution(){
QString txt("");
if(m_exifData){
ExifEntry *exifEntry = exif_data_get_entry(m_exifData, EXIF_TAG_Y_RESOLUTION);
if (exifEntry)
{
txt=txt+QString::number(exif_get_long(exifEntry->data, m_byteOrder));
}
}
return txt;
}

const QString ExifHelper::getExifXDimension(){
QString txt("");
if(m_exifData){
ExifEntry *exifEntry = exif_data_get_entry(m_exifData, EXIF_TAG_PIXEL_X_DIMENSION);
if (exifEntry)
{
txt=txt+QString::number(exif_get_long(exifEntry->data, m_byteOrder));
}
}
return txt;
}

const QString ExifHelper::getExifYDimension(){
QString txt("");
if(m_exifData){
ExifEntry *exifEntry = exif_data_get_entry(m_exifData, EXIF_TAG_PIXEL_Y_DIMENSION);
if (exifEntry)
{
txt=txt+QString::number(exif_get_long(exifEntry->data, m_byteOrder));
}
}
return txt;
}

const QString ExifHelper::getExifDate(){
QString dateTime;
if (m_exifData)
{
ExifEntry *exifEntry = exif_data_get_entry(m_exifData, EXIF_TAG_DATE_TIME_ORIGINAL);
if (exifEntry)
{
dateTime = getExifAscii(exifEntry);
}
QString exifDateFormat = "yyyy:MM:dd hh:mm:ss";
QDateTime exifDateTime = QDateTime::fromString(dateTime, exifDateFormat);
return QLocale::system().toString(exifDateTime);
}
return dateTime;
}

const QString ExifHelper::getExifGPS(){
QString txt("");
if(m_exifData){
ExifEntry *exifEntry = exif_content_get_entry(m_exifData->ifd[EXIF_IFD_GPS], (ExifTag)EXIF_TAG_GPS_LATITUDE_REF);
if(exifEntry)
{
//txt=txt+" "+((getExifAscii(exifEntry)[0]=='N')?"+":"-");
txt=txt+getExifAscii(exifEntry)+" ";
}
exifEntry = exif_content_get_entry(m_exifData->ifd[EXIF_IFD_GPS], (ExifTag)EXIF_TAG_GPS_LATITUDE);
if(exifEntry){
txt=txt+QString::number(getExifGeoCooValue(exifEntry->data,m_byteOrder),'f',4)+"°; ";
}
exifEntry = exif_content_get_entry(m_exifData->ifd[EXIF_IFD_GPS], (ExifTag)EXIF_TAG_GPS_LONGITUDE_REF);
if(exifEntry){
//txt=txt+" "+((getExifAscii(exifEntry)[0]=='E')?"+":"-");
txt=txt+" "+getExifAscii(exifEntry)+" ";
}
exifEntry = exif_content_get_entry(m_exifData->ifd[EXIF_IFD_GPS], (ExifTag)EXIF_TAG_GPS_LONGITUDE);
if(exifEntry){
txt=txt+QString::number(getExifGeoCooValue(exifEntry->data,m_byteOrder),'f',4)+"°; ";
}
exifEntry = exif_content_get_entry(m_exifData->ifd[EXIF_IFD_GPS], (ExifTag)EXIF_TAG_GPS_ALTITUDE);
if(exifEntry){
txt=txt+QString::number(getExifRationalValue(exifEntry->data,m_byteOrder),'f',2);
}
exifEntry = exif_content_get_entry(m_exifData->ifd[EXIF_IFD_GPS], (ExifTag)EXIF_TAG_GPS_ALTITUDE_REF);
if(exifEntry){
if(*(exifEntry->data)==0)
{
txt=txt+"m ASL"; //Meters Above Sea Level
}else{
txt=txt+"m BSL"; //Meters Below Sea Level?
}
}
}
return txt;
}

const QString ExifHelper::getExifCamera(){
QString txt("");
if(m_exifData){
ExifEntry *exifEntry = exif_data_get_entry(m_exifData, EXIF_TAG_MAKE);
if (exifEntry)
{
txt=txt+getExifAscii(exifEntry).toUpper()+", ";
}
exifEntry = exif_data_get_entry(m_exifData, EXIF_TAG_MODEL);
if (exifEntry)
{
txt=txt+getExifAscii(exifEntry);
}
}
return txt;
}

const QString ExifHelper::getExifAscii(ExifEntry *e){
char data[e->size];
strncpy(data,(char*)e->data,e->size);
return QVariant(data).toString();
}
double ExifHelper::getExifRationalValue(const unsigned char *e, ExifByteOrder o){
ExifRational r(exif_get_rational(e,o));
return (r.numerator/(double)r.denominator);
}
double ExifHelper::getExifGeoCooValue(const unsigned char *e, ExifByteOrder o){
return( getExifRationalValue(e,o)+
getExifRationalValue(e+sizeof(ExifRational),o)/60+
getExifRationalValue(e+2*sizeof(ExifRational),o)/3600
);
}

bool ExifHelper::isHeif(const std::string path){
//TODO use libheif method heif_check_filetype(), as soon as raspi has libheif version =>1.4
QFileInfo fileInfo(path.c_str());
if(fileInfo.suffix().toLower()=="heic") return true;
return false;
}

ExifData* ExifHelper::getExifDataFromHeif(const std::string path){
heif::Context ctx;
ctx.read_from_file(path);
heif::ImageHandle handle(ctx.get_primary_image_handle());
std::vector<heif_item_id> ids(handle.get_list_of_metadata_block_IDs("Exif"));
if(ids.empty()) return NULL;
std::vector<uint8_t> data(handle.get_metadata(ids[0]));
const unsigned char *p(&data[4]); //first 4 bytes apparently offset to tiff data
ExifData *ptr(exif_data_new_from_data(p,data.size()-4));
return ptr;
}
40 changes: 40 additions & 0 deletions src/exifhelper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef EXIFHELPER_H
#define EXIFHELPER_H

#include <libexif/exif-data.h>
#include <QString>


class ExifHelper
{
public:
ExifHelper();
virtual ~ExifHelper();

void setImage(const std::string path);
ExifData *getExifData();
int getImageRotation();
const QString getImageInfo();
const QString getExifXResolution();
const QString getExifYResolution();
const QString getExifXDimension();
const QString getExifYDimension();
const QString getExifDate();
const QString getExifGPS();
const QString getExifCamera();

private:
bool isHeif(const std::string path);
ExifData * getExifDataFromHeif(const std::string path);
const QString getExifAscii(ExifEntry *e);
double getExifRationalValue(const unsigned char *e, ExifByteOrder o);
double getExifGeoCooValue(const unsigned char *e, ExifByteOrder o);

ExifData *m_exifData;
bool m_isHeif;
ExifByteOrder m_byteOrder;
QString m_path;

};

#endif // EXIFHELPER_H
Loading