15#include <private/qicc_p.h>
16#include <private/qsimd_p.h>
17#include <private/qimage_p.h>
52 (*cinfo->err->output_message)(cinfo);
54 longjmp(myerr->setjmp_buffer, 1);
59 char buffer[JMSG_LENGTH_MAX];
60 (*cinfo->err->format_message)(cinfo,
buffer);
90 src->next_input_byte = (
const JOCTET *)(
src->memDevice->data().constData() +
src->memDevice->pos());
91 num_read =
src->memDevice->data().size() -
src->memDevice->pos();
92 src->device->seek(
src->memDevice->data().size());
94 src->next_input_byte =
src->buffer;
99 src->next_input_byte =
src->buffer;
100 src->buffer[0] = (JOCTET) 0xFF;
101 src->buffer[1] = (JOCTET) JPEG_EOI;
102 src->bytes_in_buffer = 2;
104 src->bytes_in_buffer = num_read;
120 while (num_bytes > (
long)
src->bytes_in_buffer) {
121 num_bytes -= (long)
src->bytes_in_buffer;
127 src->next_input_byte += (size_t) num_bytes;
128 src->bytes_in_buffer -= (size_t) num_bytes;
135 if (!
src->device->isSequential())
136 src->device->seek(
src->device->pos() -
src->bytes_in_buffer);
146 jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart;
157 (
void) jpeg_calc_output_dimensions(cinfo);
159 w = cinfo->output_width;
160 h = cinfo->output_height;
164#define HIGH_QUALITY_THRESHOLD 50
170 switch (cinfo->output_components) {
178 if (cinfo->out_color_space == JCS_CMYK)
187 cinfo->output_scanline = cinfo->output_height;
195 switch (
info->output_components) {
203 if (
info->out_color_space == JCS_CMYK)
217 QRect clipRect,
int quality,
229 if (!scaledClipRect.
isEmpty()) {
232 clipRect = scaledClipRect;
233 scaledClipRect =
QRect();
234 }
else if (scaledSize.
isEmpty()) {
238 scaledClipRect =
QRect();
239 }
else if (clipRect.
isEmpty()) {
242 if ((
info->image_width % scaledSize.
width()) == 0 &&
243 (
info->image_height % scaledSize.
height()) == 0) {
244 int x = scaledClipRect.
x() *
info->image_width /
246 int y = scaledClipRect.
y() *
info->image_height /
253 scaledSize = scaledClipRect.
size();
254 scaledClipRect =
QRect();
263 if (!scaledSize.
isEmpty() &&
info->image_width &&
info->image_height) {
266 double(
info->image_height) / scaledSize.
height());
271 info->scale_denom = 8;
278 if (
info->scale_denom < 2)
279 info->scale_denom = 1;
280 else if (
info->scale_denom < 4)
281 info->scale_denom = 2;
282 else if (
info->scale_denom < 8)
283 info->scale_denom = 4;
285 info->scale_denom = 8;
291 while (
info->scale_denom > 1 &&
292 ((clipRect.
x() %
info->scale_denom) != 0 ||
293 (clipRect.
y() %
info->scale_denom) != 0 ||
294 (clipRect.
width() %
info->scale_denom) != 0 ||
295 (clipRect.
height() %
info->scale_denom) != 0)) {
296 info->scale_denom /= 2;
303 info->dct_method = JDCT_IFAST;
304 info->do_fancy_upsampling = FALSE;
307 (
void) jpeg_calc_output_dimensions(
info);
310 QRect imageRect(0, 0,
info->output_width,
info->output_height);
314 }
else if (
info->scale_denom ==
info->scale_num) {
319 clip =
QRect(clipRect.
x() /
int(
info->scale_denom),
320 clipRect.
y() /
int(
info->scale_denom),
321 clipRect.
width() /
int(
info->scale_denom),
331 bool quickGray = (
info->output_components == 1 &&
340 JSAMPARRAY rows = (
info->mem->alloc_sarray)
341 ((j_common_ptr)
info, JPOOL_IMAGE,
342 info->output_width *
info->output_components, 1);
346 while (
info->output_scanline <
info->output_height) {
347 int y = int(
info->output_scanline) - clip.
y();
351 (
void) jpeg_read_scanlines(
info, rows, 1);
356 if (
info->output_components == 3) {
360 }
else if (
info->out_color_space == JCS_CMYK) {
364 for (
int i = 0;
i < clip.
width(); ++
i) {
365 *
out++ = 0xffffffffu - (
in[0] |
in[1] << 8 |
in[2] << 16 |
in[3] << 24);
371 }
else if (
info->output_components == 1) {
373 memcpy(outImage->scanLine(
y),
374 rows[0] + clip.
x(), clip.
width());
380 while (
info->output_scanline <
info->output_height) {
386 if (
info->output_scanline ==
info->output_height)
387 (
void) jpeg_finish_decompress(
info);
389 if (
info->density_unit == 1) {
390 outImage->setDotsPerMeterX(
int(100. *
info->X_density / 2.54));
391 outImage->setDotsPerMeterY(
int(100. *
info->Y_density / 2.54));
392 }
else if (
info->density_unit == 2) {
393 outImage->setDotsPerMeterX(
int(100. *
info->X_density));
394 outImage->setDotsPerMeterY(
int(100. *
info->Y_density));
397 if (scaledSize.
isValid() && scaledSize != clip.
size()) {
402 *outImage = outImage->copy(scaledClipRect);
403 return !outImage->isNull();
433 (*cinfo->err->error_exit)((j_common_ptr)cinfo);
435 dest->next_output_byte = dest->
buffer;
436 dest->free_in_buffer =
max_buf;
448 (*cinfo->err->error_exit)((j_common_ptr)cinfo);
459 next_output_byte =
buffer;
472 comment +=
it.value().toUtf8();
475 jpeg_write_marker(cinfo, JPEG_COM, (
const JOCTET *)comment.
constData(), comment.
size());
485 const QByteArray iccSignature(
"ICC_PROFILE", 12);
488 const int markers = (iccProfile.
size() + (maxIccMarkerSize - 1)) / maxIccMarkerSize;
495 jpeg_write_marker(cinfo, JPEG_APP0 + 2,
reinterpret_cast<const JOCTET *
>(block.
constData()), block.
size());
501 JSAMPROW *row_pointer,
510 bool success =
false;
511 const QList<QRgb> cmap =
image.colorTable();
519 cinfo.err = jpeg_std_error(&jerr);
523 if (!setjmp(jerr.setjmp_buffer)) {
528 jpeg_create_compress(&cinfo);
530 cinfo.dest = iod_dest;
532 cinfo.image_width =
image.width();
533 cinfo.image_height =
image.height();
536 switch (
image.format()) {
541 for (
int i =
image.colorCount(); gray &&
i;
i--) {
544 cinfo.input_components = gray ? 1 : 3;
545 cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB;
550 cinfo.input_components = 1;
551 cinfo.in_color_space = JCS_GRAYSCALE;
554 cinfo.input_components = 4;
555 cinfo.in_color_space = JCS_CMYK;
558 cinfo.input_components = 3;
559 cinfo.in_color_space = JCS_RGB;
562 jpeg_set_defaults(&cinfo);
568 if (diffInch < diffCm) {
569 cinfo.density_unit = 1;
570 cinfo.X_density =
qRound(
image.dotsPerMeterX()*2.54/100.);
571 cinfo.Y_density =
qRound(
image.dotsPerMeterY()*2.54/100.);
573 cinfo.density_unit = 2;
574 cinfo.X_density = (
image.dotsPerMeterX()+50) / 100;
575 cinfo.Y_density = (
image.dotsPerMeterY()+50) / 100;
579 cinfo.optimize_coding =
true;
582 jpeg_simple_progression(&cinfo);
584 int quality = sourceQuality >= 0 ?
qMin(
int(sourceQuality),100) : 75;
585 jpeg_set_quality(&cinfo, quality, TRUE );
586 jpeg_start_compress(&cinfo, TRUE);
589 if (cinfo.in_color_space == JCS_RGB || cinfo.in_color_space == JCS_CMYK)
592 row_pointer[0] =
new uchar[cinfo.image_width*cinfo.input_components];
593 int w = cinfo.image_width;
594 while (cinfo.next_scanline < cinfo.image_height) {
596 switch (
image.format()) {
602 for (
int i=0;
i<
w;
i++) {
603 bool bit = !!(*(
data + (
i >> 3)) & (1 << (
i & 7)));
607 for (
int i=0;
i<
w;
i++) {
608 bool bit = !!(*(
data + (
i >> 3)) & (1 << (7 -(
i & 7))));
615 for (
int i=0;
i<
w;
i++) {
616 bool bit = !!(*(
data + (
i >> 3)) & (1 << (
i & 7)));
622 for (
int i=0;
i<
w;
i++) {
623 bool bit = !!(*(
data + (
i >> 3)) & (1 << (7 -(
i & 7))));
634 for (
int i=0;
i<
w;
i++) {
640 for (
int i=0;
i<
w;
i++) {
649 memcpy(
row,
image.constScanLine(cinfo.next_scanline),
w);
654 memcpy(
row, rowImg.constScanLine(0),
w);
658 memcpy(
row,
image.constScanLine(cinfo.next_scanline),
w * 3);
665 for (
int i=0;
i<
w;
i++) {
674 auto *cmykIn =
reinterpret_cast<const quint32 *
>(
image.constScanLine(cinfo.next_scanline));
675 auto *cmykOut =
reinterpret_cast<quint32 *
>(
row);
677 for (
int i = 0;
i <
w; ++
i)
678 cmykOut[
i] = 0xffffffffu - cmykIn[
i];
680 memcpy(cmykOut, cmykIn,
w * 4);
688 const QRgb*
rgb = (
const QRgb*)rowImg.constScanLine(0);
689 for (
int i=0;
i<
w;
i++) {
698 jpeg_write_scanlines(&cinfo, row_pointer, 1);
701 jpeg_finish_compress(&cinfo);
702 jpeg_destroy_compress(&cinfo);
706 jpeg_destroy_compress(&cinfo);
724 struct jpeg_compress_struct cinfo;
725 JSAMPROW row_pointer[1];
726 row_pointer[0] =
nullptr;
730 sourceQuality, description,
731 optimize, progressive, invertCMYK);
733 delete [] row_pointer[0];
756 jpeg_destroy_decompress(&
info);
791 struct jpeg_decompress_struct
info;
816 if (
stream.readRawData(prefix,
sizeof(prefix)) !=
sizeof(prefix))
818 static const char exifMagic[6] = {
'E',
'x',
'i',
'f', 0, 0};
819 return memcmp(prefix, exifMagic, 6) == 0;
838 const int maxIfdCount = 10;
847 const qint64 headerStart = 6;
854 else if (
val == 0x4d4d)
867 for (
int n = 0;
n < maxIfdCount; ++
n) {
871 if (bytesToSkip < 0 || (
offset + headerStart >= exifData.size())) {
874 }
else if (bytesToSkip != 0) {
882 for (; numEntries > 0 &&
stream.status() == QDataStream::Ok; --numEntries) {
895 if (value < 1 || value > 8)
906 if (
stream.status() != QDataStream::Ok)
916static QImageIOHandler::Transformations
exif2Qt(
int exifOrientation)
918 switch (exifOrientation) {
936 qCWarning(lcJpeg,
"Invalid EXIF orientation");
950 info.err = jpeg_std_error(&
err);
954 jpeg_create_decompress(&
info);
957 if (!setjmp(
err.setjmp_buffer)) {
958 jpeg_save_markers(&
info, JPEG_COM, 0xFFFF);
959 jpeg_save_markers(&
info, JPEG_APP0 + 1, 0xFFFF);
960 jpeg_save_markers(&
info, JPEG_APP0 + 2, 0xFFFF);
962 (
void) jpeg_read_header(&
info, TRUE);
975 if (
marker->marker == JPEG_COM) {
976#ifndef QT_NO_IMAGEIO_TEXT_LOADING
993 }
else if (
marker->marker == JPEG_APP0 + 1) {
994 exifData.append((
const char*)
marker->data,
marker->data_length);
995 }
else if (
marker->marker == JPEG_APP0 + 2) {
996 if (
marker->data_length > 128 + 4 + 14 && strcmp((
const char *)
marker->data,
"ICC_PROFILE") == 0) {
1002 if (!exifData.isEmpty()) {
1005 if (exifOrientation > 0)
1055#if defined(__ARM_NEON__)
1061#if defined(QT_COMPILER_SUPPORTS_SSSE3)
1067#if defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2)
1095 qCWarning(lcJpeg,
"QJpegHandler::canRead() called with no device");
1148 return d->scaledSize;
1150 return d->scaledClipRect;
1155 return d->description;
1172 return d->progressive;
1175 return int(
d->transformation);
1187 d->quality =
value.toInt();
1190 d->scaledSize =
value.toSize();
1193 d->scaledClipRect =
value.toRect();
1196 d->clipRect =
value.toRect();
1199 d->description =
value.toString();
1212 d->optimize =
value.toBool();
1215 d->progressive =
value.toBool();
1218 int transformation =
value.toInt();
1219 if (transformation > 0 && transformation < 8)
1220 d->transformation = QImageIOHandler::Transformations(transformation);
IOBluetoothDevice * device
\inmodule QtCore \reentrant
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
void truncate(qsizetype pos)
Truncates the byte array at index position pos.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray mid(qsizetype index, qsizetype len=-1) const &
static QColorSpace fromIccProfile(const QByteArray &iccProfile)
Creates a QColorSpace from ICC profile iccProfile.
\inmodule QtCore\reentrant
\inmodule QtCore \reentrant
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
qint64 peek(char *data, qint64 maxlen)
The QImageIOHandler class defines the common image I/O interface for all image formats in Qt.
ImageOption
This enum describes the different options supported by QImageIOHandler.
static bool allocateImage(QSize size, QImage::Format format, QImage *image)
QIODevice * device() const
Returns the device currently assigned to the QImageIOHandler.
@ TransformationRotate270
@ TransformationFlipAndRotate90
@ TransformationMirrorAndRotate90
@ TransformationRotate180
void setFormat(const QByteArray &format)
Sets the format of the QImageIOHandler to format.
Format
The following image formats are available in Qt.
@ Format_ARGB32_Premultiplied
bool readJpegHeader(QIODevice *)
struct jpeg_decompress_struct info
Rgb888ToRgb32Converter rgb888ToRgb32ConverterPtr
QJpegHandlerPrivate(QJpegHandler *qq)
struct my_jpeg_source_mgr * iod_src
QImageIOHandler::Transformations transformation
bool supportsOption(ImageOption option) const override
Returns true if the QImageIOHandler supports the option option; otherwise returns false.
bool read(QImage *image) override
Read an image from the device, and stores it in image.
void setOption(ImageOption option, const QVariant &value) override
Sets the option option with the value value.
QVariant option(ImageOption option) const override
Returns the value assigned to option as a QVariant.
bool write(const QImage &image) override
Writes the image image to the assigned device.
bool canRead() const override
Returns true if an image can be read from the device (i.e., the image format is supported,...
\inmodule QtCore\reentrant
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
constexpr int height() const noexcept
Returns the height of the rectangle.
QRect intersected(const QRect &other) const noexcept
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr QSize size() const noexcept
Returns the size of the rectangle.
constexpr void translate(int dx, int dy) noexcept
Moves the rectangle dx along the x axis and dy along the y axis, relative to the current position.
constexpr int width() const noexcept
Returns the width of the rectangle.
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
\macro QT_RESTRICTED_CAST_FROM_ASCII
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first character in the string.
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
iterator end()
Returns an \l{STL-style iterators}{STL-style iterator} pointing just after the last character in the ...
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
QSet< QString >::iterator it
Combined button and popup list for selecting options.
#define QT_WARNING_DISABLE_GCC(text)
AudioChannelLayoutTag tag
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
int qRound(qfloat16 d) noexcept
Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
QMap< QString, QString > qt_getImageText(const QImage &image, const QString &description)
void qt_convert_rgb888_to_rgb32_mips_dspr2_asm(uint *dst, const uchar *src, int len)
static void my_error_exit(j_common_ptr cinfo)
#define HIGH_QUALITY_THRESHOLD
static void qt_init_source(j_decompress_ptr)
static void my_output_message(j_common_ptr cinfo)
static void qt_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
static void set_text(const QImage &image, j_compress_ptr cinfo, const QString &description)
static void write_icc_profile(const QImage &image, j_compress_ptr cinfo)
static bool read_jpeg_image(QImage *outImage, QSize scaledSize, QRect scaledClipRect, QRect clipRect, int quality, Rgb888ToRgb32Converter converter, j_decompress_ptr info, struct my_error_mgr *err, bool invertCMYK)
static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo, JSAMPROW *row_pointer, const QImage &image, QIODevice *device, int sourceQuality, const QString &description, bool optimize, bool progressive, bool invertCMYK)
static bool readExifHeader(QDataStream &stream)
void(QT_FASTCALL * Rgb888ToRgb32Converter)(quint32 *dst, const uchar *src, int len)
static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, const QSize &size)
static constexpr int maxMarkerSize
static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cinfo)
static void qt_init_destination(j_compress_ptr)
static void qt_term_destination(j_compress_ptr cinfo)
void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
static void qt_term_source(j_decompress_ptr cinfo)
static bool read_jpeg_size(int &w, int &h, j_decompress_ptr cinfo)
static int getExifOrientation(QByteArray &exifData)
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_ssse3(quint32 *dst, const uchar *src, int len)
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len)
void qt_convert_rgb888_to_rgb32_mips_dspr2_asm(quint32 *dst, const uchar *src, int len)
static boolean qt_empty_output_buffer(j_compress_ptr cinfo)
static boolean qt_fill_input_buffer(j_decompress_ptr cinfo)
static const char SupportedJPEGSubtypes[][14]
QT_BEGIN_NAMESPACE Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32(quint32 *dst, const uchar *src, int len)
static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
static bool write_jpeg_image(const QImage &image, QIODevice *device, int sourceQuality, const QString &description, bool optimize, bool progressive, bool invertCMYK)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qBound(const T &min, const T &val, const T &max)
constexpr T qAbs(const T &t)
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLint GLenum GLint components
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
GLdouble GLdouble GLdouble GLdouble q
GLenum GLenum GLsizei void * row
constexpr bool qIsGray(QRgb rgb)
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
constexpr int qRed(QRgb rgb)
constexpr int qGreen(QRgb rgb)
constexpr int qBlue(QRgb rgb)
#define qCpuHasFeature(feature)
QLatin1StringView QLatin1String
QTextStream out(stdout)
[7]
\inmodule QtCore \reentrant
my_jpeg_destination_mgr(QIODevice *)
my_jpeg_source_mgr(QIODevice *device)
const QBuffer * memDevice