drop support for bmp, ico, tga, jpeg and tiff

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2021-12-14 22:39:20 +02:00
parent 2b999e10bc
commit cda61d753f
82 changed files with 153 additions and 4803 deletions

View file

@ -29,7 +29,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -qq libpcre3-dev libssl-dev zlib1g-dev libzstd-dev libjansson-dev libc6-dev libpng-dev libjpeg-dev libtiff-dev libcups2-dev libfreetype6-dev libfontconfig1-dev libdbus-1-dev libicu-dev unixodbc-dev libpq-dev libsqlite3-dev xorg-dev
sudo apt-get install -qq libpcre3-dev libssl-dev zlib1g-dev libzstd-dev libjansson-dev libc6-dev libpng-dev libcups2-dev libfreetype6-dev libfontconfig1-dev libdbus-1-dev libicu-dev xorg-dev
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL

View file

@ -146,21 +146,12 @@ set(KATIE_TOOLS_SUFFIX "" CACHE STRING "Tools (moc, uic, rcc, etc.) suffix")
option(WITH_CUPS "Build CUPS support" ON)
add_feature_info(cups WITH_CUPS "build CUPS support")
option(WITH_JPEG "Build JPEG support" ON)
add_feature_info(jpeg WITH_JPEG "build JPEG support")
option(WITH_TIFF "Build TIFF support" ON)
add_feature_info(tiff WITH_TIFF "build TIFF support")
option(WITH_DBUS "Build D-Bus support" ON)
add_feature_info(dbus WITH_DBUS "build D-Bus support")
option(WITH_FONTCONFIG "Build Fontconfig support" ON)
add_feature_info(fontconfig WITH_FONTCONFIG "build Fontconfig support")
option(WITH_ODBC "Build ODBC database plugin" ON)
add_feature_info(odbc WITH_ODBC "build ODBC support")
option(WITH_INTL "Build Intl support" ON)
add_feature_info(intl WITH_INTL "build Intl support")
@ -269,23 +260,6 @@ set_package_properties(PNG PROPERTIES
TYPE REQUIRED
)
find_package(JPEG)
set_package_properties(JPEG PROPERTIES
PURPOSE "JPEG format handler"
DESCRIPTION "JPEG image codec with accelerated baseline compression and decompression"
URL "https://libjpeg-turbo.virtualgl.org/"
TYPE RECOMMENDED
)
# v3.6.0+ required for TIFFReadRGBAImageOriented()
find_package(TIFF 3.6.0)
set_package_properties(TIFF PROPERTIES
PURPOSE "TIFF format handler"
DESCRIPTION "Library for manipulation of TIFF images"
URL "http://www.libtiff.org/"
TYPE RECOMMENDED
)
find_package(Cups)
set_package_properties(Cups PROPERTIES
PURPOSE "Required for printing support"

View file

@ -12,9 +12,9 @@ build_script:
sudo apt-get update -qq
sudo apt-get install -qq libpcre3-dev libssl-dev zlib1g-dev libzstd-dev libc6-dev libpng-dev \
libjpeg-dev libtiff-dev libcups2-dev libfreetype6-dev libfontconfig1-dev libdbus-1-dev \
libicu-dev xorg-dev dbus-x11 libjansson-dev ccache
sudo apt-get install -qq libpcre3-dev libssl-dev zlib1g-dev libzstd-dev \
libc6-dev libpng-dev libcups2-dev libfreetype6-dev libfontconfig1-dev \
libdbus-1-dev libicu-dev xorg-dev dbus-x11 libjansson-dev ccache
export PATH="/usr/lib/ccache/:$PATH"

View file

@ -6,17 +6,16 @@ Vcs-Git: git://github.com/fluxer/katie.git
Vcs-browser: https://github.com/fluxer/katie
Standards-Version: 4.12.0
Build-Depends: debhelper (>= 9~), libssl-dev, zlib1g-dev, libzstd-dev,
libc6-dev, libjansson-dev, libpng-dev, libjpeg-dev, libtiff5-dev,
libcups2-dev, libfreetype6-dev, libfontconfig1-dev, libpcre3-dev,
libdbus-1-dev, libicu-dev, cmake, git, xserver-xorg-dev,
libxinerama-dev, libxrandr-dev, libxrender-dev, libxcursor-dev,
libsm-dev, unifdef | dpkg
libc6-dev, libjansson-dev, libpng-dev, libcups2-dev, libfreetype6-dev,
libfontconfig1-dev, libpcre3-dev, libdbus-1-dev, libicu-dev, cmake,
git, xserver-xorg-dev, libxinerama-dev, libxrandr-dev, libxrender-dev,
libxcursor-dev, libsm-dev, unifdef | dpkg
Package: katie-runtime
Architecture: amd64 arm64 armel armhf i386 mips mips64el mipsel ppc64el s390x hurd-i386
Section: x11
Depends: ${shlibs:Depends}, ${misc:Depends}, xdg-utils
Recommends: unixodbc, xserver-xorg-core
Recommends: xserver-xorg-core
Description: C++ toolkit derived from the Qt 4.8 framework
Katie is continuation of the Qt4 C++ toolkit with the goal to keep it alive,
clean it up, fix some bugs and backport some features from Qt5. It is based

View file

@ -7,7 +7,7 @@ Summary: C++ toolkit derived from the Qt 4.8 framework
License: BSD and LGPLv2+
URL: https://github.com/fluxer/katie
BuildRequires: gcc-c++ cmake libicu-devel libzstd-devel jansson-devel zlib-devel libpng-devel freetype-devel pcre-devel openssl-devel libX11-devel libXinerama-devel libXrandr-devel libXrender-devel libXfixes-devel libXcursor-devel libSM-devel libICE-devel dbus-devel libtiff-devel libjpeg-turbo-devel fontconfig-devel cups-devel unifdef
BuildRequires: gcc-c++ cmake libicu-devel libzstd-devel jansson-devel zlib-devel libpng-devel freetype-devel pcre-devel openssl-devel libX11-devel libXinerama-devel libXrandr-devel libXrender-devel libXfixes-devel libXcursor-devel libSM-devel libICE-devel dbus-devel fontconfig-devel cups-devel unifdef
Requires: xdg-utils
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig

View file

@ -13,16 +13,15 @@ DISTFILES = master.tar.gz
DIST_SUBDIR = ${PORTNAME}
WRKSRC = ${WRKDIR}/katie-master
USES = compiler:c++11-lang pkgconfig cmake ssl xorg jpeg desktop-file-utils
USES = compiler:c++11-lang pkgconfig cmake ssl xorg desktop-file-utils
USE_XORG = x11 xinerama xrandr xrender xfixes xcursor xext sm ice
USE_LDCONFIG = yes
RUN_DEPENDS = xdg-open:devel/xdg-utils
LIB_DEPENDS = libzstd.so:archivers/zstd libicuuc.so:devel/icu \
libicui18n.so:devel/icu libjansson.so:devel/jansson \
libpcre.so:devel/pcre libpng.so:graphics/png \
libtiff.so:graphics/tiff libfreetype.so:print/freetype2 \
libfontconfig.so:x11-fonts/fontconfig libdbus-1.so:devel/dbus \
libcups.so:print/cups
libfreetype.so:print/freetype2 libfontconfig.so:x11-fonts/fontconfig \
libdbus-1.so:devel/dbus libcups.so:print/cups
CMAKE_ARGS = -DKATIE_TOOLS_SUFFIX="-katie" -Wno-dev
OPTIONS_DEFINE = NLS

View file

@ -1406,11 +1406,7 @@ lib/katie/plugins/accessible/libqtaccessiblewidgets.so
lib/katie/plugins/designer/libqdeclarativeview.so
lib/katie/plugins/iconengines/libqsvgicon.so
lib/katie/plugins/imageformats/libqgif.so
lib/katie/plugins/imageformats/libqico.so
lib/katie/plugins/imageformats/libqjpeg.so
lib/katie/plugins/imageformats/libqsvg.so
lib/katie/plugins/imageformats/libqtga.so
lib/katie/plugins/imageformats/libqtiff.so
lib/katie/plugins/script/libqtscriptdbus.so
lib/libKtCore.so
lib/libKtCore.so.4.12

View file

@ -43,10 +43,8 @@ BUILD_DEPENDS = unifdef-[0-9]*:../../devel/unifdef
.include "../../fonts/fontconfig/buildlink3.mk"
.include "../../graphics/freetype2/buildlink3.mk"
.include "../../graphics/png/buildlink3.mk"
.include "../../graphics/tiff/buildlink3.mk"
.include "../../print/cups-base/buildlink3.mk"
.include "../../sysutils/dbus/buildlink3.mk"
.include "../../mk/pthread.buildlink3.mk"
.include "../../mk/jpeg.buildlink3.mk"
.include "../../mk/dlopen.buildlink3.mk"
.include "../../mk/bsd.pkg.mk"

View file

@ -1409,11 +1409,7 @@ lib/katie/plugins/accessible/libqtaccessiblewidgets.so
lib/katie/plugins/designer/libqdeclarativeview.so
lib/katie/plugins/iconengines/libqsvgicon.so
lib/katie/plugins/imageformats/libqgif.so
lib/katie/plugins/imageformats/libqico.so
lib/katie/plugins/imageformats/libqjpeg.so
lib/katie/plugins/imageformats/libqsvg.so
lib/katie/plugins/imageformats/libqtga.so
lib/katie/plugins/imageformats/libqtiff.so
lib/katie/plugins/script/libqtscriptdbus.so
lib/libKtCore.so
lib/libKtCore.so.4.12

View file

@ -22,10 +22,9 @@ MODULES = devel/cmake
BUILD_DEPENDS = devel/gettext,-tools
RUN_DEPENDS = devel/desktop-file-utils devel/xdg-utils
LIB_DEPENDS = archivers/zstd textproc/icu4c devel/jansson devel/pcre \
graphics/png graphics/jpeg graphics/tiff x11/dbus print/cups,-libs \
devel/gettext,-runtime
graphics/png x11/dbus print/cups,-libs devel/gettext,-runtime
WANTLIB = ${COMPILER_LIBCXX} ICE SM X11 Xcursor Xext Xfixes Xinerama Xrandr \
Xrender fontconfig freetype zstd icui18n icuuc pcre png jpeg tiff \
Xrender fontconfig freetype zstd icui18n icuuc pcre png \
dbus-1 cups intl ssl z c crypto m
SEPARATE_BUILD = Yes
CONFIGURE_ARGS = -DKATIE_TOOLS_SUFFIX="-katie" -Wno-dev

View file

@ -1433,11 +1433,7 @@ lib/katie/plugins/iconengines/
@so lib/katie/plugins/iconengines/libqsvgicon.so
lib/katie/plugins/imageformats/
@so lib/katie/plugins/imageformats/libqgif.so
@so lib/katie/plugins/imageformats/libqico.so
@so lib/katie/plugins/imageformats/libqjpeg.so
@so lib/katie/plugins/imageformats/libqsvg.so
@so lib/katie/plugins/imageformats/libqtga.so
@so lib/katie/plugins/imageformats/libqtiff.so
lib/katie/plugins/script/
@so lib/katie/plugins/script/libqtscriptdbus.so
@lib lib/libKtCore.so.${LIBKtCore_VERSION}

View file

@ -3,7 +3,7 @@
import os, glob, subprocess
components = ('core', 'dbus', 'declarative', 'gui', 'network', 'plugins',
'script', 'scripttools', 'sql', 'svg', 'test', 'uitools', 'xml')
'script', 'scripttools', 'svg', 'test', 'uitools', 'xml')
cfiles = []
tfiles = []

View file

@ -96,6 +96,7 @@
#define QT_NO_TABLETEVENT
#define QT_NO_RAWFONT
#define QT_NO_IMAGE_TEXT
#define QT_NO_IMAGEFORMAT_BMP
#define QT_NO_IMAGEFORMAT_MNG
#define QT_NO_TEXTODFWRITER
#define QT_NO_TEXTCODECPLUGIN
@ -200,7 +201,6 @@
#cmakedefine QT_NO_HTTP
#cmakedefine QT_NO_ICON
#cmakedefine QT_NO_IDENTITYPROXYMODEL
#cmakedefine QT_NO_IMAGEFORMAT_BMP
#cmakedefine QT_NO_IMAGEFORMAT_PPM
#cmakedefine QT_NO_IMAGEFORMAT_XBM
#cmakedefine QT_NO_IMAGEFORMAT_XPM

View file

@ -38,10 +38,9 @@ QT_BEGIN_NAMESPACE
The Image element is used to display images in a declarative user interface.
The source of the image is specified as a URL using the \l source property.
Images can be supplied in any of the standard image formats supported by Qt,
including bitmap formats such as PNG and JPEG, and vector graphics formats
such as SVG. If you need to display animated images, use the \l AnimatedImage
element.
Images can be supplied in any of the standard image formats supported by Katie,
including bitmap formats such as PNG and vector graphics formats such as SVG.
If you need to display animated images, use the \l AnimatedImage element.
If the \l{Item::width}{width} and \l{Item::height}{height} properties are not
specified, the Image element automatically uses the size of the loaded image.
@ -335,7 +334,7 @@ qreal QDeclarativeImage::paintedHeight() const
Image {
anchors.fill: parent
source: "reallyBigImage.jpg"
source: "reallyBigImage.png"
sourceSize.width: 1024
sourceSize.height: 1024
}
@ -352,9 +351,8 @@ qreal QDeclarativeImage::paintedHeight() const
Avoid changing this property dynamically; rendering an SVG is \e slow compared
to an image.
If the source is a non-scalable image (eg. JPEG), the loaded image will
be no greater than this property specifies. For some formats (currently only JPEG),
the whole image will never actually be loaded into memory.
If the source is a non-scalable image (eg. PNG), the loaded image will
be no greater than this property specifies.
Since QtQuick 1.1 the sourceSize can be cleared to the natural size of the image
by setting sourceSize to \c undefined.

View file

