X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=gui%2Fapisurface.cpp;h=22de5f0b0d873ab877c4c7dbd89fcdd7268e4fc6;hb=36509be82b82382adeb8b320405f35636ecf72e7;hp=3732ed5f717482ad976fbf6f9f0d9e447113b91c;hpb=994535d1b11e13c11b923933ad39021d5040a466;p=apitrace diff --git a/gui/apisurface.cpp b/gui/apisurface.cpp index 3732ed5..22de5f0 100644 --- a/gui/apisurface.cpp +++ b/gui/apisurface.cpp @@ -33,90 +33,21 @@ struct ByteArrayBuf : public std::streambuf void ApiSurface::contentsFromBase64(const QByteArray &base64) { - QByteArray dataArray = QByteArray::fromBase64(base64); - - image::Image *image; + m_base64Data = base64; /* - * Detect the PNG vs PFM images. + * We need to do the conversion to create the thumbnail */ - const char pngSignature[] = {(char)0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0}; - if (dataArray.startsWith(pngSignature)) { - ByteArrayBuf buf(dataArray); - std::istream istr(&buf); - image = image::readPNG(istr); - } else { - image = image::readPNM(dataArray.data(), dataArray.size()); - } - - /* - * FIXME: Instead of converting to QImage here, we should be deferring the conversion - * to imageviewer.cpp. - * - * XXX: We still need the thumbnail though. - */ - + image::Image *image = imageFromBase64(base64); Q_ASSERT(image); - - int width = image->width; - int height = image->height; - - m_image = QImage(width, height, QImage::Format_ARGB32); - - const unsigned char *srcRow = image->start(); - for (int y = 0; y < height; ++y) { - QRgb *dst = (QRgb *)m_image.scanLine(y); - - if (image->channelType == image::TYPE_UNORM8) { - const unsigned char *src = srcRow; - for (int x = 0; x < width; ++x) { - unsigned char rgba[4]; - for (int c = 0; c < image->channels; ++c) { - rgba[c] = *src++; - } - if (image->channels == 1) { - // Use gray-scale instead of red - rgba[1] = rgba[0]; - rgba[2] = rgba[0]; - } - dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]); - } - } else { - const float *src = (const float *)srcRow; - for (int x = 0; x < width; ++x) { - unsigned char rgba[4] = {0, 0, 0, 0xff}; - for (int c = 0; c < image->channels; ++c) { - float f = *src++; - unsigned char u; - if (f >= 1.0f) { - u = 255; - } else if (f <= 0.0f) { - u = 0; - } else { - u = f * 255 + 0.5; - } - rgba[c] = u; - } - if (image->channels == 1) { - // Use gray-scale instead of red - rgba[1] = rgba[0]; - rgba[2] = rgba[0]; - } - dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]); - } - } - - srcRow += image->stride(); - } - + QImage img = qimageFromRawImage(image); + m_thumb = thumbnail(img); delete image; - - m_thumb = thumbnail(m_image); } -QImage ApiSurface::image() const +QByteArray ApiSurface::base64Data() const { - return m_image; + return m_base64Data; } QImage ApiSurface::thumb() const @@ -175,3 +106,116 @@ void ApiFramebuffer::setType(const QString &str) m_type = str; } +image::Image * +ApiSurface::imageFromBase64(const QByteArray &base64) +{ + QByteArray dataArray = QByteArray::fromBase64(base64); + image::Image *image; + + /* + * Detect the PNG vs PFM images. + */ + const char pngSignature[] = {(char)0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0}; + if (dataArray.startsWith(pngSignature)) { + ByteArrayBuf buf(dataArray); + std::istream istr(&buf); + image = image::readPNG(istr); + } else { + image = image::readPNM(dataArray.data(), dataArray.size()); + } + + return image; +} + + +static inline unsigned char clamp(int x) +{ + if (x <= 0) { + return 0; + } + if (x > 255) { + return 255; + } + return (unsigned char) x; +} + +static inline unsigned char clamp(float x) +{ + if (x <= 0.0f) { + return 0; + } + if (x > 255.0f) { + return 255; + } + return (unsigned char) (x + 0.5f); +} + + +QImage +ApiSurface::qimageFromRawImage(const image::Image *image, + float lowerValue, + float upperValue, + bool opaque, + bool alpha) +{ + QImage img; + int width = image->width; + int height = image->height; + + img = QImage(width, height, QImage::Format_ARGB32); + + int offset = - lowerValue * 255; + int scale = 256 / (upperValue - lowerValue); + + float offset_f = - lowerValue; + float scale_f = 255.0f / (upperValue - lowerValue); + + int aMask = (opaque || alpha) ? 0xff : 0; + + const unsigned char *srcRow = image->start(); + for (int y = 0; y < height; ++y) { + QRgb *dst = (QRgb *)img.scanLine(y); + + if (image->channelType == image::TYPE_UNORM8) { + const unsigned char *src = srcRow; + for (int x = 0; x < width; ++x) { + unsigned char rgba[4] = {0, 0, 0, 0xff}; + for (int c = 0; c < image->channels; ++c) { + rgba[c] = clamp(((*src++ + offset) * scale) >> 8); + } + if (image->channels == 1) { + // Use gray-scale instead of red + rgba[1] = rgba[0]; + rgba[2] = rgba[0]; + } + if (alpha) { + rgba[2] = rgba[1] = rgba[0] = rgba[3]; + } + rgba[3] |= aMask; + dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]); + } + } else { + const float *src = (const float *)srcRow; + for (int x = 0; x < width; ++x) { + unsigned char rgba[4] = {0, 0, 0, 0xff}; + for (int c = 0; c < image->channels; ++c) { + rgba[c] = clamp((*src++ + offset_f)*scale_f); + } + if (image->channels == 1) { + // Use gray-scale instead of red + rgba[1] = rgba[0]; + rgba[2] = rgba[0]; + } + if (alpha) { + rgba[2] = rgba[1] = rgba[0] = rgba[3]; + } + rgba[3] |= aMask; + dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]); + } + } + + srcRow += image->stride(); + } + + return img; +}