/* Copyright (C) 2013 PCMan 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "loadimagejob.h" #include "mainwindow.h" #include #include #include #include using namespace LxImage; LoadImageJob::LoadImageJob(MainWindow* window, FmPath* filePath): Job(), path_(fm_path_ref(filePath)), mainWindow_(window) { } LoadImageJob::~LoadImageJob() { fm_path_unref(path_); } // This is called from the worker thread, not main thread bool LoadImageJob::run() { GFile* gfile = fm_path_to_gfile(path_); GFileInputStream* fileStream = g_file_read(gfile, cancellable_, &error_); g_object_unref(gfile); if(fileStream) { // if the file stream is successfually opened QBuffer imageBuffer; GInputStream* inputStream = G_INPUT_STREAM(fileStream); while(!g_cancellable_is_cancelled(cancellable_)) { char buffer[4096]; gssize readSize = g_input_stream_read(inputStream, buffer, 4096, cancellable_, &error_); if(readSize == -1 || readSize == 0) // error or EOF break; // append the bytes read to the image buffer imageBuffer.buffer().append(buffer, readSize); } g_input_stream_close(inputStream, NULL, NULL); // FIXME: maybe it's a better idea to implement a GInputStream based QIODevice. if(!error_ && !g_cancellable_is_cancelled(cancellable_)) { // load the image from buffer if there are no errors image_ = QImage::fromData(imageBuffer.buffer()); if(!image_.isNull()) { // if the image is loaded correctly // check if this file is a jpeg file // FIXME: can we use FmFileInfo instead if it's available? const char* basename = fm_path_get_basename(path_); char* mime_type = g_content_type_guess(basename, NULL, 0, NULL); if(mime_type && strcmp(mime_type, "image/jpeg") == 0) { // this is a jpeg file // use libexif to extract additional info embedded in jpeg files ExifLoader *exif_loader = exif_loader_new(); // write image data to exif loader int ret = exif_loader_write(exif_loader, (unsigned char*)imageBuffer.data().constData(), (unsigned int)imageBuffer.size()); ExifData *exif_data = exif_loader_get_data(exif_loader); exif_loader_unref(exif_loader); if(exif_data) { /* reference for EXIF orientation tag: * http://www.impulseadventure.com/photo/exif-orientation.html */ ExifEntry* orient_ent = exif_data_get_entry(exif_data, EXIF_TAG_ORIENTATION); if(orient_ent) { /* orientation flag found in EXIF */ gushort orient; ExifByteOrder bo = exif_data_get_byte_order(exif_data); /* bo == EXIF_BYTE_ORDER_INTEL ; */ orient = exif_get_short (orient_ent->data, bo); qreal rotate_degrees = 0.0; switch(orient) { case 1: /* no rotation */ break; case 8: rotate_degrees = 270.0; break; case 3: rotate_degrees = 180.0; break; case 6: rotate_degrees = 90.0; break; } // rotate the image according to EXIF orientation tag if(rotate_degrees != 0.0) { QTransform transform; transform.rotate(rotate_degrees); image_ = image_.transformed(transform, Qt::SmoothTransformation); } // TODO: handle other EXIF tags as well } exif_data_unref(exif_data); } } g_free(mime_type); } } } return false; } // this function is called from main thread only void LoadImageJob::finish() { // only do processing if the job is not cancelled if(!g_cancellable_is_cancelled(cancellable_)) { mainWindow_->onImageLoaded(this); } }