# HG changeset patch # User Sebastien Jodogne # Date 1586964507 -7200 # Node ID 963ea9fab4023b5a87623750d81fb3c55c5a6e16 # Parent 0c16051dfd56168b03fe5d317fb3a69eb376bf68# Parent cbe847575c62bd6a28dc528a33ce824443a97274 merge diff -r 0c16051dfd56 -r 963ea9fab402 Core/Images/PamReader.cpp --- a/Core/Images/PamReader.cpp Wed Apr 15 17:28:15 2020 +0200 +++ b/Core/Images/PamReader.cpp Wed Apr 15 17:28:27 2020 +0200 @@ -200,7 +200,30 @@ } size_t offset = content_.size() - pitch * height; - AssignWritable(format, width, height, pitch, &content_[offset]); + + { + intptr_t bufferAddr = reinterpret_cast(&content_[offset]); + if((bufferAddr % 8) == 0) + LOG(TRACE) << "PamReader::ParseContent() image address = " << bufferAddr; + else + LOG(TRACE) << "PamReader::ParseContent() image address = " << bufferAddr << " (not a multiple of 8!)"; + } + + // if we want to enforce alignment, we need to use a freshly allocated + // buffer, since we have no alignment guarantees on the original one + if (enforceAligned_) + { + if (alignedImageBuffer_ != NULL) + free(alignedImageBuffer_); + alignedImageBuffer_ = malloc(pitch * height); + memcpy(alignedImageBuffer_, &content_[offset], pitch* height); + content_ = ""; + AssignWritable(format, width, height, pitch, alignedImageBuffer_); + } + else + { + AssignWritable(format, width, height, pitch, &content_[offset]); + } // Byte swapping if needed if (bytesPerChannel != 1 && @@ -231,7 +254,7 @@ at SAFE_HEAP_LOAD_i32_2_2 (wasm-function[251132]:39) at __ZN7Orthanc9PamReader12ParseContentEv (wasm-function[11457]:8088) - Web Assenmbly IS LITTLE ENDIAN! + Web Assembly IS LITTLE ENDIAN! Perhaps in htobe16 ? */ diff -r 0c16051dfd56 -r 963ea9fab402 Core/Images/PamReader.h --- a/Core/Images/PamReader.h Wed Apr 15 17:28:15 2020 +0200 +++ b/Core/Images/PamReader.h Wed Apr 15 17:28:27 2020 +0200 @@ -46,9 +46,45 @@ private: void ParseContent(); + /** + Whether we want to use the default malloc alignment in the image buffer, + at the expense of an extra copy + */ + bool enforceAligned_; + + /** + This is actually a copy of wrappedContent_, but properly aligned. + + It is only used if the enforceAligned parameter is set to true in the + constructor. + */ + void* alignedImageBuffer_; + + /** + Points somewhere in the content_ buffer. + */ + ImageAccessor wrappedContent_; + + /** + Raw content (file bytes or answer from the server, for instance). + */ std::string content_; public: + /** + See doc for field enforceAligned_ + */ + PamReader(bool enforceAligned = false) : + enforceAligned_(enforceAligned), + alignedImageBuffer_(NULL) + { + } + + virtual ~PamReader() + { + // freeing NULL is OK + free(alignedImageBuffer_); + } #if ORTHANC_SANDBOXED == 0 void ReadFromFile(const std::string& filename); diff -r 0c16051dfd56 -r 963ea9fab402 UnitTestsSources/ImageTests.cpp --- a/UnitTestsSources/ImageTests.cpp Wed Apr 15 17:28:15 2020 +0200 +++ b/UnitTestsSources/ImageTests.cpp Wed Apr 15 17:28:27 2020 +0200 @@ -410,6 +410,28 @@ } { + // true means "enforce alignment by using a temporary buffer" + Orthanc::PamReader r(true); + r.ReadFromMemory(s); + + ASSERT_EQ(r.GetFormat(), Orthanc::PixelFormat_Grayscale16); + ASSERT_EQ(r.GetWidth(), width); + ASSERT_EQ(r.GetHeight(), height); + + v = 0; + for (unsigned int y = 0; y < height; y++) + { + const uint16_t* p = reinterpret_cast + ((const uint8_t*)r.GetConstBuffer() + y * r.GetPitch()); + ASSERT_EQ(p, r.GetConstRow(y)); + for (unsigned int x = 0; x < width; x++, p++, v++) + { + ASSERT_EQ(v, *p); + } + } + } + + { Orthanc::TemporaryFile tmp; tmp.Write(s); @@ -432,4 +454,30 @@ } } } + + { + Orthanc::TemporaryFile tmp; + tmp.Write(s); + + // true means "enforce alignment by using a temporary buffer" + Orthanc::PamReader r2(true); + r2.ReadFromFile(tmp.GetPath()); + + ASSERT_EQ(r2.GetFormat(), Orthanc::PixelFormat_Grayscale16); + ASSERT_EQ(r2.GetWidth(), width); + ASSERT_EQ(r2.GetHeight(), height); + + v = 0; + for (unsigned int y = 0; y < height; y++) + { + const uint16_t* p = reinterpret_cast + ((const uint8_t*)r2.GetConstBuffer() + y * r2.GetPitch()); + ASSERT_EQ(p, r2.GetConstRow(y)); + for (unsigned int x = 0; x < width; x++, p++, v++) + { + ASSERT_EQ(*p, v); + } + } + } + }