comparison Resources/Orthanc/Core/Images/PngWriter.cpp @ 200:03afbee0cc7b

integration of Orthanc core into Stone
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 23 Mar 2018 11:04:03 +0100
parents
children
comparison
equal deleted inserted replaced
199:dabe9982fca3 200:03afbee0cc7b
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * In addition, as a special exception, the copyright holders of this
13 * program give permission to link the code of its release with the
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it
15 * that use the same license as the "OpenSSL" library), and distribute
16 * the linked executables. You must obey the GNU General Public License
17 * in all respects for all of the code used other than "OpenSSL". If you
18 * modify file(s) with this exception, you may extend this exception to
19 * your version of the file(s), but you are not obligated to do so. If
20 * you do not wish to do so, delete this exception statement from your
21 * version. If you delete this exception statement from all source files
22 * in the program, then also delete it here.
23 *
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 **/
32
33
34 #include "../PrecompiledHeaders.h"
35 #include "PngWriter.h"
36
37 #include <vector>
38 #include <stdint.h>
39 #include <png.h>
40 #include "../OrthancException.h"
41 #include "../ChunkedBuffer.h"
42 #include "../Toolbox.h"
43
44 #if ORTHANC_SANDBOXED == 0
45 # include "../SystemToolbox.h"
46 #endif
47
48
49 // http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-4
50 // http://zarb.org/~gc/html/libpng.html
51 /*
52 void write_row_callback(png_ptr, png_uint_32 row, int pass)
53 {
54 }*/
55
56
57
58
59 /* bool isError_;
60
61 // http://www.libpng.org/pub/png/book/chapter14.html#png.ch14.div.2
62
63 static void ErrorHandler(png_structp png, png_const_charp message)
64 {
65 printf("** [%s]\n", message);
66
67 PngWriter* that = (PngWriter*) png_get_error_ptr(png);
68 that->isError_ = true;
69 printf("** %d\n", (int)that);
70
71 //((PngWriter*) payload)->isError_ = true;
72 }
73
74 static void WarningHandler(png_structp png, png_const_charp message)
75 {
76 printf("++ %d\n", (int)message);
77 }*/
78
79
80 namespace Orthanc
81 {
82 struct PngWriter::PImpl
83 {
84 png_structp png_;
85 png_infop info_;
86
87 // Filled by Prepare()
88 std::vector<uint8_t*> rows_;
89 int bitDepth_;
90 int colorType_;
91 };
92
93
94
95 PngWriter::PngWriter() : pimpl_(new PImpl)
96 {
97 pimpl_->png_ = NULL;
98 pimpl_->info_ = NULL;
99
100 pimpl_->png_ = png_create_write_struct
101 (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); //this, ErrorHandler, WarningHandler);
102 if (!pimpl_->png_)
103 {
104 throw OrthancException(ErrorCode_NotEnoughMemory);
105 }
106
107 pimpl_->info_ = png_create_info_struct(pimpl_->png_);
108 if (!pimpl_->info_)
109 {
110 png_destroy_write_struct(&pimpl_->png_, NULL);
111 throw OrthancException(ErrorCode_NotEnoughMemory);
112 }
113 }
114
115 PngWriter::~PngWriter()
116 {
117 if (pimpl_->info_)
118 {
119 png_destroy_info_struct(pimpl_->png_, &pimpl_->info_);
120 }
121
122 if (pimpl_->png_)
123 {
124 png_destroy_write_struct(&pimpl_->png_, NULL);
125 }
126 }
127
128
129
130 void PngWriter::Prepare(unsigned int width,
131 unsigned int height,
132 unsigned int pitch,
133 PixelFormat format,
134 const void* buffer)
135 {
136 pimpl_->rows_.resize(height);
137 for (unsigned int y = 0; y < height; y++)
138 {
139 pimpl_->rows_[y] = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(buffer)) + y * pitch;
140 }
141
142 switch (format)
143 {
144 case PixelFormat_RGB24:
145 pimpl_->bitDepth_ = 8;
146 pimpl_->colorType_ = PNG_COLOR_TYPE_RGB;
147 break;
148
149 case PixelFormat_RGBA32:
150 pimpl_->bitDepth_ = 8;
151 pimpl_->colorType_ = PNG_COLOR_TYPE_RGBA;
152 break;
153
154 case PixelFormat_Grayscale8:
155 pimpl_->bitDepth_ = 8;
156 pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY;
157 break;
158
159 case PixelFormat_Grayscale16:
160 case PixelFormat_SignedGrayscale16:
161 pimpl_->bitDepth_ = 16;
162 pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY;
163 break;
164
165 default:
166 throw OrthancException(ErrorCode_NotImplemented);
167 }
168 }
169
170
171 void PngWriter::Compress(unsigned int width,
172 unsigned int height,
173 unsigned int pitch,
174 PixelFormat format)
175 {
176 png_set_IHDR(pimpl_->png_, pimpl_->info_, width, height,
177 pimpl_->bitDepth_, pimpl_->colorType_, PNG_INTERLACE_NONE,
178 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
179
180 png_write_info(pimpl_->png_, pimpl_->info_);
181
182 if (height > 0)
183 {
184 switch (format)
185 {
186 case PixelFormat_Grayscale16:
187 case PixelFormat_SignedGrayscale16:
188 {
189 int transforms = 0;
190 if (Toolbox::DetectEndianness() == Endianness_Little)
191 {
192 transforms = PNG_TRANSFORM_SWAP_ENDIAN;
193 }
194
195 png_set_rows(pimpl_->png_, pimpl_->info_, &pimpl_->rows_[0]);
196 png_write_png(pimpl_->png_, pimpl_->info_, transforms, NULL);
197
198 break;
199 }
200
201 default:
202 png_write_image(pimpl_->png_, &pimpl_->rows_[0]);
203 }
204 }
205
206 png_write_end(pimpl_->png_, NULL);
207 }
208
209
210 #if ORTHANC_SANDBOXED == 0
211 void PngWriter::WriteToFileInternal(const std::string& filename,
212 unsigned int width,
213 unsigned int height,
214 unsigned int pitch,
215 PixelFormat format,
216 const void* buffer)
217 {
218 Prepare(width, height, pitch, format, buffer);
219
220 FILE* fp = SystemToolbox::OpenFile(filename, FileMode_WriteBinary);
221 if (!fp)
222 {
223 throw OrthancException(ErrorCode_CannotWriteFile);
224 }
225
226 png_init_io(pimpl_->png_, fp);
227
228 if (setjmp(png_jmpbuf(pimpl_->png_)))
229 {
230 // Error during writing PNG
231 throw OrthancException(ErrorCode_CannotWriteFile);
232 }
233
234 Compress(width, height, pitch, format);
235
236 fclose(fp);
237 }
238 #endif
239
240
241 static void MemoryCallback(png_structp png_ptr,
242 png_bytep data,
243 png_size_t size)
244 {
245 ChunkedBuffer* buffer = reinterpret_cast<ChunkedBuffer*>(png_get_io_ptr(png_ptr));
246 buffer->AddChunk(reinterpret_cast<const char*>(data), size);
247 }
248
249
250
251 #if ORTHANC_SANDBOXED == 0
252 void PngWriter::WriteToMemoryInternal(std::string& png,
253 unsigned int width,
254 unsigned int height,
255 unsigned int pitch,
256 PixelFormat format,
257 const void* buffer)
258 {
259 ChunkedBuffer chunks;
260
261 Prepare(width, height, pitch, format, buffer);
262
263 if (setjmp(png_jmpbuf(pimpl_->png_)))
264 {
265 // Error during writing PNG
266 throw OrthancException(ErrorCode_InternalError);
267 }
268
269 png_set_write_fn(pimpl_->png_, &chunks, MemoryCallback, NULL);
270
271 Compress(width, height, pitch, format);
272
273 chunks.Flatten(png);
274 }
275 #endif
276 }