@ -341,17 +341,13 @@ static QString imageFilter()
{
QString filter = QApplication::translate("IconSelector", "All Pixmaps (");
const QList<QByteArray> supportedImageFormats = QImageReader::supportedImageFormats();
const QString jpeg = QLatin1String("JPEG");
const int count = supportedImageFormats.count();
for (int i = 0; i< count; ++i) {
if (i)
filter += QLatin1Char(' ');
filter += QLatin1String("*.");
const QString outputFormat = QString::fromUtf8(supportedImageFormats.at(i));
if (outputFormat != jpeg)
filter += outputFormat.toLower();
else
filter += QLatin1String("jpg *.jpeg");
}
filter += QLatin1Char(')');
return filter;

View file

@ -314,7 +314,6 @@ set(GUI_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/image/qpixmapcache.h
${CMAKE_CURRENT_SOURCE_DIR}/image/qpixmapdata_p.h
${CMAKE_CURRENT_SOURCE_DIR}/image/qpixmapfilter_p.h
${CMAKE_CURRENT_SOURCE_DIR}/image/qbmphandler_p.h
${CMAKE_CURRENT_SOURCE_DIR}/image/qppmhandler_p.h
${CMAKE_CURRENT_SOURCE_DIR}/image/qxbmhandler_p.h
${CMAKE_CURRENT_SOURCE_DIR}/image/qxpmhandler_p.h
@ -684,7 +683,6 @@ set(GUI_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/image/qpixmap_raster.cpp
${CMAKE_CURRENT_SOURCE_DIR}/image/qpixmap_x11.cpp
# Built-in image format support
${CMAKE_CURRENT_SOURCE_DIR}/image/qbmphandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/image/qppmhandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/image/qxbmhandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/image/qxpmhandler.cpp

View file

@ -84,7 +84,7 @@ Q_GUI_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook
In the above example, a modal QFileDialog is created using a static
function. The dialog initially displays the contents of the "/home/jana"
directory, and displays files matching the patterns given in the
string "Image Files (*.png *.jpg *.bmp)". The parent of the file dialog
string "Image Files (*.png *.xpm)". The parent of the file dialog
is set to \e this, and the window title is set to "Open Image".
If you want to use multiple filters, separate each one with
@ -111,11 +111,11 @@ Q_GUI_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook
\snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 3
In the above example, the filter is set to \c{"Images (*.png *.xpm *.jpg)"},
this means that only files with the extension \c png, \c xpm,
or \c jpg will be shown in the QFileDialog. You can apply
several filters by using setNameFilters(). Use selectNameFilter() to select
one of the filters you've given as the file dialog's default filter.
In the above example, the filter is set to \c{"Images (*.png *.xpm)"},
this means that only files with the extension \c png or \c xpm,
will be shown in the QFileDialog. You can apply several filters by
using setNameFilters(). Use selectNameFilter() to select one of the
filters you've given as the file dialog's default filter.
The file dialog has two view modes: \l{QFileDialog::}{List} and
\l{QFileDialog::}{Detail}.
@ -1524,7 +1524,7 @@ QString QFileDialog::labelText(DialogLabel label) const
example:
\code
"Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
"Images (*.png *.xpm);;Text files (*.txt);;XML files (*.xml)"
\endcode
The \a options argument holds various options about how to run the dialog,
@ -1603,7 +1603,7 @@ QString QFileDialog::getOpenFileName(QWidget *parent,
filters, separate them with ';;', for instance:
\code
"Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
"Images (*.png *.xpm);;Text files (*.txt);;XML files (*.xml)"
\endcode
The dialog's caption is set to \a caption. If \a caption is not specified
@ -1685,7 +1685,7 @@ QStringList QFileDialog::getOpenFileNames(QWidget *parent,
Multiple filters are separated with ';;'. For instance:
\code
"Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
"Images (*.png *.xpm);;Text files (*.txt);;XML files (*.xml)"
\endcode
The \a options argument holds various options about how to run the dialog,
@ -2766,7 +2766,7 @@ void QFileDialogPrivate::_q_goToDirectory(const QString &path)
}
}
// Makes a list of filters from a normal filter string "Image Files (*.png *.jpg)"
// Makes a list of filters from a normal filter string "Image Files (*.png *.xpm)"
QStringList qt_clean_filter_list(const QString &filter)
{
QRegExp regexp(QString::fromLatin1(qt_file_dialog_filter_reg_exp));

View file

@ -417,7 +417,7 @@ qint64 QFileSystemModel::size(const QModelIndex &index) const
}
/*!
Returns the type of file \a index such as "Directory" or "JPEG file".
Returns the type of file \a index such as "Directory" or "PNG file".
*/
QString QFileSystemModel::type(const QModelIndex &index) const
{
@ -858,7 +858,7 @@ static inline QChar getNextChar(const QString &s, int location)
Examples:
1, 2, 10, 55, 100
01.jpg, 2.jpg, 10.jpg
01.png, 2.png, 10.png
Note on the algorithm:
Only as many characters as necessary are looked at and at most they all

View file

@ -1,827 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtGui module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbmphandler_p.h"
#ifndef QT_NO_IMAGEFORMAT_BMP
#include "qimage.h"
#include "qvariant.h"
#include "qvector.h"
#include "qcorecommon_p.h"
QT_BEGIN_NAMESPACE
static void swapPixel01(QImage *image) // 1-bpp: swap 0 and 1 pixels
{
int i;
if (image->depth() == 1 && image->colorCount() == 2) {
uint *p = (uint *)image->bits();
int nbytes = image->byteCount();
for (i=0; i<nbytes/4; i++) {
*p = ~*p;
p++;
}
uchar *p2 = (uchar *)p;
for (i=0; i<(nbytes&3); i++) {
*p2 = ~*p2;
p2++;
}
QRgb t = image->color(0); // swap color 0 and 1
image->setColor(0, image->color(1));
image->setColor(1, t);
}
}
/*
QImageIO::defineIOHandler("BMP", "^BM", 0,
read_bmp_image, write_bmp_image);
*/
/*****************************************************************************
BMP (DIB) image read/write functions
*****************************************************************************/
const int BMP_FILEHDR_SIZE = 14; // size of BMP_FILEHDR data
static QDataStream &operator>>(QDataStream &s, BMP_FILEHDR &bf)
{ // read file header
s.readRawData(bf.bfType, 2);
s >> bf.bfSize >> bf.bfReserved1 >> bf.bfReserved2 >> bf.bfOffBits;
return s;
}
static QDataStream &operator<<(QDataStream &s, const BMP_FILEHDR &bf)
{ // write file header
s.writeRawData(bf.bfType, 2);
s << bf.bfSize << bf.bfReserved1 << bf.bfReserved2 << bf.bfOffBits;
return s;
}
const int BMP_OLD = 12; // old Windows/OS2 BMP size
const int BMP_WIN = 40; // Windows BMP v3 size
const int BMP_OS2 = 64; // new OS/2 BMP size
const int BMP_WIN4 = 108; // Windows BMP v4 size
const int BMP_WIN5 = 124; // Windows BMP v5 size
const int BMP_RGB = 0; // no compression
const int BMP_RLE8 = 1; // run-length encoded, 8 bits
const int BMP_RLE4 = 2; // run-length encoded, 4 bits
const int BMP_BITFIELDS = 3; // RGB values encoded in data as bit-fields
static QDataStream &operator>>(QDataStream &s, BMP_INFOHDR &bi)
{
s >> bi.biSize;
if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2 || bi.biSize == BMP_WIN4 || bi.biSize == BMP_WIN5) {
s >> bi.biWidth >> bi.biHeight >> bi.biPlanes >> bi.biBitCount;
s >> bi.biCompression >> bi.biSizeImage;
s >> bi.biXPelsPerMeter >> bi.biYPelsPerMeter;
s >> bi.biClrUsed >> bi.biClrImportant;
}
else { // probably old Windows format
qint16 w, h;
s >> w >> h >> bi.biPlanes >> bi.biBitCount;
bi.biWidth = w;
bi.biHeight = h;
bi.biCompression = BMP_RGB; // no compression
bi.biSizeImage = 0;
bi.biXPelsPerMeter = bi.biYPelsPerMeter = 0;
bi.biClrUsed = bi.biClrImportant = 0;
}
return s;
}
static QDataStream &operator<<(QDataStream &s, const BMP_INFOHDR &bi)
{
s << bi.biSize;
s << bi.biWidth << bi.biHeight;
s << bi.biPlanes;
s << bi.biBitCount;
s << bi.biCompression;
s << bi.biSizeImage;
s << bi.biXPelsPerMeter << bi.biYPelsPerMeter;
s << bi.biClrUsed << bi.biClrImportant;
return s;
}
static int calc_shift(uint mask)
{
int result = 0;
while (mask && !(mask & 1)) {
result++;
mask >>= 1;
}
return result;
}
static bool read_dib_fileheader(QDataStream &s, BMP_FILEHDR &bf)
{
// read BMP file header
s >> bf;
if (s.status() != QDataStream::Ok)
return false;
// check header
if (qstrncmp(bf.bfType,"BM",2) != 0)
return false;
return true;
}
static bool read_dib_infoheader(QDataStream &s, BMP_INFOHDR &bi)
{
s >> bi; // read BMP info header
if (s.status() != QDataStream::Ok)
return false;
int nbits = bi.biBitCount;
int comp = bi.biCompression;
if (!(nbits == 1 || nbits == 4 || nbits == 8 || nbits == 16 || nbits == 24 || nbits == 32) ||
bi.biPlanes != 1 || comp > BMP_BITFIELDS)
return false; // weird BMP image
if (!(comp == BMP_RGB || (nbits == 4 && comp == BMP_RLE4) ||
(nbits == 8 && comp == BMP_RLE8) || ((nbits == 16 || nbits == 32) && comp == BMP_BITFIELDS)))
return false; // weird compression type
return true;
}
static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int startpos, QImage &image)
{
QIODevice* d = s.device();
if (d->atEnd()) // end of stream/file
return false;
#if 0
qDebug("offset...........%d", offset);
qDebug("startpos.........%d", startpos);
qDebug("biSize...........%d", bi.biSize);
qDebug("biWidth..........%d", bi.biWidth);
qDebug("biHeight.........%d", bi.biHeight);
qDebug("biPlanes.........%d", bi.biPlanes);
qDebug("biBitCount.......%d", bi.biBitCount);
qDebug("biCompression....%d", bi.biCompression);
qDebug("biSizeImage......%d", bi.biSizeImage);
qDebug("biXPelsPerMeter..%d", bi.biXPelsPerMeter);
qDebug("biYPelsPerMeter..%d", bi.biYPelsPerMeter);
qDebug("biClrUsed........%d", bi.biClrUsed);
qDebug("biClrImportant...%d", bi.biClrImportant);
#endif
int w = bi.biWidth, h = bi.biHeight, nbits = bi.biBitCount;
int t = bi.biSize, comp = bi.biCompression;
uint red_mask = 0;
uint green_mask = 0;
uint blue_mask = 0;
int red_shift = 0;
int green_shift = 0;
int blue_shift = 0;
int red_scale = 0;
int green_scale = 0;
int blue_scale = 0;
int ncols = 0;
int depth = 0;
QImage::Format format;
switch (nbits) {
case 32:
case 24:
case 16:
depth = 32;
format = QImage::Format_RGB32;
break;
case 8:
case 4:
depth = 8;
format = QImage::Format_Indexed8;
break;
default:
depth = 1;
format = QImage::Format_Mono;
}
if (bi.biHeight < 0)
h = -h; // support images with negative height
if (image.size() != QSize(w, h) || image.format() != format) {
image = QImage(w, h, format);
if (image.isNull()) // could not create image
return false;
}
if (depth != 32) {
ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits;
if (ncols > 256) // sanity check - don't run out of mem if color table is broken
return false;
image.setColorCount(ncols);
}
image.setDotsPerMeterX(bi.biXPelsPerMeter);
image.setDotsPerMeterY(bi.biYPelsPerMeter);
if (!d->isSequential())
d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) {
if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
return false;
if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask))
return false;
if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask))
return false;
// Read BMP v4+ header
if (bi.biSize >= BMP_WIN4) {
int alpha_mask = 0;
int CSType = 0;
int gamma_red = 0;
int gamma_green = 0;
int gamma_blue = 0;
int endpoints[9];
if (d->read((char *)&alpha_mask, sizeof(alpha_mask)) != sizeof(alpha_mask))
return false;
if (d->read((char *)&CSType, sizeof(CSType)) != sizeof(CSType))
return false;
if (d->read((char *)&endpoints, sizeof(endpoints)) != sizeof(endpoints))
return false;
if (d->read((char *)&gamma_red, sizeof(gamma_red)) != sizeof(gamma_red))
return false;
if (d->read((char *)&gamma_green, sizeof(gamma_green)) != sizeof(gamma_green))
return false;
if (d->read((char *)&gamma_blue, sizeof(gamma_blue)) != sizeof(gamma_blue))
return false;
if (bi.biSize == BMP_WIN5) {
qint32 intent = 0;
qint32 profileData = 0;
qint32 profileSize = 0;
qint32 reserved = 0;
if (d->read((char *)&intent, sizeof(intent)) != sizeof(intent))
return false;
if (d->read((char *)&profileData, sizeof(profileData)) != sizeof(profileData))
return false;
if (d->read((char *)&profileSize, sizeof(profileSize)) != sizeof(profileSize))
return false;
if (d->read((char *)&reserved, sizeof(reserved)) != sizeof(reserved) || reserved != 0)
return false;
}
}
}
if (ncols > 0) { // read color table
QSTACKARRAY(uchar, rgb, 4);
int rgb_len = t == BMP_OLD ? 3 : 4;
for (int i=0; i<ncols; i++) {
if (d->read((char *)rgb, rgb_len) != rgb_len)
return false;
image.setColor(i, qRgb(rgb[2],rgb[1],rgb[0]));
if (d->atEnd()) // truncated file
return false;
}
} else if (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32)) {
red_shift = calc_shift(red_mask);
if (((red_mask >> red_shift) + 1) == 0)
return false;
red_scale = 256 / ((red_mask >> red_shift) + 1);
green_shift = calc_shift(green_mask);
if (((green_mask >> green_shift) + 1) == 0)
return false;
green_scale = 256 / ((green_mask >> green_shift) + 1);
blue_shift = calc_shift(blue_mask);
if (((blue_mask >> blue_shift) + 1) == 0)
return false;
blue_scale = 256 / ((blue_mask >> blue_shift) + 1);
} else if (comp == BMP_RGB && (nbits == 24 || nbits == 32)) {
blue_mask = 0x000000ff;
green_mask = 0x0000ff00;
red_mask = 0x00ff0000;
blue_shift = 0;
green_shift = 8;
red_shift = 16;
blue_scale = green_scale = red_scale = 1;
} else if (comp == BMP_RGB && nbits == 16) {
blue_mask = 0x001f;
green_mask = 0x03e0;
red_mask = 0x7c00;
blue_shift = 0;
green_shift = 2;
red_shift = 7;
red_scale = 1;
green_scale = 1;
blue_scale = 8;
}
// offset can be bogus, be careful
if (offset>=0 && startpos + offset > d->pos()) {
if (!d->isSequential())
d->seek(startpos + offset); // start of image data
}
int bpl = image.bytesPerLine();
uchar *data = image.bits();
if (nbits == 1) { // 1 bit BMP image
while (--h >= 0) {
if (d->read((char*)(data + h*bpl), bpl) != bpl)
break;
}
if (ncols == 2 && qGray(image.color(0)) < qGray(image.color(1)))
swapPixel01(&image); // pixel 0 is white!
}
else if (nbits == 4) { // 4 bit BMP image
int buflen = ((w+7)/8)*4;
QSTACKARRAY(uchar, buf, buflen);
if (comp == BMP_RLE4) { // run length compression
int x=0, y=0, c, i;
quint8 b;
uchar *p = data + (h-1)*bpl;
const uchar *endp = p + w;
while (y < h) {
if (!d->getChar((char *)&b))
break;
if (b == 0) { // escape code
if (!d->getChar((char *)&b) || b == 1) {
y = h; // exit loop
} else switch (b) {
case 0: // end of line
x = 0;
y++;
p = data + (h-y-1)*bpl;
break;
case 2: // delta (jump)
{
quint8 tmp;
d->getChar((char *)&tmp);
x += tmp;
d->getChar((char *)&tmp);
y += tmp;
}
// Protection
if ((uint)x >= (uint)w)
x = w-1;
if ((uint)y >= (uint)h)
y = h-1;
p = data + (h-y-1)*bpl + x;
break;
default: // absolute mode
// Protection
if (p + b > endp)
b = endp-p;
i = (c = b)/2;
while (i--) {
d->getChar((char *)&b);
*p++ = b >> 4;
*p++ = b & 0x0f;
}
if (c & 1) {
unsigned char tmp;
d->getChar((char *)&tmp);
*p++ = tmp >> 4;
}
if ((((c & 3) + 1) & 2) == 2)
d->getChar(0); // align on word boundary
x += c;
}
} else { // encoded mode
// Protection
if (p + b > endp)
b = endp-p;
i = (c = b)/2;
d->getChar((char *)&b); // 2 pixels to be repeated
while (i--) {
*p++ = b >> 4;
*p++ = b & 0x0f;
}
if (c & 1)
*p++ = b >> 4;
x += c;
}
}
} else if (comp == BMP_RGB) { // no compression
::memset(data, 0, size_t(h) * bpl);
while (--h >= 0) {
if (d->read((char*)buf,buflen) != buflen)
break;
uchar *p = data + h*bpl;
uchar *b = buf;
for (int i=0; i<w/2; i++) { // convert nibbles to bytes
*p++ = *b >> 4;
*p++ = *b++ & 0x0f;
}
if (w & 1) // the last nibble
*p = *b >> 4;
}
}
}
else if (nbits == 8) { // 8 bit BMP image
if (comp == BMP_RLE8) { // run length compression
int x=0, y=0;
quint8 b;
uchar *p = data + (h-1)*bpl;
const uchar *endp = p + w;
while (y < h) {
if (!d->getChar((char *)&b))
break;
if (b == 0) { // escape code
if (!d->getChar((char *)&b) || b == 1) {
y = h; // exit loop
} else switch (b) {
case 0: // end of line
x = 0;
y++;
p = data + (h-y-1)*bpl;
break;
case 2: // delta (jump)
{
quint8 tmp;
d->getChar((char *)&tmp);
x += tmp;
d->getChar((char *)&tmp);
y += tmp;
}
// Protection
if ((uint)x >= (uint)w)
x = w-1;
if ((uint)y >= (uint)h)
y = h-1;
p = data + (h-y-1)*bpl + x;
break;
default: // absolute mode
// Protection
if (p + b > endp)
b = endp-p;
if (d->read((char *)p, b) != b)
return false;
if ((b & 1) == 1)
d->getChar(0); // align on word boundary
x += b;
p += b;
}
} else { // encoded mode
// Protection
if (p + b > endp)
b = endp-p;
char tmp;
d->getChar(&tmp);
memset(p, tmp, b); // repeat pixel
x += b;
p += b;
}
}
} else if (comp == BMP_RGB) { // uncompressed
while (--h >= 0) {
if (d->read((char *)data + h*bpl, bpl) != bpl)
break;
}
}
}
else if (nbits == 16 || nbits == 24 || nbits == 32) { // 16,24,32 bit BMP image
QRgb *p;
QRgb *end;
QSTACKARRAY(uchar, buf24, bpl);
int bpl24 = ((w*nbits+31)/32)*4;
uchar *b;
int c;
while (--h >= 0) {
p = (QRgb *)(data + h*bpl);
end = p + w;
if (d->read((char *)buf24,bpl24) != bpl24)
break;
b = buf24;
while (p < end) {
c = *(uchar*)b | (*(uchar*)(b+1)<<8);
if (nbits != 16)
c |= *(uchar*)(b+2)<<16;
*p++ = qRgb(((c & red_mask) >> red_shift) * red_scale,
((c & green_mask) >> green_shift) * green_scale,
((c & blue_mask) >> blue_shift) * blue_scale);
b += nbits/8;
}
}
}
if (bi.biHeight < 0) {
// Flip the image
QSTACKARRAY(uchar, buf, bpl);
h = -bi.biHeight;
for (int y = 0; y < h/2; ++y) {
memcpy(buf, data + y*bpl, bpl);
memcpy(data + y*bpl, data + (h-y-1)*bpl, bpl);
memcpy(data + (h-y-1)*bpl, buf, bpl);
}
}
return true;
}
// this is also used in qmime_win.cpp
bool qt_write_dib(QDataStream &s, QImage image)
{
int nbits;
int bpl_bmp;
int bpl = image.bytesPerLine();
QIODevice* d = s.device();
if (!d->isWritable())
return false;
if (image.depth() == 8 && image.colorCount() <= 16) {
bpl_bmp = (((bpl+1)/2+3)/4)*4;
nbits = 4;
} else if (image.depth() == 32) {
bpl_bmp = ((image.width()*24+31)/32)*4;
nbits = 24;
} else {
bpl_bmp = bpl;
nbits = image.depth();
}
BMP_INFOHDR bi;
bi.biSize = BMP_WIN; // build info header
bi.biWidth = image.width();
bi.biHeight = image.height();
bi.biPlanes = 1;
bi.biBitCount = nbits;
bi.biCompression = BMP_RGB;
bi.biSizeImage = bpl_bmp*image.height();
bi.biXPelsPerMeter = image.dotsPerMeterX() ? image.dotsPerMeterX()
: 2834; // 72 dpi default
bi.biYPelsPerMeter = image.dotsPerMeterY() ? image.dotsPerMeterY() : 2834;
bi.biClrUsed = image.colorCount();
bi.biClrImportant = image.colorCount();
s << bi; // write info header
if (s.status() != QDataStream::Ok)
return false;
if (image.depth() != 32) { // write color table
QSTACKARRAY(uchar, color_table, 4*image.colorCount());
uchar *rgb = color_table;
QVector<QRgb> c = image.colorTable();
for (int i=0; i<image.colorCount(); i++) {
*rgb++ = qBlue (c[i]);
*rgb++ = qGreen(c[i]);
*rgb++ = qRed (c[i]);
*rgb++ = 0;
}
if (d->write((char *)color_table, 4*image.colorCount()) == -1) {
return false;
}
}
if (image.format() == QImage::Format_MonoLSB)
image = image.convertToFormat(QImage::Format_Mono);
int y;
if (nbits == 1 || nbits == 8) { // direct output
for (y=image.height()-1; y>=0; y--) {
if (d->write((char*)image.scanLine(y), bpl) == -1)
return false;
}
return true;
}
QSTACKARRAY(uchar, buf, bpl_bmp);
uchar *b, *end;
uchar *p;
for (y=image.height()-1; y>=0; y--) { // write the image bits
if (nbits == 4) { // convert 8 -> 4 bits
p = image.scanLine(y);
b = buf;
end = b + image.width()/2;
while (b < end) {
*b++ = (*p << 4) | (*(p+1) & 0x0f);
p += 2;
}
if (image.width() & 1)
*b = *p << 4;
} else { // 32 bits
QRgb *p = (QRgb *)image.scanLine(y);
QRgb *end = p + image.width();
b = buf;
while (p < end) {
*b++ = qBlue(*p);
*b++ = qGreen(*p);
*b++ = qRed(*p);
p++;
}
}
if (bpl_bmp != d->write((char*)buf, bpl_bmp)) {
return false;
}
}
return true;
}
QBmpHandler::QBmpHandler()
: state(Ready)
{
}
bool QBmpHandler::readHeader()
{
state = Error;
QIODevice *d = device();
QDataStream s(d);
startpos = d->pos();
// Intel byte order
s.setByteOrder(QDataStream::LittleEndian);
// read BMP file header
if (!read_dib_fileheader(s, fileHeader))
return false;
// read BMP info header
if (!read_dib_infoheader(s, infoHeader))
return false;
state = ReadHeader;
return true;
}
bool QBmpHandler::canRead() const
{
if (state == Ready && !canRead(device()))
return false;
if (state != Error) {
setFormat("bmp");
return true;
}
return false;
}
bool QBmpHandler::canRead(QIODevice *device)
{
if (Q_UNLIKELY(!device)) {
qWarning("QBmpHandler::canRead() called with no device");
return false;
}
QSTACKARRAY(char, head, 2);
if (device->peek(head, sizeof(head)) != sizeof(head))
return false;
return (qstrncmp(head, "BM", 2) == 0);
}
bool QBmpHandler::read(QImage *image)
{
if (state == Error)
return false;
if (!image) {
qWarning("QBmpHandler::read: cannot read into null pointer");
return false;
}
if (state == Ready && !readHeader()) {
state = Error;
return false;
}
QIODevice *d = device();
QDataStream s(d);
// Intel byte order
s.setByteOrder(QDataStream::LittleEndian);
// read image
if (!read_dib_body(s, infoHeader, fileHeader.bfOffBits, startpos, *image))
return false;
state = Ready;
return true;
}
bool QBmpHandler::write(const QImage &img)
{
QImage image(img);
if (image.format() == QImage::Format_RGB16) {
image = img.convertToFormat(QImage::Format_RGB32);
}
QIODevice *d = device();
QDataStream s(d);
BMP_FILEHDR bf;
int bpl_bmp;
int bpl = image.bytesPerLine();
// Code partially repeated in qt_write_dib
if (image.depth() == 8 && image.colorCount() <= 16) {
bpl_bmp = (((bpl+1)/2+3)/4)*4;
} else if (image.depth() == 32) {
bpl_bmp = ((image.width()*24+31)/32)*4;
} else {
bpl_bmp = bpl;
}
// Intel byte order
s.setByteOrder(QDataStream::LittleEndian);
// build file header
memcpy(bf.bfType, "BM", 2);
// write file header
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
bf.bfOffBits = BMP_FILEHDR_SIZE + BMP_WIN + image.colorCount() * 4;
bf.bfSize = bf.bfOffBits + bpl_bmp*image.height();
s << bf;
// write image
return qt_write_dib(s, image);
}
bool QBmpHandler::supportsOption(ImageOption option) const
{
return option == Size
|| option == ImageFormat;
}
QVariant QBmpHandler::option(ImageOption option) const
{
if (option == Size) {
if (state == Error)
return QVariant();
if (state == Ready && !const_cast<QBmpHandler*>(this)->readHeader())
return QVariant();
return QSize(infoHeader.biWidth, infoHeader.biHeight);
} else if (option == ImageFormat) {
if (state == Error)
return QVariant();
if (state == Ready && !const_cast<QBmpHandler*>(this)->readHeader())
return QVariant();
QImage::Format format;
switch (infoHeader.biBitCount) {
case 32:
case 24:
case 16:
format = QImage::Format_RGB32;
break;
case 8:
case 4:
format = QImage::Format_Indexed8;
break;
default:
format = QImage::Format_Mono;
}
return format;
}
return QVariant();
}
void QBmpHandler::setOption(ImageOption option, const QVariant &value)
{
Q_UNUSED(option);
Q_UNUSED(value);
}
QByteArray QBmpHandler::name() const
{
return "bmp";
}
QT_END_NAMESPACE
#endif // QT_NO_IMAGEFORMAT_BMP

