comparison Core/ImageFormats/PngWriter.cpp @ 799:777b6b694da6

rename folder
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 06 May 2014 12:55:41 +0200
parents Core/FileFormats/PngWriter.cpp@2d0a347e8cfc
children ecedd89055db
comparison
equal deleted inserted replaced
798:e1d27ee2114a 799:777b6b694da6
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2014 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 case PixelFormat_SignedGrayscale16:
150 pimpl_->bitDepth_ = 16;
151 pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY;
152 break;
153
154 default:
155 throw OrthancException(ErrorCode_NotImplemented);
156 }
157 }
158
159
160 void PngWriter::Compress(unsigned int width,
161 unsigned int height,
162 unsigned int pitch,
163 PixelFormat format)
164 {
165 png_set_IHDR(pimpl_->png_, pimpl_->info_, width, height,
166 pimpl_->bitDepth_, pimpl_->colorType_, PNG_INTERLACE_NONE,
167 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
168
169 png_write_info(pimpl_->png_, pimpl_->info_);
170
171 if (height > 0)
172 {
173 switch (format)
174 {
175 case PixelFormat_Grayscale16:
176 case PixelFormat_SignedGrayscale16:
177 {
178 int transforms = 0;
179 if (Toolbox::DetectEndianness() == Endianness_Little)
180 {
181 transforms = PNG_TRANSFORM_SWAP_ENDIAN;
182 }
183
184 png_set_rows(pimpl_->png_, pimpl_->info_, &pimpl_->rows_[0]);
185 png_write_png(pimpl_->png_, pimpl_->info_, transforms, NULL);
186
187 break;
188 }
189
190 default:
191 png_write_image(pimpl_->png_, &pimpl_->rows_[0]);
192 }
193 }
194
195 png_write_end(pimpl_->png_, NULL);
196 }
197
198
199 void PngWriter::WriteToFile(const char* filename,
200 unsigned int width,
201 unsigned int height,
202 unsigned int pitch,
203 PixelFormat format,
204 const void* buffer)
205 {
206 Prepare(width, height, pitch, format, buffer);
207
208 FILE* fp = fopen(filename, "wb");
209 if (!fp)
210 {
211 throw OrthancException(ErrorCode_CannotWriteFile);
212 }
213
214 png_init_io(pimpl_->png_, fp);
215
216 if (setjmp(png_jmpbuf(pimpl_->png_)))
217 {
218 // Error during writing PNG
219 throw OrthancException(ErrorCode_CannotWriteFile);
220 }
221
222 Compress(width, height, pitch, format);
223
224 fclose(fp);
225 }
226
227
228
229
230 static void MemoryCallback(png_structp png_ptr,
231 png_bytep data,
232 png_size_t size)
233 {
234 ChunkedBuffer* buffer = reinterpret_cast<ChunkedBuffer*>(png_get_io_ptr(png_ptr));
235 buffer->AddChunk(reinterpret_cast<const char*>(data), size);
236 }
237
238
239
240 void PngWriter::WriteToMemory(std::string& png,
241 unsigned int width,
242 unsigned int height,
243 unsigned int pitch,
244 PixelFormat format,
245 const void* buffer)
246 {
247 ChunkedBuffer chunks;
248
249 Prepare(width, height, pitch, format, buffer);
250
251 if (setjmp(png_jmpbuf(pimpl_->png_)))
252 {
253 // Error during writing PNG
254 throw OrthancException(ErrorCode_InternalError);
255 }
256
257 png_set_write_fn(pimpl_->png_, &chunks, MemoryCallback, NULL);
258
259 Compress(width, height, pitch, format);
260
261 chunks.Flatten(png);
262 }
263 }