comparison Core/FileFormats/PngWriter.cpp @ 454:6f47a4262618

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