View file

@ -1,97 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtGui module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBMPHANDLER_P_H
#define QBMPHANDLER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Katie API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "QtGui/qimageiohandler.h"
#ifndef QT_NO_IMAGEFORMAT_BMP
QT_BEGIN_NAMESPACE
struct BMP_FILEHDR { // BMP file header
char bfType[2]; // "BM"
qint32 bfSize; // size of file
qint16 bfReserved1;
qint16 bfReserved2;
qint32 bfOffBits; // pointer to the pixmap bits
};
struct BMP_INFOHDR { // BMP information header
qint32 biSize; // size of this struct
qint32 biWidth; // pixmap width
qint32 biHeight; // pixmap height
qint16 biPlanes; // should be 1
qint16 biBitCount; // number of bits per pixel
qint32 biCompression; // compression method
qint32 biSizeImage; // size of image
qint32 biXPelsPerMeter; // horizontal resolution
qint32 biYPelsPerMeter; // vertical resolution
qint32 biClrUsed; // number of colors used
qint32 biClrImportant; // number of important colors
};
class QBmpHandler : public QImageIOHandler
{
public:
QBmpHandler();
bool canRead() const;
bool read(QImage *image);
bool write(const QImage &image);
QByteArray name() const;
static bool canRead(QIODevice *device);
QVariant option(ImageOption option) const;
void setOption(ImageOption option, const QVariant &value);
bool supportsOption(ImageOption option) const;
private:
bool readHeader();
enum State {
Ready,
ReadHeader,
Error
};
State state;
BMP_FILEHDR fileHeader;
BMP_INFOHDR infoHeader;
int startpos;
};
QT_END_NAMESPACE
#endif // QT_NO_IMAGEFORMAT_BMP
#endif // QBMPHANDLER_P_H

View file

