diff --git a/loadrunable.cpp b/loadrunable.cpp index c54ac99..b6192de 100644 --- a/loadrunable.cpp +++ b/loadrunable.cpp @@ -478,14 +478,17 @@ void LoadRunable::run() if(m_thumbnail) { - if(rawImage) + if(rawImage && rawImage->valid()) { + rawImage->resize(THUMB_SIZE, THUMB_SIZE); rawImage->convertToThumbnail(); - QMetaObject::invokeMethod(m_receiver, "thumbnailLoadFinish", Qt::QueuedConnection, Q_ARG(std::shared_ptr, rawImage)); } + QMetaObject::invokeMethod(m_receiver, "thumbnailLoadFinish", Qt::QueuedConnection, Q_ARG(std::shared_ptr, rawImage)); } else + { QMetaObject::invokeMethod(m_receiver, "imageLoaded", Qt::QueuedConnection, Q_ARG(std::shared_ptr, rawImage), Q_ARG(ImageInfoData, info)); + } } catch(std::exception e) { diff --git a/rawimage.cpp b/rawimage.cpp index 6e68607..1eee356 100644 --- a/rawimage.cpp +++ b/rawimage.cpp @@ -388,7 +388,11 @@ const void *RawImage::origData(uint32_t row, uint32_t col) const void RawImage::convertToThumbnail() { - m_thumbAspect = (float)width() / height(); + if(!valid()) + return; + + if(m_thumbAspect == 0.0f) + m_thumbAspect = (float)width() / height(); std::unique_ptr outptr = std::make_unique(THUMB_SIZE * THUMB_SIZE * 4 * sizeof(uint16_t)); uint16_t *out = reinterpret_cast(outptr.get()); @@ -400,6 +404,7 @@ void RawImage::convertToThumbnail() { int idx = (i*THUMB_SIZE + o)*4; int idx2 = ((i * m_height / THUMB_SIZE * m_width) + (o * m_width / THUMB_SIZE)) * m_ch; + if(m_channels == 1) { out[idx] = out[idx + 1] = out[idx + 2] = in[idx2] * scale; @@ -559,14 +564,84 @@ bool RawImage::pixel(int x, int y, double &r, double &g, double &b) const return true; } -void RawImage::downscaleTo(uint32_t size) +template +void boxResample(uint32_t w, uint32_t h, uint32_t ch, uint32_t oldw, uint32_t oldh, const uint8_t *in_, uint8_t *out_) { - /*if(size < width() || size < height()) + if(oldw == 0 || oldh == 0)return; + + const T *in = reinterpret_cast(in_); + T *out = reinterpret_cast(out_); + float max = 255.0f; + if constexpr(std::is_same::value) + max = UINT16_MAX; + + float sx = (float)oldw / w; + float sy = (float)oldh / h; + float sx_ = (float)w / oldw; + float sy_ = (float)h / oldh; + float s = 1.0 / (sx * sy); + for(uint32_t y = 0; y < h; y++) { - double s = (double)size / std::max(width(), height()); - cv::Size dsize(std::floor(width() * s), std::floor(height() * s)); - cv::resize(m_img, m_img, dsize, 0, 0, cv::INTER_AREA); - }*/ + for(uint32_t x = 0; x < w; x++) + { + float p[4] = {0.0f}; + uint32_t xx = x * oldw / w; + uint32_t yy = y * oldh / h; + uint32_t xe = std::min((x + 1) * oldw / w, oldw - 1); + uint32_t ye = std::min((y + 1) * oldh / h, oldh - 1); + for(uint32_t o = yy; o <= ye; o++) + { + float cy = o * sy_ - y; + if(cy < 0.0f)cy = 1.0f + cy * sy; + else if(sy_ + cy > 1.0f)cy = (1.0f - cy) * sy; + else cy = 1.0f; + if(yy==ye)cy = sy; + for(uint32_t i = xx; i <= xe; i++) + { + float cx = i * sx_ - x; + if(cx < 0.0f)cx = 1.0f + cx * sx; + else if(sx_ + cx > 1.0f)cx = (1.0f - cx) * sx; + else cx = 1.0f; + if(xx==xe)cx = sx; + for(uint32_t z = 0; z < ch; z++) + p[z] += in[(o * oldw + i) * ch + z] * cy * cx; + } + } + for(uint32_t z = 0; z < ch; z++) + if constexpr(std::is_floating_point::value) + out[(y * w + x) * ch + z] = p[z] * s; + else + out[(y * w + x) * ch + z] = std::clamp(std::round(p[z] * s), 0.0f, max); + } + } +} + +void RawImage::resize(uint32_t w, uint32_t h) +{ + if(!valid())return; + + std::unique_ptr old_pixels = std::move(m_pixels); + uint32_t oldw = m_width; + uint32_t oldh = m_height; + m_thumbAspect = (float)m_width / m_height; + + allocate(w, h, m_channels, m_type); + + switch(m_type) + { + case RawImage::UINT8: + boxResample(w, h, m_ch, oldw, oldh, old_pixels.get(), m_pixels.get()); + break; + case RawImage::UINT16: + boxResample(w, h, m_ch, oldw, oldh, old_pixels.get(), m_pixels.get()); + break; + case RawImage::FLOAT32: + boxResample(w, h, m_ch, oldw, oldh, old_pixels.get(), m_pixels.get()); + break; + default: + qWarning() << "Resizing format not supported"; + break; + } } std::pair RawImage::unitScale() const @@ -692,3 +767,8 @@ std::vector RawImage::split() const return planes; } + +bool RawImage::valid() const +{ + return m_width > 0 && m_height > 0; +} diff --git a/rawimage.h b/rawimage.h index bd32015..ef5b4fd 100644 --- a/rawimage.h +++ b/rawimage.h @@ -97,13 +97,14 @@ public: void convertToGLFormat(); float thumbAspect() const; bool pixel(int x, int y, double &r, double &g, double &b) const; - void downscaleTo(uint32_t size); + void resize(uint32_t w, uint32_t h); std::pair unitScale() const; static std::shared_ptr fromPlanar(const RawImage &img); static std::shared_ptr fromPlanar(const void *pixels, uint32_t w, uint32_t h, uint32_t ch, DataType type); static size_t typeSize(DataType type); std::vector split() const; + bool valid() const; }; //Q_DECLARE_SMART_POINTER_METATYPE(std::shared_ptr);