From ba99f2a78a438151e49057ebc23b53fce032d731 Mon Sep 17 00:00:00 2001 From: Felix Domke Date: Sat, 18 Nov 2006 13:14:57 +0000 Subject: [PATCH] add functions to load&scale pictures and to get exif information --- lib/gdi/Makefile.am | 2 +- lib/gdi/picexif.cpp | 630 +++++++++++++++++++++++++++++++++++++++++++++ lib/gdi/picexif.h | 81 ++++++ lib/gdi/picload.cpp | 535 ++++++++++++++++++++++++++++++++++++++ lib/gdi/picload.h | 11 + lib/python/enigma_python.i | 4 + 6 files changed, 1262 insertions(+), 1 deletion(-) create mode 100644 lib/gdi/picexif.cpp create mode 100644 lib/gdi/picexif.h create mode 100644 lib/gdi/picload.cpp create mode 100644 lib/gdi/picload.h diff --git a/lib/gdi/Makefile.am b/lib/gdi/Makefile.am index d5f7d97..ff688af 100644 --- a/lib/gdi/Makefile.am +++ b/lib/gdi/Makefile.am @@ -5,7 +5,7 @@ noinst_LIBRARIES = libenigma_gdi.a libenigma_gdi_a_SOURCES = \ region.cpp grc.cpp epng.cpp erect.cpp fb.cpp font.cpp font_arabic.cpp gfbdc.cpp \ - glcddc.cpp gpixmap.cpp lcd.cpp gfont.cpp accel.cpp + glcddc.cpp gpixmap.cpp lcd.cpp gfont.cpp accel.cpp picload.cpp picexif.cpp # ati/2dablt.cpp ati/2dcore.cpp ati/ati_core.cpp ati/test.cpp ati/2dutil.cpp diff --git a/lib/gdi/picexif.cpp b/lib/gdi/picexif.cpp new file mode 100644 index 0000000..844673c --- /dev/null +++ b/lib/gdi/picexif.cpp @@ -0,0 +1,630 @@ +#include "picexif.h" + +#define M_SOF0 0xC0 +#define M_SOF1 0xC1 +#define M_SOF2 0xC2 +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 +#define M_EOI 0xD9 +#define M_SOS 0xDA +#define M_JFIF 0xE0 +#define M_EXIF 0xE1 +#define M_COM 0xFE + +#define NUM_FORMATS 12 +#define FMT_BYTE 1 +#define FMT_STRING 2 +#define FMT_USHORT 3 +#define FMT_ULONG 4 +#define FMT_URATIONAL 5 +#define FMT_SBYTE 6 +#define FMT_UNDEFINED 7 +#define FMT_SSHORT 8 +#define FMT_SLONG 9 +#define FMT_SRATIONAL 10 +#define FMT_SINGLE 11 +#define FMT_DOUBLE 12 + +#define TAG_EXIF_VERSION 0x9000 +#define TAG_EXIF_OFFSET 0x8769 +#define TAG_INTEROP_OFFSET 0xa005 +#define TAG_MAKE 0x010F +#define TAG_MODEL 0x0110 +#define TAG_ORIENTATION 0x0112 +#define TAG_XRESOLUTION 0x011A +#define TAG_YRESOLUTION 0x011B +#define TAG_RESOLUTIONUNIT 0x0128 +#define TAG_EXPOSURETIME 0x829A +#define TAG_FNUMBER 0x829D +#define TAG_SHUTTERSPEED 0x9201 +#define TAG_APERTURE 0x9202 +#define TAG_BRIGHTNESS 0x9203 +#define TAG_MAXAPERTURE 0x9205 +#define TAG_FOCALLENGTH 0x920A +#define TAG_DATETIME_ORIGINAL 0x9003 +#define TAG_USERCOMMENT 0x9286 +#define TAG_SUBJECT_DISTANCE 0x9206 +#define TAG_FLASH 0x9209 +#define TAG_FOCALPLANEXRES 0xa20E +#define TAG_FOCALPLANEYRES 0xa20F +#define TAG_FOCALPLANEUNITS 0xa210 +#define TAG_EXIF_IMAGEWIDTH 0xA002 +#define TAG_EXIF_IMAGELENGTH 0xA003 +#define TAG_EXPOSURE_BIAS 0x9204 +#define TAG_WHITEBALANCE 0x9208 +#define TAG_METERING_MODE 0x9207 +#define TAG_EXPOSURE_PROGRAM 0x8822 +#define TAG_ISO_EQUIVALENT 0x8827 +#define TAG_COMPRESSION_LEVEL 0x9102 +#define TAG_THUMBNAIL_OFFSET 0x0201 +#define TAG_THUMBNAIL_LENGTH 0x0202 + + +Cexif::Cexif() +{ +} + +Cexif::~Cexif() +{ + //ClearExif(); +} + +void Cexif::ClearExif() +{ + if(freeinfo) + { + for(int i=0;i= MAX_SECTIONS) + { + strcpy(m_szLastError,"Too many sections in jpg file"); return false; + } + + for (a=0;a<7;a++) + { + marker = fgetc(hFile); + if (marker != 0xff) break; + + if (a >= 6) + { + strcpy(m_szLastError,"too many padding unsigned chars\n"); return false; + } + } + + if (marker == 0xff) + { + strcpy(m_szLastError,"too many padding unsigned chars!"); return false; + } + + Sections[SectionsRead].Type = marker; + + lh = fgetc(hFile); + ll = fgetc(hFile); + + itemlen = (lh << 8) | ll; + + if (itemlen < 2) + { + strcpy(m_szLastError,"invalid marker"); return false; + } + Sections[SectionsRead].Size = itemlen; + + Data = (unsigned char *)malloc(itemlen); + if (Data == NULL) + { + strcpy(m_szLastError,"Could not allocate memory"); return false; + } + Sections[SectionsRead].Data = Data; + + + Data[0] = (unsigned char)lh; + Data[1] = (unsigned char)ll; + + got = fread(Data+2, 1, itemlen-2,hFile); + if (got != itemlen-2) + { + strcpy(m_szLastError,"Premature end of file?"); return false; + } + SectionsRead += 1; + + switch(marker) + { + case M_SOS: + return true; + case M_EOI: + printf("No image in jpeg!\n"); + return false; + case M_COM: + if (HaveCom) + { + free(Sections[--SectionsRead].Data); + Sections[SectionsRead].Data=0; + } + else + { + process_COM(Data, itemlen); + HaveCom = 1; + } + break; + case M_JFIF: + free(Sections[--SectionsRead].Data); + Sections[SectionsRead].Data=0; + break; + case M_EXIF: + if (memcmp(Data+2, "Exif", 4) == 0) + { + m_exifinfo->IsExif = process_EXIF((unsigned char *)Data+2, itemlen); + } + else + { + free(Sections[--SectionsRead].Data); + Sections[SectionsRead].Data=0; + } + break; + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + process_SOFn(Data, marker); + break; + default: + break; + } + } + + fclose(hFile); + return true; +} + +bool Cexif::process_EXIF(unsigned char * CharBuf, unsigned int length) +{ + m_exifinfo->Comments[0] = '\0'; + ExifImageWidth = 0; + + static const unsigned char ExifHeader[] = "Exif\0\0"; + if(memcmp(CharBuf+0, ExifHeader,6)) + { + strcpy(m_szLastError,"Incorrect Exif header"); return false; + } + + if (memcmp(CharBuf+6,"II",2) == 0) MotorolaOrder = 0; + else + { + if (memcmp(CharBuf+6,"MM",2) == 0) MotorolaOrder = 1; + else + { + strcpy(m_szLastError,"Invalid Exif alignment marker."); return false; + } + } + + if (Get16u(CharBuf+8) != 0x2a) + { + strcpy(m_szLastError,"Invalid Exif start (1)"); return false; + } + int FirstOffset = Get32u(CharBuf+10); + if (FirstOffset < 8 || FirstOffset > 16) + { + strcpy(m_szLastError,"Suspicious offset of first IFD value"); return 0; + } + unsigned char * LastExifRefd = CharBuf; + + if (!ProcessExifDir(CharBuf+14, CharBuf+6, length-6, m_exifinfo, &LastExifRefd)) return false; + + if (m_exifinfo->FocalplaneXRes != 0) + m_exifinfo->CCDWidth = (float)(ExifImageWidth * m_exifinfo->FocalplaneUnits / m_exifinfo->FocalplaneXRes); + + return true; +} + +int Cexif::Get16m(void * Short) +{ + return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1]; +} + +int Cexif::Get16u(void * Short) +{ + if (MotorolaOrder) + { + return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1]; + } + else + { + return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0]; + } +} + +long Cexif::Get32s(void * Long) +{ + if (MotorolaOrder) + { + return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16) | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 ); + } + else + { + return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16) | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 ); + } +} + +unsigned long Cexif::Get32u(void * Long) +{ + return (unsigned long)Get32s(Long) & 0xffffffff; +} + +bool Cexif::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, EXIFINFO * const m_exifinfo, unsigned char ** const LastExifRefdP ) +{ + int de, a, NumDirEntries; + unsigned ThumbnailOffset = 0; + unsigned ThumbnailSize = 0; + + NumDirEntries = Get16u(DirStart); + + if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)) + { + strcpy(m_szLastError,"Illegally sized directory"); return 0; + } + + for (de=0;de= NUM_FORMATS) + { + strcpy(m_szLastError,"Illegal format code in EXIF dir"); return 0; + } + + BytesCount = Components * BytesPerFormat[Format]; + + if (BytesCount > 4) + { + unsigned OffsetVal; + OffsetVal = Get32u(DirEntry+8); + if (OffsetVal+BytesCount > ExifLength) + { + strcpy(m_szLastError,"Illegal pointer offset value in EXIF."); return 0; + } + ValuePtr = OffsetBase+OffsetVal; + } + else ValuePtr = DirEntry+8; + + if (*LastExifRefdP < ValuePtr+BytesCount) *LastExifRefdP = ValuePtr+BytesCount; + + switch(Tag) + { + case TAG_MAKE: + strncpy(m_exifinfo->CameraMake, (char*)ValuePtr, 31); + break; + case TAG_MODEL: + strncpy(m_exifinfo->CameraModel, (char*)ValuePtr, 39); + break; + case TAG_EXIF_VERSION: + strncpy(m_exifinfo->Version,(char*)ValuePtr, 4); + break; + case TAG_DATETIME_ORIGINAL: + strncpy(m_exifinfo->DateTime, (char*)ValuePtr, 19); + break; + case TAG_USERCOMMENT: + for (a=BytesCount;;) + { + a--; + if (((char*)ValuePtr)[a] == ' ') ((char*)ValuePtr)[a] = '\0'; + else break; + + if (a == 0) break; + } + + if (memcmp(ValuePtr, "ASCII",5) == 0) + { + for (a=5;a<10;a++) + { + char c; + c = ((char*)ValuePtr)[a]; + if (c != '\0' && c != ' ') + { + strncpy(m_exifinfo->Comments, (char*)ValuePtr+a, 199); + break; + } + } + + } + else strncpy(m_exifinfo->Comments, (char*)ValuePtr, 199); + break; + case TAG_FNUMBER: + m_exifinfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_APERTURE: + case TAG_MAXAPERTURE: + if (m_exifinfo->ApertureFNumber == 0) + { + //m_exifinfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5); + } + break; + case TAG_BRIGHTNESS: + m_exifinfo->Brightness = (float)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_FOCALLENGTH: + m_exifinfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_SUBJECT_DISTANCE: + m_exifinfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_EXPOSURETIME: + m_exifinfo->ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_SHUTTERSPEED: + if (m_exifinfo->ExposureTime == 0) + { + //m_exifinfo->ExposureTime = (float) (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2))); + } + break; + case TAG_FLASH: + if ((int)ConvertAnyFormat(ValuePtr, Format) & 7) strcpy(m_exifinfo->FlashUsed,"fire"); + else strcpy(m_exifinfo->FlashUsed,"not fired"); + break; + case TAG_ORIENTATION: + m_exifinfo->Orient = (int)ConvertAnyFormat(ValuePtr, Format); + switch((int)ConvertAnyFormat(ValuePtr, Format)) + { + case 1: strcpy(m_exifinfo->Orientation,"Top-Left"); break; + case 2: strcpy(m_exifinfo->Orientation,"Top-Right"); break; + case 3: strcpy(m_exifinfo->Orientation,"Bottom-Right"); break; + case 4: strcpy(m_exifinfo->Orientation,"Bottom-Left"); break; + case 5: strcpy(m_exifinfo->Orientation,"Left-Top"); break; + case 6: strcpy(m_exifinfo->Orientation,"Right-Top"); break; + case 7: strcpy(m_exifinfo->Orientation,"Right-Bottom"); break; + case 8: strcpy(m_exifinfo->Orientation,"Left-Bottom"); break; + default: strcpy(m_exifinfo->Orientation,"Undefined rotation value"); + } + break; + case TAG_EXIF_IMAGELENGTH: + case TAG_EXIF_IMAGEWIDTH: + a = (int)ConvertAnyFormat(ValuePtr, Format); + if (ExifImageWidth < a) ExifImageWidth = a; + break; + case TAG_FOCALPLANEXRES: + m_exifinfo->FocalplaneXRes = (float)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_FOCALPLANEYRES: + m_exifinfo->FocalplaneYRes = (float)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_RESOLUTIONUNIT: + switch((int)ConvertAnyFormat(ValuePtr, Format)) + { + case 2: strcpy(m_exifinfo->ResolutionUnit,"inches"); break; + case 3: strcpy(m_exifinfo->ResolutionUnit,"centimeters"); break; + default: strcpy(m_exifinfo->ResolutionUnit,"reserved"); + } + break; + case TAG_FOCALPLANEUNITS: + switch((int)ConvertAnyFormat(ValuePtr, Format)) + { + case 1: m_exifinfo->FocalplaneUnits = 1.0f; break; + case 2: m_exifinfo->FocalplaneUnits = 1.0f; break; + case 3: m_exifinfo->FocalplaneUnits = 0.3937007874f; break; + case 4: m_exifinfo->FocalplaneUnits = 0.03937007874f; break; + case 5: m_exifinfo->FocalplaneUnits = 0.00003937007874f; + } + break; + case TAG_EXPOSURE_BIAS: + m_exifinfo->ExposureBias = (float) ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_WHITEBALANCE: + switch((int)ConvertAnyFormat(ValuePtr, Format)) + { + case 0: strcpy(m_exifinfo->LightSource,"unknown"); break; + case 1: strcpy(m_exifinfo->LightSource,"Daylight"); break; + case 2: strcpy(m_exifinfo->LightSource,"Fluorescent"); break; + case 3: strcpy(m_exifinfo->LightSource,"Tungsten"); break; + case 17: strcpy(m_exifinfo->LightSource,"Standard light A"); break; + case 18: strcpy(m_exifinfo->LightSource,"Standard light B"); break; + case 19: strcpy(m_exifinfo->LightSource,"Standard light C"); break; + case 20: strcpy(m_exifinfo->LightSource,"D55"); break; + case 21: strcpy(m_exifinfo->LightSource,"D65"); break; + case 22: strcpy(m_exifinfo->LightSource,"D75"); break; + default: strcpy(m_exifinfo->LightSource,"other"); break; + } + break; + case TAG_METERING_MODE: + switch((int)ConvertAnyFormat(ValuePtr, Format)) + { + case 0: strcpy(m_exifinfo->MeteringMode,"unknown"); break; + case 1: strcpy(m_exifinfo->MeteringMode,"Average"); break; + case 2: strcpy(m_exifinfo->MeteringMode,"Center-Weighted-Average"); break; + case 3: strcpy(m_exifinfo->MeteringMode,"Spot"); break; + case 4: strcpy(m_exifinfo->MeteringMode,"MultiSpot"); break; + case 5: strcpy(m_exifinfo->MeteringMode,"Pattern"); break; + case 6: strcpy(m_exifinfo->MeteringMode,"Partial"); break; + default: strcpy(m_exifinfo->MeteringMode,"other"); break; + } + break; + case TAG_EXPOSURE_PROGRAM: + switch((int)ConvertAnyFormat(ValuePtr, Format)) + { + case 0: strcpy(m_exifinfo->ExposureProgram,"not defined"); break; + case 1: strcpy(m_exifinfo->ExposureProgram,"Manual"); break; + case 2: strcpy(m_exifinfo->ExposureProgram,"Normal program"); break; + case 3: strcpy(m_exifinfo->ExposureProgram,"Aperture priority"); break; + case 4: strcpy(m_exifinfo->ExposureProgram,"Shutter priority"); break; + case 5: strcpy(m_exifinfo->ExposureProgram,"Creative program"); break; + case 6: strcpy(m_exifinfo->ExposureProgram,"Action program"); break; + case 7: strcpy(m_exifinfo->ExposureProgram,"Portrait mode"); break; + case 8: strcpy(m_exifinfo->ExposureProgram,"Landscape mode"); break; + default: strcpy(m_exifinfo->ExposureProgram,"reserved"); break; + } + break; + case TAG_ISO_EQUIVALENT: + m_exifinfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); + if ( m_exifinfo->ISOequivalent < 50 ) m_exifinfo->ISOequivalent *= 200; + break; + case TAG_COMPRESSION_LEVEL: + m_exifinfo->CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_XRESOLUTION: + m_exifinfo->Xresolution = (float)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_YRESOLUTION: + m_exifinfo->Yresolution = (float)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_THUMBNAIL_OFFSET: + ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_THUMBNAIL_LENGTH: + ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); + break; + } + + if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET) + { + unsigned char * SubdirStart; + SubdirStart = OffsetBase + Get32u(ValuePtr); + if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) + { + strcpy(m_szLastError,"Illegal subdirectory link"); return 0; + } + ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP); + continue; + } + } + + + unsigned char * SubdirStart; + unsigned Offset; + Offset = Get16u(DirStart+2+12*NumDirEntries); + if (Offset) + { + SubdirStart = OffsetBase + Offset; + if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) + { + strcpy(m_szLastError,"Illegal subdirectory link"); return 0; + } + ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP); + } + + if (ThumbnailSize && ThumbnailOffset) + { + if (ThumbnailSize + ThumbnailOffset <= ExifLength) + { + m_exifinfo->ThumbnailPointer = OffsetBase + ThumbnailOffset; + m_exifinfo->ThumbnailSize = ThumbnailSize; + } + } + + return 1; +} + +double Cexif::ConvertAnyFormat(void * ValuePtr, int Format) +{ + double Value = 0; + + switch(Format) + { + case FMT_SBYTE: Value = *(signed char *)ValuePtr; break; + case FMT_BYTE: Value = *(unsigned char *)ValuePtr; break; + case FMT_USHORT: Value = Get16u(ValuePtr); break; + case FMT_ULONG: Value = Get32u(ValuePtr); break; + case FMT_URATIONAL: + case FMT_SRATIONAL: + { + int Num = Get32s(ValuePtr); + int Den = Get32s(4+(char *)ValuePtr); + if (Den == 0) Value = 0; + else Value = (double)Num/Den; + break; + } + case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break; + case FMT_SLONG: Value = Get32s(ValuePtr); break; + case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break; + case FMT_DOUBLE: Value = *(double *)ValuePtr; break; + } + return Value; +} + +void Cexif::process_COM (const unsigned char * Data, int length) +{ + int ch,a; + char Comment[MAX_COMMENT+1]; + int nch=0; + + if (length > MAX_COMMENT) length = MAX_COMMENT; + + for (a=2;a=0x20) || ch == '\n' || ch == '\t') Comment[nch++] = (char)ch; + else Comment[nch++] = '?'; + } + Comment[nch] = '\0'; + strcpy(m_exifinfo->Comments,Comment); +} + +void Cexif::process_SOFn (const unsigned char * Data, int marker) +{ + int data_precision, num_components; + + data_precision = Data[2]; + m_exifinfo->Height = Get16m((void*)(Data+3)); + m_exifinfo->Width = Get16m((void*)(Data+5)); + num_components = Data[7]; + + if (num_components == 3) strcpy(m_exifinfo->IsColor,"yes"); + else strcpy(m_exifinfo->IsColor,"no"); + + m_exifinfo->Process = marker; +} + diff --git a/lib/gdi/picexif.h b/lib/gdi/picexif.h new file mode 100644 index 0000000..cd321d7 --- /dev/null +++ b/lib/gdi/picexif.h @@ -0,0 +1,81 @@ +#ifndef __exif_h__ +#define __exif_h__ + +#include +#include +#include +#include + +#define MAX_COMMENT 1000 +#define MAX_SECTIONS 20 + + +typedef struct tag_ExifInfo { + char Version [5]; + char CameraMake [32]; + char CameraModel [40]; + char DateTime [20]; + char Orientation [20]; + char MeteringMode [30]; + char Comments[MAX_COMMENT]; + char FlashUsed [20]; + char IsColor [5]; + char ResolutionUnit [20]; + char ExposureProgram[30]; + char LightSource [20]; + float Xresolution; + float Yresolution; + float Brightness; + float ExposureTime; + float ExposureBias; + float Distance; + float CCDWidth; //in milimeters + float FocalplaneXRes; + float FocalplaneYRes; + float FocalplaneUnits; + float FocalLength; + float ApertureFNumber; + int Height, Width; + int CompressionLevel; + int ISOequivalent; + int Process; + int Orient; + unsigned char * ThumbnailPointer; + unsigned ThumbnailSize; + bool IsExif; +} EXIFINFO; + +static const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; + +class Cexif +{ + typedef struct tag_Section_t{ + unsigned char* Data; + int Type; + unsigned Size; + } Section_t; +public: + EXIFINFO* m_exifinfo; + char m_szLastError[256]; + Cexif(); + ~Cexif(); + bool DecodeExif(const char *filename); + void ClearExif(); +protected: + bool process_EXIF(unsigned char * CharBuf, unsigned int length); + void process_COM (const unsigned char * Data, int length); + void process_SOFn (const unsigned char * Data, int marker); + int Get16u(void * Short); + int Get16m(void * Short); + long Get32s(void * Long); + unsigned long Get32u(void * Long); + double ConvertAnyFormat(void * ValuePtr, int Format); + bool ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, EXIFINFO * const pInfo, unsigned char ** const LastExifRefdP); + int ExifImageWidth; + int MotorolaOrder; + Section_t Sections[MAX_SECTIONS]; + int SectionsRead; + bool freeinfo; +}; + +#endif// __exif_h__ diff --git a/lib/gdi/picload.cpp b/lib/gdi/picload.cpp new file mode 100644 index 0000000..28a8991 --- /dev/null +++ b/lib/gdi/picload.cpp @@ -0,0 +1,535 @@ +#include "picload.h" +#include "picexif.h" + +#include + +#include +#include +#include +#include + +extern "C" { +#include +//#include "transupp.h" +} +#include + +unsigned char *pic_buffer=NULL; + +static unsigned char *simple_resize(unsigned char * orgin, int ox, int oy, int dx, int dy) +{ + unsigned char *cr, *p, *l; + int i, j, k, ip; + cr = new unsigned char[dx * dy * 3]; + if (cr == NULL) + { + printf("[RESIZE] Error: malloc\n"); + return(orgin); + } + l = cr; + + for (j = 0; j < dy; j++,l += dx * 3) + { + p = orgin + (j * oy / dy * ox * 3); + for (i = 0, k = 0; i < dx; i++, k += 3) + { + ip = i * ox / dx * 3; + l[k] = p[ip]; + l[k+1] = p[ip + 1]; + l[k+2] = p[ip + 2]; + } + } + delete [] orgin; + return(cr); +} + +static unsigned char *color_resize(unsigned char * orgin, int ox, int oy, int dx, int dy) +{ + unsigned char *cr, *p, *q; + int i, j, k, l, xa, xb, ya, yb; + int sq, r, g, b; + cr = new unsigned char[dx * dy * 3]; + if (cr == NULL) + { + printf("[RESIZE] Error: malloc\n"); + return(orgin); + } + p = cr; + + for (j = 0; j < dy; j++) + { + for (i = 0; i < dx; i++, p += 3) + { + xa = i * ox / dx; + ya = j * oy / dy; + xb = (i + 1) * ox / dx; + if (xb >= ox) + xb = ox - 1; + yb = (j + 1) * oy / dy; + if (yb >= oy) + yb = oy - 1; + for (l = ya, r = 0, g = 0, b = 0, sq = 0; l <= yb; l++) + { + q = orgin + ((l * ox + xa) * 3); + for (k = xa; k <= xb; k++, q += 3, sq++) + { + r += q[0]; g += q[1]; b += q[2]; + } + } + p[0] = r / sq; p[1] = g / sq; p[2] = b / sq; + } + } + delete [] orgin; + return(cr); +} + +//------------------------------------------------------------------- + +struct r_jpeg_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf envbuffer; +}; + +void jpeg_cb_error_exit(j_common_ptr cinfo) +{ + struct r_jpeg_error_mgr *mptr; + mptr = (struct r_jpeg_error_mgr *) cinfo->err; + (*cinfo->err->output_message) (cinfo); + longjmp(mptr->envbuffer, 1); +} + +static int jpeg_save(unsigned char *image_buffer, const char * filename, int quality, int image_height, int image_width) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1];/* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + if ((outfile = fopen(filename, "wb")) == NULL) + { + eDebug("[JPEG] can't open %s", filename); + return -1; + } + jpeg_stdio_dest(&cinfo, outfile); + + cinfo.image_width = image_width; + cinfo.image_height = image_height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE ); + jpeg_start_compress(&cinfo, TRUE); + row_stride = image_width * 3; + while (cinfo.next_scanline < cinfo.image_height) + { + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + jpeg_finish_compress(&cinfo); + fclose(outfile); + jpeg_destroy_compress(&cinfo); + return 0; +} + + +static int jpeg_load(const char *filename, int *x, int *y) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_decompress_struct *ciptr = &cinfo; + struct r_jpeg_error_mgr emgr; + FILE *fh; + + if (!(fh = fopen(filename, "rb"))) + return 0; + + ciptr->err = jpeg_std_error(&emgr.pub); + emgr.pub.error_exit = jpeg_cb_error_exit; + if (setjmp(emgr.envbuffer) == 1) + { + jpeg_destroy_decompress(ciptr); + fclose(fh); + return 0; + } + + jpeg_create_decompress(ciptr); + jpeg_stdio_src(ciptr, fh); + jpeg_read_header(ciptr, TRUE); + ciptr->out_color_space = JCS_RGB; + ciptr->scale_denom = 1; + + jpeg_start_decompress(ciptr); + + *x=ciptr->output_width; + *y=ciptr->output_height; + + if(ciptr->output_components == 3) + { + JSAMPLE *lb = (JSAMPLE *)(*ciptr->mem->alloc_small)((j_common_ptr) ciptr, JPOOL_PERMANENT, ciptr->output_width * ciptr->output_components); + pic_buffer = new unsigned char[ciptr->output_height * ciptr->output_width * ciptr->output_components]; + unsigned char *bp = pic_buffer; + + while (ciptr->output_scanline < ciptr->output_height) + { + jpeg_read_scanlines(ciptr, &lb, 1); + memcpy(bp, lb, ciptr->output_width * ciptr->output_components); + bp += ciptr->output_width * ciptr->output_components; + } + } + jpeg_finish_decompress(ciptr); + jpeg_destroy_decompress(ciptr); + fclose(fh); + return 1; +} + +//--------------------------------------------------------------------------------------------- + +#define BMP_TORASTER_OFFSET 10 +#define BMP_SIZE_OFFSET 18 +#define BMP_BPP_OFFSET 28 +#define BMP_RLE_OFFSET 30 +#define BMP_COLOR_OFFSET 54 + +#define fill4B(a) ((4 - ((a) % 4 )) & 0x03) + +static int bmp_load(const char *filename, int *x, int *y) +{ + unsigned char buff[4]; + + int fd = open(filename, O_RDONLY); + if (fd == -1) return 0; + if (lseek(fd, BMP_SIZE_OFFSET, SEEK_SET) == -1) return 0; + read(fd, buff, 4); + *x = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24); + read(fd, buff, 4); + *y = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24); + if (lseek(fd, BMP_TORASTER_OFFSET, SEEK_SET) == -1) return 0; + read(fd, buff, 4); + int raster = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24); + if (lseek(fd, BMP_BPP_OFFSET, SEEK_SET) == -1) return 0; + read(fd, buff, 2); + int bpp = buff[0] + (buff[1] << 8); + + //printf("x=%d, y=%d,bpp=%d\n",*x, *y, bpp); + pic_buffer = new unsigned char[(*x) * (*y) * 3]; + unsigned char *wr_buffer = pic_buffer + (*x) * ((*y) - 1) * 3; + + switch (bpp) + { + case 24: + { + int skip = fill4B((*x) * 3); + lseek(fd, raster, SEEK_SET); + unsigned char c; + for (int i = 0; i < (*y); i++) + { + read(fd, wr_buffer, (*x) * 3); + for (int j = 0; j < (*x) * 3 ; j = j + 3) + { + c = wr_buffer[j]; + wr_buffer[j] = wr_buffer[j + 2]; + wr_buffer[j + 2] = c; + } + if (skip) + read(fd, buff, skip); + wr_buffer -= (*x) * 3; + } + break; + } + default: + return 0; + } + + close(fd); + return 1; +} + +//--------------------------------------------------------------------------------------------- + +static int png_load(const char *filename, int *x, int *y) +{ + static const png_color_16 my_background = {0, 0, 0, 0, 0}; + + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + unsigned int i; + int bit_depth, color_type, interlace_type; + int number_passes, pass; + png_byte * fbptr; + FILE * fh; + + if (!(fh = fopen(filename, "rb"))) return 0; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) + return 0; + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + fclose(fh); + return 0; + } + + if (setjmp(png_ptr->jmpbuf)) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fh); + return 0; + } + + png_init_io(png_ptr, fh); + + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_set_palette_to_rgb(png_ptr); + png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } + + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + png_set_gray_to_rgb(png_ptr); + png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + + if (bit_depth < 8) png_set_packing(png_ptr); + if (bit_depth == 16) png_set_strip_16(png_ptr); + + number_passes = png_set_interlace_handling(png_ptr); + png_read_update_info(png_ptr, info_ptr); + + if (width * 3 != png_get_rowbytes(png_ptr, info_ptr)) + { + eDebug("[PNG] Error processing"); + return 0; + } + + pic_buffer = new unsigned char[width * height * 3]; + *x=width; + *y=height; + + for(pass = 0; pass < number_passes; pass++) + { + fbptr = (png_byte *)pic_buffer; + for (i = 0; i < height; i++, fbptr += width * 3) + png_read_row(png_ptr, fbptr, NULL); + } + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fh); + return 1; +} + +//--------------------------------------------------------------------------------------------- + +PyObject *getExif(const char *filename) +{ + PyObject *list = PyList_New(0); + Cexif *m_exif = new Cexif(); + if(m_exif->DecodeExif(filename)) + { + + if(m_exif->m_exifinfo->IsExif) + { + char tmp[256]; + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->Version)); + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->CameraMake)); + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->CameraModel)); + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->DateTime)); + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->Comments)); + PyList_Append(list, PyString_FromFormat("%d x %d", m_exif->m_exifinfo->Width, m_exif->m_exifinfo->Height)); + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->Orientation)); + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->MeteringMode)); + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->ExposureProgram)); + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->LightSource)); + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->FlashUsed)); + PyList_Append(list, PyString_FromFormat("%d", m_exif->m_exifinfo->CompressionLevel)); + PyList_Append(list, PyString_FromFormat("%d", m_exif->m_exifinfo->ISOequivalent)); + sprintf(tmp, "%.2f", m_exif->m_exifinfo->Xresolution); + PyList_Append(list, PyString_FromString(tmp)); + sprintf(tmp, "%.2f", m_exif->m_exifinfo->Yresolution); + PyList_Append(list, PyString_FromString(tmp)); + PyList_Append(list, PyString_FromString(m_exif->m_exifinfo->ResolutionUnit)); + sprintf(tmp, "%.2f", m_exif->m_exifinfo->Brightness); + PyList_Append(list, PyString_FromString(tmp)); + sprintf(tmp, "%.5f sec.", m_exif->m_exifinfo->ExposureTime); + PyList_Append(list, PyString_FromString(tmp)); + sprintf(tmp, "%.5f", m_exif->m_exifinfo->ExposureBias); + PyList_Append(list, PyString_FromString(tmp)); + sprintf(tmp, "%.5f", m_exif->m_exifinfo->Distance); + PyList_Append(list, PyString_FromString(tmp)); + sprintf(tmp, "%.5f", m_exif->m_exifinfo->CCDWidth); + PyList_Append(list, PyString_FromString(tmp)); + sprintf(tmp, "%.2f", m_exif->m_exifinfo->ApertureFNumber); + PyList_Append(list, PyString_FromString(tmp)); + } + else PyList_Append(list, PyString_FromString(m_exif->m_szLastError)); + + m_exif->ClearExif(); + } + else PyList_Append(list, PyString_FromString(m_exif->m_szLastError)); + + delete m_exif; + + return list; +} + +//--------------------------------------------------------------------------------------------- + +int loadPic(ePtr &result, std::string filename, int w, int h, int aspect, int resize_mode, int rotate, int background, std::string cachefile) +{ + result = 0; + int ox=0, oy=0, imx, imy; + pic_buffer=NULL; + bool cache=false; + + if(cachefile.length()) + { + cache = true; + if(jpeg_load(cachefile.c_str(), &ox, &oy)) + eDebug("[CACHEPIC] x-size=%d, y-size=%d", ox, oy); + } + + if(pic_buffer==NULL) + { + unsigned int pos = filename.find_last_of("."); + if (pos == std::string::npos) + pos = filename.length() - 1; + std::string ext = filename.substr(pos); + std::transform(ext.begin(), ext.end(), ext.begin(), (int(*)(int)) toupper); + if(ext == ".JPEG" || ext == ".JPG") + jpeg_load(filename.c_str(), &ox, &oy); + else if(ext == ".BMP") + bmp_load(filename.c_str(), &ox, &oy); + else if(ext == ".PNG") + png_load(filename.c_str(), &ox, &oy); + else + { + eDebug("[PIC] "); + return 0; + } + + eDebug("[FULLPIC] x-size=%d, y-size=%d", ox, oy); + + if(pic_buffer==NULL) + return 0; + + double aspect_ratio; + switch(aspect) + { + case 1: aspect_ratio = 1.777 / ((double)720/576); break; //16:9 + case 2: aspect_ratio = 1.600 / ((double)720/576); break; //16:10 + //case 3: aspect_ratio = 1.250 / ((double)720/576); break; //5:4 + default: aspect_ratio = 1.333 / ((double)720/576); //4:3 + } + + if((aspect_ratio * oy * w / ox) <= h) + { + imx = w; + imy = (int)(aspect_ratio*oy*w/ox); + } + else + { + imx = (int)((1.0/aspect_ratio)*ox*h/oy); + imy = h; + } + + if(resize_mode) pic_buffer = color_resize(pic_buffer, ox, oy, imx, imy); + else pic_buffer = simple_resize(pic_buffer, ox, oy, imx, imy); + + ox = imx; + oy = imy; + + if(cache) + { + jpeg_save(pic_buffer, cachefile.c_str(), 50, oy, ox); + eDebug("[SAVEPIC] x-size=%d, y-size=%d", ox, oy); + } + + } + + + result=new gPixmap(eSize(w, h), 32); + gSurface *surface = result->surface; + int a=0, b=0; + int nc=0, oc=0; + int o_y=0, u_y=0, v_x=0, h_x=0; + unsigned char clear[4] = {0x00,0x00,0x00,0x00}; + if(background) clear[3]=0xFF; + unsigned char *tmp_buffer = new unsigned char[4]; + + if(oy < h) + { + o_y=(h-oy)/2; + u_y=h-oy-o_y; + } + if(ox < w) + { + v_x=(w-ox)/2; + h_x=w-ox-v_x; + } + + //eDebug("o_y=%d u_y=%d v_x=%d h_x=%d", o_y, u_y, v_x, h_x); + + if(oy < h) + for(a=0; a<(o_y*ox)+1; a++, nc+=4) + { + memcpy(tmp_buffer, clear, sizeof(clear)); + tmp_buffer=((unsigned char *)(surface->data)) + nc; + } + + for(a=0; adata)) + nc; + } + + for(b=0; b<(ox*3); b+=3, nc+=4) + { + tmp_buffer[3]=0xFF; + tmp_buffer[2]=pic_buffer[oc++]; + tmp_buffer[1]=pic_buffer[oc++]; + tmp_buffer[0]=pic_buffer[oc++]; + + tmp_buffer=((unsigned char *)(surface->data)) + nc; + } + + if(ox < w) + for(b=0; bdata)) + nc; + } + } + + if(oy < h) + for(a=0; a<(u_y*ox)+1; a++, nc+=4) + { + memcpy(tmp_buffer, clear, sizeof(clear)); + tmp_buffer=((unsigned char *)(surface->data)) + nc; + } + + //eDebug("[PIC] buffer=%d, nc=%d oc=%d ox=%d, oy=%d",w*h*4, nc, oc, ox, oy); + + surface->clut.data=0; + surface->clut.colors=0; + surface->clut.start=0; + + delete [] pic_buffer; + + return 0; +} diff --git a/lib/gdi/picload.h b/lib/gdi/picload.h new file mode 100644 index 0000000..7d5d8b2 --- /dev/null +++ b/lib/gdi/picload.h @@ -0,0 +1,11 @@ +#ifndef __picload_h__ +#define __picload_h__ + +#include "Python.h" +#include +#include + +SWIG_VOID(int) loadPic(ePtr &SWIG_OUTPUT, std::string filename, int x, int y, int aspect, int resize_mode=0, int rotate=0, int background=0, std::string cachefile=""); +PyObject *getExif(const char *filename); + +#endif // __picload_h__ diff --git a/lib/python/enigma_python.i b/lib/python/enigma_python.i index cb87359..3772a23 100644 --- a/lib/python/enigma_python.i +++ b/lib/python/enigma_python.i @@ -88,6 +88,8 @@ is usually caused by not marking PSignals as immutable. #include #include #include +#include +#include extern void runMainloop(); extern void quitMainloop(int exit_code); @@ -207,6 +209,8 @@ typedef long time_t; %include %include %include +%include +%include /************** eptr **************/ %template(eActionMapPtr) ePtr; -- 2.7.4