@ -313,16 +313,12 @@ bool QImageData::checkForAlphaPixels() const
formats:
\table
\header \o Format \o Description \o Qt's support
\row \o BMP \o Windows Bitmap \o Read/write
\header \o Format \o Description \o Katie's support
\row \o GIF \o Graphic Interchange Format (optional) \o Read
\row \o JPG \o Joint Photographic Experts Group \o Read/write
\row \o JPEG \o Joint Photographic Experts Group \o Read/write
\row \o PNG \o Portable Network Graphics \o Read/write
\row \o PBM \o Portable Bitmap \o Read
\row \o PGM \o Portable Graymap \o Read
\row \o PPM \o Portable Pixmap \o Read/write
\row \o TIFF \o Tagged Image File Format \o Read/write
\row \o XBM \o X11 Bitmap \o Read/write
\row \o XPM \o X11 Pixmap \o Read/write
\endtable
@ -3571,7 +3567,7 @@ QImage QImage::rgbSwapped() const
the image was successfully loaded; otherwise returns false.
The loader attempts to read the image using the specified \a format, e.g.,
PNG or JPG. If \a format is not specified (which is the default), the
PNG or XPM. If \a format is not specified (which is the default), the
loader probes the file for a header to guess the file format.
The file name can either refer to an actual file on disk or to one
@ -3621,7 +3617,7 @@ bool QImage::load(QIODevice* device, const char* format)
returns false.
The loader attempts to read the image using the specified \a format, e.g.,
PNG or JPG. If \a format is not specified (which is the default), the
PNG or XPM. If \a format is not specified (which is the default), the
loader probes the file for a header to guess the file format.
\sa {QImage#Reading and Writing Image Files}{Reading and Writing Image Files}
@ -3742,9 +3738,9 @@ bool QImageData::doImageIO(const QImage *image, QImageWriter *writer, int qualit
\fn QDataStream &operator<<(QDataStream &stream, const QImage &image)
\relates QImage
Writes the given \a image to the given \a stream as a PNG image,
or as a BMP image if the stream's version is 1. Note that writing
the stream to a file will not produce a valid image file.
Writes the given \a image to the given \a stream as a PNG image.
Note that writing the stream to a file will not produce a valid
image file.
\sa QImage::save(), {Serializing Qt Data Types}
*/

View file

@ -490,11 +490,11 @@ QImageIOPlugin::~QImageIOPlugin()
Returns the capabilities on the plugin, based on the data in \a
device and the format \a format. For example, if the
QImageIOHandler supports the BMP format, and the data in the
device starts with the characters "BM", this function should
return \l CanRead. If \a format is "bmp" and the handler supports
both reading and writing, this function should return \l CanRead |
\l CanWrite.
QImageIOHandler supports the PNG format, and the data in the
device starts with the magick bits for that format, this function
should return \l CanRead. If \a format is "png" and the handler
supports both reading and writing, this function should return
\l CanRead | \l CanWrite.
*/
/*!
@ -503,7 +503,7 @@ QImageIOPlugin::~QImageIOPlugin()
Returns the list of image keys this plugin supports.
These keys are usually the names of the image formats that are implemented
in the plugin (e.g., "jpg" or "gif").
in the plugin (e.g., "svg" or "gif").
\sa capabilities()
*/

View file

@ -114,7 +114,6 @@
#include "qguicommon_p.h"
// image handlers
#include "qbmphandler_p.h"
#include "qppmhandler_p.h"
#include "qxbmhandler_p.h"
#include "qxpmhandler_p.h"
@ -135,10 +134,6 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
// check if we have built-in support for the format first
if (form == "png") {
handler = new QPngHandler;
#ifndef QT_NO_IMAGEFORMAT_BMP
} else if (form == "bmp") {
handler = new QBmpHandler;
#endif
#ifndef QT_NO_IMAGEFORMAT_XPM
} else if (form == "xpm") {
handler = new QXpmHandler;
@ -172,11 +167,6 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
if (QPngHandler::canRead(device)) {
handler = new QPngHandler;
}
#ifndef QT_NO_IMAGEFORMAT_BMP
if (!handler && QBmpHandler::canRead(device)) {
handler = new QBmpHandler;
}
#endif
#ifndef QT_NO_IMAGEFORMAT_XPM
if (!handler && QXpmHandler::canRead(device)) {
handler = new QXpmHandler;
@ -506,7 +496,7 @@ QIODevice *QImageReader::device() const
QImageReader will create a QFile object and open it in \l
QIODevice::ReadOnly mode, and use this when reading images.
If \a fileName does not include a file extension (e.g., .png or .bmp),
If \a fileName does not include a file extension (e.g., .png or .xpm),
QImageReader will cycle through all supported extensions until it finds
a matching file.
@ -541,7 +531,7 @@ QString QImageReader::fileName() const
support setting the quality, this value is ignored.
The value range of \a quality depends on the image format. For
example, the "jpeg" format supports a quality range from 0 (low
example, the "png" format supports a quality range from 0 (low
quality, high compression) to 100 (high quality, low compression).
\sa quality()
@ -1024,10 +1014,7 @@ QString QImageReader::errorString() const
false.
Different image formats support different options. Call this function to
determine whether a certain option is supported by the current format. For
example, the PNG format allows you to embed text into the image's metadata
(see text()), and the BMP format allows you to determine the image's size
without loading the whole image into memory (see size()).
determine whether a certain option is supported by the current format.
\snippet doc/src/snippets/code/src_gui_image_qimagereader.cpp 3
@ -1078,32 +1065,19 @@ QByteArray QImageReader::imageFormat(QIODevice *device)
\table
\header \o Format \o Description
\row \o BMP \o Windows Bitmap
\row \o GIF \o Graphic Interchange Format (optional)
\row \o JPG \o Joint Photographic Experts Group
\row \o JPEG \o Joint Photographic Experts Group
\row \o PNG \o Portable Network Graphics
\row \o PBM \o Portable Bitmap
\row \o PGM \o Portable Graymap
\row \o PPM \o Portable Pixmap
\row \o TIFF \o Tagged Image File Format
\row \o XBM \o X11 Bitmap
\row \o XPM \o X11 Pixmap
\row \o SVG \o Scalable Vector Graphics
\row \o TGA \o Targa Image Format
\endtable
Reading and writing SVG files is supported through Qt's
\l{QtSvg Module}{SVG Module}.
TGA support only extends to reading non-RLE compressed files. In particular
calls to \l{http://doc.qt.io/qt-4.8/qimageioplugin.html#capabilities}{capabilities}
for the tga plugin returns only QImageIOPlugin::CanRead, not QImageIOPlugin::CanWrite.
To configure Qt with GIF support, pass \c -qt-gif to the \c
configure script or check the appropriate option in the graphical
installer.
Note that the QApplication instance must be created before this function is
called.
@ -1113,9 +1087,6 @@ QList<QByteArray> QImageReader::supportedImageFormats()
{
QList<QByteArray> formats = QList<QByteArray>()
<< "png"
#ifndef QT_NO_IMAGEFORMAT_BMP
<< "bmp"
#endif
#ifndef QT_NO_IMAGEFORMAT_PPM
<< "ppm" << "pgm" << "pbm"
#endif

View file

@ -87,7 +87,6 @@
#include "qguicommon_p.h"
// image handlers
#include "qbmphandler_p.h"
#include "qppmhandler_p.h"
#include "qxbmhandler_p.h"
#include "qxpmhandler_p.h"
@ -104,10 +103,6 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device,
// check if any built-in handlers can write the image
if (form == "png") {
handler = new QPngHandler;
#ifndef QT_NO_IMAGEFORMAT_BMP
} else if (form == "bmp") {
handler = new QBmpHandler;
#endif
#ifndef QT_NO_IMAGEFORMAT_XPM
} else if (form == "xpm") {
handler = new QXpmHandler;
@ -328,7 +323,7 @@ QString QImageWriter::fileName() const
support setting the quality, this value is ignored.
The value range of \a quality depends on the image format. For
example, the "jpeg" format supports a quality range from 0 (low
example, the "png" format supports a quality range from 0 (low
quality, high compression) to 100 (high quality, low compression).
\sa quality()
@ -353,9 +348,7 @@ int QImageWriter::quality() const
of an image. For image formats that do not support setting the
compression, this value is ignored.
The value range of \a compression depends on the image format. For
example, the "tiff" format supports two values, 0(no compression) and
1(LZW-compression).
The value range of \a compression depends on the image format.
\sa compression()
*/
@ -508,12 +501,8 @@ bool QImageWriter::supportsOption(QImageIOHandler::ImageOption option) const
\table
\header \o Format \o Description
\row \o BMP \o Windows Bitmap
\row \o JPG \o Joint Photographic Experts Group
\row \o JPEG \o Joint Photographic Experts Group
\row \o PNG \o Portable Network Graphics
\row \o PPM \o Portable Pixmap
\row \o TIFF \o Tagged Image File Format
\row \o XBM \o X11 Bitmap
\row \o XPM \o X11 Pixmap
\endtable
@ -530,9 +519,6 @@ QList<QByteArray> QImageWriter::supportedImageFormats()
{
QList<QByteArray> formats;
formats << "png";
#ifndef QT_NO_IMAGEFORMAT_BMP
formats << "bmp";
#endif
#ifndef QT_NO_IMAGEFORMAT_PPM
formats << "ppm";
#endif

View file

@ -1356,10 +1356,7 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode)
file, optionally manipulating the image data, before the QImage
object is converted into a QPixmap to be shown on
screen. Alternatively, if no manipulation is desired, the image
file can be loaded directly into a QPixmap. On Windows, the
QPixmap class also supports conversion between \c HBITMAP and
QPixmap. On Symbian, the QPixmap class also supports conversion
between CFbsBitmap and QPixmap.
file can be loaded directly into a QPixmap.
QPixmap provides a collection of functions that can be used to
obtain a variety of information about the pixmap. In addition,
@ -1388,10 +1385,7 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode)
\table
\header \o Format \o Description \o Qt's support
\row \o BMP \o Windows Bitmap \o Read/write
\row \o GIF \o Graphic Interchange Format (optional) \o Read
\row \o JPG \o Joint Photographic Experts Group \o Read/write
\row \o JPEG \o Joint Photographic Experts Group \o Read/write
\row \o PNG \o Portable Network Graphics \o Read/write
\row \o PBM \o Portable Bitmap \o Read
\row \o PGM \o Portable Graymap \o Read
@ -1457,16 +1451,6 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode)
QPixmap using the fromImage(). If this is too expensive an
operation, you can use QBitmap::fromImage() instead.
In addition, on Windows, the QPixmap class supports conversion to
and from HBITMAP: the toWinHBITMAP() function creates a HBITMAP
equivalent to the QPixmap, based on the given HBitmapFormat, and
returns the HBITMAP handle. The fromWinHBITMAP() function returns
a QPixmap that is equivalent to the given bitmap which has the
specified format. The QPixmap class also supports conversion to
and from HICON: the toWinHICON() function creates a HICON equivalent
to the QPixmap, and returns the HICON handle. The fromWinHICON()
function returns a QPixmap that is equivalent to the given icon.
In addition, on Symbian, the QPixmap class supports conversion to
and from CFbsBitmap: the toSymbianCFbsBitmap() function creates
CFbsBitmap equivalent to the QPixmap, based on given mode and returns
@ -1587,7 +1571,7 @@ void QPixmap::setAlphaChannel(const QPixmap &alphaChannel)
Returns the alpha channel of the pixmap as a new grayscale QPixmap in which
each pixel's red, green, and blue values are given the alpha value of the
original pixmap. The color depth of the returned pixmap is the system depth
on X11 and 8-bit on Windows and Mac OS X.
on X11 and 8-bit.
You can use this function while debugging
to get a visible image of the alpha channel. If the pixmap doesn't have an
@ -1640,8 +1624,7 @@ QBitmap QPixmap::mask() const
/*!
Returns the default pixmap depth used by the application.
On Windows and Mac, the default depth is always 32. On X11 and
embedded, the depth of the screen will be returned by this
On X11 and the depth of the screen will be returned by this
function.
\sa depth(), QColormap::depth(), {QPixmap#Pixmap Information}{Pixmap Information}

View file

@ -530,28 +530,6 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n
bool hasAlpha = false;
bool hasMask = false;
if (QImageWriter::supportedImageFormats().contains("jpeg") && colorMode != QPrinter::GrayScale) {
QBuffer buffer(&imageData);
QImageWriter writer(&buffer, "jpeg");
writer.setQuality(94);
writer.write(image);
dct = true;
if (format != QImage::Format_RGB32) {
softMaskData.resize(w * h);
uchar *sdata = (uchar *)softMaskData.data();
for (int y = 0; y < h; ++y) {
const QRgb *rgb = (const QRgb *)image.constScanLine(y);
for (int x = 0; x < w; ++x) {
uchar alpha = qAlpha(*rgb);
*sdata++ = alpha;
hasMask |= (alpha < 255);
hasAlpha |= (alpha != 0 && alpha != 255);
++rgb;
}
}
}
} else {
imageData.resize(colorMode == QPrinter::GrayScale ? w * h : 3 * w * h);
uchar *data = (uchar *)imageData.data();
softMaskData.resize(w * h);
@ -582,7 +560,6 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n
}
if (format == QImage::Format_RGB32)
hasAlpha = hasMask = false;
}
int maskObject = 0;
int softMaskObject = 0;
if (hasAlpha) {

View file

@ -272,13 +272,7 @@ static QByteArray compressHelper(const QImage &image, bool gray, int *format)
Q_ASSERT(image.format() != QImage::Format_ARGB32_Premultiplied);
if (depth != 1 && !gray && QImageWriter::supportedImageFormats().contains("jpeg")) {
QBuffer buffer(&pixelData);
QImageWriter writer(&buffer, "jpeg");
writer.setQuality(94);
writer.write(image);
*format = DCT;
} else {
int width = image.width();
int height = image.height();
int size = width*height;
@ -346,7 +340,6 @@ static QByteArray compressHelper(const QImage &image, bool gray, int *format)
pixelData = runlengthEncode(pixelData);
*format = Runlength;
}
}
return QPdf::ascii85Encode(pixelData);
}

View file

@ -2917,8 +2917,7 @@ QTextTableFormat::QTextTableFormat(const QTextFormat &fmt)
occupy is specified using setWidth() and setHeight().
Images can be supplied in any format for which Qt has an image
reader, so SVG drawings can be included alongside PNG, TIFF and
other bitmap formats.
reader, so SVG drawings can be included alongside PNG.
\sa QImage, QImageReader
*/

View file

@ -238,11 +238,11 @@ QUrl QDeclarativeFolderListModel::parentFolder() const
The \a nameFilters property contains a list of file name filters.
The filters may include the ? and * wildcards.
The example below filters on PNG and JPEG files:
The example below filters on PNG and XPM files:
\qml
FolderListModel {
nameFilters: [ "*.png", "*.jpg" ]
nameFilters: [ "*.png", "*.xpm" ]
}
\endqml

View file

@ -28,16 +28,7 @@ add_subdirectory(iconengines/svgiconengine)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins/imageformats")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins/imageformats")
add_subdirectory(imageformats/gif)
add_subdirectory(imageformats/ico)
add_subdirectory(imageformats/svg)
add_subdirectory(imageformats/tga)
if(WITH_JPEG AND JPEG_FOUND)
add_subdirectory(imageformats/jpeg)
endif()
if(WITH_TIFF AND TIFF_FOUND)
add_subdirectory(imageformats/tiff)
endif()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins/script")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins/script")

View file

@ -1,22 +0,0 @@
set(QICOPLUGIN_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/qicohandler.h
)
set(QICOPLUGIN_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/qicoplugin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/qicohandler.cpp
)
katie_setup_target(qicoplugin ${QICOPLUGIN_SOURCES} ${QICOPLUGIN_HEADERS})
add_library(qicoplugin MODULE ${qicoplugin_SOURCES})
target_link_libraries(qicoplugin KtCore KtGui)
set_target_properties(qicoplugin PROPERTIES OUTPUT_NAME qico)
katie_setup_plugin(qicoplugin)
install(
TARGETS qicoplugin
DESTINATION ${KATIE_PLUGINS_PATH}/imageformats
COMPONENT Runtime
)

View file

@ -1,876 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the plugins of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\class QtIcoHandler
\since 4.4
\brief The QtIcoHandler class provides support for the ICO image format.
\internal
*/
#include "qicohandler.h"
#include <QtCore/qendian.h>
#include <QtGui/QImage>
#include <QtCore/QFile>
#include <QtCore/QBuffer>
#include "qvariant.h"
#include "qcorecommon_p.h"
#include "qguicommon_p.h"
QT_BEGIN_NAMESPACE
// These next two structs represent how the icon information is stored
// in an ICO file.
typedef struct
{
quint8 bWidth; // Width of the image
quint8 bHeight; // Height of the image (times 2)
quint8 bColorCount; // Number of colors in image (0 if >=8bpp) [ not ture ]
quint8 bReserved; // Reserved
quint16 wPlanes; // Color Planes
quint16 wBitCount; // Bits per pixel
quint32 dwBytesInRes; // how many bytes in this resource?
quint32 dwImageOffset; // where in the file is this image
} ICONDIRENTRY, *LPICONDIRENTRY;
#define ICONDIRENTRY_SIZE 16
typedef struct
{
quint16 idReserved; // Reserved
quint16 idType; // resource type (1 for icons)
quint16 idCount; // how many images?
ICONDIRENTRY idEntries[1]; // the entries for each image
} ICONDIR, *LPICONDIR;
#define ICONDIR_SIZE 6 // Exclude the idEntries field
typedef struct { // BMP information header
quint32 biSize; // size of this struct
quint32 biWidth; // pixmap width
quint32 biHeight; // pixmap height (specifies the combined height of the XOR and AND masks)
quint16 biPlanes; // should be 1
quint16 biBitCount; // number of bits per pixel
quint32 biCompression; // compression method
quint32 biSizeImage; // size of image
quint32 biXPelsPerMeter; // horizontal resolution
quint32 biYPelsPerMeter; // vertical resolution
quint32 biClrUsed; // number of colors used
quint32 biClrImportant; // number of important colors
} BMP_INFOHDR ,*LPBMP_INFOHDR;
#define BMP_INFOHDR_SIZE 40
class ICOReader
{
public:
ICOReader(QIODevice * iodevice);
int count();
QImage iconAt(int index);
static bool canRead(QIODevice *iodev);
static QList<QImage> read(QIODevice * device);
static bool write(QIODevice * device, const QList<QImage> & images);
private:
bool readHeader();
bool readIconEntry(int index, ICONDIRENTRY * iconEntry);
bool readBMPHeader(quint32 imageOffset, BMP_INFOHDR * header);
void findColorInfo(QImage & image);
void readColorTable(QImage & image);
void readBMP(QImage & image);
void read1BitBMP(QImage & image);
void read4BitBMP(QImage & image);
void read8BitBMP(QImage & image);
void read16_24_32BMP(QImage & image);
struct IcoAttrib
{
int nbits;
int ncolors;
int h;
int w;
int depth;
} icoAttrib;
QIODevice * iod;
qint64 startpos;
bool headerRead;
ICONDIR iconDir;
};
// Data readers and writers that takes care of alignment and endian stuff.
static bool readIconDirEntry(QIODevice *iodev, ICONDIRENTRY *iconDirEntry)
{
if (iodev) {
QSTACKARRAY(uchar, tmp, ICONDIRENTRY_SIZE);
if (iodev->read((char*)tmp, ICONDIRENTRY_SIZE) == ICONDIRENTRY_SIZE) {
iconDirEntry->bWidth = tmp[0];
iconDirEntry->bHeight = tmp[1];
iconDirEntry->bColorCount = tmp[2];
iconDirEntry->bReserved = tmp[3];
iconDirEntry->wPlanes = qFromLittleEndian<quint16>(&tmp[4]);
iconDirEntry->wBitCount = qFromLittleEndian<quint16>(&tmp[6]);
iconDirEntry->dwBytesInRes = qFromLittleEndian<quint32>(&tmp[8]);
iconDirEntry->dwImageOffset = qFromLittleEndian<quint32>(&tmp[12]);
return true;
}
}
return false;
}
static bool writeIconDirEntry(QIODevice *iodev, const ICONDIRENTRY &iconEntry)
{
if (iodev) {
QSTACKARRAY(uchar, tmp, ICONDIRENTRY_SIZE);
tmp[0] = iconEntry.bWidth;
tmp[1] = iconEntry.bHeight;
tmp[2] = iconEntry.bColorCount;
tmp[3] = iconEntry.bReserved;
qToLittleEndian<quint16>(iconEntry.wPlanes, &tmp[4]);
qToLittleEndian<quint16>(iconEntry.wBitCount, &tmp[6]);
qToLittleEndian<quint32>(iconEntry.dwBytesInRes, &tmp[8]);
qToLittleEndian<quint32>(iconEntry.dwImageOffset, &tmp[12]);
return (iodev->write((char*)tmp, ICONDIRENTRY_SIZE) == ICONDIRENTRY_SIZE);
}
return false;
}
static bool readIconDir(QIODevice *iodev, ICONDIR *iconDir)
{
if (iodev) {
QSTACKARRAY(uchar, tmp, ICONDIR_SIZE);
if (iodev->read((char*)tmp, ICONDIR_SIZE) == ICONDIR_SIZE) {
iconDir->idReserved = qFromLittleEndian<quint16>(&tmp[0]);
iconDir->idType = qFromLittleEndian<quint16>(&tmp[2]);
iconDir->idCount = qFromLittleEndian<quint16>(&tmp[4]);
return true;
}
}
return false;
}
static bool writeIconDir(QIODevice *iodev, const ICONDIR &iconDir)
{
if (iodev) {
QSTACKARRAY(uchar, tmp, 6);
qToLittleEndian(iconDir.idReserved, tmp);
qToLittleEndian(iconDir.idType, &tmp[2]);
qToLittleEndian(iconDir.idCount, &tmp[4]);
return (iodev->write((char*)tmp, 6) == 6);
}
return false;
}
static bool readBMPInfoHeader(QIODevice *iodev, BMP_INFOHDR *pHeader)
{
if (iodev) {
QSTACKARRAY(uchar, header, BMP_INFOHDR_SIZE);
if (iodev->read((char*)header, BMP_INFOHDR_SIZE) == BMP_INFOHDR_SIZE) {
pHeader->biSize = qFromLittleEndian<quint32>(&header[0]);
pHeader->biWidth = qFromLittleEndian<quint32>(&header[4]);
pHeader->biHeight = qFromLittleEndian<quint32>(&header[8]);
pHeader->biPlanes = qFromLittleEndian<quint16>(&header[12]);
pHeader->biBitCount = qFromLittleEndian<quint16>(&header[14]);
pHeader->biCompression = qFromLittleEndian<quint32>(&header[16]);
pHeader->biSizeImage = qFromLittleEndian<quint32>(&header[20]);
pHeader->biXPelsPerMeter = qFromLittleEndian<quint32>(&header[24]);
pHeader->biYPelsPerMeter = qFromLittleEndian<quint32>(&header[28]);
pHeader->biClrUsed = qFromLittleEndian<quint32>(&header[32]);
pHeader->biClrImportant = qFromLittleEndian<quint32>(&header[36]);
return true;
}
}
return false;
}
static bool writeBMPInfoHeader(QIODevice *iodev, const BMP_INFOHDR &header)
{
if (iodev) {
QSTACKARRAY(uchar, tmp, BMP_INFOHDR_SIZE);
qToLittleEndian<quint32>(header.biSize, &tmp[0]);
qToLittleEndian<quint32>(header.biWidth, &tmp[4]);
qToLittleEndian<quint32>(header.biHeight, &tmp[8]);
qToLittleEndian<quint16>(header.biPlanes, &tmp[12]);
qToLittleEndian<quint16>(header.biBitCount, &tmp[14]);
qToLittleEndian<quint32>(header.biCompression, &tmp[16]);
qToLittleEndian<quint32>(header.biSizeImage, &tmp[20]);
qToLittleEndian<quint32>(header.biXPelsPerMeter, &tmp[24]);
qToLittleEndian<quint32>(header.biYPelsPerMeter, &tmp[28]);
qToLittleEndian<quint32>(header.biClrUsed, &tmp[32]);
qToLittleEndian<quint32>(header.biClrImportant, &tmp[36]);
return (iodev->write((char*)tmp, BMP_INFOHDR_SIZE) == BMP_INFOHDR_SIZE);
}
return false;
}
ICOReader::ICOReader(QIODevice * iodevice)
: iod(iodevice)
, startpos(0)
, headerRead(false)
{
}
int ICOReader::count()
{
if (readHeader()) {
return iconDir.idCount;
}
return 0;
}
bool ICOReader::canRead(QIODevice *iodev)
{
Q_ASSERT(iodev);
bool isProbablyICO = false;
qint64 oldPos = iodev->pos();
ICONDIR ikonDir;
if (readIconDir(iodev, &ikonDir)) {
qint64 readBytes = ICONDIR_SIZE;
if (readIconDirEntry(iodev, &ikonDir.idEntries[0])) {
readBytes += ICONDIRENTRY_SIZE;
// ICO format does not have a magic identifier, so we read 6 different values, which will hopefully be enough to identify the file.
if ( ikonDir.idReserved == 0
&& ikonDir.idType == 1
&& ikonDir.idEntries[0].bReserved == 0
&& ikonDir.idEntries[0].wPlanes <= 1
&& ikonDir.idEntries[0].wBitCount <= 32 // Bits per pixel
&& ikonDir.idEntries[0].dwBytesInRes >= 40 // Must be over 40, since sizeof (infoheader) == 40
) {
isProbablyICO = true;
}
if (iodev->isSequential()) {
// Our structs might be padded due to alignment, so we need to fetch each member before we ungetChar() !
quint32 tmp = ikonDir.idEntries[0].dwImageOffset;
iodev->ungetChar((tmp >> 24) & 0xff);
iodev->ungetChar((tmp >> 16) & 0xff);
iodev->ungetChar((tmp >> 8) & 0xff);
iodev->ungetChar(tmp & 0xff);
tmp = ikonDir.idEntries[0].dwBytesInRes;
iodev->ungetChar((tmp >> 24) & 0xff);
iodev->ungetChar((tmp >> 16) & 0xff);
iodev->ungetChar((tmp >> 8) & 0xff);
iodev->ungetChar(tmp & 0xff);
tmp = ikonDir.idEntries[0].wBitCount;
iodev->ungetChar((tmp >> 8) & 0xff);
iodev->ungetChar(tmp & 0xff);
tmp = ikonDir.idEntries[0].wPlanes;
iodev->ungetChar((tmp >> 8) & 0xff);
iodev->ungetChar(tmp & 0xff);
iodev->ungetChar(ikonDir.idEntries[0].bReserved);
iodev->ungetChar(ikonDir.idEntries[0].bColorCount);
iodev->ungetChar(ikonDir.idEntries[0].bHeight);
iodev->ungetChar(ikonDir.idEntries[0].bWidth);
}
}
if (iodev->isSequential()) {
// Our structs might be padded due to alignment, so we need to fetch each member before we ungetChar() !
quint32 tmp = ikonDir.idCount;
iodev->ungetChar((tmp >> 8) & 0xff);
iodev->ungetChar(tmp & 0xff);
tmp = ikonDir.idType;
iodev->ungetChar((tmp >> 8) & 0xff);
iodev->ungetChar(tmp & 0xff);
tmp = ikonDir.idReserved;
iodev->ungetChar((tmp >> 8) & 0xff);
iodev->ungetChar(tmp & 0xff);
}
}
if (!iodev->isSequential()) {
iodev->seek(oldPos);
}
return isProbablyICO;
}
bool ICOReader::readHeader()
{
if (iod && !headerRead) {
startpos = iod->pos();
if (readIconDir(iod, &iconDir)) {
if (iconDir.idReserved == 0 || iconDir.idType == 1)
headerRead = true;
}
}
return headerRead;
}
bool ICOReader::readIconEntry(int index, ICONDIRENTRY *iconEntry)
{
if (iod) {
if (iod->seek(startpos + ICONDIR_SIZE + (index * ICONDIRENTRY_SIZE))) {
return readIconDirEntry(iod, iconEntry);
}
}
return false;
}
bool ICOReader::readBMPHeader(quint32 imageOffset, BMP_INFOHDR * header)
{
if (iod) {
if (iod->seek(startpos + imageOffset)) {
if (readBMPInfoHeader(iod, header)) {
return true;
}
}
}
return false;
}
void ICOReader::findColorInfo(QImage & image)
{
if (icoAttrib.ncolors > 0) { // set color table
readColorTable(image);
} else if (icoAttrib.nbits == 16) { // don't support RGB values for 15/16 bpp
image = QImage();
}
}
void ICOReader::readColorTable(QImage & image)
{
if (iod) {
image.setColorCount(icoAttrib.ncolors);
QSTACKARRAY(uchar, rgb, 4);
for (int i=0; i<icoAttrib.ncolors; i++) {
if (iod->read((char*)rgb, 4) != 4) {
image = QImage();
break;
}
image.setColor(i, qRgb(rgb[2],rgb[1],rgb[0]));
}
} else {
image = QImage();
}
}
void ICOReader::readBMP(QImage & image)
{
if (icoAttrib.nbits == 1) { // 1 bit BMP image
read1BitBMP(image);
} else if (icoAttrib.nbits == 4) { // 4 bit BMP image
read4BitBMP(image);
} else if (icoAttrib.nbits == 8) {
read8BitBMP(image);
} else if (icoAttrib.nbits == 16 || icoAttrib.nbits == 24 || icoAttrib.nbits == 32 ) { // 16,24,32 bit BMP image
read16_24_32BMP(image);
}
}
/**
* NOTE: A 1 bit BMP is only flipped vertically, and not horizontally like all other color depths!
* (This is the same with the bitmask)
*
*/
void ICOReader::read1BitBMP(QImage & image)
{
if (iod) {
int h = image.height();
int bpl = image.bytesPerLine();
while (--h >= 0) {
if (iod->read((char*)image.scanLine(h),bpl) != bpl) {
image = QImage();
break;
}
}
} else {
image = QImage();
}
}
void ICOReader::read4BitBMP(QImage & image)
{
if (iod) {
int h = icoAttrib.h;
int buflen = ((icoAttrib.w+7)/8)*4;
QSTACKARRAY(uchar, buf, buflen);
while (--h >= 0) {
if (iod->read((char*)buf,buflen) != buflen) {
image = QImage();
break;
}
uchar *p = image.scanLine(h);
uchar *b = buf;
for (int i=0; i<icoAttrib.w/2; i++) { // convert nibbles to bytes
*p++ = *b >> 4;
*p++ = *b++ & 0x0f;
}
if (icoAttrib.w & 1) // the last nibble
*p = *b >> 4;
}
} else {
image = QImage();
}
}
void ICOReader::read8BitBMP(QImage & image)
{
if (iod) {
int h = icoAttrib.h;
int bpl = image.bytesPerLine();
while (--h >= 0) {
if (iod->read((char *)image.scanLine(h), bpl) != bpl) {
image = QImage();
break;
}
}
} else {
image = QImage();
}
}
void ICOReader::read16_24_32BMP(QImage & image)
{
if (iod) {
int h = icoAttrib.h;
QRgb *p;
QRgb *end;
QSTACKARRAY(uchar, buf, image.bytesPerLine());
int bpl = ((icoAttrib.w*icoAttrib.nbits+31)/32)*4;
uchar *b;
while (--h >= 0) {
p = (QRgb *)image.scanLine(h);
end = p + icoAttrib.w;
if (iod->read((char *)buf, bpl) != bpl) {
image = QImage();
break;
}
b = buf;
while (p < end) {
if (icoAttrib.nbits == 24)
*p++ = qRgb(*(b+2), *(b+1), *b);
else if (icoAttrib.nbits == 32)
*p++ = qRgba(*(b+2), *(b+1), *b, *(b+3));
b += icoAttrib.nbits/8;
}
}
} else {
image = QImage();
}
}
QImage ICOReader::iconAt(int index)
{
QImage img;
if (count() > index) { // forces header to be read
ICONDIRENTRY iconEntry;
if (readIconEntry(index, &iconEntry)) {
static const uchar pngMagicData[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
iod->seek(iconEntry.dwImageOffset);
const QByteArray pngMagic = QByteArray::fromRawData((char*)pngMagicData, sizeof(pngMagicData));
const bool isPngImage = (iod->read(pngMagic.size()) == pngMagic);
if (isPngImage) {
iod->seek(iconEntry.dwImageOffset);
return QImage::fromData(iod->read(iconEntry.dwBytesInRes), "png");
}
BMP_INFOHDR header;
if (readBMPHeader(iconEntry.dwImageOffset, &header)) {
icoAttrib.nbits = header.biBitCount ? header.biBitCount : iconEntry.wBitCount;
switch (icoAttrib.nbits) {
case 32:
case 24:
case 16:
icoAttrib.depth = 32;
break;
case 8:
case 4:
icoAttrib.depth = 8;
break;
default:
icoAttrib.depth = 1;
}
if (icoAttrib.depth == 32) // there's no colormap
icoAttrib.ncolors = 0;
else // # colors used
icoAttrib.ncolors = header.biClrUsed ? header.biClrUsed : 1 << icoAttrib.nbits;
if (icoAttrib.ncolors > 256) //color table can't be more than 256
return img;
icoAttrib.w = iconEntry.bWidth;
if (icoAttrib.w == 0)
icoAttrib.w = header.biWidth;
icoAttrib.h = iconEntry.bHeight;
if (icoAttrib.h == 0)
icoAttrib.h = header.biHeight/2;
QImage::Format format = QImage::Format_ARGB32;
if (icoAttrib.nbits == 24)
format = QImage::Format_RGB32;
else if (icoAttrib.ncolors == 2 && icoAttrib.depth == 1)
format = QImage::Format_Mono;
else if (icoAttrib.ncolors > 0)
format = QImage::Format_Indexed8;
QImage image(icoAttrib.w, icoAttrib.h, format);
if (!image.isNull()) {
findColorInfo(image);
if (!image.isNull()) {
readBMP(image);
if (!image.isNull()) {
QImage mask(image.width(), image.height(), QImage::Format_Mono);
if (!mask.isNull()) {
mask.setColorTable(monoColorTable());
read1BitBMP(mask);
if (!mask.isNull()) {
img = QImage(image.width(), image.height(), QImage::Format_ARGB32 );
img = image;
img.setAlphaChannel(mask);
// (Luckily, it seems that setAlphaChannel() does not ruin the alpha values
// of partially transparent pixels in those icons that have that)
}
}
}
}
}
}
}
}
return img;
}
/*!
Reads all the icons from the given \a device, and returns them as
a list of QImage objects.
Each image has an alpha channel that represents the mask from the
corresponding icon.
\sa write()
*/
QList<QImage> ICOReader::read(QIODevice * device)
{
QList<QImage> images;
ICOReader reader(device);
for (int i = 0; i < reader.count(); i++)
images += reader.iconAt(i);
return images;
}
/*!
Writes all the QImages in the \a images list to the given \a
device. Returns true if the images are written successfully;
otherwise returns false.
The first image in the list is stored as the first icon in the
device, and is therefore used as the default icon by applications.
The alpha channel of each image is converted to a mask for each
corresponding icon.
\sa read()
*/
bool ICOReader::write(QIODevice * device, const QList<QImage> & images)
{
bool retValue = false;
if (images.count()) {
qint64 origOffset = device->pos();
ICONDIR id;
id.idReserved = 0;
id.idType = 1;
id.idCount = images.count();
ICONDIRENTRY * entries = new ICONDIRENTRY[id.idCount];
BMP_INFOHDR * bmpHeaders = new BMP_INFOHDR[id.idCount];
QByteArray * imageData = new QByteArray[id.idCount];
for (int i=0; i<id.idCount; i++) {
QImage image = images[i];
// Scale down the image if it is larger than 128 pixels in either width or height
if (image.width() > 128 || image.height() > 128)
{
image = image.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
QImage maskImage(image.width(), image.height(), QImage::Format_Mono);
image = image.convertToFormat(QImage::Format_ARGB32);
if (image.hasAlphaChannel()) {
maskImage = image.createAlphaMask();
} else {
maskImage.fill(0xff);
}
maskImage = maskImage.convertToFormat(QImage::Format_Mono);
int nbits = 32;
int bpl_bmp = ((image.width()*nbits+31)/32)*4;
entries[i].bColorCount = 0;
entries[i].bReserved = 0;
entries[i].wBitCount = nbits;
entries[i].bHeight = image.height();
entries[i].bWidth = image.width();
entries[i].dwBytesInRes = BMP_INFOHDR_SIZE + (bpl_bmp * image.height())
+ (maskImage.bytesPerLine() * maskImage.height());
entries[i].wPlanes = 1;
if (i == 0)
entries[i].dwImageOffset = origOffset + ICONDIR_SIZE
+ (id.idCount * ICONDIRENTRY_SIZE);
else
entries[i].dwImageOffset = entries[i-1].dwImageOffset + entries[i-1].dwBytesInRes;
bmpHeaders[i].biBitCount = entries[i].wBitCount;
bmpHeaders[i].biClrImportant = 0;
bmpHeaders[i].biClrUsed = entries[i].bColorCount;
bmpHeaders[i].biCompression = 0;
bmpHeaders[i].biHeight = entries[i].bHeight * 2; // 2 is for the mask
bmpHeaders[i].biPlanes = entries[i].wPlanes;
bmpHeaders[i].biSize = BMP_INFOHDR_SIZE;
bmpHeaders[i].biSizeImage = entries[i].dwBytesInRes - BMP_INFOHDR_SIZE;
bmpHeaders[i].biWidth = entries[i].bWidth;
bmpHeaders[i].biXPelsPerMeter = 0;
bmpHeaders[i].biYPelsPerMeter = 0;
QBuffer buffer(&imageData[i]);
buffer.open(QIODevice::WriteOnly);
QSTACKARRAY(uchar, buf, bpl_bmp);
uchar *b;
int y;
for (y = image.height() - 1; y >= 0; y--) { // write the image bits
// 32 bits
QRgb *p = (QRgb *)image.scanLine(y);
QRgb *end = p + image.width();
b = buf;
int x = 0;
while (p < end) {
*b++ = qBlue(*p);
*b++ = qGreen(*p);
*b++ = qRed(*p);
*b++ = qAlpha(*p);
if (qAlpha(*p) > 0) // Even mostly transparent pixels must not be masked away
maskImage.setPixel(x, y, Qt::color1); // (i.e. createAlphaMask() takes away too much)
p++;
x++;
}
buffer.write((char*)buf, bpl_bmp);
}
maskImage.invertPixels(); // seems as though it needs this
// NOTE! !! The mask is only flipped vertically - not horizontally !!
for (y = maskImage.height() - 1; y >= 0; y--)
buffer.write((char*)maskImage.scanLine(y), maskImage.bytesPerLine());
}
if (writeIconDir(device, id)) {
int i;
bool bOK = true;
for (i = 0; i < id.idCount && bOK; i++) {
bOK = writeIconDirEntry(device, entries[i]);
}
if (bOK) {
for (i = 0; i < id.idCount && bOK; i++) {
bOK = writeBMPInfoHeader(device, bmpHeaders[i]);
bOK &= (device->write(imageData[i]) == (int) imageData[i].size());
}
retValue = bOK;
}
}
delete [] entries;
delete [] bmpHeaders;
delete [] imageData;
}
return retValue;
}
/*!
Constructs an instance of QtIcoHandler initialized to use \a device.
*/
QtIcoHandler::QtIcoHandler(QIODevice *device)
{
m_currentIconIndex = 0;
setDevice(device);
m_pICOReader = new ICOReader(device);
}
/*!
Destructor for QtIcoHandler.
*/
QtIcoHandler::~QtIcoHandler()
{
delete m_pICOReader;
}
QVariant QtIcoHandler::option(ImageOption option) const
{
if (option == Size) {
QIODevice *device = QImageIOHandler::device();
qint64 oldPos = device->pos();
ICONDIRENTRY iconEntry;
if (device->seek(oldPos + ICONDIR_SIZE + (m_currentIconIndex * ICONDIRENTRY_SIZE))) {
if (readIconDirEntry(device, &iconEntry)) {
device->seek(oldPos);
return QSize(iconEntry.bWidth, iconEntry.bHeight);
}
}
if (!device->isSequential()) {
device->seek(oldPos);
}
}
return QVariant();
}
bool QtIcoHandler::supportsOption(ImageOption option) const
{
return option == Size;
}
/*!
* Verifies if some values (magic bytes) are set as expected in the header of the file.
* If the magic bytes were found, it is assumed that the QtIcoHandler can read the file.
*
*/
bool QtIcoHandler::canRead() const
{
if (QtIcoHandler::canRead(device())) {
setFormat("ico");
return true;
}
return false;
}
/*! This static function is used by the plugin code, and is provided for convenience only.
\a device must be an opened device with pointing to the start of the header data of the ICO file.
*/
bool QtIcoHandler::canRead(QIODevice *device)
{
if (Q_UNLIKELY(!device)) {
qWarning("QtIcoHandler::canRead() called with no device");
return false;
}
return ICOReader::canRead(device);
}
/*! \reimp
*/
bool QtIcoHandler::read(QImage *image)
{
bool bSuccess = false;
QImage img = m_pICOReader->iconAt(m_currentIconIndex);
// Make sure we only write to \a image when we succeed.
if (!img.isNull()) {
bSuccess = true;
*image = img;
}
return bSuccess;
}
/*! \reimp
*/
bool QtIcoHandler::write(const QImage &image)
{
QIODevice *device = QImageIOHandler::device();
QList<QImage> imgs;
imgs.append(image);
return ICOReader::write(device, imgs);
}
/*!
* Return the common identifier of the format.
* For ICO format this will return "ico".
*/
QByteArray QtIcoHandler::name() const
{
return "ico";
}
/*! \reimp
*/
int QtIcoHandler::imageCount() const
{
return m_pICOReader->count();
}
/*! \reimp
*/
bool QtIcoHandler::jumpToImage(int imageNumber)
{
if (imageNumber < imageCount()) {
m_currentIconIndex = imageNumber;
}
return (imageNumber < imageCount());
}
/*! \reimp
*/
bool QtIcoHandler::jumpToNextImage()
{
return jumpToImage(m_currentIconIndex + 1);
}
QT_END_NAMESPACE

View file

@ -1,59 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the plugins of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTICOHANDLER_H
#define QTICOHANDLER_H
#include <QtGui/QImageIOHandler>
QT_BEGIN_NAMESPACE
class ICOReader;
class QtIcoHandler: public QImageIOHandler
{
public:
QtIcoHandler(QIODevice *device);
virtual ~QtIcoHandler();
bool canRead() const;
bool read(QImage *image);
bool write(const QImage &image);
QByteArray name() const;
int imageCount() const;
bool jumpToImage(int imageNumber);
bool jumpToNextImage();
static bool canRead(QIODevice *device);
bool supportsOption(ImageOption option) const;
QVariant option(ImageOption option) const;
private:
int m_currentIconIndex;
ICOReader *m_pICOReader;
};
QT_END_NAMESPACE
#endif /* QTICOHANDLER_H */

View file

@ -1,70 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the plugins of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qimageiohandler.h"
#include "qdebug.h"
#include "qicohandler.h"
QT_BEGIN_NAMESPACE
class QICOPlugin : public QImageIOPlugin
{
public:
QStringList keys() const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
};
QStringList QICOPlugin::keys() const
{
static const QStringList list = QStringList()
<< QLatin1String("ico");
return list;
}
QImageIOPlugin::Capabilities QICOPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "ico")
return Capabilities(CanRead | CanWrite);
if (!format.isEmpty())
return 0;
if (!device->isOpen())
return 0;
Capabilities cap;
if (device->isReadable() && QtIcoHandler::canRead(device))
cap |= CanRead;
if (device->isWritable())
cap |= CanWrite;
return cap;
}
QImageIOHandler *QICOPlugin::create(QIODevice *device, const QByteArray &format) const
{
QImageIOHandler *handler = new QtIcoHandler(device);
handler->setDevice(device);
handler->setFormat(format);
return handler;
}
Q_EXPORT_PLUGIN2(qico, QICOPlugin)
QT_END_NAMESPACE

View file

@ -1,24 +0,0 @@
include_directories(${JPEG_INCLUDE_DIR})
set(QJPEGPLUGIN_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/qjpeghandler_p.h
)
set(QJPEGPLUGIN_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/qjpegplugin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/qjpeghandler.cpp
)
katie_setup_target(qjpegplugin ${QJPEGPLUGIN_SOURCES} ${QJPEGPLUGIN_HEADERS})
add_library(qjpegplugin MODULE ${qjpegplugin_SOURCES})
target_link_libraries(qjpegplugin KtCore KtGui ${JPEG_LIBRARIES})
set_target_properties(qjpegplugin PROPERTIES OUTPUT_NAME qjpeg)
katie_setup_plugin(qjpegplugin)
install(
TARGETS qjpegplugin
DESTINATION ${KATIE_PLUGINS_PATH}/imageformats
COMPONENT Runtime
)

View file

@ -1,845 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the plugins of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qjpeghandler_p.h"
#include "qimage.h"
#include "qvariant.h"
#include "qvector.h"
#include "qbuffer.h"
#include "qplatformdefs.h"
#include "qcorecommon_p.h"
#include "qguicommon_p.h"
#include <stdio.h> // jpeglib needs this to be pre-included
#include <setjmp.h>
#ifdef FAR
#undef FAR
#endif
// including jpeglib.h seems to be a little messy
extern "C" {
#define XMD_H // shut JPEGlib up
#include <jpeglib.h>
#ifdef const
# undef const // remove crazy C hackery in jconfig.h
#endif
}
#if defined(JPEG_TRUE)
// this jpeglib.h uses JPEG_boolean
typedef JPEG_boolean boolean;
#endif
QT_BEGIN_NAMESPACE
void QT_FASTCALL convert_rgb888_to_rgb32_C(quint32 *dst, const uchar *src, int len)
{
// Expand 24->32 bpp.
for (int i = 0; i < len; ++i) {
*dst++ = qRgb(src[0], src[1], src[2]);
src += 3;
}
}
struct my_error_mgr : public jpeg_error_mgr {
jmp_buf setjmp_buffer;
};
#if defined(Q_C_CALLBACKS)
extern "C" {
#endif
static void my_error_exit (j_common_ptr cinfo)
{
my_error_mgr* myerr = (my_error_mgr*) cinfo->err;
QSTACKARRAY(char, buffer, JMSG_LENGTH_MAX);
(*cinfo->err->format_message)(cinfo, buffer);
qWarning("%s", buffer);
longjmp(myerr->setjmp_buffer, 1);
}
#if defined(Q_C_CALLBACKS)
}
#endif
struct my_jpeg_source_mgr : public jpeg_source_mgr {
// Nothing dynamic - cannot rely on destruction over longjump
QIODevice *device;
JOCTET buffer[QT_BUFFSIZE];
const QBuffer *memDevice;
public:
my_jpeg_source_mgr(QIODevice *device);
};
#if defined(Q_C_CALLBACKS)
extern "C" {
#endif
static void qt_init_source(j_decompress_ptr)
{
}
static boolean qt_fill_input_buffer(j_decompress_ptr cinfo)
{
my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
qint64 num_read = 0;
if (src->memDevice) {
src->next_input_byte = (const JOCTET *)(src->memDevice->data().constData() + src->memDevice->pos());
num_read = src->memDevice->data().size() - src->memDevice->pos();
src->device->seek(src->memDevice->data().size());
} else {
src->next_input_byte = src->buffer;
num_read = src->device->read((char*)src->buffer, QT_BUFFSIZE);
}
if (num_read <= 0) {
// Insert a fake EOI marker - as per jpeglib recommendation
src->next_input_byte = src->buffer;
src->buffer[0] = (JOCTET) 0xFF;
src->buffer[1] = (JOCTET) JPEG_EOI;
src->bytes_in_buffer = 2;
} else {
src->bytes_in_buffer = num_read;
}
return TRUE;
}
static void qt_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
{
my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
// `dumb' implementation from jpeglib
/* Just a dumb implementation for now. Could use fseek() except
* it doesn't work on pipes. Not clear that being smart is worth
* any trouble anyway --- large skips are infrequent.
*/
if (num_bytes > 0) {
while (num_bytes > (long) src->bytes_in_buffer) { // Should not happen in case of memDevice
num_bytes -= (long) src->bytes_in_buffer;
(void) qt_fill_input_buffer(cinfo);
/* note we assume that qt_fill_input_buffer will never return false,
* so suspension need not be handled.
*/
}
src->next_input_byte += (size_t) num_bytes;
src->bytes_in_buffer -= (size_t) num_bytes;
}
}
static void qt_term_source(j_decompress_ptr cinfo)
{
my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
if (!src->device->isSequential())
src->device->seek(src->device->pos() - src->bytes_in_buffer);
}
#if defined(Q_C_CALLBACKS)
}
#endif
inline my_jpeg_source_mgr::my_jpeg_source_mgr(QIODevice *device)
{
jpeg_source_mgr::init_source = qt_init_source;
jpeg_source_mgr::fill_input_buffer = qt_fill_input_buffer;
jpeg_source_mgr::skip_input_data = qt_skip_input_data;
jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart;
jpeg_source_mgr::term_source = qt_term_source;
this->device = device;
memDevice = qobject_cast<QBuffer *>(device);
bytes_in_buffer = 0;
next_input_byte = buffer;
}
inline static bool read_jpeg_size(int &w, int &h, j_decompress_ptr cinfo)
{
(void) jpeg_calc_output_dimensions(cinfo);
w = cinfo->output_width;
h = cinfo->output_height;
return true;
}
#define HIGH_QUALITY_THRESHOLD 50
inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cinfo)
{
bool result = true;
switch (cinfo->output_components) {
case 1:
format = QImage::Format_Indexed8;
break;
case 3:
case 4:
format = QImage::Format_RGB32;
break;
default:
result = false;
break;
}
cinfo->output_scanline = cinfo->output_height;
return result;
}
static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
const QSize& size)
{
QImage::Format format;
switch (info->output_components) {
case 1:
format = QImage::Format_Indexed8;
break;
case 3:
case 4:
format = QImage::Format_RGB32;
break;
default:
return false; // unsupported format
}
if (dest->size() != size || dest->format() != format) {
*dest = QImage(size, format);
if (format == QImage::Format_Indexed8) {
dest->setColorTable(grayColorTable());
}
}
return !dest->isNull();
}
static bool read_jpeg_image(QImage *outImage,
QSize scaledSize, QRect scaledClipRect,
QRect clipRect, int quality, j_decompress_ptr info, struct my_error_mgr* err )
{
if (!setjmp(err->setjmp_buffer)) {
// If possible, merge the scaledClipRect into either scaledSize
// or clipRect to avoid doing a separate scaled clipping pass.
// Best results are achieved by clipping before scaling, not after.
if (!scaledClipRect.isEmpty()) {
if (scaledSize.isEmpty() && clipRect.isEmpty()) {
// No clipping or scaling before final clip.
clipRect = scaledClipRect;
scaledClipRect = QRect();
} else if (scaledSize.isEmpty()) {
// Clipping, but no scaling: combine the clip regions.
scaledClipRect.translate(clipRect.topLeft());
clipRect = scaledClipRect.intersected(clipRect);
scaledClipRect = QRect();
} else if (clipRect.isEmpty()) {
// No clipping, but scaling: if we can map back to an
// integer pixel boundary, then clip before scaling.
if ((info->image_width % scaledSize.width()) == 0 &&
(info->image_height % scaledSize.height()) == 0) {
int x = scaledClipRect.x() * info->image_width /
scaledSize.width();
int y = scaledClipRect.y() * info->image_height /
scaledSize.height();
int width = (scaledClipRect.right() + 1) *
info->image_width / scaledSize.width() - x;
int height = (scaledClipRect.bottom() + 1) *
info->image_height / scaledSize.height() - y;
clipRect = QRect(x, y, width, height);
scaledSize = scaledClipRect.size();
scaledClipRect = QRect();
}
} else {
// Clipping and scaling: too difficult to figure out,
// and not a likely use case, so do it the long way.
}
}
// Determine the scale factor to pass to libjpeg for quick downscaling.
if (!scaledSize.isEmpty()) {
if (clipRect.isEmpty()) {
info->scale_denom =
qMin(info->image_width / scaledSize.width(),
info->image_height / scaledSize.height());
} else {
info->scale_denom =
qMin(clipRect.width() / scaledSize.width(),
clipRect.height() / scaledSize.height());
}
if (info->scale_denom < 2) {
info->scale_denom = 1;
} else if (info->scale_denom < 4) {
info->scale_denom = 2;
} else if (info->scale_denom < 8) {
info->scale_denom = 4;
} else {
info->scale_denom = 8;
}
info->scale_num = 1;
if (!clipRect.isEmpty()) {
// Correct the scale factor so that we clip accurately.
// It is recommended that the clip rectangle be aligned
// on an 8-pixel boundary for best performance.
while (info->scale_denom > 1 &&
((clipRect.x() % info->scale_denom) != 0 ||
(clipRect.y() % info->scale_denom) != 0 ||
(clipRect.width() % info->scale_denom) != 0 ||
(clipRect.height() % info->scale_denom) != 0)) {
info->scale_denom /= 2;
}
}
}
// If high quality not required, use fast decompression
if( quality < HIGH_QUALITY_THRESHOLD ) {
info->dct_method = JDCT_IFAST;
info->do_fancy_upsampling = FALSE;
}
(void) jpeg_calc_output_dimensions(info);
// Determine the clip region to extract.
QRect imageRect(0, 0, info->output_width, info->output_height);
QRect clip;
if (clipRect.isEmpty()) {
clip = imageRect;
} else if (info->scale_denom == info->scale_num) {
clip = clipRect.intersected(imageRect);
} else {
// The scale factor was corrected above to ensure that
// we don't miss pixels when we scale the clip rectangle.
clip = QRect(clipRect.x() / int(info->scale_denom),
clipRect.y() / int(info->scale_denom),
clipRect.width() / int(info->scale_denom),
clipRect.height() / int(info->scale_denom));
clip = clip.intersected(imageRect);
}
// Allocate memory for the clipped QImage.
if (!ensureValidImage(outImage, info, clip.size()))
longjmp(err->setjmp_buffer, 1);
// Avoid memcpy() overhead if grayscale with no clipping.
bool quickGray = (info->output_components == 1 &&
clip == imageRect);
if (!quickGray) {
// Ask the jpeg library to allocate a temporary row.
// The library will automatically delete it for us later.
// The libjpeg docs say we should do this before calling
// jpeg_start_decompress(). We can't use "new" here
// because we are inside the setjmp() block and an error
// in the jpeg input stream would cause a memory leak.
JSAMPARRAY rows = (info->mem->alloc_sarray)
((j_common_ptr)info, JPOOL_IMAGE,
info->output_width * info->output_components, 1);
(void) jpeg_start_decompress(info);
while (info->output_scanline < info->output_height) {
int y = int(info->output_scanline) - clip.y();
if (y >= clip.height())
break; // We've read the entire clip region, so abort.
(void) jpeg_read_scanlines(info, rows, 1);
if (y < 0)
continue; // Haven't reached the starting line yet.
if (info->output_components == 3) {
uchar *in = rows[0] + clip.x() * 3;
QRgb *out = (QRgb*)outImage->scanLine(y);
convert_rgb888_to_rgb32_C(out, in, clip.width());
} else if (info->out_color_space == JCS_CMYK) {
// Convert CMYK->RGB.
uchar *in = rows[0] + clip.x() * 4;
QRgb *out = (QRgb*)outImage->scanLine(y);
for (int i = 0; i < clip.width(); ++i) {
int k = in[3];
*out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
k * in[2] / 255);
in += 4;
}
} else if (info->output_components == 1) {
// Grayscale.
memcpy(outImage->scanLine(y),
rows[0] + clip.x(), clip.width());
}
}
} else {
// Load unclipped grayscale data directly into the QImage.
(void) jpeg_start_decompress(info);
while (info->output_scanline < info->output_height) {
uchar *row = outImage->scanLine(info->output_scanline);
(void) jpeg_read_scanlines(info, &row, 1);
}
}
if (info->output_scanline == info->output_height)
(void) jpeg_finish_decompress(info);
if (info->density_unit == 1) {
outImage->setDotsPerMeterX(int(100. * info->X_density / 2.54));
outImage->setDotsPerMeterY(int(100. * info->Y_density / 2.54));
} else if (info->density_unit == 2) {
outImage->setDotsPerMeterX(int(100. * info->X_density));
outImage->setDotsPerMeterY(int(100. * info->Y_density));
}
if (scaledSize.isValid() && scaledSize != clip.size()) {
*outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, quality >= HIGH_QUALITY_THRESHOLD ? Qt::SmoothTransformation : Qt::FastTransformation);
}
if (!scaledClipRect.isEmpty())
*outImage = outImage->copy(scaledClipRect);
return !outImage->isNull();
}
else
return false;
}
struct my_jpeg_destination_mgr : public jpeg_destination_mgr {
// Nothing dynamic - cannot rely on destruction over longjump
QIODevice *device;
JOCTET buffer[QT_BUFFSIZE];
public:
my_jpeg_destination_mgr(QIODevice *);
};
#if defined(Q_C_CALLBACKS)
extern "C" {
#endif
static void qt_init_destination(j_compress_ptr)
{
}
static boolean qt_empty_output_buffer(j_compress_ptr cinfo)
{
my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
int written = dest->device->write((char*)dest->buffer, QT_BUFFSIZE);
if (written == -1)
(*cinfo->err->error_exit)((j_common_ptr)cinfo);
dest->next_output_byte = dest->buffer;
dest->free_in_buffer = QT_BUFFSIZE;
return TRUE;
}
static void qt_term_destination(j_compress_ptr cinfo)
{
my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
qint64 n = QT_BUFFSIZE - dest->free_in_buffer;
qint64 written = dest->device->write((char*)dest->buffer, n);
if (written == -1)
(*cinfo->err->error_exit)((j_common_ptr)cinfo);
}
#if defined(Q_C_CALLBACKS)
}
#endif
inline my_jpeg_destination_mgr::my_jpeg_destination_mgr(QIODevice *device)
{
jpeg_destination_mgr::init_destination = qt_init_destination;
jpeg_destination_mgr::empty_output_buffer = qt_empty_output_buffer;
jpeg_destination_mgr::term_destination = qt_term_destination;
this->device = device;
next_output_byte = buffer;
free_in_buffer = QT_BUFFSIZE;
}
static bool write_jpeg_image(const QImage &image, QIODevice *device, int quality)
{
bool success = false;
const QVector<QRgb> cmap = image.colorTable();
struct jpeg_compress_struct cinfo;
JSAMPROW row_pointer[1];
row_pointer[0] = 0;
struct my_jpeg_destination_mgr *iod_dest = new my_jpeg_destination_mgr(device);
struct my_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jerr.error_exit = my_error_exit;
if (!setjmp(jerr.setjmp_buffer)) {
// WARNING:
// this if loop is inside a setjmp/longjmp branch
// do not create C++ temporaries here because the destructor may never be called
// if you allocate memory, make sure that you can free it (row_pointer[0])
jpeg_create_compress(&cinfo);
cinfo.dest = iod_dest;
cinfo.image_width = image.width();
cinfo.image_height = image.height();
bool gray=false;
switch (image.format()) {
case QImage::Format_Mono:
case QImage::Format_MonoLSB:
case QImage::Format_Indexed8:
gray = true;
for (int i = image.colorCount(); gray && i--;) {
gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) &&
qRed(cmap[i]) == qBlue(cmap[i]));
}
cinfo.input_components = gray ? 1 : 3;
cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB;
break;
default:
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
}
jpeg_set_defaults(&cinfo);
qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.))
+ qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.));
qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.))
+ qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54;
if (diffInch < diffCm) {
cinfo.density_unit = 1; // dots/inch
cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.);
cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.);
} else {
cinfo.density_unit = 2; // dots/cm
cinfo.X_density = (image.dotsPerMeterX()+50) / 100;
cinfo.Y_density = (image.dotsPerMeterY()+50) / 100;
}
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
jpeg_start_compress(&cinfo, TRUE);
row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
int w = cinfo.image_width;
while (cinfo.next_scanline < cinfo.image_height) {
uchar *row = row_pointer[0];
switch (image.format()) {
case QImage::Format_Mono:
case QImage::Format_MonoLSB:
if (gray) {
const uchar* data = image.constScanLine(cinfo.next_scanline);
if (image.format() == QImage::Format_MonoLSB) {
for (int i=0; i<w; i++) {
bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
row[i] = qRed(cmap[bit]);
}
} else {
for (int i=0; i<w; i++) {
bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
row[i] = qRed(cmap[bit]);
}
}
} else {
const uchar* data = image.constScanLine(cinfo.next_scanline);
if (image.format() == QImage::Format_MonoLSB) {
for (int i=0; i<w; i++) {
bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
*row++ = qRed(cmap[bit]);
*row++ = qGreen(cmap[bit]);
*row++ = qBlue(cmap[bit]);
}
} else {
for (int i=0; i<w; i++) {
bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
*row++ = qRed(cmap[bit]);
*row++ = qGreen(cmap[bit]);
*row++ = qBlue(cmap[bit]);
}
}
}
break;
case QImage::Format_Indexed8:
if (gray) {
const uchar* pix = image.constScanLine(cinfo.next_scanline);
for (int i=0; i<w; i++) {
*row = qRed(cmap[*pix]);
++row; ++pix;
}
} else {
const uchar* pix = image.constScanLine(cinfo.next_scanline);
for (int i=0; i<w; i++) {
*row++ = qRed(cmap[*pix]);
*row++ = qGreen(cmap[*pix]);
*row++ = qBlue(cmap[*pix]);
++pix;
}
}
break;
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
{
const QRgb* rgb = (const QRgb*)image.constScanLine(cinfo.next_scanline);
for (int i=0; i<w; i++) {
*row++ = qRed(*rgb);
*row++ = qGreen(*rgb);
*row++ = qBlue(*rgb);
++rgb;
}
}
break;
default:
{
// (Testing shows that this way is actually faster than converting to RGB888 + memcpy)
QImage rowImg = image.copy(0, cinfo.next_scanline, w, 1).convertToFormat(QImage::Format_RGB32);
const QRgb* rgb = (const QRgb*)rowImg.constScanLine(0);
for (int i=0; i<w; i++) {
*row++ = qRed(*rgb);
*row++ = qGreen(*rgb);
*row++ = qBlue(*rgb);
++rgb;
}
}
break;
}
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
success = true;
} else {
jpeg_destroy_compress(&cinfo);
success = false;
}
delete iod_dest;
delete [] row_pointer[0];
return success;
}
class QJpegHandlerPrivate
{
public:
enum State {
Ready,
ReadHeader,
Error
};
QJpegHandlerPrivate(QJpegHandler *qq)
: quality(75), iod_src(0), state(Ready), q(qq)
{}
~QJpegHandlerPrivate()
{
if(iod_src)
{
jpeg_destroy_decompress(&info);
delete iod_src;
iod_src = 0;
}
}
bool readJpegHeader(QIODevice*);
bool read(QImage *image);
int quality;
QVariant size;
QImage::Format format;
QSize scaledSize;
QRect scaledClipRect;
QRect clipRect;
struct jpeg_decompress_struct info;
struct my_jpeg_source_mgr * iod_src;
struct my_error_mgr err;
State state;
QJpegHandler *q;
};
/*!
\internal
*/
bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
{
if(state == Ready)
{
state = Error;
iod_src = new my_jpeg_source_mgr(device);
jpeg_create_decompress(&info);
info.src = iod_src;
info.err = jpeg_std_error(&err);
err.error_exit = my_error_exit;
if (!setjmp(err.setjmp_buffer)) {
(void) jpeg_read_header(&info, TRUE);
int width = 0;
int height = 0;
read_jpeg_size(width, height, &info);
size = QSize(width, height);
format = QImage::Format_Invalid;
read_jpeg_format(format, &info);
state = ReadHeader;
return true;
}
else
{
return false;
}
}
else if(state == Error)
return false;
return true;
}
bool QJpegHandlerPrivate::read(QImage *image)
{
if(state == Ready)
readJpegHeader(q->device());
if(state == ReadHeader)
{
bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, &info, &err);
state = success ? Ready : Error;
return success;
}
return false;
}
QJpegHandler::QJpegHandler()
: d(new QJpegHandlerPrivate(this))
{
}
QJpegHandler::~QJpegHandler()
{
delete d;
}
bool QJpegHandler::canRead() const
{
if(d->state == QJpegHandlerPrivate::Ready && !canRead(device()))
return false;
if (d->state != QJpegHandlerPrivate::Error) {
setFormat("jpeg");
return true;
}
return false;
}
bool QJpegHandler::canRead(QIODevice *device)
{
if (Q_UNLIKELY(!device)) {
qWarning("QJpegHandler::canRead() called with no device");
return false;
}
QSTACKARRAY(char, buffer, 2);
if (device->peek(buffer, 2) != 2)
return false;
return uchar(buffer[0]) == 0xff && uchar(buffer[1]) == 0xd8;
}
bool QJpegHandler::read(QImage *image)
{
if (!canRead())
return false;
return d->read(image);
}
bool QJpegHandler::write(const QImage &image)
{
return write_jpeg_image(image, device(), d->quality);
}
bool QJpegHandler::supportsOption(ImageOption option) const
{
return option == Quality
|| option == ScaledSize
|| option == ScaledClipRect
|| option == ClipRect
|| option == Size
|| option == ImageFormat;
}
QVariant QJpegHandler::option(ImageOption option) const
{
switch(option) {
case Quality:
return d->quality;
case ScaledSize:
return d->scaledSize;
case ScaledClipRect:
return d->scaledClipRect;
case ClipRect:
return d->clipRect;
case Size:
d->readJpegHeader(device());
return d->size;
case ImageFormat:
d->readJpegHeader(device());
return d->format;
default:
return QVariant();
}
}
void QJpegHandler::setOption(ImageOption option, const QVariant &value)
{
switch(option) {
case Quality: {
const int newquality = value.toInt();
// -1 means default quality.
d->quality = (newquality >= 0 ? qMin(newquality, 100) : 75);
break;
}
case ScaledSize:
d->scaledSize = value.toSize();
break;
case ScaledClipRect:
d->scaledClipRect = value.toRect();
break;
case ClipRect:
d->clipRect = value.toRect();
break;
default:
break;
}
}
QByteArray QJpegHandler::name() const
{
return "jpeg";
}
QT_END_NAMESPACE

