mirror of
https://github.com/aseprite/aseprite.git
synced 2024-12-29 09:23:32 +00:00
e5ba8e0922
- Rename _rgba/_graya to raster::rgba()/graya() - Add raster::color_t type (alias for uint32_t) - Rename raster::GfxObj to Object. And GfxObj::getType() to Object::type() - Move conversion from raster::Image/Palette to Allegro BITMAP/RGB to raster/conversion_alleg.h file - Add raster/color_scales.h - Rename image_* functions to raster/primitives.h - Reimplement ink processing with templates instead of macros
231 lines
6.4 KiB
C++
231 lines
6.4 KiB
C++
/* Aseprite
|
|
* Copyright (C) 2001-2013 David Capello
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "app/thumbnail_generator.h"
|
|
|
|
#include "app/app.h"
|
|
#include "app/document.h"
|
|
#include "app/file/file.h"
|
|
#include "app/file_system.h"
|
|
#include "base/bind.h"
|
|
#include "base/scoped_lock.h"
|
|
#include "base/thread.h"
|
|
#include "raster/conversion_alleg.h"
|
|
#include "raster/image.h"
|
|
#include "raster/palette.h"
|
|
#include "raster/primitives.h"
|
|
#include "raster/rotate.h"
|
|
#include "raster/sprite.h"
|
|
|
|
#include <allegro.h>
|
|
|
|
#define MAX_THUMBNAIL_SIZE 128
|
|
|
|
namespace app {
|
|
|
|
class ThumbnailGenerator::Worker {
|
|
public:
|
|
Worker(FileOp* fop, IFileItem* fileitem)
|
|
: m_fop(fop)
|
|
, m_fileitem(fileitem)
|
|
, m_thumbnail(NULL)
|
|
, m_palette(NULL)
|
|
, m_thread(Bind<void>(&Worker::loadBgThread, this)) {
|
|
}
|
|
|
|
~Worker() {
|
|
fop_stop(m_fop);
|
|
m_thread.join();
|
|
|
|
fop_free(m_fop);
|
|
}
|
|
|
|
IFileItem* getFileItem() { return m_fileitem; }
|
|
bool isDone() const { return fop_is_done(m_fop); }
|
|
double getProgress() const { return fop_get_progress(m_fop); }
|
|
|
|
private:
|
|
void loadBgThread() {
|
|
try {
|
|
fop_operate(m_fop, NULL);
|
|
|
|
// Post load
|
|
fop_post_load(m_fop);
|
|
|
|
// Convert the loaded document into the Allegro bitmap "m_thumbnail".
|
|
const Sprite* sprite = (m_fop->document && m_fop->document->getSprite()) ? m_fop->document->getSprite():
|
|
NULL;
|
|
if (!fop_is_stop(m_fop) && sprite) {
|
|
// The palette to convert the Image to a BITMAP
|
|
m_palette.reset(new Palette(*sprite->getPalette(FrameNumber(0))));
|
|
|
|
// Render the 'sprite' in one plain 'image'
|
|
base::UniquePtr<Image> image(Image::create(sprite->getPixelFormat(),
|
|
sprite->getWidth(),
|
|
sprite->getHeight()));
|
|
sprite->render(image, 0, 0, FrameNumber(0));
|
|
|
|
// Calculate the thumbnail size
|
|
int thumb_w = MAX_THUMBNAIL_SIZE * image->getWidth() / MAX(image->getWidth(), image->getHeight());
|
|
int thumb_h = MAX_THUMBNAIL_SIZE * image->getHeight() / MAX(image->getWidth(), image->getHeight());
|
|
if (MAX(thumb_w, thumb_h) > MAX(image->getWidth(), image->getHeight())) {
|
|
thumb_w = image->getWidth();
|
|
thumb_h = image->getHeight();
|
|
}
|
|
thumb_w = MID(1, thumb_w, MAX_THUMBNAIL_SIZE);
|
|
thumb_h = MID(1, thumb_h, MAX_THUMBNAIL_SIZE);
|
|
|
|
// Stretch the 'image'
|
|
m_thumbnail.reset(Image::create(image->getPixelFormat(), thumb_w, thumb_h));
|
|
clear_image(m_thumbnail, 0);
|
|
image_scale(m_thumbnail, image, 0, 0, thumb_w, thumb_h);
|
|
}
|
|
|
|
delete m_fop->document;
|
|
|
|
// Set the thumbnail of the file-item.
|
|
if (m_thumbnail) {
|
|
BITMAP* bmp = create_bitmap_ex(16, m_thumbnail->getWidth(), m_thumbnail->getHeight());
|
|
convert_image_to_allegro(m_thumbnail, bmp, 0, 0, m_palette);
|
|
m_fileitem->setThumbnail(bmp);
|
|
}
|
|
}
|
|
catch (const std::exception& e) {
|
|
fop_error(m_fop, "Error loading file:\n%s", e.what());
|
|
}
|
|
fop_done(m_fop);
|
|
}
|
|
|
|
FileOp* m_fop;
|
|
IFileItem* m_fileitem;
|
|
base::UniquePtr<Image> m_thumbnail;
|
|
base::UniquePtr<Palette> m_palette;
|
|
base::thread m_thread;
|
|
};
|
|
|
|
static void delete_singleton(ThumbnailGenerator* singleton)
|
|
{
|
|
delete singleton;
|
|
}
|
|
|
|
ThumbnailGenerator* ThumbnailGenerator::instance()
|
|
{
|
|
static ThumbnailGenerator* singleton = NULL;
|
|
if (singleton == NULL) {
|
|
singleton = new ThumbnailGenerator();
|
|
App::instance()->Exit.connect(Bind<void>(&delete_singleton, singleton));
|
|
}
|
|
return singleton;
|
|
}
|
|
|
|
ThumbnailGenerator::WorkerStatus ThumbnailGenerator::getWorkerStatus(IFileItem* fileitem, double& progress)
|
|
{
|
|
base::scoped_lock hold(m_workersAccess);
|
|
|
|
for (WorkerList::iterator
|
|
it=m_workers.begin(), end=m_workers.end(); it!=end; ++it) {
|
|
Worker* worker = *it;
|
|
if (worker->getFileItem() == fileitem) {
|
|
if (worker->isDone())
|
|
return ThumbnailIsDone;
|
|
else {
|
|
progress = worker->getProgress();
|
|
return WorkingOnThumbnail;
|
|
}
|
|
}
|
|
}
|
|
return WithoutWorker;
|
|
}
|
|
|
|
bool ThumbnailGenerator::checkWorkers()
|
|
{
|
|
base::scoped_lock hold(m_workersAccess);
|
|
bool doingWork = !m_workers.empty();
|
|
|
|
for (WorkerList::iterator
|
|
it=m_workers.begin(); it != m_workers.end(); ) {
|
|
if ((*it)->isDone()) {
|
|
delete *it;
|
|
it = m_workers.erase(it);
|
|
}
|
|
else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
return doingWork;
|
|
}
|
|
|
|
void ThumbnailGenerator::addWorkerToGenerateThumbnail(IFileItem* fileitem)
|
|
{
|
|
double progress;
|
|
|
|
if (fileitem->isBrowsable() ||
|
|
fileitem->getThumbnail() != NULL ||
|
|
getWorkerStatus(fileitem, progress) != WithoutWorker)
|
|
return;
|
|
|
|
FileOp* fop = fop_to_load_document(fileitem->getFileName().c_str(),
|
|
FILE_LOAD_SEQUENCE_NONE |
|
|
FILE_LOAD_ONE_FRAME);
|
|
if (!fop)
|
|
return;
|
|
|
|
if (fop->has_error()) {
|
|
fop_free(fop);
|
|
}
|
|
else {
|
|
Worker* worker = new Worker(fop, fileitem);
|
|
try {
|
|
base::scoped_lock hold(m_workersAccess);
|
|
m_workers.push_back(worker);
|
|
}
|
|
catch (...) {
|
|
delete worker;
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ThumbnailGenerator::stopAllWorkers()
|
|
{
|
|
base::thread* ptr = new base::thread(Bind<void>(&ThumbnailGenerator::stopAllWorkersBackground, this));
|
|
m_stopThread.reset(ptr);
|
|
}
|
|
|
|
void ThumbnailGenerator::stopAllWorkersBackground()
|
|
{
|
|
WorkerList workersCopy;
|
|
{
|
|
base::scoped_lock hold(m_workersAccess);
|
|
workersCopy = m_workers;
|
|
m_workers.clear();
|
|
}
|
|
|
|
for (WorkerList::iterator
|
|
it=workersCopy.begin(), end=workersCopy.end(); it!=end; ++it) {
|
|
delete *it;
|
|
}
|
|
}
|
|
|
|
} // namespace app
|