Skip to content

Commit

Permalink
Fix copy function. Add conversion methods for copy function (#57)
Browse files Browse the repository at this point in the history
* Fix copy function. Add conversion methods for copy function

* Bump version

* fix "position of copied data"

* cosmetic

* cosmetic

* add unit-test & fix implementation

* fix grammar

* add conversions for "Copy"

* remove accidentally checked in files

* add copy-unit-tests

* add unittest

* cosmetic

---------

Co-authored-by: Soyer, Sebastian <sebastian.soyer@zeiss.com>
Co-authored-by: ptahmose <jbohl@h-quer.de>
  • Loading branch information
3 people committed Jun 26, 2023
1 parent d805090 commit 73df0b2
Show file tree
Hide file tree
Showing 8 changed files with 603 additions and 55 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0091 NEW) # enable new "MSVC runtime library selection" (https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html)

project(libCZI
VERSION 0.48.2
VERSION 0.49.0
HOMEPAGE_URL "https://github.com/ZEISS/libczi"
DESCRIPTION "libCZI is an Open Source Cross-Platform C++ library to read and write CZI")

Expand Down
34 changes: 25 additions & 9 deletions Src/libCZI/BitmapOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,21 @@ using namespace std;
case PixelType::Gray16:
switch (dstPixelType)
{
case PixelType::Gray8:break;
case PixelType::Gray8:
Copy<PixelType::Gray16, PixelType::Gray8>(srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
return;
case PixelType::Gray16:
Copy<PixelType::Gray16, PixelType::Gray16>(srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
return;
case PixelType::Gray32Float:break;
case PixelType::Bgr24:break;
case PixelType::Bgr48:break;
case PixelType::Gray32Float:
Copy<PixelType::Gray16, PixelType::Gray32Float>(srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
return;
case PixelType::Bgr24:
Copy<PixelType::Gray16, PixelType::Bgr24>(srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
return;
case PixelType::Bgr48:
Copy<PixelType::Gray16, PixelType::Bgr48>(srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
return;
default:break;
}
break;
Expand Down Expand Up @@ -139,10 +147,18 @@ using namespace std;
case PixelType::Bgr48:
switch (dstPixelType)
{
case PixelType::Gray8:break;
case PixelType::Gray16:break;
case PixelType::Gray32Float:break;
case PixelType::Bgr24:break;
case PixelType::Gray8:
Copy<PixelType::Bgr48, PixelType::Gray8>(srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
return;
case PixelType::Gray16:
Copy<PixelType::Bgr48, PixelType::Gray16>(srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
return;
case PixelType::Gray32Float:
Copy<PixelType::Bgr48, PixelType::Gray32Float>(srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
return;
case PixelType::Bgr24:
Copy<PixelType::Bgr48, PixelType::Bgr24>(srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
return;
case PixelType::Bgr48:
Copy<PixelType::Bgr48, PixelType::Bgr48>(srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
return;
Expand All @@ -156,7 +172,7 @@ using namespace std;
throw std::logic_error("It seems that this conversion is not implemented...");
}

/*static*/void CBitmapOperations::CopyOffseted(const CopyOffsetedInfo& info)
/*static*/void CBitmapOperations::CopyWithOffset(const CopyWithOffsetInfo& info)
{
const IntRect srcRect = IntRect{ info.xOffset,info.yOffset,info.srcWidth,info.srcHeight };
const IntRect dstRect = IntRect{ 0,0,info.dstWidth,info.dstHeight };
Expand Down
34 changes: 18 additions & 16 deletions Src/libCZI/BitmapOperations.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,27 @@ class CBitmapOperations
template <typename tFlt>
static void NNScale2(libCZI::PixelType tSrcPixelType, libCZI::PixelType tDstPixelType, const NNResizeInfo2<tFlt>& resizeInfo);

struct CopyOffsetedInfo
/// This structure gathers the information needed to copy a source bitmap into
/// a destination bitmap at a specified offset.
struct CopyWithOffsetInfo
{
int xOffset;
int yOffset;
libCZI::PixelType srcPixelType;
const void* srcPtr;
int srcStride;
int srcWidth;
int srcHeight;
libCZI::PixelType dstPixelType;
void* dstPtr;
int dstStride;
int dstWidth;
int dstHeight;

bool drawTileBorder;
int xOffset; ///< The offset in x direction where the source bitmap is to be placed in the destination bitmap.
int yOffset; ///< The offset in x direction where the source bitmap is to be placed in the destination bitmap.
libCZI::PixelType srcPixelType; ///< The pixel type of the source bitmap.
const void* srcPtr; ///< Pointer to the source bitmap.
int srcStride; ///< The stride of the source bitmap in bytes.
int srcWidth; ///< The width of the source bitmap in pixels.
int srcHeight; ///< The height of the source bitmap in pixels.
libCZI::PixelType dstPixelType; ///< The pixel type of the destination bitmap.
void* dstPtr; ///< Pointer to the destination bitmap.
int dstStride; ///< The stride of the destination bitmap in bytes.
int dstWidth; ///< The width of the destination bitmap in pixels.
int dstHeight; ///< The height of the destination bitmap in pixels.

bool drawTileBorder; ///< If true, a one-pixel wide border is drawn around the copied source bitmap.
};

static void CopyOffseted(const CopyOffsetedInfo& info);
static void CopyWithOffset(const CopyWithOffsetInfo& info);
static void Copy(libCZI::PixelType srcPixelType, const void* srcPtr, int srcStride, libCZI::PixelType dstPixelType, void* dstPtr, int dstStride, int width, int height, bool drawTileBorder);

template <libCZI::PixelType tSrcPixelType, libCZI::PixelType tDstPixelType>
Expand Down
40 changes: 40 additions & 0 deletions Src/libCZI/BitmapOperations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,46 @@ inline void CBitmapOperations::Copy<libCZI::PixelType::Bgr24, libCZI::PixelType:
{
Copy<libCZI::PixelType::Bgr24, libCZI::PixelType::Bgr48, CConvBgr24ToBgr48>(CConvBgr24ToBgr48(), srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
}
template <>
inline void CBitmapOperations::Copy<libCZI::PixelType::Gray16, libCZI::PixelType::Gray8>(const void* srcPtr, int srcStride, void* dstPtr, int dstStride, int width, int height, bool drawTileBorder)
{
Copy<libCZI::PixelType::Gray16, libCZI::PixelType::Gray8, CConvGray16ToGray8>(CConvGray16ToGray8(), srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
}
template <>
inline void CBitmapOperations::Copy<libCZI::PixelType::Gray16, libCZI::PixelType::Gray32Float>(const void* srcPtr, int srcStride, void* dstPtr, int dstStride, int width, int height, bool drawTileBorder)
{
Copy<libCZI::PixelType::Gray16, libCZI::PixelType::Gray32Float, CConvGray16ToGray32Float>(CConvGray16ToGray32Float(), srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
}
template <>
inline void CBitmapOperations::Copy<libCZI::PixelType::Gray16, libCZI::PixelType::Bgr24>(const void* srcPtr, int srcStride, void* dstPtr, int dstStride, int width, int height, bool drawTileBorder)
{
Copy<libCZI::PixelType::Gray16, libCZI::PixelType::Bgr24, CConvGray16ToBgr24>(CConvGray16ToBgr24(), srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
}
template <>
inline void CBitmapOperations::Copy<libCZI::PixelType::Gray16, libCZI::PixelType::Bgr48>(const void* srcPtr, int srcStride, void* dstPtr, int dstStride, int width, int height, bool drawTileBorder)
{
Copy<libCZI::PixelType::Gray16, libCZI::PixelType::Bgr48, CConvGray16ToBgr48>(CConvGray16ToBgr48(), srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
}
template <>
inline void CBitmapOperations::Copy<libCZI::PixelType::Bgr48, libCZI::PixelType::Gray8>(const void* srcPtr, int srcStride, void* dstPtr, int dstStride, int width, int height, bool drawTileBorder)
{
Copy<libCZI::PixelType::Bgr48, libCZI::PixelType::Gray8, CConvBgr48ToGray8>(CConvBgr48ToGray8(), srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
}
template <>
inline void CBitmapOperations::Copy<libCZI::PixelType::Bgr48, libCZI::PixelType::Gray16>(const void* srcPtr, int srcStride, void* dstPtr, int dstStride, int width, int height, bool drawTileBorder)
{
Copy<libCZI::PixelType::Bgr48, libCZI::PixelType::Gray16, CConvBgr48ToGray16>(CConvBgr48ToGray16(), srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
}
template <>
inline void CBitmapOperations::Copy<libCZI::PixelType::Bgr48, libCZI::PixelType::Gray32Float>(const void* srcPtr, int srcStride, void* dstPtr, int dstStride, int width, int height, bool drawTileBorder)
{
Copy<libCZI::PixelType::Bgr48, libCZI::PixelType::Gray32Float, CConvBgr48ToGray32Float>(CConvBgr48ToGray32Float(), srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
}
template <>
inline void CBitmapOperations::Copy<libCZI::PixelType::Bgr48, libCZI::PixelType::Bgr24>(const void* srcPtr, int srcStride, void* dstPtr, int dstStride, int width, int height, bool drawTileBorder)
{
Copy<libCZI::PixelType::Bgr48, libCZI::PixelType::Bgr24, CConvBgr48ToBgr24>(CConvBgr48ToBgr24(), srcPtr, srcStride, dstPtr, dstStride, width, height, drawTileBorder);
}

//------------------------------------------------------------------------------------------------------------

Expand Down
48 changes: 23 additions & 25 deletions Src/libCZI/SingleChannelScalingTileAccessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,25 @@ CSingleChannelScalingTileAccessor::CSingleChannelScalingTileAccessor(std::shared

void CSingleChannelScalingTileAccessor::ScaleBlt(libCZI::IBitmapData* bmDest, float zoom, const libCZI::IntRect& roi, const SbInfo& sbInfo)
{
const auto sb = this->sbBlkRepository->ReadSubBlock(sbInfo.index);
if (GetSite()->IsEnabled(LOGLEVEL_CHATTYINFORMATION))
{
stringstream ss;
ss << " bounds: " << Utils::DimCoordinateToString(&sb->GetSubBlockInfo().coordinate);
GetSite()->Log(LOGLEVEL_CHATTYINFORMATION, ss);
}

const auto source = sb->CreateBitmap();

// In order not to run into trouble with floating point precision, if the scale is exactly 1, we refrain from using the scaling operation
// and do instead a simple copy operation. This should ensure a pixel-accurate result if zoom is exactly 1.
if (zoom == 1)
{
const auto sb = this->sbBlkRepository->ReadSubBlock(sbInfo.index);
const auto source = sb->CreateBitmap();
ScopedBitmapLockerSP srcLck{ source };
ScopedBitmapLockerP dstLck{ bmDest };
CBitmapOperations::CopyOffsetedInfo info;
info.xOffset = sbInfo.logicalRect.x;
info.yOffset = sbInfo.logicalRect.y;
CBitmapOperations::CopyWithOffsetInfo info;
info.xOffset = sbInfo.logicalRect.x - roi.x;
info.yOffset = sbInfo.logicalRect.y - roi.y;
info.srcPixelType = source->GetPixelType();
info.srcPtr = srcLck.ptrDataRoi;
info.srcStride = srcLck.stride;
Expand All @@ -90,13 +98,13 @@ void CSingleChannelScalingTileAccessor::ScaleBlt(libCZI::IBitmapData* bmDest, fl
info.dstHeight = bmDest->GetHeight();
info.drawTileBorder = false;

CBitmapOperations::CopyOffseted(info);
CBitmapOperations::CopyWithOffset(info);
}
else
{
// calculate the intersection of the subblock (logical rect) and the destination
const auto intersect = Utilities::Intersect(sbInfo.logicalRect, roi);

const double roiSrcTopLeftX = double(intersect.x - sbInfo.logicalRect.x) / sbInfo.logicalRect.w;
const double roiSrcTopLeftY = double(intersect.y - sbInfo.logicalRect.y) / sbInfo.logicalRect.h;
const double roiSrcBttmRightX = double(intersect.x + intersect.w - sbInfo.logicalRect.x) / sbInfo.logicalRect.w;
Expand All @@ -120,17 +128,7 @@ void CSingleChannelScalingTileAccessor::ScaleBlt(libCZI::IBitmapData* bmDest, fl
dstRoi.w *= bmDest->GetWidth();
dstRoi.h *= bmDest->GetHeight();

const auto sb = this->sbBlkRepository->ReadSubBlock(sbInfo.index);
if (GetSite()->IsEnabled(LOGLEVEL_CHATTYINFORMATION))
{
stringstream ss;
ss << " bounds: " << Utils::DimCoordinateToString(&sb->GetSubBlockInfo().coordinate);
GetSite()->Log(LOGLEVEL_CHATTYINFORMATION, ss);
}

const auto spBm = sb->CreateBitmap();

CBitmapOperations::NNResize(spBm.get(), bmDest, srcRoi, dstRoi);
CBitmapOperations::NNResize(source.get(), bmDest, srcRoi, dstRoi);
}
}

Expand Down Expand Up @@ -223,13 +221,13 @@ std::vector<CSingleChannelScalingTileAccessor::SbInfo> CSingleChannelScalingTile
}
}

SbInfo sbinfo;
sbinfo.logicalRect = info.logicalRect;
sbinfo.physicalSize = info.physicalSize;
sbinfo.mIndex = info.mIndex;
sbinfo.index = idx;
sblks.push_back(sbinfo);
return true;
SbInfo sbinfo;
sbinfo.logicalRect = info.logicalRect;
sbinfo.physicalSize = info.physicalSize;
sbinfo.mIndex = info.mIndex;
sbinfo.index = idx;
sblks.push_back(sbinfo);
return true;
});

return sblks;
Expand Down
4 changes: 2 additions & 2 deletions Src/libCZI/SingleChannelTileCompositor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ using namespace libCZI;
{
ScopedBitmapLockerP srcLck{ source };
ScopedBitmapLockerP dstLck{ dest };
CBitmapOperations::CopyOffsetedInfo info;
CBitmapOperations::CopyWithOffsetInfo info;
info.xOffset = x;
info.yOffset = y;
info.srcPixelType = source->GetPixelType();
Expand All @@ -30,7 +30,7 @@ using namespace libCZI;

info.drawTileBorder = drawTileBorder;

CBitmapOperations::CopyOffseted(info);
CBitmapOperations::CopyWithOffset(info);
}

/*-----------------------------------------------------------------------------------------------*/
Expand Down
Loading

0 comments on commit 73df0b2

Please sign in to comment.