View file

@ -1,56 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the plugins of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QJPEGHANDLER_P_H
#define QJPEGHANDLER_P_H
#include <QtGui/qimageiohandler.h>
#include <QtCore/QSize>
#include <QtCore/QRect>
QT_BEGIN_NAMESPACE
class QJpegHandlerPrivate;
class QJpegHandler : public QImageIOHandler
{
public:
QJpegHandler();
~QJpegHandler();
bool canRead() const;
bool read(QImage *image);
bool write(const QImage &image);
QByteArray name() const;
static bool canRead(QIODevice *device);
QVariant option(ImageOption option) const;
void setOption(ImageOption option, const QVariant &value);
bool supportsOption(ImageOption option) const;
private:
QJpegHandlerPrivate *d;
};
QT_END_NAMESPACE
#endif // QJPEGHANDLER_P_H

View file

@ -1,82 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the plugins of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qimageiohandler.h"
#include "qstringlist.h"
#include "qjpeghandler_p.h"
QT_BEGIN_NAMESPACE
class QJpegPlugin : public QImageIOPlugin
{
public:
QJpegPlugin();
~QJpegPlugin();
QStringList keys() const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
};
QJpegPlugin::QJpegPlugin()
{
}
QJpegPlugin::~QJpegPlugin()
{
}
QStringList QJpegPlugin::keys() const
{
static const QStringList list = QStringList()
<< QLatin1String("jpg")
<< QLatin1String("jpeg");
return list;
}
QImageIOPlugin::Capabilities QJpegPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "jpg" || format == "jpeg")
return Capabilities(CanRead | CanWrite);
if (!format.isEmpty())
return 0;
if (!device->isOpen())
return 0;
Capabilities cap;
if (device->isReadable() && QJpegHandler::canRead(device))
cap |= CanRead;
if (device->isWritable())
cap |= CanWrite;
return cap;
}
QImageIOHandler *QJpegPlugin::create(QIODevice *device, const QByteArray &format) const
{
QImageIOHandler *handler = new QJpegHandler;
handler->setDevice(device);
handler->setFormat(format);
return handler;
}
Q_EXPORT_PLUGIN2(qjpeg, QJpegPlugin)
QT_END_NAMESPACE

