# HG changeset patch # User Sebastien Jodogne # Date 1441105599 -7200 # Node ID 292bce3f54ed89b49179bf2e80ade95e6825a238 # Parent 6cccf1da35c606ad5f7f84f8995911ce1392c8ab JpegWriter diff -r 6cccf1da35c6 -r 292bce3f54ed CMakeLists.txt --- a/CMakeLists.txt Tue Sep 01 12:42:49 2015 +0200 +++ b/CMakeLists.txt Tue Sep 01 13:06:39 2015 +0200 @@ -40,7 +40,8 @@ SET(USE_SYSTEM_LUA ON CACHE BOOL "Use the system version of Lua") SET(USE_SYSTEM_DCMTK ON CACHE BOOL "Use the system version of DCMTK") SET(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of Boost") -SET(USE_SYSTEM_LIBPNG ON CACHE BOOL "Use the system version of LibPng") +SET(USE_SYSTEM_LIBPNG ON CACHE BOOL "Use the system version of libpng") +SET(USE_SYSTEM_LIBJPEG ON CACHE BOOL "Use the system version of libjpeg") SET(USE_SYSTEM_CURL ON CACHE BOOL "Use the system version of LibCurl") SET(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL") SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib") @@ -123,6 +124,8 @@ Core/ImageFormats/ImageAccessor.cpp Core/ImageFormats/ImageBuffer.cpp Core/ImageFormats/ImageProcessing.cpp + #Core/ImageFormats/JpegReader.cpp # TODO + Core/ImageFormats/JpegWriter.cpp Core/ImageFormats/PngReader.cpp Core/ImageFormats/PngWriter.cpp Core/SQLite/Connection.cpp @@ -195,7 +198,7 @@ UnitTestsSources/FileStorageTests.cpp UnitTestsSources/FromDcmtkTests.cpp UnitTestsSources/MemoryCacheTests.cpp - UnitTestsSources/PngTests.cpp + UnitTestsSources/ImageTests.cpp UnitTestsSources/RestApiTests.cpp UnitTestsSources/SQLiteTests.cpp UnitTestsSources/SQLiteChromiumTests.cpp @@ -247,6 +250,7 @@ include(${CMAKE_SOURCE_DIR}/Resources/CMake/JsonCppConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibCurlConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibPngConfiguration.cmake) +include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibJpegConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/LuaConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/MongooseConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/PugixmlConfiguration.cmake) @@ -370,6 +374,7 @@ ${GOOGLE_LOG_SOURCES} ${JSONCPP_SOURCES} ${LIBPNG_SOURCES} + ${LIBJPEG_SOURCES} ${LUA_SOURCES} ${MONGOOSE_SOURCES} ${PUGIXML_SOURCES} diff -r 6cccf1da35c6 -r 292bce3f54ed Core/ImageFormats/JpegWriter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/ImageFormats/JpegWriter.cpp Tue Sep 01 13:06:39 2015 +0200 @@ -0,0 +1,261 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "JpegWriter.h" + +#include "../OrthancException.h" +#include "../Logging.h" + +#include +#include +#include +#include +#include +#include + +namespace Orthanc +{ + namespace + { + class ErrorManager + { + private: + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ + std::string message; + + static void OutputMessage(j_common_ptr cinfo) + { + char message[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message) (cinfo, message); + + ErrorManager* that = reinterpret_cast(cinfo->err); + that->message = std::string(message); + } + + + static void ErrorExit(j_common_ptr cinfo) + { + (*cinfo->err->output_message) (cinfo); + + ErrorManager* that = reinterpret_cast(cinfo->err); + longjmp(that->setjmp_buffer, 1); + } + + + public: + ErrorManager() + { + memset(&pub, 0, sizeof(struct jpeg_error_mgr)); + memset(&setjmp_buffer, 0, sizeof(jmp_buf)); + + jpeg_std_error(&pub); + pub.error_exit = ErrorExit; + pub.output_message = OutputMessage; + } + + struct jpeg_error_mgr* GetPublic() + { + return &pub; + } + + jmp_buf& GetJumpBuffer() + { + return setjmp_buffer; + } + + const std::string& GetMessage() const + { + return message; + } + }; + } + + + static void GetLines(std::vector& lines, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer) + { + if (format != PixelFormat_Grayscale8 && + format != PixelFormat_RGB24) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + lines.resize(height); + + uint8_t* base = const_cast(reinterpret_cast(buffer)); + for (unsigned int y = 0; y < height; y++) + { + lines[y] = base + static_cast(y) * static_cast(pitch); + } + } + + + static void Compress(struct jpeg_compress_struct& cinfo, + std::vector& lines, + unsigned int width, + unsigned int height, + PixelFormat format, + int quality) + { + cinfo.image_width = width; + cinfo.image_height = height; + + switch (format) + { + case PixelFormat_Grayscale8: + cinfo.input_components = 1; + cinfo.in_color_space = JCS_GRAYSCALE; + break; + + case PixelFormat_RGB24: + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + break; + + default: + throw OrthancException(ErrorCode_InternalError); + } + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + jpeg_write_scanlines(&cinfo, &lines[0], height); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + } + + + void JpegWriter::SetQuality(uint8_t quality) + { + if (quality <= 0 || quality > 100) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + quality_ = quality; + } + + + void JpegWriter::WriteToFile(const char* filename, + unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer) + { + FILE* fp = fopen(filename, "wb"); + if (fp == NULL) + { + throw OrthancException(ErrorCode_FullStorage); + } + + std::vector lines; + GetLines(lines, height, pitch, format, buffer); + + struct jpeg_compress_struct cinfo; + memset(&cinfo, 0, sizeof(struct jpeg_compress_struct)); + + ErrorManager jerr; + cinfo.err = jerr.GetPublic(); + + if (setjmp(jerr.GetJumpBuffer())) + { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_compress(&cinfo); + fclose(fp); + LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage(); + throw OrthancException(ErrorCode_InternalError); + } + + // Do not allocate data on the stack below this line! + + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, fp); + Compress(cinfo, lines, width, height, format, quality_); + + // Everything went fine, "setjmp()" didn't get called + + fclose(fp); + } + + + void JpegWriter::WriteToMemory(std::string& jpeg, + unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer) + { + std::vector lines; + GetLines(lines, height, pitch, format, buffer); + + struct jpeg_compress_struct cinfo; + memset(&cinfo, 0, sizeof(struct jpeg_compress_struct)); + + ErrorManager jerr; + + unsigned char* data = NULL; + unsigned long size; + + if (setjmp(jerr.GetJumpBuffer())) + { + jpeg_destroy_compress(&cinfo); + + if (data != NULL) + { + free(data); + } + + LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage(); + throw OrthancException(ErrorCode_InternalError); + } + + // Do not allocate data on the stack below this line! + + jpeg_create_compress(&cinfo); + cinfo.err = jerr.GetPublic(); + jpeg_mem_dest(&cinfo, &data, &size); + + Compress(cinfo, lines, width, height, format, quality_); + + // Everything went fine, "setjmp()" didn't get called + + jpeg.assign(reinterpret_cast(data), size); + free(data); + } +} diff -r 6cccf1da35c6 -r 292bce3f54ed Core/ImageFormats/JpegWriter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/ImageFormats/JpegWriter.h Tue Sep 01 13:06:39 2015 +0200 @@ -0,0 +1,87 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "ImageAccessor.h" + +#include +#include + +namespace Orthanc +{ + class JpegWriter + { + private: + int quality_; + + public: + JpegWriter() : quality_(90) + { + } + + void SetQuality(uint8_t quality); + + uint8_t GetQuality() const + { + return quality_; + } + + void WriteToFile(const char* filename, + unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer); + + void WriteToMemory(std::string& jpeg, + unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer); + + void WriteToFile(const char* filename, + const ImageAccessor& accessor) + { + WriteToFile(filename, accessor.GetWidth(), accessor.GetHeight(), + accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer()); + } + + void WriteToMemory(std::string& jpeg, + const ImageAccessor& accessor) + { + WriteToMemory(jpeg, accessor.GetWidth(), accessor.GetHeight(), + accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer()); + } + }; +} diff -r 6cccf1da35c6 -r 292bce3f54ed Plugins/Include/orthanc/OrthancCPlugin.h --- a/Plugins/Include/orthanc/OrthancCPlugin.h Tue Sep 01 12:42:49 2015 +0200 +++ b/Plugins/Include/orthanc/OrthancCPlugin.h Tue Sep 01 13:06:39 2015 +0200 @@ -27,7 +27,8 @@ * The plugin must return a string containing its version number. * * The name and the version of a plugin is only used to prevent it - * from being loaded twice. + * from being loaded twice. Note that, in C++, it is mandatory to + * declare these functions within an extern "C" section. * * To ensure multi-threading safety, the various REST callbacks are * guaranteed to be executed in mutual exclusion since Orthanc diff -r 6cccf1da35c6 -r 292bce3f54ed Resources/CMake/LibJpegConfiguration.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/CMake/LibJpegConfiguration.cmake Tue Sep 01 13:06:39 2015 +0200 @@ -0,0 +1,93 @@ +if (STATIC_BUILD OR NOT USE_SYSTEM_LIBJPEG) + set(LIBJPEG_SOURCES_DIR ${CMAKE_BINARY_DIR}/jpeg-9a) + DownloadPackage( + "3353992aecaee1805ef4109aadd433e7" + "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/jpegsrc.v9a.tar.gz" + "${LIBJPEG_SOURCES_DIR}") + + include_directories( + ${LIBJPEG_SOURCES_DIR} + ) + + list(APPEND LIBJPEG_SOURCES + ${LIBJPEG_SOURCES_DIR}/jaricom.c + ${LIBJPEG_SOURCES_DIR}/jcapimin.c + ${LIBJPEG_SOURCES_DIR}/jcapistd.c + ${LIBJPEG_SOURCES_DIR}/jcarith.c + ${LIBJPEG_SOURCES_DIR}/jccoefct.c + ${LIBJPEG_SOURCES_DIR}/jccolor.c + ${LIBJPEG_SOURCES_DIR}/jcdctmgr.c + ${LIBJPEG_SOURCES_DIR}/jchuff.c + ${LIBJPEG_SOURCES_DIR}/jcinit.c + ${LIBJPEG_SOURCES_DIR}/jcmarker.c + ${LIBJPEG_SOURCES_DIR}/jcmaster.c + ${LIBJPEG_SOURCES_DIR}/jcomapi.c + ${LIBJPEG_SOURCES_DIR}/jcparam.c + ${LIBJPEG_SOURCES_DIR}/jcprepct.c + ${LIBJPEG_SOURCES_DIR}/jcsample.c + ${LIBJPEG_SOURCES_DIR}/jctrans.c + ${LIBJPEG_SOURCES_DIR}/jdapimin.c + ${LIBJPEG_SOURCES_DIR}/jdapistd.c + ${LIBJPEG_SOURCES_DIR}/jdarith.c + ${LIBJPEG_SOURCES_DIR}/jdatadst.c + ${LIBJPEG_SOURCES_DIR}/jdatasrc.c + ${LIBJPEG_SOURCES_DIR}/jdcoefct.c + ${LIBJPEG_SOURCES_DIR}/jdcolor.c + ${LIBJPEG_SOURCES_DIR}/jddctmgr.c + ${LIBJPEG_SOURCES_DIR}/jdhuff.c + ${LIBJPEG_SOURCES_DIR}/jdinput.c + ${LIBJPEG_SOURCES_DIR}/jcmainct.c + ${LIBJPEG_SOURCES_DIR}/jdmainct.c + ${LIBJPEG_SOURCES_DIR}/jdmarker.c + ${LIBJPEG_SOURCES_DIR}/jdmaster.c + ${LIBJPEG_SOURCES_DIR}/jdmerge.c + ${LIBJPEG_SOURCES_DIR}/jdpostct.c + ${LIBJPEG_SOURCES_DIR}/jdsample.c + ${LIBJPEG_SOURCES_DIR}/jdtrans.c + ${LIBJPEG_SOURCES_DIR}/jerror.c + ${LIBJPEG_SOURCES_DIR}/jfdctflt.c + ${LIBJPEG_SOURCES_DIR}/jfdctfst.c + ${LIBJPEG_SOURCES_DIR}/jfdctint.c + ${LIBJPEG_SOURCES_DIR}/jidctflt.c + ${LIBJPEG_SOURCES_DIR}/jidctfst.c + ${LIBJPEG_SOURCES_DIR}/jidctint.c + #${LIBJPEG_SOURCES_DIR}/jmemansi.c + #${LIBJPEG_SOURCES_DIR}/jmemdos.c + #${LIBJPEG_SOURCES_DIR}/jmemmac.c + ${LIBJPEG_SOURCES_DIR}/jmemmgr.c + #${LIBJPEG_SOURCES_DIR}/jmemname.c + ${LIBJPEG_SOURCES_DIR}/jmemnobs.c + ${LIBJPEG_SOURCES_DIR}/jquant1.c + ${LIBJPEG_SOURCES_DIR}/jquant2.c + ${LIBJPEG_SOURCES_DIR}/jutils.c + + # ${LIBJPEG_SOURCES_DIR}/rdbmp.c + # ${LIBJPEG_SOURCES_DIR}/rdcolmap.c + # ${LIBJPEG_SOURCES_DIR}/rdgif.c + # ${LIBJPEG_SOURCES_DIR}/rdppm.c + # ${LIBJPEG_SOURCES_DIR}/rdrle.c + # ${LIBJPEG_SOURCES_DIR}/rdswitch.c + # ${LIBJPEG_SOURCES_DIR}/rdtarga.c + # ${LIBJPEG_SOURCES_DIR}/transupp.c + # ${LIBJPEG_SOURCES_DIR}/wrbmp.c + # ${LIBJPEG_SOURCES_DIR}/wrgif.c + # ${LIBJPEG_SOURCES_DIR}/wrppm.c + # ${LIBJPEG_SOURCES_DIR}/wrrle.c + # ${LIBJPEG_SOURCES_DIR}/wrtarga.c + ) + + configure_file( + ${LIBJPEG_SOURCES_DIR}/jconfig.txt + ${LIBJPEG_SOURCES_DIR}/jconfig.h COPYONLY + ) + +else() + include(FindJPEG) + + if (NOT ${JPEG_FOUND}) + message(FATAL_ERROR "Unable to find libjpeg") + endif() + + include_directories(${JPEG_INCLUDE_DIR}) + link_libraries(${JPEG_LIBRARIES}) +endif() diff -r 6cccf1da35c6 -r 292bce3f54ed Resources/CMake/LibPngConfiguration.cmake --- a/Resources/CMake/LibPngConfiguration.cmake Tue Sep 01 12:42:49 2015 +0200 +++ b/Resources/CMake/LibPngConfiguration.cmake Tue Sep 01 13:06:39 2015 +0200 @@ -52,7 +52,7 @@ include(FindPNG) if (NOT ${PNG_FOUND}) - message(FATAL_ERROR "Unable to find LibPNG") + message(FATAL_ERROR "Unable to find libpng") endif() include_directories(${PNG_INCLUDE_DIRS}) diff -r 6cccf1da35c6 -r 292bce3f54ed UnitTestsSources/ImageTests.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UnitTestsSources/ImageTests.cpp Tue Sep 01 13:06:39 2015 +0200 @@ -0,0 +1,212 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "PrecompiledHeadersUnitTests.h" +#include "gtest/gtest.h" + +#include +#include "../Core/ImageFormats/ImageBuffer.h" +#include "../Core/ImageFormats/PngReader.h" +#include "../Core/ImageFormats/PngWriter.h" +#include "../Core/ImageFormats/JpegWriter.h" +#include "../Core/Toolbox.h" +#include "../Core/Uuid.h" + + +TEST(PngWriter, ColorPattern) +{ + Orthanc::PngWriter w; + int width = 17; + int height = 61; + int pitch = width * 3; + + std::vector image(height * pitch); + for (int y = 0; y < height; y++) + { + uint8_t *p = &image[0] + y * pitch; + for (int x = 0; x < width; x++, p += 3) + { + p[0] = (y % 3 == 0) ? 255 : 0; + p[1] = (y % 3 == 1) ? 255 : 0; + p[2] = (y % 3 == 2) ? 255 : 0; + } + } + + w.WriteToFile("UnitTestsResults/ColorPattern.png", width, height, pitch, Orthanc::PixelFormat_RGB24, &image[0]); + + std::string f, md5; + Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/ColorPattern.png"); + Orthanc::Toolbox::ComputeMD5(md5, f); + ASSERT_EQ("604e785f53c99cae6ea4584870b2c41d", md5); +} + +TEST(PngWriter, Gray8Pattern) +{ + Orthanc::PngWriter w; + int width = 17; + int height = 256; + int pitch = width; + + std::vector image(height * pitch); + for (int y = 0; y < height; y++) + { + uint8_t *p = &image[0] + y * pitch; + for (int x = 0; x < width; x++, p++) + { + *p = y; + } + } + + w.WriteToFile("UnitTestsResults/Gray8Pattern.png", width, height, pitch, Orthanc::PixelFormat_Grayscale8, &image[0]); + + std::string f, md5; + Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/Gray8Pattern.png"); + Orthanc::Toolbox::ComputeMD5(md5, f); + ASSERT_EQ("5a9b98bea3d0a6d983980cc38bfbcdb3", md5); +} + +TEST(PngWriter, Gray16Pattern) +{ + Orthanc::PngWriter w; + int width = 256; + int height = 256; + int pitch = width * 2 + 16; + + std::vector image(height * pitch); + + int v = 0; + for (int y = 0; y < height; y++) + { + uint16_t *p = reinterpret_cast(&image[0] + y * pitch); + for (int x = 0; x < width; x++, p++, v++) + { + *p = v; + } + } + + w.WriteToFile("UnitTestsResults/Gray16Pattern.png", width, height, pitch, Orthanc::PixelFormat_Grayscale16, &image[0]); + + std::string f, md5; + Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/Gray16Pattern.png"); + Orthanc::Toolbox::ComputeMD5(md5, f); + ASSERT_EQ("0785866a08bf0a02d2eeff87f658571c", md5); +} + +TEST(PngWriter, EndToEnd) +{ + Orthanc::PngWriter w; + unsigned int width = 256; + unsigned int height = 256; + unsigned int pitch = width * 2 + 16; + + std::vector image(height * pitch); + + int v = 0; + for (unsigned int y = 0; y < height; y++) + { + uint16_t *p = reinterpret_cast(&image[0] + y * pitch); + for (unsigned int x = 0; x < width; x++, p++, v++) + { + *p = v; + } + } + + std::string s; + w.WriteToMemory(s, width, height, pitch, Orthanc::PixelFormat_Grayscale16, &image[0]); + + { + Orthanc::PngReader r; + 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(*p, v); + } + } + } + + { + Orthanc::Toolbox::TemporaryFile tmp; + Orthanc::Toolbox::WriteFile(s, tmp.GetPath()); + + Orthanc::PngReader r2; + 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); + } + } + } +} + + + + +TEST(JpegWriter, Basic) +{ + Orthanc::ImageBuffer img(16, 16, Orthanc::PixelFormat_Grayscale8); + Orthanc::ImageAccessor accessor = img.GetAccessor(); + for (unsigned int y = 0, value = 0; y < img.GetHeight(); y++) + { + uint8_t* p = reinterpret_cast(accessor.GetRow(y)); + for (unsigned int x = 0; x < img.GetWidth(); x++, p++) + { + *p = value++; + } + } + + Orthanc::JpegWriter w; + w.WriteToFile("UnitTestsResults/hello.jpg", accessor); + + std::string s; + w.WriteToMemory(s, accessor); + Orthanc::Toolbox::WriteFile(s, "UnitTestsResults/hello2.jpg"); +} diff -r 6cccf1da35c6 -r 292bce3f54ed UnitTestsSources/PngTests.cpp --- a/UnitTestsSources/PngTests.cpp Tue Sep 01 12:42:49 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersUnitTests.h" -#include "gtest/gtest.h" - -#include -#include "../Core/ImageFormats/PngReader.h" -#include "../Core/ImageFormats/PngWriter.h" -#include "../Core/Toolbox.h" -#include "../Core/Uuid.h" - - -TEST(PngWriter, ColorPattern) -{ - Orthanc::PngWriter w; - int width = 17; - int height = 61; - int pitch = width * 3; - - std::vector image(height * pitch); - for (int y = 0; y < height; y++) - { - uint8_t *p = &image[0] + y * pitch; - for (int x = 0; x < width; x++, p += 3) - { - p[0] = (y % 3 == 0) ? 255 : 0; - p[1] = (y % 3 == 1) ? 255 : 0; - p[2] = (y % 3 == 2) ? 255 : 0; - } - } - - w.WriteToFile("UnitTestsResults/ColorPattern.png", width, height, pitch, Orthanc::PixelFormat_RGB24, &image[0]); - - std::string f, md5; - Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/ColorPattern.png"); - Orthanc::Toolbox::ComputeMD5(md5, f); - ASSERT_EQ("604e785f53c99cae6ea4584870b2c41d", md5); -} - -TEST(PngWriter, Gray8Pattern) -{ - Orthanc::PngWriter w; - int width = 17; - int height = 256; - int pitch = width; - - std::vector image(height * pitch); - for (int y = 0; y < height; y++) - { - uint8_t *p = &image[0] + y * pitch; - for (int x = 0; x < width; x++, p++) - { - *p = y; - } - } - - w.WriteToFile("UnitTestsResults/Gray8Pattern.png", width, height, pitch, Orthanc::PixelFormat_Grayscale8, &image[0]); - - std::string f, md5; - Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/Gray8Pattern.png"); - Orthanc::Toolbox::ComputeMD5(md5, f); - ASSERT_EQ("5a9b98bea3d0a6d983980cc38bfbcdb3", md5); -} - -TEST(PngWriter, Gray16Pattern) -{ - Orthanc::PngWriter w; - int width = 256; - int height = 256; - int pitch = width * 2 + 16; - - std::vector image(height * pitch); - - int v = 0; - for (int y = 0; y < height; y++) - { - uint16_t *p = reinterpret_cast(&image[0] + y * pitch); - for (int x = 0; x < width; x++, p++, v++) - { - *p = v; - } - } - - w.WriteToFile("UnitTestsResults/Gray16Pattern.png", width, height, pitch, Orthanc::PixelFormat_Grayscale16, &image[0]); - - std::string f, md5; - Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/Gray16Pattern.png"); - Orthanc::Toolbox::ComputeMD5(md5, f); - ASSERT_EQ("0785866a08bf0a02d2eeff87f658571c", md5); -} - -TEST(PngWriter, EndToEnd) -{ - Orthanc::PngWriter w; - unsigned int width = 256; - unsigned int height = 256; - unsigned int pitch = width * 2 + 16; - - std::vector image(height * pitch); - - int v = 0; - for (unsigned int y = 0; y < height; y++) - { - uint16_t *p = reinterpret_cast(&image[0] + y * pitch); - for (unsigned int x = 0; x < width; x++, p++, v++) - { - *p = v; - } - } - - std::string s; - w.WriteToMemory(s, width, height, pitch, Orthanc::PixelFormat_Grayscale16, &image[0]); - - { - Orthanc::PngReader r; - 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(*p, v); - } - } - } - - { - Orthanc::Toolbox::TemporaryFile tmp; - Orthanc::Toolbox::WriteFile(s, tmp.GetPath()); - - Orthanc::PngReader r2; - 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); - } - } - } -}