"Fossies" - the Fresh Open Source Software Archive

Member "src/imageloaderfreeimage.cpp" (28 Sep 2008, 13012 Bytes) of package /windows/misc/PosteRazor-1.9.5-Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "imageloaderfreeimage.cpp" see the Fossies "Dox" file reference documentation.

    1 /*
    2     PosteRazor - Make your own poster!
    3     Copyright (C) 2005-2008 by Alessandro Portale
    4     http://posterazor.sourceforge.net/
    5 
    6     This file is part of PosteRazor
    7 
    8     PosteRazor is free software; you can redistribute it and/or modify
    9     it under the terms of the GNU General Public License as published by
   10     the Free Software Foundation, either version 3 of the License, or
   11     (at your option) any later version.
   12 
   13     PosteRazor is distributed in the hope that it will be useful,
   14     but WITHOUT ANY WARRANTY; without even the implied warranty of
   15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16     GNU General Public License for more details.
   17 
   18     You should have received a copy of the GNU General Public License
   19     along with PosteRazor; if not, write to the Free Software
   20     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
   21 */
   22 
   23 #include "FreeImage.h"
   24 #include "imageloaderfreeimage.h"
   25 #include <qendian.h>
   26 #include <QStringList>
   27 #include <QColor>
   28 #include <math.h>
   29 
   30 static QString FreeImageErrorMessage;
   31 
   32 void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const char *message)
   33 {
   34     Q_UNUSED(fif)
   35     FreeImageErrorMessage = message;
   36 }
   37 
   38 class FreeImageInitializer
   39 {
   40 public:
   41     FreeImageInitializer()
   42     {
   43         FreeImage_Initialise();
   44         FreeImage_SetOutputMessage(FreeImageErrorHandler);
   45     }
   46 
   47     ~FreeImageInitializer()
   48     {
   49         FreeImage_DeInitialise();
   50     }
   51 };
   52 
   53 ImageLoaderFreeImage::ImageLoaderFreeImage(QObject *parent)
   54     : QObject(parent)
   55     , m_bitmap(NULL)
   56     , m_widthPixels(0)
   57     , m_heightPixels(0)
   58     , m_horizontalDotsPerMeter(0)
   59     , m_verticalDotsPerMeter(0)
   60 {
   61     const static FreeImageInitializer initializer;
   62 }
   63 
   64 ImageLoaderFreeImage::~ImageLoaderFreeImage()
   65 {
   66     disposeImage();
   67 }
   68 
   69 void ImageLoaderFreeImage::disposeImage()
   70 {
   71     if (m_bitmap) {
   72         FreeImage_Unload(m_bitmap);
   73         m_bitmap = NULL;
   74     }
   75 }
   76 
   77 bool ImageLoaderFreeImage::loadInputImage(const QString &imageFileName, QString &errorMessage)
   78 {
   79     bool result = false;
   80 
   81     FreeImageErrorMessage.clear();
   82 
   83     const FREE_IMAGE_FORMAT fileType = FreeImage_GetFileType(imageFileName.toAscii(), 0);
   84     FIBITMAP* newImage = FreeImage_Load(fileType, imageFileName.toAscii(), TIFF_CMYK|JPEG_CMYK);
   85 
   86     // Filter out images which FreeImage can load but not convert to Rgb24
   87     // And images which we simply don't handle
   88     if (newImage) {
   89         const FREE_IMAGE_TYPE type = FreeImage_GetImageType(newImage);
   90         if (type != FIT_BITMAP   // 1pbb Monochrome, 1-8bpp Palette, 8bpp Greyscale,
   91                                  // 24bpp Rgb, 32bpp Argb, 32bpp Cmyk
   92             && type != FIT_RGB16 // 16bpp Greyscale, 48bpp Rgb
   93             ) {
   94             FreeImage_Unload(newImage);
   95             newImage = NULL;
   96         }
   97     }
   98 
   99     if (newImage) {
  100         result = true;
  101         disposeImage();
  102 
  103         m_bitmap = newImage;
  104 
  105         m_widthPixels = FreeImage_GetWidth(m_bitmap);
  106         m_heightPixels = FreeImage_GetHeight(m_bitmap);
  107 
  108         m_horizontalDotsPerMeter = FreeImage_GetDotsPerMeterX(m_bitmap);
  109         m_verticalDotsPerMeter = FreeImage_GetDotsPerMeterY(m_bitmap);
  110 
  111         if (m_horizontalDotsPerMeter == 0)
  112             m_horizontalDotsPerMeter = 2835; // 72 dpi
  113         if (m_verticalDotsPerMeter == 0)
  114             m_verticalDotsPerMeter = 2835;
  115 
  116         m_imageFileName = imageFileName;
  117 
  118         if (colorDataType() == Types::ColorTypeRGB && bitsPerPixel() == 32) {
  119             // Sometimes, there are strange .PSD images like this (FreeImage bug?)
  120             RGBQUAD white = { 255, 255, 255, 0 };
  121             FIBITMAP *Image24Bit = FreeImage_Composite(m_bitmap, FALSE, &white);
  122             FreeImage_Unload(m_bitmap);
  123             m_bitmap = Image24Bit;
  124         }
  125     }
  126 
  127     errorMessage = FreeImageErrorMessage;
  128 
  129     return result;
  130 }
  131 
  132 bool ImageLoaderFreeImage::isImageLoaded() const
  133 {
  134     return (m_bitmap != NULL);
  135 }
  136 
  137 bool ImageLoaderFreeImage::isJpeg() const
  138 {
  139     return FreeImage_GetFileType(m_imageFileName.toAscii(), 0) == FIF_JPEG;
  140 }
  141 
  142 QString ImageLoaderFreeImage::fileName() const
  143 {
  144     return m_imageFileName;
  145 }
  146 
  147 QSize ImageLoaderFreeImage::sizePixels() const
  148 {
  149     return QSize(m_widthPixels, m_heightPixels);
  150 }
  151 
  152 double ImageLoaderFreeImage::horizontalDotsPerUnitOfLength(Types::UnitsOfLength unit) const
  153 {
  154     return m_horizontalDotsPerMeter / Types::convertBetweenUnitsOfLength(1, Types::UnitOfLengthMeter, unit);
  155 }
  156 
  157 double ImageLoaderFreeImage::verticalDotsPerUnitOfLength(Types::UnitsOfLength unit) const
  158 {
  159     return m_verticalDotsPerMeter / Types::convertBetweenUnitsOfLength(1, Types::UnitOfLengthMeter, unit);
  160 }
  161 
  162 QSizeF ImageLoaderFreeImage::size(Types::UnitsOfLength unit) const
  163 {
  164     const QSize sizePixels = this->sizePixels();
  165     return QSizeF(sizePixels.width() / horizontalDotsPerUnitOfLength(unit), sizePixels.height() / verticalDotsPerUnitOfLength(unit));
  166 }
  167 
  168 const QImage ImageLoaderFreeImage::imageAsRGB(const QSize &size) const
  169 {
  170     const QSize resultSize = size.isValid()?size:sizePixels();
  171     const bool isRGB24 = colorDataType() == Types::ColorTypeRGB && bitsPerPixel() == 24;
  172     const bool isARGB32 = colorDataType() == Types::ColorTypeRGBA && bitsPerPixel() == 32;
  173     QImage result(resultSize, isARGB32?QImage::Format_ARGB32:QImage::Format_RGB32);
  174 
  175     const int width = resultSize.width();
  176     const int height = resultSize.height();
  177     const QSize sizePixels = this->sizePixels();
  178 
  179     FIBITMAP* originalImage = m_bitmap;
  180     FIBITMAP* temp24BPPImage = NULL;
  181     FIBITMAP* scaledImage = NULL;
  182 
  183     if (!(isRGB24 || isARGB32)) {
  184         if (colorDataType() == Types::ColorTypeCMYK) {
  185             const bool isCmykJpeg = isJpeg(); // Value range inverted
  186             temp24BPPImage = FreeImage_Allocate(sizePixels.width(), sizePixels.height(), 24);
  187             const unsigned int columnsCount = sizePixels.width();
  188             const unsigned int scanlinesCount = sizePixels.height();
  189             for (unsigned int scanline = 0; scanline < scanlinesCount; scanline++) {
  190                 const BYTE* const cmykBits = FreeImage_GetScanLine(m_bitmap, scanline);
  191                 tagRGBTRIPLE* const rgbBits = (tagRGBTRIPLE *)FreeImage_GetScanLine(temp24BPPImage, scanline);
  192 
  193                 for (unsigned int column = 0; column < columnsCount; column++) {
  194                     const unsigned int cmykColumn = column * 4;
  195 
  196                     const QColor rgbColor = isCmykJpeg?
  197                         QColor::fromCmyk(255 - cmykBits[cmykColumn], 255 - cmykBits[cmykColumn + 1], 255 - cmykBits[cmykColumn + 2], 255 - cmykBits[cmykColumn + 3])
  198                         :QColor::fromCmyk(cmykBits[cmykColumn], cmykBits[cmykColumn + 1], cmykBits[cmykColumn + 2], cmykBits[cmykColumn + 3]);
  199 
  200                     rgbBits[column].rgbtRed = (BYTE)rgbColor.red();
  201                     rgbBits[column].rgbtGreen = (BYTE)rgbColor.green();
  202                     rgbBits[column].rgbtBlue = (BYTE)rgbColor.blue();
  203                 }
  204             }
  205         } else {
  206             temp24BPPImage = FreeImage_ConvertTo24Bits(originalImage);
  207         }
  208         originalImage = temp24BPPImage;
  209     }
  210 
  211     if (resultSize != sizePixels) {
  212         scaledImage = FreeImage_Rescale(originalImage, width, height, FILTER_BOX);
  213         originalImage = scaledImage;
  214     }
  215 
  216     for (int scanline = 0; scanline < height; scanline++) {
  217         QRgb *targetData = (QRgb*)result.scanLine(scanline);
  218         if (isARGB32) {
  219             const tagRGBQUAD *sourceRgba = (tagRGBQUAD*)FreeImage_GetScanLine(originalImage, height - scanline - 1);
  220             for (int column = 0; column < width; column++) {
  221                 *targetData++ = qRgba(sourceRgba->rgbRed, sourceRgba->rgbGreen, sourceRgba->rgbBlue, sourceRgba->rgbReserved);
  222                 sourceRgba++;
  223             }
  224         } else {
  225             const tagRGBTRIPLE *sourceRgb = (tagRGBTRIPLE*)FreeImage_GetScanLine(originalImage, height - scanline - 1);
  226             for (int column = 0; column < width; column++) {
  227                 *targetData++ = qRgb(sourceRgb->rgbtRed, sourceRgb->rgbtGreen, sourceRgb->rgbtBlue);
  228                 sourceRgb++;
  229             }
  230         }
  231     }
  232 
  233     if (temp24BPPImage)
  234         FreeImage_Unload(temp24BPPImage);
  235 
  236     if (scaledImage)
  237         FreeImage_Unload(scaledImage);
  238 
  239     return result;
  240 }
  241 
  242 int ImageLoaderFreeImage::bitsPerPixel() const
  243 {
  244     return FreeImage_GetBPP(m_bitmap);
  245 }
  246 
  247 Types::ColorTypes ImageLoaderFreeImage::colorDataType() const
  248 {
  249     Types::ColorTypes colorDatatype = Types::ColorTypeRGB;
  250     const FREE_IMAGE_COLOR_TYPE imageColorType = FreeImage_GetColorType(m_bitmap);
  251 
  252     if (imageColorType == FIC_MINISBLACK || imageColorType == FIC_MINISWHITE) {
  253         colorDatatype = bitsPerPixel()==1?Types::ColorTypeMonochrome:Types::ColorTypeGreyscale;
  254     } else {
  255         colorDatatype =
  256             imageColorType==FIC_PALETTE?Types::ColorTypePalette:
  257             imageColorType==FIC_RGB?Types::ColorTypeRGB:
  258             imageColorType==FIC_RGBALPHA?Types::ColorTypeRGBA:
  259             /*imageColorType==FIC_CMYK?*/Types::ColorTypeCMYK;
  260     }
  261 
  262     return colorDatatype;
  263 }
  264 
  265 const QByteArray ImageLoaderFreeImage::bits() const
  266 {
  267     const unsigned int bitsPerLine = m_widthPixels * bitsPerPixel();
  268     const unsigned int bytesPerLine = (unsigned int)ceil(bitsPerLine/8.0);
  269     const unsigned int imageBytesCount = bytesPerLine * m_heightPixels;
  270 
  271     QByteArray result(imageBytesCount, 0);
  272     char *destination = result.data();
  273     FreeImage_ConvertToRawBits((BYTE*)destination, m_bitmap, bytesPerLine, bitsPerPixel(), FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, hasFreeImageVersionCorrectTopDownInConvertBits());
  274 
  275     const unsigned long numberOfPixels = m_widthPixels * m_heightPixels;
  276 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
  277     if (colorDataType() == Types::ColorTypeRGB && bitsPerPixel() == 24) {
  278         for (unsigned int pixelIndex = 0; pixelIndex < numberOfPixels; pixelIndex++) {
  279             char *pixelPtr = destination + pixelIndex*3;
  280             const char temp = pixelPtr[0];
  281             pixelPtr[0] = pixelPtr[2];
  282             pixelPtr[2] = temp;
  283             pixelPtr+=3;
  284         }
  285     } else if (colorDataType() == Types::ColorTypeRGBA && bitsPerPixel() == 32) {
  286         unsigned int* argbDestination = (unsigned int*)destination;
  287         for (unsigned int pixelIndex = 0; pixelIndex < numberOfPixels; pixelIndex++)
  288             *argbDestination++ = qToBigEndian(*argbDestination);
  289     } else
  290 #endif // FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
  291     if (colorDataType() == Types::ColorTypeRGB && bitsPerPixel() == 48) {
  292         // Apparently, the 48 bit data has to be reordered on Windows and ppc/i386 OSX
  293         // TODO: So maybe this swap belongs into the PDFwriter. Investigate.
  294         unsigned short* rgb48Destination = (unsigned short*)destination;
  295         const unsigned long numberOfSwaps = numberOfPixels * 3; // Words are swapped
  296         for (unsigned int pixelIndex = 0; pixelIndex < numberOfSwaps; pixelIndex++)
  297             *rgb48Destination++ = qToBigEndian(*rgb48Destination);
  298     }
  299 
  300     return result;
  301 }
  302 
  303 const QVector<QRgb> ImageLoaderFreeImage::colorTable() const
  304 {
  305     QVector<QRgb> result;
  306 
  307     const RGBQUAD* const palette = FreeImage_GetPalette(m_bitmap);
  308     if (palette) {
  309         const int count = FreeImage_GetColorsUsed(m_bitmap);
  310         result.resize(count);
  311         for (int i = 0; i < count; i++)
  312             result.replace(i, qRgb(palette[i].rgbRed, palette[i].rgbGreen, palette[i].rgbBlue));
  313     }
  314 
  315     return result;
  316 }
  317 
  318 const QVector<QPair<QStringList, QString> > &ImageLoaderFreeImage::imageFormats() const
  319 {
  320     static QVector<QPair<QStringList, QString> > formats;
  321     if (formats.empty()) {
  322         const int pluginsCount = FreeImage_GetFIFCount();
  323         for (int pluginIndex = 0; pluginIndex < pluginsCount; pluginIndex++) {
  324             const FREE_IMAGE_FORMAT fif = (FREE_IMAGE_FORMAT)pluginIndex;
  325             if (FreeImage_FIFSupportsReading(fif)) {
  326                 const QString pluginExtensions(FreeImage_GetFIFExtensionList(fif));
  327                 const QString pluginDescription(FreeImage_GetFIFDescription(fif));
  328                 formats.append(QPair<QStringList, QString> (pluginExtensions.split(','), pluginDescription));
  329             }
  330         }
  331     }
  332     return formats;
  333 }
  334 
  335 bool ImageLoaderFreeImage::hasFreeImageVersionCorrectTopDownInConvertBits()
  336 {
  337     return FREEIMAGE_MAJOR_VERSION >= 3 && FREEIMAGE_MINOR_VERSION >= 10;
  338 }
  339 QString ImageLoaderFreeImage::libraryName() const
  340 {
  341     return QLatin1String("FreeImage");
  342 }
  343 
  344 QString ImageLoaderFreeImage::libraryAboutText() const
  345 {
  346     static const QString copyrightMessage(FreeImage_GetCopyrightMessage());
  347     return copyrightMessage;
  348 }