View file

@ -1,24 +0,0 @@
set(QTGAPLUGIN_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/qtgahandler.h
${CMAKE_CURRENT_SOURCE_DIR}/qtgafile.h
)
set(QTGAPLUGIN_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/qtgaplugin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/qtgahandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/qtgafile.cpp
)
katie_setup_target(qtgaplugin ${QTGAPLUGIN_SOURCES} ${QTGAPLUGIN_HEADERS})
add_library(qtgaplugin MODULE ${qtgaplugin_SOURCES})
target_link_libraries(qtgaplugin KtCore KtGui)
set_target_properties(qtgaplugin PROPERTIES OUTPUT_NAME qtga)
katie_setup_plugin(qtgaplugin)
install(
TARGETS qtgaplugin
DESTINATION ${KATIE_PLUGINS_PATH}/imageformats
COMPONENT Runtime
)

View file

@ -1,254 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtQuick3D module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtgafile.h"
#include <QtCore/QIODevice>
#include <QtCore/QDebug>
#include <QtCore/QDateTime>
QT_BEGIN_NAMESPACE
struct TgaReader
{
virtual ~TgaReader() {}
virtual QRgb operator()(QIODevice *s) const = 0;
};
struct Tga16Reader : public TgaReader
{
~Tga16Reader() {}
QRgb operator()(QIODevice *s) const
{
char ch1, ch2;
if (s->getChar(&ch1) && s->getChar(&ch2)) {
quint16 d = (int(ch1) & 0xFF) | ((int(ch2) & 0xFF) << 8);
QRgb result = (d & 0x8000) ? 0xFF000000 : 0x00000000;
result |= (d & 0x7C00 << 6) | (d & 0x03E0 << 3) | (d & 0x001F);
return result;
} else {
return 0;
}
}
};
struct Tga24Reader : public TgaReader
{
QRgb operator()(QIODevice *s) const
{
char r, g, b;
if (s->getChar(&b) && s->getChar(&g) && s->getChar(&r))
return qRgb(uchar(r), uchar(g), uchar(b));
else
return 0;
}
};
struct Tga32Reader : public TgaReader
{
QRgb operator()(QIODevice *s) const
{
char r, g, b, a;
if (s->getChar(&b) && s->getChar(&g) && s->getChar(&r) && s->getChar(&a))
return qRgba(uchar(r), uchar(g), uchar(b), uchar(a));
else
return 0;
}
};
/*!
\class QTgaFile
\since 4.8
\internal
File data container for a TrueVision Graphics format file.
Format is as described here:
http://local.wasp.uwa.edu.au/~pbourke/dataformats/tga/
http://netghost.narod.ru/gff2/graphics/summary/tga.htm
Usage is:
\code
QTgaFile tga(myFile);
QImage tgaImage;
if (tga.isValid())
tgaImage = tga.readImage();
\endcode
The class is designed to handle sequential and non-sequential
sources, so during construction the mHeader is read. Then during
the readImage() call the rest of the data is read.
After passing myFile to the constructor, if the QIODevice *myFile
is read, or has seek() called, the results are undefined - so don't
do that.
*/
/*!
Construct a new QTgaFile object getting data from \a device.
The object does not take ownership of the \a device, but until the
object is destroyed do not do any non-const operations, eg seek or
read on the device.
*/
QTgaFile::QTgaFile(QIODevice *device)
: mDevice(device)
{
::memset(mHeader, 0, HeaderSize);
if (!mDevice->isReadable())
{
mErrorMessage = QObject::tr("Could not read image data");
return;
}
if (mDevice->isSequential())
{
mErrorMessage = QObject::tr("Sequential device (eg socket) for image read not supported");
return;
}
if (!mDevice->seek(0))
{
mErrorMessage = QObject::tr("Seek file/device for image read failed");
return;
}
int bytes = device->read((char*)mHeader, HeaderSize);
if (bytes != HeaderSize)
{
mErrorMessage = QObject::tr("Image mHeader read failed");
device->seek(0);
return;
}
if (mHeader[ImageType] != 2)
{
// TODO: should support other image types
mErrorMessage = QObject::tr("Image type not supported");
device->seek(0);
return;
}
int bitsPerPixel = mHeader[PixelDepth];
bool validDepth = (bitsPerPixel == 16 || bitsPerPixel == 24 || bitsPerPixel == 32);
if (!validDepth)
{
mErrorMessage = QObject::tr("Image depth not valid");
}
int fileBytes = mDevice->size();
if (!mDevice->seek(fileBytes - FooterSize))
{
mErrorMessage = QObject::tr("Could not seek to image read footer");
device->seek(0);
return;
}
char footer[FooterSize];
bytes = mDevice->read((char*)footer, FooterSize);
if (bytes != FooterSize)
{
mErrorMessage = QObject::tr("Could not read footer");
}
if (qstrncmp(&footer[SignatureOffset], "TRUEVISION-XFILE", 16) != 0)
{
mErrorMessage = QObject::tr("Image type (non-TrueVision 2.0) not supported");
}
if (!mDevice->seek(0))
{
mErrorMessage = QObject::tr("Could not reset to start position");
}
}
/*!
\internal
Destroy the device, recovering any resources.
*/
QTgaFile::~QTgaFile()
{
}
/*!
\internal
Reads an image file from the QTgaFile's device, and returns it.
This method seeks to the absolute position of the image data in the file,
so no assumptions are made about where the devices read pointer is when this
method is called. For this reason only random access devices are supported.
If the constructor completed successfully, such that isValid() returns true,
then this method is likely to succeed, unless the file is somehow corrupted.
In the case that the read fails, the QImage returned will be null, such that
QImage::isNull() will be true.
*/
QImage QTgaFile::readImage()
{
if (!isValid())
return QImage();
int offset = mHeader[IdLength]; // Mostly always zero
// Even in TrueColor files a color pallette may be present
if (mHeader[ColorMapType] == 1)
offset += littleEndianInt(&mHeader[CMapLength]) * littleEndianInt(&mHeader[CMapDepth]);
mDevice->seek(HeaderSize + offset);
char dummy;
for (int i = 0; i < offset; ++i)
mDevice->getChar(&dummy);
int bitsPerPixel = mHeader[PixelDepth];
int imageWidth = width();
int imageHeight = height();
unsigned char desc = mHeader[ImageDescriptor];
//unsigned char xCorner = desc & 0x10; // 0 = left, 1 = right
unsigned char yCorner = desc & 0x20; // 0 = lower, 1 = upper
QImage im(imageWidth, imageHeight, QImage::Format_ARGB32);
TgaReader *reader = 0;
if (bitsPerPixel == 16)
reader = new Tga16Reader();
else if (bitsPerPixel == 24)
reader = new Tga24Reader();
else if (bitsPerPixel == 32)
reader = new Tga32Reader();
else
return QImage();
TgaReader &read = *reader;
// For now only deal with yCorner, since no one uses xCorner == 1
// Also this is upside down, since Qt has the origin flipped
if (yCorner)
{
for (int y = 0; y < imageHeight; ++y)
for (int x = 0; x < imageWidth; ++x)
im.setPixel(x, y, read(mDevice));
}
else
{
for (int y = imageHeight - 1; y >= 0; --y)
for (int x = 0; x < imageWidth; ++x)
im.setPixel(x, y, read(mDevice));
}
delete reader;
// TODO: add processing of TGA extension information - ie TGA 2.0 files
return im;
}
QT_END_NAMESPACE

