comparison OrthancFramework/Sources/Images/PngWriter.cpp @ 4044:d25f4c0fa160 framework

splitting code into OrthancFramework and OrthancServer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 10 Jun 2020 20:30:34 +0200
parents Core/Images/PngWriter.cpp@94f4a18a79cc
children bf7b9edf6b81
comparison
equal deleted inserted replaced
4043:6c6239aec462 4044:d25f4c0fa160
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-2020 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(data, size);
247 }
248
249
250
251 void PngWriter::WriteToMemoryInternal(std::string& png,
252 unsigned int width,
253 unsigned int height,
254 unsigned int pitch,
255 PixelFormat format,
256 const void* buffer)
257 {
258 ChunkedBuffer chunks;
259
260 Prepare(width, height, pitch, format, buffer);
261
262 if (setjmp(png_jmpbuf(pimpl_->png_)))
263 {
264 // Error during writing PNG
265 throw OrthancException(ErrorCode_InternalError);
266 }
267
268 png_set_write_fn(pimpl_->png_, &chunks, MemoryCallback, NULL);
269
270 Compress(width, height, pitch, format);
271
272 chunks.Flatten(png);
273 }
274 }