winix/core/image.cpp

416 lines
7.9 KiB
C++
Raw Normal View History

/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010-2011, Tomasz Sowa
* All rights reserved.
*
*/
#include <ctime>
#include "image.h"
#include "utf8.h"
#include "log.h"
#include "system.h"
#include "plugin.h"
void Image::SetDb(Db * pdb)
{
db = pdb;
}
void Image::SetConfig(Config * pconfig)
{
config = pconfig;
}
void Image::SetSystem(System * psystem)
{
system = psystem;
}
// first thread (objects locked)
void Image::Resize(const Item & item, size_t cx, size_t cy, int aspect_mode, int quality)
{
item_temp.type = WINIX_IMAGE_TYPE_RESIZE;
item_temp.file = item;
item_temp.cx = cx;
item_temp.cy = cy;
item_temp.aspect_mode = aspect_mode;
item_temp.quality = quality;
CheckParam(item_temp);
image_tab.insert(image_tab.end(), item_temp);
WakeUpThread();
}
// first thread (objects locked)
void Image::CreateThumb(const Item & item, size_t cx, size_t cy, int aspect_mode, int quality)
{
item_temp.type = WINIX_IMAGE_TYPE_CREATE_THUMB;
item_temp.file = item;
item_temp.cx = cx;
item_temp.cy = cy;
item_temp.aspect_mode = aspect_mode;
item_temp.quality = quality;
CheckParam(item_temp);
image_tab.insert(image_tab.end(), item_temp);
WakeUpThread();
}
void Image::CheckParam(ImageItem & item)
{
if( item.aspect_mode < 1 )
item.aspect_mode = 1;
if( item.aspect_mode > 7 )
item.aspect_mode = 7;
if( item.quality < 0 )
item.quality = 0;
if( item.quality > 100 )
item.quality = 100;
if( item_temp.cx < 5 )
item_temp.cx = 5;
if( item_temp.cy < 5 )
item_temp.cy = 5;
if( item_temp.cx > 10000 )
item_temp.cx = 10000;
if( item_temp.cy > 10000 )
item_temp.cy = 10000;
}
// second thread (objects locked)
bool Image::SignalReceived()
{
return !image_tab.empty();
}
// second thread (objects not locked)
void Image::Do()
{
ImageTab::iterator i;
bool end;
Lock();
i = image_tab.begin();
Unlock();
do
{
Lock();
if( i != image_tab.end() )
{
item_work = *i;
image_tab.erase(i++);
end = false;
}
else
{
end = true;
}
Unlock();
if( !end )
CreateImage();
}
while( !end && !IsExitSignal() );
}
void Image::Add(const std::wstring & in, TextStream<std::string> & out)
{
Ezc::WideToUTF8(in, add_tempa);
out << add_tempa;
}
void Image::EscapePath(const std::string & path, TextStream<std::string> & out, bool clear_stream)
{
if( clear_stream )
out.Clear();
out << '"';
for(size_t i=0 ; i<path.size() ; ++i)
{
if( path[i] == '"' )
out << '\\';
out << path[i];
}
out << '\"';
}
/*
from: http://www.imagemagick.org/script/command-line-processing.php#geometry
scale% Height and width both scaled by specified percentage.
scale-x%xscale-y% Height and width individually scaled by specified percentages. (Only one % symbol needed.)
width Width given, height automagically selected to preserve aspect ratio.
xheight Height given, width automagically selected to preserve aspect ratio.
widthxheight Maximum values of height and width given, aspect ratio preserved.
widthxheight^ Minimum values of width and height given, aspect ratio preserved.
widthxheight! Width and height emphatically given, original aspect ratio ignored.
widthxheight> Change as per widthxheight but only if an image dimension exceeds a specified dimension.
widthxheight< Change dimensions only if both image dimensions exceed specified dimensions.
*/
void Image::SelectAspect()
{
switch( item_work.aspect_mode )
{
case WINIX_IMAGE_MODE_1:
command << item_work.cx;
break;
case WINIX_IMAGE_MODE_3:
command << item_work.cx << "x" << item_work.cy;
break;
case WINIX_IMAGE_MODE_4:
command << '"' << item_work.cx << "x" << item_work.cy << "^\"";
break;
case WINIX_IMAGE_MODE_5:
command << '"' << item_work.cx << "x" << item_work.cy << "!\"";
break;
case WINIX_IMAGE_MODE_6:
command << '"' << item_work.cx << "x" << item_work.cy << ">\"";
break;
case WINIX_IMAGE_MODE_7:
command << '"' << item_work.cx << "x" << item_work.cy << "<\"";
break;
case WINIX_IMAGE_MODE_2:
default:
command << "x" << item_work.cy;
break;
}
}
// second thread (objects locked)
bool Image::CreateInputFileName()
{
if( system->MakeFilePath(item_work.file, src_path) )
{
Ezc::WideToUTF8(src_path, input_file_name);
return true;
}
else
{
log << log1 << "Image: cannot create a source path" << logend;
return false;
}
}
// second thread (objects locked)
void Image::CreateTmpFileName()
{
stream_tmp_path.Clear();
stream_tmp_path << config->upload_dir << L"/tmp/image_" << std::time(0);
Ezc::WideToUTF8(stream_tmp_path.Str(), tmp_file_name);
}
// second thread (objects are not locked)
bool Image::CreateCommand()
{
Lock();
iq.SetAll(true, false);
iq.WhereId(item_work.file.id);
// !! skoro teraz i tak wczytujemy caly obiekt
// to teraz w kolejce wystarczy zapamietywac tylko samo item.id (a nie caly obiekt item)
// the file could have been changed especially when there is a long queue of files
if( db->GetItem(item_work.file, iq) != WINIX_ERR_OK )
{
Unlock();
return false;
}
if( !CreateInputFileName() )
{
Unlock();
return false;
}
command.Clear();
Add(config->convert_cmd, command);
command << " ";
EscapePath(input_file_name, command, false);
command << " -quiet -quality " << item_work.quality;
if( item_work.type == WINIX_IMAGE_TYPE_RESIZE )
command << " -resize ";
else
command << " -strip -thumbnail ";
SelectAspect();
CreateTmpFileName();
command << " ";
EscapePath(tmp_file_name, command, false);
log << log4 << "Image: running: " << command.Str() << logend;
Unlock();
return true;
}
// second thread (objects are not locked)
void Image::SaveImage()
{
bool moved = false;
Lock();
// the file could have been changed especially when creating the image lasted too long
iq.SetAll(true, false);
iq.WhereId(item_work.file.id);
if( db->GetItem(item_work.file, iq) == WINIX_ERR_OK )
{
bool thumb = (item_work.type == WINIX_IMAGE_TYPE_CREATE_THUMB);
if( system->MakeFilePath(item_work.file, dst_path, thumb, true, config->upload_dirs_chmod) )
{
if( RenameFile(stream_tmp_path.Str(), dst_path) )
{
if( thumb )
{
item_work.file.has_thumb = true;
db->EditHasThumbById(true, item_work.file.id);
log << log3 << "Image: generated a thumbnail: " << dst_path << logend;
plugin.Call(WINIX_CREATED_THUMB, &item_work.file);
}
else
{
log << log3 << "Image: image resized: " << dst_path << logend;
plugin.Call(WINIX_IMAGE_RESIZED, &item_work.file);
}
moved = true;
}
else
{
log << log1 << "Image: cannot move a temporary file: " << stream_tmp_path.Str() << ", to: " << dst_path << logend;
}
}
else
{
log << log1 << "Image: cannot create a destination path" << logend;
}
}
if( !moved )
::RemoveFile(stream_tmp_path.Str());
Unlock();
}
// second thread (objects are not locked)
void Image::CreateImage()
{
if( !CreateCommand() )
return;
int res = std::system(command.CStr());
if( res == 0 )
{
SaveImage();
}
else
{
Lock();
log << log3 << "Image: some problems with creating an image"
<< ", 'convert' process returned: " << res << logend;
Unlock();
}
}
// second thread (objects are not locked)
// !! there is a problem with GIF files
// Bus error (core dumped)
/*
#include "wand/MagickWand.h"
// compiler options:
// include: -I/usr/local/include/ImageMagick
// link with: `MagickWand-config --ldflags --libs`
void Image::CreateThumbnail()
{
Ezc::WideToUTF8(item_work.source, sourcea);
Ezc::WideToUTF8(item_work.dst, dsta);
MagickWandGenesis();
MagickWand * wand = NewMagickWand();
if( MagickReadImage(wand, sourcea.c_str()) )
{
MagickThumbnailImage(wand, item_work.cx, item_work.cy);
if( MagickWriteImage(wand, dsta.c_str()) )
{
Lock();
log << log3 << "Image: created a thumbnail: " << dsta << logend;
Unlock();
}
}
DestroyMagickWand(wand);
MagickWandTerminus();
}
*/