View file

@ -1,131 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtQuick3D module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTGAFILE_H
#define QTGAFILE_H
#include <QtGui/QColor>
#include <QtGui/QImage>
QT_BEGIN_NAMESPACE
class QIODevice;
class QTgaFile
{
public:
enum Compression {
NoCompression = 0,
RleCompression = 1
};
enum HeaderOffset {
IdLength = 0, /* 00h Size of Image ID field */
ColorMapType = 1, /* 01h Color map type */
ImageType = 2, /* 02h Image type code */
CMapStart = 3, /* 03h Color map origin */
CMapLength = 5, /* 05h Color map length */
CMapDepth = 7, /* 07h Depth of color map entries */
XOffset = 8, /* 08h X origin of image */
YOffset = 10, /* 0Ah Y origin of image */
Width = 12, /* 0Ch Width of image */
Height = 14, /* 0Eh Height of image */
PixelDepth = 16, /* 10h Image pixel size */
ImageDescriptor = 17, /* 11h Image descriptor byte */
HeaderSize = 18
};
enum FooterOffset {
ExtensionOffset = 0,
DeveloperOffset = 4,
SignatureOffset = 8,
FooterSize = 26
};
QTgaFile(QIODevice *);
~QTgaFile();
inline bool isValid() const;
QImage readImage();
inline int xOffset() const;
inline int yOffset() const;
inline int width() const;
inline int height() const;
inline QSize size() const;
inline Compression compression() const;
private:
static inline quint16 littleEndianInt(const unsigned char *d);
QString mErrorMessage;
unsigned char mHeader[HeaderSize];
QIODevice *mDevice;
};
inline bool QTgaFile::isValid() const
{
return mErrorMessage.isEmpty();
}
/*!
\internal
Returns the integer encoded in the two little endian bytes at \a d.
*/
inline quint16 QTgaFile::littleEndianInt(const unsigned char *d)
{
return d[0] + d[1] * 256;
}
inline int QTgaFile::xOffset() const
{
return littleEndianInt(&mHeader[XOffset]);
}
inline int QTgaFile::yOffset() const
{
return littleEndianInt(&mHeader[YOffset]);
}
inline int QTgaFile::width() const
{
return littleEndianInt(&mHeader[Width]);
}
inline int QTgaFile::height() const
{
return littleEndianInt(&mHeader[Height]);
}
inline QSize QTgaFile::size() const
{
return QSize(width(), height());
}
inline QTgaFile::Compression QTgaFile::compression() const
{
// TODO: for now, only handle type 2 files, with no color table
// and no compression
return NoCompression;
}
QT_END_NAMESPACE
#endif // QTGAFILE_H

View file

@ -1,106 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtQuick3D module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtgahandler.h"
#include "qtgafile.h"
#include <QtCore/QVariant>
#include <QtCore/QDebug>
#include <QtGui/QImage>
QT_BEGIN_NAMESPACE
QTgaHandler::QTgaHandler()
: QImageIOHandler()
, tga(0)
{
}
QTgaHandler::~QTgaHandler()
{
delete tga;
}
bool QTgaHandler::canRead() const
{
if (!tga)
tga = new QTgaFile(device());
if (tga->isValid())
{
setFormat("tga");
return true;
}
return false;
}
bool QTgaHandler::canRead(QIODevice *device)
{
if (Q_UNLIKELY(!device)) {
qWarning("QTgaHandler::canRead() called with no device");
return false;
}
const qint64 oldpos = device->pos();
QTgaFile tga(device);
const bool isvalid = tga.isValid();
device->seek(oldpos);
return isvalid;
}
bool QTgaHandler::read(QImage *image)
{
if (!canRead())
return false;
*image = tga->readImage();
return !image->isNull();
}
QByteArray QTgaHandler::name() const
{
return "tga";
}
QVariant QTgaHandler::option(ImageOption option) const
{
if (option == Size && canRead()) {
return tga->size();
} else if (option == CompressionRatio) {
return tga->compression();
} else if (option == ImageFormat) {
return QImage::Format_ARGB32;
}
return QVariant();
}
void QTgaHandler::setOption(ImageOption option, const QVariant &value)
{
Q_UNUSED(option);
Q_UNUSED(value);
}
bool QTgaHandler::supportsOption(ImageOption option) const
{
return option == CompressionRatio
|| option == Size
|| option == ImageFormat;
}
QT_END_NAMESPACE

View file

@ -1,54 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtQuick3D module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTGAHANDLER_H
#define QTGAHANDLER_H
#include <QtGui/QImageIOHandler>
QT_BEGIN_NAMESPACE
class QTgaFile;
class QTgaHandler : public QImageIOHandler
{
public:
QTgaHandler();
~QTgaHandler();
bool canRead() const;
bool read(QImage *image);
QByteArray name() const;
static bool canRead(QIODevice *device);
QVariant option(ImageOption option) const;
void setOption(ImageOption option, const QVariant &value);
bool supportsOption(ImageOption option) const;
private:
mutable QTgaFile *tga;
};
QT_END_NAMESPACE
#endif // QTGAHANDLER_H

View file

@ -1,68 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the QtQuick3D module of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtGui/QImageIOHandler>
#include <QtCore/QDebug>
#include "qtgahandler.h"
QT_BEGIN_NAMESPACE
class QTgaPlugin : public QImageIOPlugin
{
public:
Capabilities capabilities(QIODevice * device, const QByteArray & format) const;
QImageIOHandler * create(QIODevice * device, const QByteArray & format = QByteArray()) const;
QStringList keys() const;
};
QImageIOPlugin::Capabilities QTgaPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "tga")
return Capabilities(CanRead);
if (!format.isEmpty())
return 0;
if (!device->isOpen())
return 0;
Capabilities cap;
if (device->isReadable() && QTgaHandler::canRead(device))
cap |= CanRead;
return cap;
}
QImageIOHandler* QTgaPlugin::create(QIODevice *device, const QByteArray &format) const
{
QImageIOHandler *tgaHandler = new QTgaHandler();
tgaHandler->setDevice(device);
tgaHandler->setFormat(format);
return tgaHandler;
}
QStringList QTgaPlugin::keys() const
{
static const QStringList list = QStringList()
<< QLatin1String("tga");
return list;
}
Q_EXPORT_PLUGIN2(qtga, QTgaPlugin)
QT_END_NAMESPACE

View file

@ -1,24 +0,0 @@
include_directories(${TIFF_INCLUDE_DIR})
set(QTIFFPLUGIN_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/qtiffhandler_p.h
)
set(QTIFFPLUGIN_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/qtiffplugin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/qtiffhandler.cpp
)
katie_setup_target(qtiffplugin ${QTIFFPLUGIN_SOURCES} ${QTIFFPLUGIN_HEADERS})
add_library(qtiffplugin MODULE ${qtiffplugin_SOURCES})
target_link_libraries(qtiffplugin KtCore KtGui ${TIFF_LIBRARIES})
set_target_properties(qtiffplugin PROPERTIES OUTPUT_NAME qtiff)
katie_setup_plugin(qtiffplugin)
install(
TARGETS qtiffplugin
DESTINATION ${KATIE_PLUGINS_PATH}/imageformats
COMPONENT Runtime
)

View file

