You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kipi-plugins/kipi-plugins/jpeglossless/convert2grayscale.cpp

272 lines
7.5 KiB

/* ============================================================
*
* This file is a part of kipi-plugins project
* http://www.kipi-plugins.org
*
* Date : 2003-10-14
* Description : batch images grayscale conversion
*
* Copyright (C) 2004-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
* Copyright (C) 2003-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
*
* NOTE: Do not use kdDebug() in this implementation because
* it will be multithreaded. Use tqDebug() instead.
* See B.K.O #133026 for details.
*
* 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, 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.
*
* ============================================================ */
#define XMD_H
// C++ includes.
#include <cstdio>
// C Ansi includes.
extern "C"
{
#include <sys/types.h>
#include <unistd.h>
#include <jpeglib.h>
}
// TQt includes.
#include <tqimage.h>
#include <tqstring.h>
#include <tqwmatrix.h>
#include <tqfile.h>
#include <tqfileinfo.h>
// KDE includes.
#include <kprocess.h>
#include <tdelocale.h>
#include <kurl.h>
#include <tdetempfile.h>
// Local includes.
#include "utils.h"
#include "transupp.h"
#include "convert2grayscale.h"
#include "convert2grayscale.moc"
namespace KIPIJPEGLossLessPlugin
{
ImageGrayScale::ImageGrayScale()
: TQObject()
{
m_tmpFile = new KTempFile(TQString(), TQString("kipiplugin-grayscale"));
m_tmpFile->setAutoDelete(true);
}
ImageGrayScale::~ImageGrayScale()
{
delete m_tmpFile;
}
bool ImageGrayScale::image2GrayScale(const TQString& src, TQString& err)
{
TQFileInfo fi(src);
if (!fi.exists() || !fi.isReadable() || !fi.isWritable())
{
err = i18n("Error in opening input file");
return false;
}
if ( !m_tmpFile->file() )
{
err = i18n("Error in opening temporary file");
return false;
}
TQString tmp = m_tmpFile->name();
if (Utils::isRAW(src))
{
err = i18n("Cannot convert to gray scale RAW file");
return false;
}
else if (Utils::isJPEG(src))
{
if (!image2GrayScaleJPEG(src, tmp, err))
return false;
}
else
{
// B.K.O #123499 : using Image Magick API here instead QT API
// else RAW/TIFF/PNG 16 bits image are broken!
if (!image2GrayScaleImageMagick(src, tmp, err))
return false;
// We update metadata on new image.
Utils tools(this);
if (!tools.updateMetadataImageMagick(tmp, err))
return false;
}
// Move back to original file
if (!Utils::MoveFile(tmp, src))
{
err = i18n("Cannot update source image");
return false;
}
return true;
}
bool ImageGrayScale::image2GrayScaleJPEG(const TQString& src, const TQString& dest, TQString& err)
{
JCOPY_OPTION copyoption = JCOPYOPT_ALL;
jpeg_transform_info transformoption;
memset(&transformoption, 0, sizeof(jpeg_transform_info));
transformoption.transform = JXFORM_NONE;
transformoption.force_grayscale = true;
transformoption.trim = false;
struct jpeg_decompress_struct srcinfo;
struct jpeg_compress_struct dstinfo;
struct jpeg_error_mgr jsrcerr;
struct jpeg_error_mgr jdsterr;
jvirt_barray_ptr * src_coef_arrays;
jvirt_barray_ptr * dst_coef_arrays;
// Initialize the JPEG decompression object with default error handling
srcinfo.err = jpeg_std_error(&jsrcerr);
jpeg_create_decompress(&srcinfo);
// Initialize the JPEG compression object with default error handling
dstinfo.err = jpeg_std_error(&jdsterr);
jpeg_create_compress(&dstinfo);
FILE *input_file;
FILE *output_file;
input_file = fopen(TQFile::encodeName(src), "rb");
if (!input_file)
{
tqDebug("Image2GrayScale: Error in opening input file");
err = i18n("Error in opening input file");
return false;
}
output_file = fopen(TQFile::encodeName(dest), "wb");
if (!output_file)
{
fclose(input_file);
tqDebug("Image2GrayScale: Error in opening output file");
err = i18n("Error in opening output file");
return false;
}
// Open jpeglib stream
jpeg_stdio_src(&srcinfo, input_file);
// Setup decompression object to save desired markers in memory
jcopy_markers_setup(&srcinfo, copyoption);
// Decompression startup: read start of JPEG datastream to see what's there
(void) jpeg_read_header(&srcinfo, true);
// Request any required workspace
jtransform_request_workspace(&srcinfo, &transformoption);
// Read source file as DCT coefficients
src_coef_arrays = jpeg_read_coefficients(&srcinfo);
// Initialize destination compression parameters from source values
jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
// Adjust output image parameters
dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption);
// Specify data destination for compression
jpeg_stdio_dest(&dstinfo, output_file);
// Do not write a JFIF header if previously the image did not contain it
dstinfo.write_JFIF_header = false;
// Start compressor (note no image data is actually written here)
jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
// Copy to the output file any extra markers that we want to preserve (merging from src file with TQt tmp file)
jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
// Execute the actual jpeg transformations
jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transformoption);
// Finish compression and release memory
jpeg_finish_compress(&dstinfo);
jpeg_destroy_compress(&dstinfo);
(void) jpeg_finish_decompress(&srcinfo);
jpeg_destroy_decompress(&srcinfo);
fclose(input_file);
fclose(output_file);
return true;
}
bool ImageGrayScale::image2GrayScaleImageMagick(const TQString& src, const TQString& dest, TQString& err)
{
TDEProcess process;
process.clearArguments();
process << "convert";
process << "-verbose";
process << "-type" << "Grayscale";
process << src + TQString("[0]") << dest;
tqDebug("ImageMagick Command line args:");
TQValueList<TQCString> args = process.args();
for (TQValueList<TQCString>::iterator it = args.begin(); it != args.end(); ++it)
tqDebug("%s", (const char*)(*it));
connect(&process, TQT_SIGNAL(receivedStderr(TDEProcess *, char*, int)),
this, TQT_SLOT(slotReadStderr(TDEProcess*, char*, int)));
if (!process.start(TDEProcess::Block, TDEProcess::Stderr))
return false;
if (!process.normalExit())
return false;
switch (process.exitStatus())
{
case 0: // Process finished successfully !
{
return true;
break;
}
case 15: // process aborted !
{
return false;
break;
}
}
// Processing error !
err = i18n("Cannot convert to gray scale: %1").arg(m_stdErr.replace('\n', ' '));
return false;
}
void ImageGrayScale::slotReadStderr(TDEProcess*, char* buffer, int buflen)
{
m_stdErr.append(TQString::fromLocal8Bit(buffer, buflen));
}
} // NameSpace KIPIJPEGLossLessPlugin