comparison OrthancServer/UnitTestsSources/ImageTests.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 UnitTestsSources/ImageTests.cpp@219de90c1f43
children 05b8fd21089c
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 "PrecompiledHeadersUnitTests.h"
35 #include "gtest/gtest.h"
36
37 #include "../Core/Images/Font.h"
38 #include "../Core/Images/Image.h"
39 #include "../Core/Images/ImageProcessing.h"
40 #include "../Core/Images/JpegReader.h"
41 #include "../Core/Images/JpegWriter.h"
42 #include "../Core/Images/PngReader.h"
43 #include "../Core/Images/PngWriter.h"
44 #include "../Core/Images/PamReader.h"
45 #include "../Core/Images/PamWriter.h"
46 #include "../Core/SystemToolbox.h"
47 #include "../Core/Toolbox.h"
48 #include "../Core/TemporaryFile.h"
49 #include "../OrthancServer/OrthancConfiguration.h" // For the FontRegistry
50
51 #include <stdint.h>
52
53
54 TEST(PngWriter, ColorPattern)
55 {
56 Orthanc::PngWriter w;
57 unsigned int width = 17;
58 unsigned int height = 61;
59 unsigned int pitch = width * 3;
60
61 std::vector<uint8_t> image(height * pitch);
62 for (unsigned int y = 0; y < height; y++)
63 {
64 uint8_t *p = &image[0] + y * pitch;
65 for (unsigned int x = 0; x < width; x++, p += 3)
66 {
67 p[0] = (y % 3 == 0) ? 255 : 0;
68 p[1] = (y % 3 == 1) ? 255 : 0;
69 p[2] = (y % 3 == 2) ? 255 : 0;
70 }
71 }
72
73 Orthanc::ImageAccessor accessor;
74 accessor.AssignReadOnly(Orthanc::PixelFormat_RGB24, width, height, pitch, &image[0]);
75
76 w.WriteToFile("UnitTestsResults/ColorPattern.png", accessor);
77
78 std::string f, md5;
79 Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/ColorPattern.png");
80 Orthanc::Toolbox::ComputeMD5(md5, f);
81 ASSERT_EQ("604e785f53c99cae6ea4584870b2c41d", md5);
82 }
83
84 TEST(PngWriter, Gray8Pattern)
85 {
86 Orthanc::PngWriter w;
87 int width = 17;
88 int height = 256;
89 int pitch = width;
90
91 std::vector<uint8_t> image(height * pitch);
92 for (int y = 0; y < height; y++)
93 {
94 uint8_t *p = &image[0] + y * pitch;
95 for (int x = 0; x < width; x++, p++)
96 {
97 *p = y;
98 }
99 }
100
101 Orthanc::ImageAccessor accessor;
102 accessor.AssignReadOnly(Orthanc::PixelFormat_Grayscale8, width, height, pitch, &image[0]);
103
104 w.WriteToFile("UnitTestsResults/Gray8Pattern.png", accessor);
105
106 std::string f, md5;
107 Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/Gray8Pattern.png");
108 Orthanc::Toolbox::ComputeMD5(md5, f);
109 ASSERT_EQ("5a9b98bea3d0a6d983980cc38bfbcdb3", md5);
110 }
111
112 TEST(PngWriter, Gray16Pattern)
113 {
114 Orthanc::PngWriter w;
115 int width = 256;
116 int height = 256;
117 int pitch = width * 2 + 16;
118
119 std::vector<uint8_t> image(height * pitch);
120
121 int v = 0;
122 for (int y = 0; y < height; y++)
123 {
124 uint16_t *p = reinterpret_cast<uint16_t*>(&image[0] + y * pitch);
125 for (int x = 0; x < width; x++, p++, v++)
126 {
127 *p = v;
128 }
129 }
130
131 Orthanc::ImageAccessor accessor;
132 accessor.AssignReadOnly(Orthanc::PixelFormat_Grayscale16, width, height, pitch, &image[0]);
133 w.WriteToFile("UnitTestsResults/Gray16Pattern.png", accessor);
134
135 std::string f, md5;
136 Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/Gray16Pattern.png");
137 Orthanc::Toolbox::ComputeMD5(md5, f);
138 ASSERT_EQ("0785866a08bf0a02d2eeff87f658571c", md5);
139 }
140
141 TEST(PngWriter, EndToEnd)
142 {
143 Orthanc::PngWriter w;
144 unsigned int width = 256;
145 unsigned int height = 256;
146 unsigned int pitch = width * 2 + 16;
147
148 std::vector<uint8_t> image(height * pitch);
149
150 int v = 0;
151 for (unsigned int y = 0; y < height; y++)
152 {
153 uint16_t *p = reinterpret_cast<uint16_t*>(&image[0] + y * pitch);
154 for (unsigned int x = 0; x < width; x++, p++, v++)
155 {
156 *p = v;
157 }
158 }
159
160 Orthanc::ImageAccessor accessor;
161 accessor.AssignReadOnly(Orthanc::PixelFormat_Grayscale16, width, height, pitch, &image[0]);
162
163 std::string s;
164 w.WriteToMemory(s, accessor);
165
166 {
167 Orthanc::PngReader r;
168 r.ReadFromMemory(s);
169
170 ASSERT_EQ(r.GetFormat(), Orthanc::PixelFormat_Grayscale16);
171 ASSERT_EQ(r.GetWidth(), width);
172 ASSERT_EQ(r.GetHeight(), height);
173
174 v = 0;
175 for (unsigned int y = 0; y < height; y++)
176 {
177 const uint16_t *p = reinterpret_cast<const uint16_t*>((const uint8_t*) r.GetConstBuffer() + y * r.GetPitch());
178 ASSERT_EQ(p, r.GetConstRow(y));
179 for (unsigned int x = 0; x < width; x++, p++, v++)
180 {
181 ASSERT_EQ(*p, v);
182 }
183 }
184 }
185
186 {
187 Orthanc::TemporaryFile tmp;
188 tmp.Write(s);
189
190 Orthanc::PngReader r2;
191 r2.ReadFromFile(tmp.GetPath());
192
193 ASSERT_EQ(r2.GetFormat(), Orthanc::PixelFormat_Grayscale16);
194 ASSERT_EQ(r2.GetWidth(), width);
195 ASSERT_EQ(r2.GetHeight(), height);
196
197 v = 0;
198 for (unsigned int y = 0; y < height; y++)
199 {
200 const uint16_t *p = reinterpret_cast<const uint16_t*>((const uint8_t*) r2.GetConstBuffer() + y * r2.GetPitch());
201 ASSERT_EQ(p, r2.GetConstRow(y));
202 for (unsigned int x = 0; x < width; x++, p++, v++)
203 {
204 ASSERT_EQ(*p, v);
205 }
206 }
207 }
208 }
209
210
211
212
213 TEST(JpegWriter, Basic)
214 {
215 std::string s;
216
217 {
218 Orthanc::Image img(Orthanc::PixelFormat_Grayscale8, 16, 16, false);
219 for (unsigned int y = 0, value = 0; y < img.GetHeight(); y++)
220 {
221 uint8_t* p = reinterpret_cast<uint8_t*>(img.GetRow(y));
222 for (unsigned int x = 0; x < img.GetWidth(); x++, p++)
223 {
224 *p = value++;
225 }
226 }
227
228 Orthanc::JpegWriter w;
229 w.WriteToFile("UnitTestsResults/hello.jpg", img);
230
231 w.WriteToMemory(s, img);
232 Orthanc::SystemToolbox::WriteFile(s, "UnitTestsResults/hello2.jpg");
233
234 std::string t;
235 Orthanc::SystemToolbox::ReadFile(t, "UnitTestsResults/hello.jpg");
236 ASSERT_EQ(s.size(), t.size());
237 ASSERT_EQ(0, memcmp(s.c_str(), t.c_str(), s.size()));
238 }
239
240 {
241 Orthanc::JpegReader r1, r2;
242 r1.ReadFromFile("UnitTestsResults/hello.jpg");
243 ASSERT_EQ(16u, r1.GetWidth());
244 ASSERT_EQ(16u, r1.GetHeight());
245
246 r2.ReadFromMemory(s);
247 ASSERT_EQ(16u, r2.GetWidth());
248 ASSERT_EQ(16u, r2.GetHeight());
249
250 for (unsigned int y = 0; y < r1.GetHeight(); y++)
251 {
252 const uint8_t* p1 = reinterpret_cast<const uint8_t*>(r1.GetConstRow(y));
253 const uint8_t* p2 = reinterpret_cast<const uint8_t*>(r2.GetConstRow(y));
254 for (unsigned int x = 0; x < r1.GetWidth(); x++)
255 {
256 ASSERT_EQ(*p1, *p2);
257 }
258 }
259 }
260 }
261
262
263 TEST(Font, Basic)
264 {
265 Orthanc::Image s(Orthanc::PixelFormat_RGB24, 640, 480, false);
266 memset(s.GetBuffer(), 0, s.GetPitch() * s.GetHeight());
267
268 {
269 Orthanc::OrthancConfiguration::ReaderLock lock;
270 ASSERT_GE(1u, lock.GetConfiguration().GetFontRegistry().GetSize());
271 lock.GetConfiguration().GetFontRegistry().GetFont(0).Draw
272 (s, "Hello world É\n\rComment ça va ?\nq", 50, 60, 255, 0, 0);
273 }
274
275 Orthanc::PngWriter w;
276 w.WriteToFile("UnitTestsResults/font.png", s);
277 }
278
279 TEST(PamWriter, ColorPattern)
280 {
281 Orthanc::PamWriter w;
282 unsigned int width = 17;
283 unsigned int height = 61;
284 unsigned int pitch = width * 3;
285
286 std::vector<uint8_t> image(height * pitch);
287 for (unsigned int y = 0; y < height; y++)
288 {
289 uint8_t *p = &image[0] + y * pitch;
290 for (unsigned int x = 0; x < width; x++, p += 3)
291 {
292 p[0] = (y % 3 == 0) ? 255 : 0;
293 p[1] = (y % 3 == 1) ? 255 : 0;
294 p[2] = (y % 3 == 2) ? 255 : 0;
295 }
296 }
297
298 Orthanc::ImageAccessor accessor;
299 accessor.AssignReadOnly(Orthanc::PixelFormat_RGB24, width, height, pitch, &image[0]);
300
301 w.WriteToFile("UnitTestsResults/ColorPattern.pam", accessor);
302
303 std::string f, md5;
304 Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/ColorPattern.pam");
305 Orthanc::Toolbox::ComputeMD5(md5, f);
306 ASSERT_EQ("81a3441754e88969ebbe53e69891e841", md5);
307 }
308
309 TEST(PamWriter, Gray8Pattern)
310 {
311 Orthanc::PamWriter w;
312 int width = 17;
313 int height = 256;
314 int pitch = width;
315
316 std::vector<uint8_t> image(height * pitch);
317 for (int y = 0; y < height; y++)
318 {
319 uint8_t *p = &image[0] + y * pitch;
320 for (int x = 0; x < width; x++, p++)
321 {
322 *p = y;
323 }
324 }
325
326 Orthanc::ImageAccessor accessor;
327 accessor.AssignReadOnly(Orthanc::PixelFormat_Grayscale8, width, height, pitch, &image[0]);
328
329 w.WriteToFile("UnitTestsResults/Gray8Pattern.pam", accessor);
330
331 std::string f, md5;
332 Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/Gray8Pattern.pam");
333 Orthanc::Toolbox::ComputeMD5(md5, f);
334 ASSERT_EQ("7873c408d26a9d11dd1c1de5e69cc0a3", md5);
335 }
336
337 TEST(PamWriter, Gray16Pattern)
338 {
339 Orthanc::PamWriter w;
340 int width = 256;
341 int height = 256;
342 int pitch = width * 2 + 16;
343
344 std::vector<uint8_t> image(height * pitch);
345
346 int v = 0;
347 for (int y = 0; y < height; y++)
348 {
349 uint16_t *p = reinterpret_cast<uint16_t*>(&image[0] + y * pitch);
350 for (int x = 0; x < width; x++, p++, v++)
351 {
352 *p = v;
353 }
354 }
355
356 Orthanc::ImageAccessor accessor;
357 accessor.AssignReadOnly(Orthanc::PixelFormat_Grayscale16, width, height, pitch, &image[0]);
358 w.WriteToFile("UnitTestsResults/Gray16Pattern.pam", accessor);
359
360 std::string f, md5;
361 Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/Gray16Pattern.pam");
362 Orthanc::Toolbox::ComputeMD5(md5, f);
363 ASSERT_EQ("b268772bf28f3b2b8520ff21c5e3dcb6", md5);
364 }
365
366 TEST(PamWriter, EndToEnd)
367 {
368 Orthanc::PamWriter w;
369 unsigned int width = 256;
370 unsigned int height = 256;
371 unsigned int pitch = width * 2 + 16;
372
373 std::vector<uint8_t> image(height * pitch);
374
375 int v = 0;
376 for (unsigned int y = 0; y < height; y++)
377 {
378 uint16_t *p = reinterpret_cast<uint16_t*>(&image[0] + y * pitch);
379 for (unsigned int x = 0; x < width; x++, p++, v++)
380 {
381 *p = v;
382 }
383 }
384
385 Orthanc::ImageAccessor accessor;
386 accessor.AssignReadOnly(Orthanc::PixelFormat_Grayscale16, width, height, pitch, &image[0]);
387
388 std::string s;
389 w.WriteToMemory(s, accessor);
390
391 {
392 Orthanc::PamReader r;
393 r.ReadFromMemory(s);
394
395 ASSERT_EQ(r.GetFormat(), Orthanc::PixelFormat_Grayscale16);
396 ASSERT_EQ(r.GetWidth(), width);
397 ASSERT_EQ(r.GetHeight(), height);
398
399 v = 0;
400 for (unsigned int y = 0; y < height; y++)
401 {
402 const uint16_t *p = reinterpret_cast<const uint16_t*>
403 ((const uint8_t*) r.GetConstBuffer() + y * r.GetPitch());
404 ASSERT_EQ(p, r.GetConstRow(y));
405 for (unsigned int x = 0; x < width; x++, p++, v++)
406 {
407 ASSERT_EQ(v, *p);
408 }
409 }
410 }
411
412 {
413 // true means "enforce alignment by using a temporary buffer"
414 Orthanc::PamReader r(true);
415 r.ReadFromMemory(s);
416
417 ASSERT_EQ(r.GetFormat(), Orthanc::PixelFormat_Grayscale16);
418 ASSERT_EQ(r.GetWidth(), width);
419 ASSERT_EQ(r.GetHeight(), height);
420
421 v = 0;
422 for (unsigned int y = 0; y < height; y++)
423 {
424 const uint16_t* p = reinterpret_cast<const uint16_t*>
425 ((const uint8_t*)r.GetConstBuffer() + y * r.GetPitch());
426 ASSERT_EQ(p, r.GetConstRow(y));
427 for (unsigned int x = 0; x < width; x++, p++, v++)
428 {
429 ASSERT_EQ(v, *p);
430 }
431 }
432 }
433
434 {
435 Orthanc::TemporaryFile tmp;
436 tmp.Write(s);
437
438 Orthanc::PamReader r2;
439 r2.ReadFromFile(tmp.GetPath());
440
441 ASSERT_EQ(r2.GetFormat(), Orthanc::PixelFormat_Grayscale16);
442 ASSERT_EQ(r2.GetWidth(), width);
443 ASSERT_EQ(r2.GetHeight(), height);
444
445 v = 0;
446 for (unsigned int y = 0; y < height; y++)
447 {
448 const uint16_t *p = reinterpret_cast<const uint16_t*>
449 ((const uint8_t*) r2.GetConstBuffer() + y * r2.GetPitch());
450 ASSERT_EQ(p, r2.GetConstRow(y));
451 for (unsigned int x = 0; x < width; x++, p++, v++)
452 {
453 ASSERT_EQ(*p, v);
454 }
455 }
456 }
457
458 {
459 Orthanc::TemporaryFile tmp;
460 tmp.Write(s);
461
462 // true means "enforce alignment by using a temporary buffer"
463 Orthanc::PamReader r2(true);
464 r2.ReadFromFile(tmp.GetPath());
465
466 ASSERT_EQ(r2.GetFormat(), Orthanc::PixelFormat_Grayscale16);
467 ASSERT_EQ(r2.GetWidth(), width);
468 ASSERT_EQ(r2.GetHeight(), height);
469
470 v = 0;
471 for (unsigned int y = 0; y < height; y++)
472 {
473 const uint16_t* p = reinterpret_cast<const uint16_t*>
474 ((const uint8_t*)r2.GetConstBuffer() + y * r2.GetPitch());
475 ASSERT_EQ(p, r2.GetConstRow(y));
476 for (unsigned int x = 0; x < width; x++, p++, v++)
477 {
478 ASSERT_EQ(*p, v);
479 }
480 }
481 }
482
483 }