@ -1,642 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the plugins of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtiffhandler_p.h"
#include "qvariant.h"
#include "qdebug.h"
#include "qimage.h"
extern "C" {
#include "tiffio.h"
}
QT_BEGIN_NAMESPACE
tsize_t qtiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
{
QIODevice* device = static_cast<QTiffHandler*>(fd)->device();
return device->isReadable() ? device->read(static_cast<char *>(buf), size) : -1;
}
tsize_t qtiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
{
return static_cast<QTiffHandler*>(fd)->device()->write(static_cast<char *>(buf), size);
}
toff_t qtiffSeekProc(thandle_t fd, toff_t off, int whence)
{
QIODevice *device = static_cast<QTiffHandler*>(fd)->device();
switch (whence) {
case SEEK_SET:
device->seek(off);
break;
case SEEK_CUR:
device->seek(device->pos() + off);
break;
case SEEK_END:
device->seek(device->size() + off);
break;
}
return device->pos();
}
int qtiffCloseProc(thandle_t /*fd*/)
{
return 0;
}
toff_t qtiffSizeProc(thandle_t fd)
{
return static_cast<QTiffHandler*>(fd)->device()->size();
}
int qtiffMapProc(thandle_t /*fd*/, tdata_t* /*pbase*/, toff_t* /*psize*/)
{
return 0;
}
void qtiffUnmapProc(thandle_t /*fd*/, tdata_t /*base*/, toff_t /*size*/)
{
}
// for 32 bits images
inline void rotate_right_mirror_horizontal(QImage *const image)// rotate right->mirrored horizontal
{
const int height = image->height();
const int width = image->width();
QImage generated(/* width = */ height, /* height = */ width, image->format());
const uint32 *originalPixel = reinterpret_cast<const uint32*>(image->bits());
uint32 *const generatedPixels = reinterpret_cast<uint32*>(generated.bits());
for (int row=0; row < height; ++row) {
for (int col=0; col < width; ++col) {
int idx = col * height + row;
generatedPixels[idx] = *originalPixel;
++originalPixel;
}
}
*image = generated;
}
inline void rotate_right_mirror_vertical(QImage *const image) // rotate right->mirrored vertical
{
const int height = image->height();
const int width = image->width();
QImage generated(/* width = */ height, /* height = */ width, image->format());
const int lastCol = width - 1;
const int lastRow = height - 1;
const uint32 *pixel = reinterpret_cast<const uint32*>(image->bits());
uint32 *const generatedBits = reinterpret_cast<uint32*>(generated.bits());
for (int row=0; row < height; ++row) {
for (int col=0; col < width; ++col) {
int idx = (lastCol - col) * height + (lastRow - row);
generatedBits[idx] = *pixel;
++pixel;
}
}
*image = generated;
}
static void qConvert32BitOrder(void *buffer, int width)
{
uint32 *target = reinterpret_cast<uint32 *>(buffer);
for (int32 x=0; x<width; ++x) {
uint32 p = target[x];
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
target[x] = (p & 0xff000000) >> 24
| (p & 0x00ff0000) << 8
| (p & 0x0000ff00) << 8
| (p & 0x000000ff) << 8;
#else
// convert between ARGB and ABGR
target[x] = (p & 0xff000000)
| ((p & 0x00ff0000) >> 16)
| (p & 0x0000ff00)
| ((p & 0x000000ff) << 16);
#endif
}
}
QTiffHandler::QTiffHandler() : QImageIOHandler()
{
compression = NoCompression;
}
bool QTiffHandler::canRead() const
{
if (canRead(device())) {
setFormat("tiff");
return true;
}
return false;
}
bool QTiffHandler::canRead(QIODevice *device)
{
if (Q_UNLIKELY(!device)) {
qWarning("QTiffHandler::canRead() called with no device");
return false;
}
// need the magic from the beginning
Q_ASSERT(device->pos() == 0);
const QByteArray header = device->peek(4);
return header == QByteArray::fromRawData("\x49\x49\x2A\x00", 4)
|| header == QByteArray::fromRawData("\x4D\x4D\x00\x2A", 4);
}
bool QTiffHandler::read(QImage *image)
{
if (!canRead())
return false;
TIFF *const tiff = TIFFClientOpen("foo",
"r",
this,
qtiffReadProc,
qtiffWriteProc,
qtiffSeekProc,
qtiffCloseProc,
qtiffSizeProc,
qtiffMapProc,
qtiffUnmapProc);
if (!tiff) {
return false;
}
uint32 width;
uint32 height;
uint16 photometric;
if (!TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width)
|| !TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height)
|| !TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric)) {
TIFFClose(tiff);
return false;
}
// BitsPerSample defaults to 1 according to the TIFF spec.
uint16 bitPerSample;
if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample))
bitPerSample = 1;
uint16 samplesPerPixel; // they may be e.g. grayscale with 2 samples per pixel
if (!TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel))
samplesPerPixel = 1;
bool grayscale = photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE;
if (grayscale && bitPerSample == 1 && samplesPerPixel == 1) {
if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono)
*image = QImage(width, height, QImage::Format_Mono);
QVector<QRgb> colortable(2);
if (photometric == PHOTOMETRIC_MINISBLACK) {
colortable[0] = 0xff000000;
colortable[1] = 0xffffffff;
} else {
colortable[0] = 0xffffffff;
colortable[1] = 0xff000000;
}
image->setColorTable(colortable);
if (!image->isNull()) {
for (uint32 y=0; y<height; ++y) {
if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
TIFFClose(tiff);
return false;
}
}
}
} else {
if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8 && samplesPerPixel == 1) {
if (image->size() != QSize(width, height) || image->format() != QImage::Format_Indexed8)
*image = QImage(width, height, QImage::Format_Indexed8);
if (!image->isNull()) {
const uint16 tableSize = 256;
QVector<QRgb> qtColorTable(tableSize);
if (grayscale) {
for (int i = 0; i<tableSize; ++i) {
const int c = (photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i);
qtColorTable[i] = qRgb(c, c, c);
}
} else {
// create the color table
uint16 *redTable = 0;
uint16 *greenTable = 0;
uint16 *blueTable = 0;
if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) {
TIFFClose(tiff);
return false;
}
if (!redTable || !greenTable || !blueTable) {
TIFFClose(tiff);
return false;
}
for (int i = 0; i<tableSize ;++i) {
const int red = redTable[i] / 257;
const int green = greenTable[i] / 257;
const int blue = blueTable[i] / 257;
qtColorTable[i] = qRgb(red, green, blue);
}
}
image->setColorTable(qtColorTable);
for (uint32 y=0; y<height; ++y) {
if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
TIFFClose(tiff);
return false;
}
}
// free redTable, greenTable and greenTable done by libtiff
}
} else {
if (image->size() != QSize(width, height) || image->format() != QImage::Format_ARGB32)
*image = QImage(width, height, QImage::Format_ARGB32);
if (!image->isNull()) {
const int stopOnError = 1;
if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), ORIENTATION_TOPLEFT, stopOnError)) {
for (uint32 y=0; y<height; ++y)
qConvert32BitOrder(image->scanLine(y), width);
} else {
TIFFClose(tiff);
return false;
}
}
}
}
if (image->isNull()) {
TIFFClose(tiff);
return false;
}
float resX = 0;
float resY = 0;
uint16 resUnit;
if (!TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit))
resUnit = RESUNIT_INCH;
if (TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &resX)
&& TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &resY)) {
switch(resUnit) {
case RESUNIT_CENTIMETER:
image->setDotsPerMeterX(qRound(resX * 100));
image->setDotsPerMeterY(qRound(resY * 100));
break;
case RESUNIT_INCH:
image->setDotsPerMeterX(qRound(resX * (100 / 2.54)));
image->setDotsPerMeterY(qRound(resY * (100 / 2.54)));
break;
default:
// do nothing as defaults have already
// been set within the QImage class
break;
}
}
// rotate the image if the orientation is defined in the file
uint16 orientationTag;
if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientationTag)) {
if (image->format() == QImage::Format_ARGB32) {
// TIFFReadRGBAImageOriented() flip the image but does not rotate them
switch (orientationTag) {
case 5:
rotate_right_mirror_horizontal(image);
break;
case 6:
rotate_right_mirror_vertical(image);
break;
case 7:
rotate_right_mirror_horizontal(image);
break;
case 8:
rotate_right_mirror_vertical(image);
break;
}
} else {
switch (orientationTag) {
case 1: // default orientation
break;
case 2: // mirror horizontal
*image = image->mirrored(true, false);
break;
case 3: // mirror both
*image = image->mirrored(true, true);
break;
case 4: // mirror vertical
*image = image->mirrored(false, true);
break;
case 5: // rotate right mirror horizontal
{
QMatrix transformation;
transformation.rotate(90);
*image = image->transformed(transformation);
*image = image->mirrored(true, false);
break;
}
case 6: // rotate right
{
QMatrix transformation;
transformation.rotate(90);
*image = image->transformed(transformation);
break;
}
case 7: // rotate right, mirror vertical
{
QMatrix transformation;
transformation.rotate(90);
*image = image->transformed(transformation);
*image = image->mirrored(false, true);
break;
}
case 8: // rotate left
{
QMatrix transformation;
transformation.rotate(270);
*image = image->transformed(transformation);
break;
}
}
}
}
TIFFClose(tiff);
return true;
}
static bool checkGrayscale(const QVector<QRgb> &colorTable)
{
if (colorTable.size() != 256)
return false;
const bool increasing = (colorTable.at(0) == 0xff000000);
for (int i = 0; i < 256; ++i) {
if ((increasing && colorTable.at(i) != qRgb(i, i, i))
|| (!increasing && colorTable.at(i) != qRgb(255 - i, 255 - i, 255 - i)))
return false;
}
return true;
}
bool QTiffHandler::write(const QImage &image)
{
if (!device()->isWritable())
return false;
TIFF *const tiff = TIFFClientOpen("foo",
"w",
this,
qtiffReadProc,
qtiffWriteProc,
qtiffSeekProc,
qtiffCloseProc,
qtiffSizeProc,
qtiffMapProc,
qtiffUnmapProc);
if (!tiff)
return false;
const int width = image.width();
const int height = image.height();
if (!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width)
|| !TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height)
|| !TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
TIFFClose(tiff);
return false;
}
// set the resolution
bool resolutionSet = false;
const int dotPerMeterX = image.dotsPerMeterX();
const int dotPerMeterY = image.dotsPerMeterY();
if ((dotPerMeterX % 100) == 0
&& (dotPerMeterY % 100) == 0) {
resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER)
&& TIFFSetField(tiff, TIFFTAG_XRESOLUTION, dotPerMeterX/100.0)
&& TIFFSetField(tiff, TIFFTAG_YRESOLUTION, dotPerMeterY/100.0);
} else {
resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)
&& TIFFSetField(tiff, TIFFTAG_XRESOLUTION, static_cast<float>(image.logicalDpiX()))
&& TIFFSetField(tiff, TIFFTAG_YRESOLUTION, static_cast<float>(image.logicalDpiY()));
}
if (!resolutionSet) {
TIFFClose(tiff);
return false;
}
// configure image depth
const QImage::Format format = image.format();
if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) {
uint16 photometric = PHOTOMETRIC_MINISBLACK;
if (image.colorTable().at(0) == 0xffffffff)
photometric = PHOTOMETRIC_MINISWHITE;
if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
|| !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE)
|| !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 1)) {
TIFFClose(tiff);
return false;
}
// try to do the conversion in chunks no greater than 16 MB
int chunks = (width * height / (1024 * 1024 * 16)) + 1;
int chunkHeight = qMax(height / chunks, 1);
int y = 0;
while (y < height) {
QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_Mono);
int chunkStart = y;
int chunkEnd = y + chunk.height();
while (y < chunkEnd) {
if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) {
TIFFClose(tiff);
return false;
}
++y;
}
}
TIFFClose(tiff);
} else if (format == QImage::Format_Indexed8) {
const QVector<QRgb> colorTable = image.colorTable();
bool isGrayscale = checkGrayscale(colorTable);
if (isGrayscale) {
uint16 photometric = PHOTOMETRIC_MINISBLACK;
if (image.colorTable().at(0) == 0xffffffff)
photometric = PHOTOMETRIC_MINISWHITE;
if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
|| !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS)
|| !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
TIFFClose(tiff);
return false;
}
} else {
if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE)
|| !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS)
|| !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
TIFFClose(tiff);
return false;
}
//// write the color table
// allocate the color tables
uint16 *redTable = static_cast<uint16 *>(malloc(256 * sizeof(uint16)));
uint16 *greenTable = static_cast<uint16 *>(malloc(256 * sizeof(uint16)));
uint16 *blueTable = static_cast<uint16 *>(malloc(256 * sizeof(uint16)));
if (!redTable || !greenTable || !blueTable) {
free(redTable);
free(greenTable);
free(blueTable);
TIFFClose(tiff);
return false;
}
// set the color table
const int tableSize = colorTable.size();
Q_ASSERT(tableSize <= 256);
for (int i = 0; i<tableSize; ++i) {
const QRgb color = colorTable.at(i);
redTable[i] = qRed(color) * 257;
greenTable[i] = qGreen(color) * 257;
blueTable[i] = qBlue(color) * 257;
}
const bool setColorTableSuccess = TIFFSetField(tiff, TIFFTAG_COLORMAP, redTable, greenTable, blueTable);
free(redTable);
free(greenTable);
free(blueTable);
if (!setColorTableSuccess) {
TIFFClose(tiff);
return false;
}
}
//// write the data
// try to do the conversion in chunks no greater than 16 MB
int chunks = (width * height/ (1024 * 1024 * 16)) + 1;
int chunkHeight = qMax(height / chunks, 1);
int y = 0;
while (y < height) {
QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y));
int chunkStart = y;
int chunkEnd = y + chunk.height();
while (y < chunkEnd) {
if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) {
TIFFClose(tiff);
return false;
}
++y;
}
}
TIFFClose(tiff);
} else {
if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
|| !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW)
|| !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4)
|| !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
TIFFClose(tiff);
return false;
}
// try to do the ARGB32 conversion in chunks no greater than 16 MB
int chunks = (width * height * 4 / (1024 * 1024 * 16)) + 1;
int chunkHeight = qMax(height / chunks, 1);
int y = 0;
while (y < height) {
QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_ARGB32);
int chunkStart = y;
int chunkEnd = y + chunk.height();
while (y < chunkEnd) {
qConvert32BitOrder(chunk.scanLine(y - chunkStart), width);
if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) {
TIFFClose(tiff);
return false;
}
++y;
}
}
TIFFClose(tiff);
}
return true;
}
QByteArray QTiffHandler::name() const
{
return "tiff";
}
QVariant QTiffHandler::option(ImageOption option) const
{
if (option == Size && canRead()) {
QSize imageSize;
qint64 pos = device()->pos();
TIFF *tiff = TIFFClientOpen("foo",
"r",
const_cast<QTiffHandler*>(this),
qtiffReadProc,
qtiffWriteProc,
qtiffSeekProc,
qtiffCloseProc,
qtiffSizeProc,
qtiffMapProc,
qtiffUnmapProc);
if (tiff) {
uint32 width = 0;
uint32 height = 0;
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height);
imageSize = QSize(width, height);
TIFFClose(tiff);
}
device()->seek(pos);
if (imageSize.isValid())
return imageSize;
} else if (option == CompressionRatio) {
return compression;
} else if (option == ImageFormat) {
return QImage::Format_ARGB32;
}
return QVariant();
}
void QTiffHandler::setOption(ImageOption option, const QVariant &value)
{
if (option == CompressionRatio && value.type() == QVariant::Int)
compression = value.toInt();
}
bool QTiffHandler::supportsOption(ImageOption option) const
{
return option == CompressionRatio
|| option == Size
|| option == ImageFormat;
}
QT_END_NAMESPACE

View file

@ -1,56 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the plugins of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTIFFHANDLER_P_H
#define QTIFFHANDLER_P_H
#include <QtGui/qimageiohandler.h>
QT_BEGIN_NAMESPACE
class QTiffHandler : public QImageIOHandler
{
public:
QTiffHandler();
bool canRead() const;
bool read(QImage *image);
bool write(const QImage &image);
QByteArray name() const;
static bool canRead(QIODevice *device);
QVariant option(ImageOption option) const;
void setOption(ImageOption option, const QVariant &value);
bool supportsOption(ImageOption option) const;
enum Compression {
NoCompression = 0,
LzwCompression = 1
};
private:
int compression;
};
QT_END_NAMESPACE
#endif // QTIFFHANDLER_P_H

View file

@ -1,83 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the plugins of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qimageiohandler.h"
#include "qstringlist.h"
#include "qtiffhandler_p.h"
QT_BEGIN_NAMESPACE
class QTiffPlugin : public QImageIOPlugin
{
public:
QTiffPlugin();
~QTiffPlugin();
QStringList keys() const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
};
QTiffPlugin::QTiffPlugin()
{
}
QTiffPlugin::~QTiffPlugin()
{
}
QStringList QTiffPlugin::keys() const
{
static const QStringList list = QStringList()
<< QLatin1String("tif")
<< QLatin1String("tiff");
return list;
}
QImageIOPlugin::Capabilities QTiffPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "tif" || format == "tiff")
return Capabilities(CanRead | CanWrite);
if (!format.isEmpty())
return 0;
if (!device->isOpen())
return 0;
Capabilities cap;
if (device->isReadable() && QTiffHandler::canRead(device))
cap |= CanRead;
if (device->isWritable())
cap |= CanWrite;
return cap;
}
QImageIOHandler *QTiffPlugin::create(QIODevice *device, const QByteArray &format) const
{
QImageIOHandler *handler = new QTiffHandler;
handler->setDevice(device);
handler->setFormat(format);
return handler;
}
Q_EXPORT_PLUGIN2(qtiff, QTiffPlugin)
QT_END_NAMESPACE

View file

@ -1455,7 +1455,7 @@ void tst_QDir::equalityOperator_data()
<< false;
QTest::newRow("diff-namefilters") << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files)
<< SRCDIR << "*.jpg" << int(QDir::Name) << int(QDir::Files)
<< SRCDIR << "*.png" << int(QDir::Name) << int(QDir::Files)
<< false;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,8 +1,8 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>images/designer.png</file>
<file>images/wine.jpeg</file>
<file>images/wine-big.jpeg</file>
<file>images/wine.png</file>
<file>images/wine-big.png</file>
<file>random.data</file>
</qresource>
</RCC>

View file

@ -742,7 +742,7 @@ void tst_QGraphicsView::moveItemCache()
QGraphicsScene scene(0, 0, 300, 300);
QPixmap pix(QLatin1String(":/images/wine.jpeg"));
QPixmap pix(QLatin1String(":/images/wine.png"));
QVERIFY(!pix.isNull());
QList<QGraphicsItem *> items;
@ -839,7 +839,7 @@ void tst_QGraphicsView::paintItemCache()
QGraphicsScene scene(0, 0, 300, 300);
QPixmap pix(QLatin1String(":/images/wine.jpeg"));
QPixmap pix(QLatin1String(":/images/wine.png"));
QVERIFY(!pix.isNull());
QList<QGraphicsItem *> items;
@ -854,7 +854,7 @@ void tst_QGraphicsView::paintItemCache()
item->setPos(-100, -100);
scene.addItem(item);
QPixmap pix2(QLatin1String(":/images/wine-big.jpeg"));
QPixmap pix2(QLatin1String(":/images/wine-big.png"));
item = new UpdatedPixmapCacheItem(updatePartial);
item->setPixmap(pix2);
item->setCacheMode((QGraphicsItem::CacheMode)cacheMode);

View file

@ -1,10 +1,3 @@
katie_gui_test(tst_bench_qimagereader
${CMAKE_CURRENT_SOURCE_DIR}/tst_qimagereader.cpp
)
if(WITH_JPEG AND JPEG_FOUND)
target_compile_definitions(tst_bench_qimagereader PRIVATE -DQTEST_HAVE_JPEG)
endif()
if(WITH_TIFF AND TIFF_FOUND)
target_compile_definitions(tst_bench_qimagereader PRIVATE -DQTEST_HAVE_TIFF)
endif()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 953 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 B

View file

@ -74,25 +74,12 @@ private:
tst_QImageReader::tst_QImageReader()
{
images << QPair<QString, QByteArray>(QLatin1String("colorful.bmp"), QByteArray("bmp"));
images << QPair<QString, QByteArray>(QLatin1String("font.bmp"), QByteArray("bmp"));
images << QPair<QString, QByteArray>(QLatin1String("crash-signed-char.bmp"), QByteArray("bmp"));
images << QPair<QString, QByteArray>(QLatin1String("4bpp-rle.bmp"), QByteArray("bmp"));
images << QPair<QString, QByteArray>(QLatin1String("tst7.bmp"), QByteArray("bmp"));
images << QPair<QString, QByteArray>(QLatin1String("16bpp.bmp"), QByteArray("bmp"));
images << QPair<QString, QByteArray>(QLatin1String("negativeheight.bmp"), QByteArray("bmp"));
images << QPair<QString, QByteArray>(QLatin1String("marble.xpm"), QByteArray("xpm"));
images << QPair<QString, QByteArray>(QLatin1String("kollada.png"), QByteArray("png"));
images << QPair<QString, QByteArray>(QLatin1String("teapot.ppm"), QByteArray("ppm"));
images << QPair<QString, QByteArray>(QLatin1String("runners.ppm"), QByteArray("ppm"));
images << QPair<QString, QByteArray>(QLatin1String("test.ppm"), QByteArray("ppm"));
images << QPair<QString, QByteArray>(QLatin1String("gnus.xbm"), QByteArray("xbm"));
#if defined QTEST_HAVE_JPEG
images << QPair<QString, QByteArray>(QLatin1String("beavis.jpg"), QByteArray("jpeg"));
images << QPair<QString, QByteArray>(QLatin1String("YCbCr_cmyk.jpg"), QByteArray("jpeg"));
images << QPair<QString, QByteArray>(QLatin1String("YCbCr_rgb.jpg"), QByteArray("jpeg"));
images << QPair<QString, QByteArray>(QLatin1String("task210380.jpg"), QByteArray("jpeg"));
#endif
images << QPair<QString, QByteArray>(QLatin1String("earth.gif"), QByteArray("gif"));
images << QPair<QString, QByteArray>(QLatin1String("trolltech.gif"), QByteArray("gif"));
}

View file

@ -255,7 +255,7 @@ void tst_QPixmap::fromImageReader_data()
image.save(QString::fromLatin1("test.png"));
// RGB32
const QString rgb32Path = tempDir + QString::fromLatin1("/rgb32.jpg");
const QString rgb32Path = tempDir + QString::fromLatin1("/rgb32.png");
image.save(rgb32Path);
QTest::newRow("gradient RGB32") << rgb32Path;

View file

@ -1,7 +0,0 @@
if(WITH_JPEG AND JPEG_FOUND)
katie_test(tst_bench_jpeg
${CMAKE_CURRENT_SOURCE_DIR}/jpeg.cpp
)
target_link_libraries(tst_bench_jpeg KtGui)
endif()

View file

@ -1,68 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 Ivailo Monev
**
** This file is part of the test suite of the Katie Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QDebug>
#include <qtest.h>
#include <QtTest/QtTest>
#include <QFile>
#include <QByteArray>
#include <QBuffer>
#include <QImageReader>
#include <QSize>
class tst_jpeg : public QObject
{
Q_OBJECT
private slots:
void jpegDecodingQtWebkitStyle();
};
void tst_jpeg::jpegDecodingQtWebkitStyle()
{
// QtWebkit currently calls size() to get the image size for layouting purposes.
// Then when it is in the viewport (we assume that here) it actually gets decoded.
QFile inputJpeg(QLatin1String(SRCDIR "n900.jpeg"));
QVERIFY(inputJpeg.exists());
inputJpeg.open(QIODevice::ReadOnly);
QByteArray imageData = inputJpeg.readAll();
QBuffer buffer;
buffer.setData(imageData);
buffer.open(QBuffer::ReadOnly);
QCOMPARE(buffer.size(), qint64(19016));
QBENCHMARK{
for (int i = 0; i < 50; i++) {
QImageReader reader(&buffer, "jpeg");
QSize size = reader.size();
QVERIFY(!size.isNull());
QByteArray format = reader.format();
QVERIFY(!format.isEmpty());
QImage img = reader.read();
QVERIFY(!img.isNull());
buffer.reset();
}
}
}
QTEST_MAIN(tst_jpeg)
#include "moc_jpeg.cpp"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB