added: a new winix function: imgcrop

for cropping images (and thumbnails)
       www.domain.com/dir/file.jpg/imgcrop  -- crop an image
       www.domain.com/dir/file.jpg/imgcrop/thumb  -- crop an image's thumbnail
       www.domain.com/dir/file.jpg/imgcrop/newthumb  -- crop and create a new thumbnail (from an original image)
       www.domain.com/dir/imgcrop -- show images' list with above options
added: to Image class: some methods for cropping




git-svn-id: svn://ttmath.org/publicrep/winix/trunk@919 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
2013-03-29 22:03:28 +00:00
parent 8d9a021eab
commit 495499d12f
27 changed files with 1374 additions and 793 deletions

View File

@@ -2,7 +2,7 @@
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010-2012, Tomasz Sowa
* Copyright (c) 2010-2013, Tomasz Sowa
* All rights reserved.
*
*/
@@ -13,6 +13,7 @@
#include "log.h"
#include "system.h"
#include "plugin.h"
#include "lock.h"
@@ -35,15 +36,91 @@ void Image::SetSystem(System * psystem)
}
// first thread (objects locked)
void Image::Resize(const Item & item, size_t cx, size_t cy, int aspect_mode, int quality)
Image::Scale Image::GetImageScale(long dir_id)
{
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;
Scale scale;
Mount * m = system->mounts.CalcMount(dir_id);
scale.cx = config->image_cx;
scale.cy = config->image_cy;
scale.aspect_mode = config->image_mode;
scale.quality = config->image_quality;
// reading width and height from the mount point (if exists)
int index = system->mounts.MountParImageSize();
if( m && m->param[index].defined && m->param[index].arg.size() == 2 )
{
scale.cx = Tol(m->param[index].arg[0]);
scale.cy = Tol(m->param[index].arg[1]);
}
// reading image mode from the mount point (if exists)
index = system->mounts.MountParImageMode();
if( m && m->param[index].defined && m->param[index].arg.size() == 1 )
scale.aspect_mode = Toi(m->param[index].arg[0]);
// reading image quality from the mount point (if exists)
index = system->mounts.MountParImageQuality();
if( m && m->param[index].defined && m->param[index].arg.size() == 1 )
scale.quality = Toi(m->param[index].arg[0]);
return scale;
}
// first thread (objects locked)
Image::Scale Image::GetThumbScale(long dir_id)
{
Scale scale;
Mount * m = system->mounts.CalcMount(dir_id);
scale.cx = config->thumb_cx;
scale.cy = config->thumb_cy;
scale.aspect_mode = config->thumb_mode;
scale.quality = config->thumb_quality;
// reading width and height from the mount point (if exists)
int index = system->mounts.MountParThumbSize();
if( m && m->param[index].defined && m->param[index].arg.size() == 2 )
{
scale.cx = Tol(m->param[index].arg[0]);
scale.cy = Tol(m->param[index].arg[1]);
}
// reading thumb mode from the mount point (if exists)
index = system->mounts.MountParThumbMode();
if( m && m->param[index].defined && m->param[index].arg.size() == 1 )
scale.aspect_mode = Toi(m->param[index].arg[0]);
// reading image quality from the mount point (if exists)
index = system->mounts.MountParThumbQuality();
if( m && m->param[index].defined && m->param[index].arg.size() == 1 )
scale.quality = Toi(m->param[index].arg[0]);
return scale;
}
// first thread (objects locked)
void Image::Resize(long file_id, size_t cx, size_t cy, int aspect_mode, int quality)
{
item_temp.type = WINIX_IMAGE_TYPE_RESIZE;
item_temp.file_id = file_id;
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);
@@ -51,15 +128,16 @@ void Image::Resize(const Item & item, size_t cx, size_t cy, int aspect_mode, int
}
// first thread (objects locked)
void Image::CreateThumb(const Item & item, size_t cx, size_t cy, int aspect_mode, int quality)
void Image::CreateThumb(long file_id, size_t thumb_cx, size_t thumb_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;
item_temp.type = WINIX_IMAGE_TYPE_CREATE_THUMB;
item_temp.file_id = file_id;
item_temp.thumb_cx = thumb_cx;
item_temp.thumb_cy = thumb_cy;
item_temp.aspect_mode = aspect_mode;
item_temp.quality = quality;
CheckParam(item_temp);
image_tab.insert(image_tab.end(), item_temp);
@@ -68,31 +146,75 @@ void Image::CreateThumb(const Item & item, size_t cx, size_t cy, int aspect_mode
// first thread (objects locked)
void Image::Crop(long file_id, size_t xoffset, size_t yoffset, size_t cx, size_t cy, int quality)
{
item_temp.type = WINIX_IMAGE_TYPE_CROP;
item_temp.file_id = file_id;
item_temp.xoffset = xoffset;
item_temp.yoffset = yoffset;
item_temp.cx = cx;
item_temp.cy = cy;
item_temp.quality = quality;
CheckParam(item_temp);
image_tab.insert(image_tab.end(), item_temp);
WakeUpThread();
}
// first thread (objects locked)
void Image::CropThumb(long file_id, size_t xoffset, size_t yoffset, size_t cx, size_t cy, int quality)
{
item_temp.type = WINIX_IMAGE_TYPE_CROP_THUMB;
item_temp.file_id = file_id;
item_temp.xoffset = xoffset;
item_temp.yoffset = yoffset;
item_temp.cx = cx;
item_temp.cy = cy;
item_temp.quality = quality;
CheckParam(item_temp);
image_tab.insert(image_tab.end(), item_temp);
WakeUpThread();
}
// first thread (objects locked)
void Image::CropNewThumb(long file_id, size_t xoffset, size_t yoffset, size_t cx, size_t cy,
size_t thumb_cx, size_t thumb_cy, int aspect_mode, int quality)
{
item_temp.type = WINIX_IMAGE_TYPE_CREATE_CROP_NEW_THUMB;
item_temp.file_id = file_id;
item_temp.xoffset = xoffset;
item_temp.yoffset = yoffset;
item_temp.cx = cx;
item_temp.cy = cy;
item_temp.thumb_cx = thumb_cx;
item_temp.thumb_cy = thumb_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;
SetMinMax(item.aspect_mode, 1, 7);
SetMinMax(item.quality, 0, 100);
SetMinMax(item.cx, 1, 30000);
SetMinMax(item.cy, 1, 30000);
SetMinMax(item.thumb_cx, 1, 30000);
SetMinMax(item.thumb_cy, 1, 30000);
SetMinMax(item.xoffset, 0, 30000);
SetMinMax(item.yoffset, 0, 30000);
}
@@ -117,7 +239,7 @@ bool end;
do
{
Lock();
class Lock lock_object(synchro);
if( i != image_tab.end() )
{
@@ -130,7 +252,7 @@ bool end;
end = true;
}
Unlock();
lock_object.Unlock();
if( !end )
CreateImage();
@@ -163,7 +285,8 @@ void Image::EscapePath(const std::string & path, TextStream<std::string> & out,
if( path[i] == '"' )
out << '\\';
out << path[i];
if( path[i] != 0 )
out << path[i];
}
out << '\"';
@@ -184,37 +307,37 @@ widthxheight! Width and height emphatically given, original aspect ratio ignor
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()
void Image::SelectAspect(size_t cx, size_t cy)
{
switch( item_work.aspect_mode )
{
case WINIX_IMAGE_MODE_1:
command << item_work.cx;
command << cx;
break;
case WINIX_IMAGE_MODE_3:
command << item_work.cx << "x" << item_work.cy;
command << cx << "x" << cy;
break;
case WINIX_IMAGE_MODE_4:
command << '"' << item_work.cx << "x" << item_work.cy << "^\"";
command << '"' << cx << "x" << cy << "^\"";
break;
case WINIX_IMAGE_MODE_5:
command << '"' << item_work.cx << "x" << item_work.cy << "!\"";
command << '"' << cx << "x" << cy << "!\"";
break;
case WINIX_IMAGE_MODE_6:
command << '"' << item_work.cx << "x" << item_work.cy << ">\"";
command << '"' << cx << "x" << cy << ">\"";
break;
case WINIX_IMAGE_MODE_7:
command << '"' << item_work.cx << "x" << item_work.cy << "<\"";
command << '"' << cx << "x" << cy << "<\"";
break;
case WINIX_IMAGE_MODE_2:
default:
command << "x" << item_work.cy;
command << "x" << cy;
break;
}
}
@@ -224,7 +347,17 @@ void Image::SelectAspect()
// second thread (objects locked)
bool Image::CreateInputFileName()
{
if( system->MakeFilePath(item_work.file, src_path) )
bool thumb = (item_work.type == WINIX_IMAGE_TYPE_CROP_THUMB);
if( thumb && !file_work.has_thumb )
{
log << log1 << "Image: file id: " << file_work.id << ", url: " << file_work.url
<< " doesn't have a thumbnail yet (skipping)" << logend;
return false;
}
if( system->MakeFilePath(file_work, src_path, thumb) )
{
PT::WideToUTF8(src_path, input_file_name);
return true;
@@ -237,6 +370,7 @@ bool Image::CreateInputFileName()
}
// second thread (objects locked)
void Image::CreateTmpFileName()
{
@@ -250,26 +384,17 @@ void Image::CreateTmpFileName()
// second thread (objects are not locked)
bool Image::CreateCommand()
{
Lock();
class Lock lock_object(synchro);
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)
iq.WhereId(item_work.file_id);
// 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();
if( db->GetItem(file_work, iq) != WINIX_ERR_OK )
return false;
}
if( !CreateInputFileName() )
{
Unlock();
return false;
}
command.Clear();
Add(config->convert_cmd, command);
@@ -279,11 +404,38 @@ bool Image::CreateCommand()
command << " -quiet -quality " << item_work.quality;
if( item_work.type == WINIX_IMAGE_TYPE_RESIZE )
{
command << " -resize ";
SelectAspect(item_work.cx, item_work.cy);
}
else
if( item_work.type == WINIX_IMAGE_TYPE_CREATE_THUMB )
{
command << " -strip -thumbnail ";
SelectAspect(item_work.thumb_cx, item_work.thumb_cy);
}
else
if( item_work.type == WINIX_IMAGE_TYPE_CROP )
{
command << " -crop " << item_work.cx << "x" << item_work.cy
<< "+" << item_work.xoffset << "+" << item_work.yoffset << " +repage ";
}
else
if( item_work.type == WINIX_IMAGE_TYPE_CROP_THUMB )
{
command << " -strip -crop " << item_work.cx << "x" << item_work.cy
<< "+" << item_work.xoffset << "+" << item_work.yoffset
<< " +repage ";
}
else
if( item_work.type == WINIX_IMAGE_TYPE_CREATE_CROP_NEW_THUMB )
{
command << " -strip -crop " << item_work.cx << "x" << item_work.cy
<< "+" << item_work.xoffset << "+" << item_work.yoffset
<< " +repage -thumbnail ";
SelectAspect(item_work.thumb_cx, item_work.thumb_cy);
}
SelectAspect();
CreateTmpFileName();
command << " ";
@@ -291,7 +443,6 @@ bool Image::CreateCommand()
log << log4 << "Image: running: " << command.Str() << logend;
Unlock();
return true;
}
@@ -299,43 +450,77 @@ return true;
// second thread (objects are locked)
void Image::ImageSavedCorrectly()
{
if( item_work.type == WINIX_IMAGE_TYPE_CREATE_THUMB )
{
if( !file_work.has_thumb )
{
file_work.has_thumb = true;
db->EditHasThumbById(true, file_work.id);
}
log << log3 << "Image: generated a thumbnail: " << dst_path << logend;
plugin.Call((Session*)0, WINIX_CREATED_THUMB, &file_work);
}
else
if( item_work.type == WINIX_IMAGE_TYPE_RESIZE )
{
log << log3 << "Image: image resized: " << dst_path << logend;
plugin.Call((Session*)0, WINIX_IMAGE_RESIZED, &file_work);
}
else
if( item_work.type == WINIX_IMAGE_TYPE_CROP )
{
log << log3 << "Image: image cropped: " << dst_path << logend;
// !! IMPROVE ME add a correct message
//plugin.Call((Session*)0, WINIX_IMAGE_RESIZED, &file_work);
}
else
if( item_work.type == WINIX_IMAGE_TYPE_CROP_THUMB )
{
log << log3 << "Image: image thumbnail cropped: " << dst_path << logend;
// !! IMPROVE ME add a correct message
//plugin.Call((Session*)0, WINIX_IMAGE_RESIZED, &file_work);
}
else
if( item_work.type == WINIX_IMAGE_TYPE_CREATE_CROP_NEW_THUMB )
{
log << log3 << "Image: a new thumbnail from an original image was cropped: " << dst_path << logend;
// !! IMPROVE ME add a correct message
//plugin.Call((Session*)0, WINIX_IMAGE_RESIZED, &file_work);
}
}
// second thread (objects are not locked)
void Image::SaveImage()
{
bool moved = false;
Lock();
class Lock lock_object(synchro);
// the file could have been changed especially when creating the image lasted too long
iq.SetAll(true, false);
iq.WhereId(item_work.file.id);
iq.WhereId(item_work.file_id);
if( db->GetItem(item_work.file, iq) == WINIX_ERR_OK )
if( db->GetItem(file_work, iq) == WINIX_ERR_OK )
{
bool thumb = (item_work.type == WINIX_IMAGE_TYPE_CREATE_THUMB);
bool thumb = (item_work.type == WINIX_IMAGE_TYPE_CREATE_THUMB ||
item_work.type == WINIX_IMAGE_TYPE_CROP_THUMB ||
item_work.type == WINIX_IMAGE_TYPE_CREATE_CROP_NEW_THUMB );
if( system->MakeFilePath(item_work.file, dst_path, thumb, true, config->upload_dirs_chmod) )
if( system->MakeFilePath(file_work, 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((Session*)0, WINIX_CREATED_THUMB, &item_work.file);
}
else
{
log << log3 << "Image: image resized: " << dst_path << logend;
plugin.Call((Session*)0, WINIX_IMAGE_RESIZED, &item_work.file);
}
moved = true;
ImageSavedCorrectly();
}
else
{
log << log1 << "Image: cannot move a temporary file: " << stream_tmp_path.Str() << ", to: " << dst_path << logend;
log << log1 << "Image: cannot move a temporary file: " << stream_tmp_path.Str()
<< ", to: " << dst_path << logend;
::RemoveFile(stream_tmp_path.Str());
}
}
else
@@ -343,11 +528,6 @@ bool moved = false;
log << log1 << "Image: cannot create a destination path" << logend;
}
}
if( !moved )
::RemoveFile(stream_tmp_path.Str());
Unlock();
}
@@ -355,21 +535,20 @@ bool moved = false;
// second thread (objects are not locked)
void Image::CreateImage()
{
if( !CreateCommand() )
return;
int res = std::system(command.CStr());
if( res == 0 )
if( CreateCommand() )
{
SaveImage();
}
else
{
Lock();
log << log3 << "Image: some problems with creating an image"
<< ", 'convert' process returned: " << res << logend;
Unlock();
int res = std::system(command.CStr());
if( res == 0 )
{
SaveImage();
}
else
{
class Lock lock_object(synchro);
log << log3 << "Image: some problems with creating an image"
<< ", 'convert' process returned: " << res << logend;
}
}
}