1281 lines
32 KiB
C++
1281 lines
32 KiB
C++
/*
|
|
//paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}]
|
|
//paragraph [10] Footnote: [{\footnote{] [}}]
|
|
//[ue] [\"{u}]
|
|
//[ae] [\"{a}]
|
|
//[TOC] [\tableofcontents]
|
|
|
|
[1] Picture Algebra: Class Definitions
|
|
|
|
Dezember 2004 Christian Bohnbuck, Uwe Hartmann, Marion Langen and Holger
|
|
M[ue]nx during Prof. G[ue]ting's practical course
|
|
'Extensible Database Systems' at Fernuniversit[ae]t Hagen.
|
|
|
|
March 2005, M. Spiekermann. Function strtupr renamed to xstrtupr
|
|
since a name conflict with /mingw/include/string.h must be resolved.
|
|
|
|
December 2005, Victor Almeida deleted the deprecated algebra levels
|
|
(~executable~, ~descriptive~, and ~hibrid~). Only the executable
|
|
level remains. Models are also removed from type constructors.
|
|
|
|
[TOC]
|
|
|
|
1 Introduction
|
|
|
|
See the documentation of ~PictureAlgebra.h~ for a general introduction to
|
|
the Picture algebra.
|
|
|
|
This module contains all methods required for ~Picture~
|
|
to represent a SECONDO ~picture~ object plus functions required by
|
|
SECONDO to use ~Picture~ plus basic SECONDO operators on ~picture~.
|
|
|
|
2 Includes and other preparations
|
|
|
|
*/
|
|
|
|
|
|
#include <unistd.h>
|
|
#include <fstream>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#include "Algebra.h"
|
|
#include "QueryProcessor.h"
|
|
#include "StandardTypes.h"
|
|
#include "Symbols.h"
|
|
#include "NestedList.h"
|
|
#include "Base64.h"
|
|
|
|
#include "PictureAlgebra.h"
|
|
#include "JPEGPicture.h"
|
|
#include "ImageConverter.h"
|
|
|
|
#include "DateTime.h"
|
|
#include "LogMsg.h"
|
|
#include "../../Tools/Flob/Flob.h"
|
|
#include "StringUtils.h"
|
|
|
|
#include "Algebras/FText/FTextAlgebra.h"
|
|
#include "ListUtils.h"
|
|
|
|
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <ctime>
|
|
#include <sstream>
|
|
#include <array>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
extern NestedList* nl;
|
|
extern QueryProcessor *qp;
|
|
|
|
using namespace datetime;
|
|
|
|
/*
|
|
|
|
Helper function to convert a string to upper case.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void xstrupr(char *str)
|
|
{
|
|
size_t i,len;
|
|
|
|
len = strlen(str);
|
|
for (i=0; i < len; ++i)
|
|
{
|
|
str[i] = toupper(str[i]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
3 Implementation of class ~Picture~
|
|
|
|
Please note that other methods are located in other modules of this
|
|
algebra!
|
|
|
|
See the documentation of ~PictureAlgebra.h~ for details on the behaviour
|
|
of the methods implemented here.
|
|
|
|
3.1 Constructors and destructor
|
|
|
|
*/
|
|
|
|
Picture::Picture(string imgdataB64,
|
|
string fn,
|
|
string cat,
|
|
bool isp,
|
|
string dt,
|
|
bool autoPortrait) : Attribute(true),jpegData(0) {
|
|
if (PA_DEBUG) cerr << "Picture::Picture()-1 called" << endl;
|
|
|
|
strcpy(filename, fn.c_str());
|
|
strcpy(category, cat.c_str());
|
|
strcpy(date, dt.c_str());
|
|
isPortrait = isp;
|
|
SetDefined(true);
|
|
|
|
if (PA_DEBUG) {
|
|
cerr << "Picture::Picture()-1 imgdataBase64.length()="
|
|
<< imgdataB64.length()
|
|
<< endl;
|
|
cerr << "Picture::Picture()-1 filename="
|
|
<< filename
|
|
<< endl;
|
|
cerr << "Picture::Picture()-1 category="
|
|
<< category
|
|
<< endl;
|
|
cerr << "Picture::Picture()-1 date="
|
|
<< date
|
|
<< endl;
|
|
cerr << "Picture::Picture()-1 isPortrait="
|
|
<< isPortrait
|
|
<< endl;
|
|
}
|
|
|
|
Base64 b64;
|
|
|
|
unsigned long size = b64.sizeDecoded(imgdataB64.size());
|
|
char* imgdata = new char[size];
|
|
unsigned long len = b64.decode(imgdataB64, imgdata);
|
|
|
|
if (PA_DEBUG) {
|
|
cerr << "Picture::Picture()-1 size=" << size << endl;
|
|
cerr << "Picture::Picture()-1 len=" << len << endl;
|
|
}
|
|
|
|
assert( len <= size );
|
|
|
|
STRING_T name;
|
|
CImageConverter *converter;
|
|
ImageType imgType;
|
|
|
|
strcpy(name, filename);
|
|
xstrupr(name);
|
|
|
|
if (PA_DEBUG) cerr << "Picture::Picture() upper value " << name << endl;
|
|
|
|
if (strstr(name, ".JPG")) {
|
|
if (PA_DEBUG)
|
|
cerr << "Picture::Picture() JPEG Format detected" << endl;
|
|
|
|
imgType = IMAGE_JPEG;
|
|
} else if (strstr(name, ".TGA")) {
|
|
if (PA_DEBUG)
|
|
cerr << "Picture::Picture() TGA Format detected" << endl;
|
|
|
|
imgType = IMAGE_TGA;
|
|
} else if (strstr(name, ".PCX")) {
|
|
if (PA_DEBUG)
|
|
cerr << "Picture::Picture() PCX Format detected" << endl;
|
|
|
|
imgType = IMAGE_PCX;
|
|
} else if (strstr(name, ".BMP")) {
|
|
if (PA_DEBUG)
|
|
cerr << "Picture::Picture() Bitmap Format detected" << endl;
|
|
|
|
imgType = IMAGE_BMP;
|
|
} else {
|
|
if (PA_DEBUG)
|
|
cerr << "Picture::Picture() unknown image format: "
|
|
<< filename
|
|
<< endl;
|
|
|
|
delete[] imgdata;
|
|
jpegData.clean();
|
|
SetDefined(false);
|
|
return;
|
|
}
|
|
|
|
if (imgType != IMAGE_JPEG) {
|
|
converter =
|
|
new CImageConverter(imgType,
|
|
(unsigned char*)imgdata,
|
|
(unsigned long)size);
|
|
|
|
if (!converter->Defined()) {
|
|
if (PA_DEBUG)
|
|
cerr << "Picture::Picture() cannot read image: "
|
|
<< filename
|
|
<< endl;
|
|
delete[] imgdata;
|
|
jpegData.clean();
|
|
SetDefined(false);
|
|
return;
|
|
} else {
|
|
delete[] imgdata;
|
|
|
|
// generate jpeg data
|
|
imgdata = (char*)converter->GetJpegData(len);
|
|
|
|
strcat(filename, ".JPG");
|
|
|
|
if (PA_DEBUG)
|
|
cerr << "Picture::Picture() image converted, size: "
|
|
<< len
|
|
<< endl;
|
|
}
|
|
|
|
delete converter;
|
|
}
|
|
|
|
jpegData.resize(len);
|
|
jpegData.write(imgdata, len);
|
|
|
|
//if (PA_DEBUG)
|
|
// cerr << "Picture::Picture()-1 jpegData="
|
|
// << (unsigned int) jpegData
|
|
// << endl;
|
|
|
|
|
|
|
|
createHistograms(imgdata, len);
|
|
if(autoPortrait){
|
|
isPortrait = GetWidth() < GetHeight();
|
|
}
|
|
|
|
|
|
delete[] imgdata;
|
|
|
|
if (PA_DEBUG) cerr << "Picture::Picture()-1 done" << endl;
|
|
}
|
|
|
|
Picture::Picture(char* imgdata,
|
|
unsigned long size,
|
|
string fn,
|
|
string cat,
|
|
bool isp,
|
|
string dt) : Attribute(true),jpegData(0) {
|
|
if (PA_DEBUG) cerr << "Picture::Picture()-2 called" << endl;
|
|
|
|
Set(imgdata, size, fn, cat, isp, dt);
|
|
|
|
if (PA_DEBUG) cerr << "Picture::Picture()-2 done" << endl;
|
|
}
|
|
|
|
Picture::~Picture(void) {
|
|
if (PA_DEBUG) cerr << "Picture::~Picture() called" << endl;
|
|
|
|
//if (PA_DEBUG)
|
|
// cerr << "Picture::~Picture() jpegData="
|
|
// << (unsigned int) jpegData
|
|
// << endl;
|
|
|
|
if (PA_DEBUG) cerr << "Picture::~Picture() done" << endl;
|
|
}
|
|
|
|
/*
|
|
|
|
3.2 Pre-calculate histograms
|
|
|
|
*/
|
|
|
|
void Picture::createHistograms(char* imgdata, unsigned long size) {
|
|
if (PA_DEBUG) cerr << "Picture::createHistograms called" << endl;
|
|
|
|
JPEGPicture rgb( (unsigned char *) imgdata, size );
|
|
|
|
unsigned long int rgbSize;
|
|
unsigned char * rgbData = rgb.GetImageData( rgbSize );
|
|
|
|
double maxValue = 0.0;
|
|
|
|
// store picture attributes
|
|
width = JPEGPicture::GetWidth((unsigned char*)imgdata, size);
|
|
height = JPEGPicture::GetHeight((unsigned char*)imgdata, size);
|
|
isGrayscale = JPEGPicture::IsGrayScale((unsigned char*)imgdata, size);
|
|
|
|
const unsigned int numOfPixels = rgbSize/3;
|
|
if ( !( (3 * numOfPixels) == rgbSize ))
|
|
{
|
|
cerr << "height: " << height << endl;
|
|
cerr << "width: " << width << endl;
|
|
cerr << "rgbSize: " << rgbSize << endl;
|
|
}
|
|
//assert( numOfPixels == (height*width) );
|
|
const double relFactor = 100.0 * 1.0 / (double)numOfPixels;
|
|
|
|
// compute percentage values
|
|
|
|
for (int i=HC_RED; i<=HC_BRIGHTNESS; i++)
|
|
{
|
|
histogram[i] = Histogram( rgbData, rgbSize, (HistogramChannel)i );
|
|
if ( histogram[i].GetHistogramMaxValue() > maxValue )
|
|
maxValue = histogram[i].GetHistogramMaxValue();
|
|
histogram[i].SetHistogramMaxValue( maxValue );
|
|
histogram[i].ScaleValues(relFactor);
|
|
|
|
if (RTFlag::isActive("PA:histogramCheck")) {
|
|
histogram[i].CheckSum((int)numOfPixels);
|
|
histogram[i].CheckSum(100.0);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
3.3 Accessing image data
|
|
|
|
*/
|
|
|
|
string Picture::GetJPEGBase64Data(void) {
|
|
if (PA_DEBUG) cerr << "Picture::GetJPEGBase64Data() called" << endl;
|
|
|
|
//if (PA_DEBUG)
|
|
// cerr << "Picture::GetJPEGBase64Data() jpegData->Size()="
|
|
// << jpegData->Size()
|
|
// << endl;
|
|
|
|
Base64 b64;
|
|
|
|
unsigned long size;
|
|
char* imgdata = GetJPEGData(size);
|
|
|
|
string res;
|
|
|
|
b64.encode(imgdata, size, res);
|
|
|
|
delete [] imgdata;
|
|
|
|
if (PA_DEBUG)
|
|
cerr << "Picture::GetJPEGBase64Data() res.length()="
|
|
<< res.length()
|
|
<< endl;
|
|
|
|
return res;
|
|
}
|
|
|
|
char* Picture::GetJPEGData(unsigned long& size) const {
|
|
if (PA_DEBUG) cerr << "Picture::GetJPEGData() called" << endl;
|
|
|
|
size = jpegData.getSize();
|
|
char* buf = new char[size];
|
|
jpegData.read(buf, size);
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
|
|
3.4 Setting object value
|
|
|
|
*/
|
|
|
|
void Picture::Set(char* imgdata,
|
|
unsigned long size,
|
|
string fn,
|
|
string cat,
|
|
bool isp,
|
|
string dt) {
|
|
if (PA_DEBUG) cerr << "Picture::Set()-2 called" << endl;
|
|
|
|
strcpy(filename, fn.c_str());
|
|
strcpy(category, cat.c_str());
|
|
strcpy(date, dt.c_str());
|
|
isPortrait = isp;
|
|
SetDefined(true);
|
|
|
|
jpegData.resize(size);
|
|
jpegData.write(imgdata, size);
|
|
|
|
createHistograms(imgdata, size);
|
|
|
|
if (PA_DEBUG) cerr << "Picture::Set()-2 done" << endl;
|
|
}
|
|
|
|
/*
|
|
|
|
3.5 ~Attribute~ implementation
|
|
|
|
*/
|
|
|
|
size_t Picture::HashValue(void) const {
|
|
if (PA_DEBUG) cerr << "Picture::HashValue() called" << endl;
|
|
|
|
if (!IsDefined()) return 0;
|
|
|
|
unsigned long h = 0;
|
|
|
|
string str = filename;
|
|
str += category;
|
|
str += date;
|
|
const char *s = str.c_str();
|
|
while (*s != 0) {
|
|
h = 5*h+*s;
|
|
s++;
|
|
}
|
|
|
|
h = 5*h+(isPortrait ? 1 : 0);
|
|
|
|
unsigned long size;
|
|
char* buf = GetJPEGData(size);
|
|
for (unsigned int i = 0; i < size; i++) h = 5*h+buf[i];
|
|
delete [] buf;
|
|
|
|
return h;
|
|
}
|
|
|
|
void Picture::CopyFrom(const Attribute* attr) {
|
|
if (PA_DEBUG) cerr << "Picture::CopyFrom() called" << endl;
|
|
|
|
const Picture* p = (const Picture*) attr;
|
|
|
|
// copy simple attributes
|
|
|
|
jpegData.clean();
|
|
SetDefined( p->IsDefined());
|
|
|
|
if (IsDefined()) {
|
|
isPortrait = p->isPortrait;
|
|
strcpy(filename, p->filename);
|
|
strcpy(category, p->category);
|
|
strcpy(date, p->date);
|
|
|
|
if (PA_DEBUG)
|
|
cerr << "Picture::CopyFrom() filename" << p->filename << endl;
|
|
|
|
jpegData.copyFrom(p->jpegData);
|
|
memcpy((void*)histogram,(void*) p->histogram, sizeof(histogram));
|
|
}
|
|
}
|
|
|
|
int Picture::Compare(const Attribute* a) const {
|
|
if (PA_DEBUG) cerr << "Picture::Compare() called" << endl;
|
|
|
|
const Picture* p = (const Picture*) a;
|
|
|
|
if (PA_DEBUG) {
|
|
cerr << "Picture::Compare() filename=" << filename << endl;
|
|
cerr << "Picture::Compare() p->filename=" << p->filename << endl;
|
|
}
|
|
|
|
int res = strcmp(filename, p->filename);
|
|
if (res != 0) return res;
|
|
|
|
if (PA_DEBUG) cerr << "Picture::Compare() filename equal" << endl;
|
|
|
|
res = strcmp(category, p->category);
|
|
if (res != 0) return res;
|
|
|
|
if (PA_DEBUG) cerr << "Picture::Compare() category equal" << endl;
|
|
|
|
res = strcmp(date, p->date);
|
|
if (res != 0) return res;
|
|
|
|
if (PA_DEBUG) cerr << "Picture::Compare() date equal" << endl;
|
|
|
|
if (isPortrait && !p->isPortrait) return -1;
|
|
if (!isPortrait && p->isPortrait) return 1;
|
|
|
|
if (PA_DEBUG) cerr << "Picture::Compare() isPortrait equal" << endl;
|
|
|
|
return SimpleCompare(a);
|
|
}
|
|
|
|
Picture* Picture::Clone(void) const {
|
|
if (PA_DEBUG) cerr << "Picture::Clone() called" << endl;
|
|
|
|
Picture* p = new Picture(0);
|
|
|
|
if (PA_DEBUG) cerr << "Picture::Clone() address is " << (void*) p << endl;
|
|
|
|
p->CopyFrom((const Attribute*) this);
|
|
|
|
return p;
|
|
}
|
|
|
|
/*
|
|
|
|
3.6 Methods required for SECONDO operators
|
|
|
|
*/
|
|
|
|
bool Picture::Export(string filename) {
|
|
if (PA_DEBUG) cerr << "Picture::Export() called" << endl;
|
|
|
|
unsigned long size;
|
|
char* buf = GetJPEGData(size);
|
|
|
|
ofstream ofs(filename.c_str(), ios::out|ios::trunc|ios::binary);
|
|
if (!ofs) {
|
|
cerr << "could not create file '" << filename << "'" << endl;
|
|
return false;
|
|
}
|
|
|
|
ofs.write(buf, size);
|
|
ofs.close();
|
|
delete[] buf;
|
|
return true;
|
|
}
|
|
|
|
bool Picture::Display(void) {
|
|
if (PA_DEBUG) cerr << "Picture::Display() called" << endl;
|
|
|
|
#ifndef SECONDO_WIN32
|
|
|
|
static unsigned int fileCtr = 0;
|
|
unsigned long size;
|
|
char* buf = GetJPEGData(size);
|
|
|
|
stringstream fileStr;
|
|
fileStr << "/tmp/SECONDO.PictureAlgebra.";
|
|
fileStr << ++fileCtr;
|
|
|
|
char* filename = strdup(fileStr.str().c_str());
|
|
int fd = mkstemp(filename);
|
|
if (fd < 0) {
|
|
cerr << "could not create temporary file '"
|
|
<< filename
|
|
<< "': "
|
|
<< endl;
|
|
perror("mkstemp");
|
|
free(filename);
|
|
delete[] buf;
|
|
return false;
|
|
}
|
|
|
|
if (PA_DEBUG) cerr << "Picture::Display() temp file " << filename << endl;
|
|
|
|
unsigned int len = write(fd, buf, size);
|
|
if (len != size) {
|
|
cerr << "Picture::Display() could only partially write to temp file '"
|
|
<< filename
|
|
<< "'"
|
|
<< endl;
|
|
unlink(filename);
|
|
free(filename);
|
|
delete[] buf;
|
|
return false;
|
|
}
|
|
|
|
close(fd);
|
|
|
|
string cmd = PROG_DISPLAY;
|
|
cmd += " ";
|
|
cmd += filename;
|
|
|
|
|
|
if(system(cmd.c_str()) != 0){
|
|
cerr << " problem in executing external command " << cmd << endl;
|
|
}
|
|
|
|
if (unlink(filename) < 0) {
|
|
cerr << "Picture::Display() could not remove temporary file '"
|
|
<< filename
|
|
<< "': ";
|
|
perror("unlink");
|
|
free(filename);
|
|
delete[] buf;
|
|
return false;
|
|
}
|
|
|
|
free(filename);
|
|
delete[] buf;
|
|
|
|
#else
|
|
|
|
cerr << "Not yet implemented for win32 systems!" << endl;
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
|
|
3.7 Other methods
|
|
|
|
*/
|
|
|
|
int Picture::SimpleCompare(const Attribute* a) const {
|
|
if (PA_DEBUG) cerr << "Picture::SimpleCompare() called" << endl;
|
|
|
|
const Picture* p = (const Picture*) a;
|
|
|
|
unsigned long size1;
|
|
char* buf1 = GetJPEGData(size1);
|
|
|
|
unsigned long size2;
|
|
char* buf2 = p->GetJPEGData(size2);
|
|
|
|
int size = size1 < size2 ? size1 : size2;
|
|
|
|
int res = memcmp(buf1, buf2, size);
|
|
|
|
delete [] buf1;
|
|
delete [] buf2;
|
|
|
|
if (res != 0)
|
|
return res;
|
|
else if (size1 < size2)
|
|
return -1;
|
|
else if (size1 > size2)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
4 Nested list representation of class ~Picture~
|
|
|
|
*/
|
|
|
|
static ListExpr OutPicture(ListExpr typeInfo, Word value) {
|
|
if (PA_DEBUG) cerr << "OutPicture() called" << endl;
|
|
|
|
Picture* p = (Picture*) value.addr;
|
|
|
|
if (PA_DEBUG) cerr << "OutPicture() #1 p=" << (void*) p << endl;
|
|
if (PA_DEBUG) cerr << "OutPicture() filename=" << p->GetFilename() << endl;
|
|
|
|
if (p->IsDefined()) {
|
|
ListExpr imgdata = nl->TextAtom();
|
|
nl->AppendText(imgdata, p->GetJPEGBase64Data());
|
|
|
|
return
|
|
nl->FiveElemList(
|
|
nl->StringAtom(p->GetFilename()),
|
|
nl->StringAtom(p->GetDate()),
|
|
nl->StringAtom(p->GetCategory()),
|
|
nl->BoolAtom(p->IsPortrait()),
|
|
imgdata);
|
|
} else
|
|
return nl->SymbolAtom(Symbol::UNDEFINED());
|
|
}
|
|
|
|
static Word InPicture(const ListExpr typeInfo,
|
|
const ListExpr instance,
|
|
const int errorPos,
|
|
ListExpr& errorInfo,
|
|
bool& correct) {
|
|
if (PA_DEBUG) cerr << "InPicture() called" << endl;
|
|
|
|
if (nl->ListLength(instance) == 5) {
|
|
if (PA_DEBUG) cerr << "InPicture() list length is correct" << endl;
|
|
|
|
ListExpr filename = nl->First(instance);
|
|
ListExpr date = nl->Second(instance);
|
|
ListExpr category = nl->Third(instance);
|
|
ListExpr isportrait = nl->Fourth(instance);
|
|
ListExpr imgdata = nl->Fifth(instance);
|
|
|
|
if(PA_DEBUG){
|
|
cerr << nl->StringValue(filename) << endl;
|
|
cerr << nl->StringValue(category) << endl;
|
|
cerr << nl->StringValue(date) << endl;
|
|
}
|
|
|
|
if (nl->IsAtom(filename)
|
|
&& nl->AtomType(filename) == StringType
|
|
&& nl->IsAtom(date)
|
|
&& nl->AtomType(date) == StringType
|
|
&& nl->IsAtom(isportrait)
|
|
&& nl->AtomType(category) == StringType
|
|
&& nl->IsAtom(isportrait)
|
|
&& ( (nl->AtomType(isportrait) == BoolType)
|
|
|| nl->IsEqual(isportrait,"auto"))
|
|
&& nl->IsAtom(imgdata)
|
|
&& nl->AtomType(imgdata) == TextType) {
|
|
if (PA_DEBUG)
|
|
cerr << "InPicture() list elements are correct" << endl;
|
|
|
|
DateTime dt(instanttype);
|
|
|
|
if (dt.ReadFrom(nl->StringValue(date))) {
|
|
if (PA_DEBUG)
|
|
cerr << "InPicture() date is correct" << endl;
|
|
string imgdataBase64 = "";
|
|
string current;
|
|
TextScanInfo info;
|
|
while (nl->GetNextText(imgdata, current, 72*1000+1000, info)) {
|
|
imgdataBase64 += current;
|
|
if (PA_DEBUG)
|
|
cerr << "InPicture() position="
|
|
<< imgdataBase64.length()
|
|
<< endl;
|
|
}
|
|
|
|
if (PA_DEBUG)
|
|
cerr << "InPicture() imgdataBase64.length()="
|
|
<< imgdataBase64.length()
|
|
<< endl;
|
|
|
|
correct = true;
|
|
bool isp = false;
|
|
bool autoPortrait = false;
|
|
if(nl->AtomType(isportrait)==BoolType){
|
|
isp = nl->BoolValue(isportrait);
|
|
} else {
|
|
autoPortrait = true;
|
|
}
|
|
|
|
Picture* pic =
|
|
new Picture(imgdataBase64,
|
|
nl->StringValue(filename),
|
|
nl->StringValue(category),
|
|
isp,
|
|
nl->StringValue(date),
|
|
autoPortrait);
|
|
if (PA_DEBUG)
|
|
cerr << "InPicture() created picture at "
|
|
<< (void*) pic
|
|
<< endl;
|
|
return SetWord(pic);
|
|
} else
|
|
if (PA_DEBUG)
|
|
cerr << "InPicture() date is not correct" << endl;
|
|
|
|
}
|
|
}
|
|
|
|
correct = false;
|
|
return SetWord(Address(0));
|
|
}
|
|
|
|
/*
|
|
|
|
5 Description Signature Type Constructor of ~Picture~
|
|
|
|
*/
|
|
|
|
static ListExpr PictureProperty(void) {
|
|
return
|
|
nl->TwoElemList(
|
|
nl->FiveElemList(
|
|
nl->StringAtom("Signature"),
|
|
nl->StringAtom("Example Type List"),
|
|
nl->StringAtom("List Rep"),
|
|
nl->StringAtom("Example List"),
|
|
nl->StringAtom("Remarks")),
|
|
nl->FiveElemList(
|
|
nl->StringAtom("-> DATA"),
|
|
nl->StringAtom(Picture::BasicType()),
|
|
nl->StringAtom(
|
|
"(<file> <date> <category> <isportrait> <data> )"),
|
|
nl->StringAtom("n/a"),
|
|
nl->StringAtom("<date> is in instant format.")));
|
|
}
|
|
|
|
/*
|
|
|
|
6 Persistant storage of ~Picture~
|
|
|
|
*/
|
|
|
|
static Word CreatePicture(const ListExpr typeInfo) {
|
|
if (PA_DEBUG) cerr << "CreatePicture() called" << endl;
|
|
|
|
Picture* p = new Picture(false);
|
|
if (PA_DEBUG) cerr << "CreatePicture() address is " << (void*) p << endl;
|
|
return SetWord(p);
|
|
}
|
|
|
|
static void DeletePicture(const ListExpr typeInfo, Word& w) {
|
|
if (PA_DEBUG)
|
|
cerr << "DeletePicture() called for "
|
|
<< (void*) w.addr
|
|
<< endl;
|
|
|
|
delete (Picture*) w.addr;
|
|
if (PA_DEBUG) cerr << "DeletePicture() #2" << endl;
|
|
w.addr = 0;
|
|
if (PA_DEBUG) cerr << "DeletePicture() done" << endl;
|
|
}
|
|
|
|
static void ClosePicture(const ListExpr typeInfo, Word& w) {
|
|
if (PA_DEBUG)
|
|
cerr << "ClosePicture() called for "
|
|
<< (void*) w.addr
|
|
<< endl;
|
|
|
|
delete (Picture*) w.addr;
|
|
if (PA_DEBUG) cerr << "ClosePicture() #1" << endl;
|
|
w.addr = 0;
|
|
if (PA_DEBUG) cerr << "ClosePicture() done" << endl;
|
|
}
|
|
|
|
static Word ClonePicture(const ListExpr typeInfo, const Word& w) {
|
|
if (PA_DEBUG) cerr << "ClonePicture() called" << endl;
|
|
|
|
return SetWord(((Picture*) w.addr)->Clone());
|
|
}
|
|
|
|
static int SizeOfPicture(void) {
|
|
if (PA_DEBUG) cerr << "SizeOfPicture() called" << endl;
|
|
|
|
return sizeof(Picture);
|
|
}
|
|
|
|
static bool OpenPicture(SmiRecord& rec, size_t& offset,
|
|
const ListExpr typeInfo,
|
|
Word& w) {
|
|
if (PA_DEBUG) cerr << "OpenPicture() called" << endl;
|
|
|
|
return OpenAttribute<Picture>(rec, offset, typeInfo,w);
|
|
}
|
|
|
|
static bool SavePicture(SmiRecord& rec, size_t& offset,
|
|
const ListExpr typeInfo,
|
|
Word& w) {
|
|
if (PA_DEBUG) cerr << "SavePicture() called" << endl;
|
|
return SaveAttribute<Picture>(rec, offset, typeInfo, w);
|
|
}
|
|
|
|
/*
|
|
|
|
7 Kind checking of ~Picture~
|
|
|
|
*/
|
|
|
|
static bool CheckPicture(ListExpr type, ListExpr& errorInfo) {
|
|
if (PA_DEBUG) cerr << "CheckPicture() called" << endl;
|
|
return nl->IsEqual(type, Picture::BasicType());
|
|
}
|
|
|
|
/*
|
|
|
|
8 Cast function of ~Picture~
|
|
|
|
*/
|
|
|
|
static void* CastPicture(void* addr) {
|
|
if (PA_DEBUG)
|
|
cerr << "CastPicture() called, addr="
|
|
<< (void*) addr
|
|
<< endl;
|
|
|
|
return new (addr) Picture;
|
|
}
|
|
|
|
/*
|
|
|
|
9 Type constructor of ~Picture~
|
|
|
|
*/
|
|
|
|
TypeConstructor* picture = 0;
|
|
|
|
void initPicture(){
|
|
picture = new TypeConstructor (
|
|
Picture::BasicType(), //name
|
|
PictureProperty, //property function describing
|
|
// signature
|
|
OutPicture, InPicture, //Out and In functions
|
|
0, 0, //SaveToList and RestoreFromList
|
|
// functions
|
|
CreatePicture, DeletePicture, //object creation and deletion
|
|
OpenPicture, SavePicture, //object open and save
|
|
ClosePicture, ClonePicture, //object close and clone
|
|
CastPicture, //cast function
|
|
SizeOfPicture, //sizeof function
|
|
CheckPicture //kind checking function
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
10 Type mapping functions
|
|
|
|
*/
|
|
|
|
ListExpr PictureDateTypeMap(ListExpr args) {
|
|
if (PA_DEBUG) cerr << "PictureDateTypeMap() called" << endl;
|
|
|
|
if (nl->ListLength(args) == 1) {
|
|
if (nl->IsEqual(nl->First(args), Picture::BasicType()))
|
|
return nl->SymbolAtom(Instant::BasicType());
|
|
else {
|
|
string lexpr;
|
|
nl->WriteToString(lexpr, nl->First(args));
|
|
ErrorReporter::ReportError(
|
|
"expected 'picture' argument but received '"+lexpr+"'");
|
|
}
|
|
} else
|
|
ErrorReporter::ReportError(
|
|
"expected one argument but received "
|
|
+stringutils::int2str(nl->ListLength(args)));
|
|
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
|
}
|
|
|
|
|
|
|
|
ListExpr PictureExportTypeMap(ListExpr args) {
|
|
if (PA_DEBUG) cerr << "PictureExportTypeMap() called" << endl;
|
|
|
|
string lexpr;
|
|
|
|
if (nl->ListLength(args) == 2) {
|
|
if (!nl->IsEqual(nl->First(args), Picture::BasicType())) {
|
|
nl->WriteToString(lexpr, nl->First(args));
|
|
ErrorReporter::ReportError(
|
|
"expected 'picture' as first argument but received '"
|
|
+lexpr
|
|
+"'");
|
|
} else if (!nl->IsEqual(nl->Second(args), FText::BasicType())) {
|
|
nl->WriteToString(lexpr, nl->Second(args));
|
|
ErrorReporter::ReportError(
|
|
"expected 'FText' as second argument but received '"
|
|
+lexpr
|
|
+"'");
|
|
} else
|
|
return nl->SymbolAtom(CcBool::BasicType());
|
|
} else
|
|
ErrorReporter::ReportError(
|
|
"expected two arguments but received "
|
|
+stringutils::int2str(nl->ListLength(args)));
|
|
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ListExpr PictureImportpictureTypeMap(ListExpr args) {
|
|
if (PA_DEBUG) cerr << "PicturereadpictureTypeMap() called" << endl;
|
|
|
|
string lexpr;
|
|
|
|
if (nl->ListLength(args) == 1) {
|
|
ListExpr first = nl->First(args);
|
|
if (!FText::checkType(first)) {
|
|
nl->WriteToString(lexpr, nl->First(args));
|
|
ErrorReporter::ReportError(
|
|
"expected text as first argument but received '"
|
|
+lexpr
|
|
+"'");
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
|
}
|
|
}
|
|
else { ErrorReporter::ReportError(
|
|
"expected one argument but received "
|
|
+stringutils::int2str(nl->ListLength(args)));
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
|
|
|
|
|
}
|
|
|
|
|
|
return nl->SymbolAtom(Picture::BasicType());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ListExpr PictureSimpleEqualsTypeMap(ListExpr args) {
|
|
if (PA_DEBUG) cerr << "PictureSimpleEqualTypeMap() called" << endl;
|
|
|
|
string lexpr;
|
|
|
|
if (nl->ListLength(args) == 2) {
|
|
if (!nl->IsEqual(nl->First(args), Picture::BasicType())) {
|
|
nl->WriteToString(lexpr, nl->First(args));
|
|
ErrorReporter::ReportError(
|
|
"expected 'picture' as first argument but received '"
|
|
+lexpr
|
|
+"'");
|
|
} else if (!nl->IsEqual(nl->Second(args), Picture::BasicType())) {
|
|
nl->WriteToString(lexpr, nl->Second(args));
|
|
ErrorReporter::ReportError(
|
|
"expected 'picture' as second argument but received '"
|
|
+lexpr
|
|
+"'");
|
|
} else
|
|
return nl->SymbolAtom(CcBool::BasicType());
|
|
} else
|
|
ErrorReporter::ReportError(
|
|
"expected two arguments but received "
|
|
+stringutils::int2str(nl->ListLength(args)));
|
|
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
|
}
|
|
|
|
/*
|
|
|
|
11 Value mapping functions
|
|
|
|
*/
|
|
|
|
int PictureFilenameValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s) {
|
|
if (PA_DEBUG) cerr << "PictureFilenameValueMap() called" << endl;
|
|
|
|
Picture* p = ((Picture*) args[0].addr);
|
|
|
|
result = qp->ResultStorage(s);
|
|
|
|
if (p->IsDefined())
|
|
((CcString*) result.addr)->Set(true,
|
|
(STRING_T*) p->GetFilename().c_str());
|
|
else
|
|
((CcString*) result.addr)->Set(false, (STRING_T*) "");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int PictureCategoryValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s) {
|
|
if (PA_DEBUG) cerr << "PictureCategoryValueMap() called" << endl;
|
|
|
|
Picture* p = ((Picture*) args[0].addr);
|
|
|
|
result = qp->ResultStorage(s);
|
|
|
|
if (p->IsDefined())
|
|
((CcString*) result.addr)->Set(true,
|
|
(STRING_T*) p->GetCategory().c_str());
|
|
else
|
|
((CcString*) result.addr)->Set(false, (STRING_T*) "");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int PictureDateValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s) {
|
|
if (PA_DEBUG) cerr << "PictureCategoryValueMap() called" << endl;
|
|
|
|
Picture* p = ((Picture*) args[0].addr);
|
|
|
|
result = qp->ResultStorage(s);
|
|
|
|
if (p->IsDefined())
|
|
((DateTime*) result.addr)->ReadFrom(p->GetDate());
|
|
else
|
|
((DateTime*) result.addr)->ReadFrom("undefined");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int PictureIsPortraitValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s) {
|
|
if (PA_DEBUG) cerr << "PictureIsPortraitValueMap() called" << endl;
|
|
|
|
Picture* p = ((Picture*) args[0].addr);
|
|
|
|
result = qp->ResultStorage(s);
|
|
|
|
if (p->IsDefined())
|
|
((CcBool*) result.addr)->Set(true, p->IsPortrait());
|
|
else
|
|
((CcBool*) result.addr)->Set(false, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int PictureDisplayValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s) {
|
|
if (PA_DEBUG) cerr << "PictureDisplayValueMap() called" << endl;
|
|
|
|
Picture* p = (Picture*) args[0].addr;
|
|
|
|
if (PA_DEBUG)
|
|
cerr << "PictureDisplayValueMap() filename"
|
|
<< p->GetFilename()
|
|
<< endl;
|
|
|
|
result = qp->ResultStorage(s);
|
|
|
|
if (p->IsDefined()) {
|
|
((CcBool*) result.addr)->Set(true, p->Display());
|
|
} else
|
|
((CcBool*) result.addr)->Set(false, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int PictureExportValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s) {
|
|
if (PA_DEBUG) cerr << "PictureExportValueMap() called" << endl;
|
|
|
|
Picture* p = (Picture*) args[0].addr;
|
|
FText* str = static_cast<FText*>(args[1].addr);
|
|
string name = str->GetValue();
|
|
|
|
result = qp->ResultStorage(s);
|
|
|
|
if (p->IsDefined())
|
|
((CcBool*) result.addr)->Set(true,
|
|
p->Export(name));
|
|
else
|
|
((CcBool*) result.addr)->Set(false, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int PictureImportpictureValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s) {
|
|
if (PA_DEBUG) cerr << "PictureImportpictureValueMap() called" << endl;
|
|
|
|
FText* str = static_cast<FText*>(args[0].addr);
|
|
result = qp->ResultStorage(s);
|
|
Picture* pic = static_cast<Picture*>( result.addr );
|
|
bool portrait = false;
|
|
string file;
|
|
|
|
|
|
if(!str->IsDefined()){
|
|
pic->SetDefined(false);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
string name = str->GetValue();
|
|
|
|
ifstream in (name.c_str(), ios::binary | ios::in);
|
|
|
|
if(!in){
|
|
pic->SetDefined(false);
|
|
return 0;
|
|
}
|
|
|
|
in.seekg (0, in.end);
|
|
size_t len = in.tellg();
|
|
in.seekg (0, in.beg);
|
|
|
|
char* buffer = new char [len];
|
|
in.read (buffer,len);
|
|
in.close();
|
|
|
|
|
|
std::array<char, 64> buf;
|
|
buf.fill(0);
|
|
time_t rawtime;
|
|
time(&rawtime);
|
|
const auto timeinfo = localtime(&rawtime);
|
|
strftime(buf.data(), sizeof(buf), "%Y-%m-%d-%H:%M:%S", timeinfo);
|
|
std::string timeStr(buf.data());
|
|
|
|
|
|
pic->Set(buffer,len, "unknown","unknown",false,timeStr);
|
|
|
|
int height = (int) pic->GetHeight();
|
|
int width = (int) pic->GetWidth();
|
|
|
|
|
|
|
|
|
|
if (height > width)
|
|
{
|
|
portrait = true;
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t count1 = std::count(name.begin(), name.end(), '/');
|
|
|
|
if (count1 == 0)
|
|
{
|
|
size_t end = name.find_last_of('/');
|
|
size_t lens = 0;
|
|
file = name.substr(lens, end);
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
size_t begin = name.find_first_of('/');
|
|
size_t end = name.find_last_of('/');
|
|
size_t lens = end - begin;
|
|
file = name.substr(lens+1,end);
|
|
}
|
|
|
|
|
|
|
|
pic->Set(buffer,len, file,"unknown",portrait,timeStr);
|
|
|
|
|
|
|
|
|
|
|
|
delete[] buffer;
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int PictureSimpleEqualsValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s) {
|
|
if (PA_DEBUG) cerr << "PictureSimpleEqualsValueMap() called" << endl;
|
|
|
|
Picture* p1 = (Picture*) args[0].addr;
|
|
Picture* p2 = (Picture*) args[1].addr;
|
|
|
|
result = qp->ResultStorage(s);
|
|
|
|
if (p1->IsDefined() && p2->IsDefined())
|
|
((CcBool*) result.addr)->Set(true,
|
|
p1->SimpleCompare((Attribute*) p2) == 0);
|
|
else
|
|
((CcBool*) result.addr)->Set(false, false);
|
|
|
|
return 0;
|
|
}
|
|
|