Mercurial > hg > orthanc-wsi
comparison Framework/Inputs/PlainTiff.cpp @ 298:fa734a851551
New option: "tiff-alignment" to control deep zoom of plain TIFF over IIIF
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 18 Jul 2023 08:19:16 +0200 |
parents | |
children | 7020852a8fa9 |
comparison
equal
deleted
inserted
replaced
297:c1687b8fc800 | 298:fa734a851551 |
---|---|
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-2023 Osimis S.A., Belgium | |
6 * Copyright (C) 2021-2023 Sebastien Jodogne, ICTEAM UCLouvain, Belgium | |
7 * | |
8 * This program is free software: you can redistribute it and/or | |
9 * modify it under the terms of the GNU Affero General Public License | |
10 * as published by the Free Software Foundation, either version 3 of | |
11 * the License, or (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, but | |
14 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 * Affero General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU Affero General Public License | |
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 **/ | |
21 | |
22 | |
23 #include "PlainTiff.h" | |
24 | |
25 #include "../TiffReader.h" | |
26 | |
27 #include <Images/Image.h> | |
28 #include <Images/ImageProcessing.h> | |
29 #include <Logging.h> | |
30 #include <OrthancException.h> | |
31 | |
32 #include <cassert> | |
33 #include <string.h> | |
34 | |
35 | |
36 namespace OrthancWSI | |
37 { | |
38 PlainTiff::PlainTiff(const std::string& path, | |
39 unsigned int tileWidth, | |
40 unsigned int tileHeight, | |
41 unsigned int paddingAlignement, | |
42 uint8_t paddingRed, | |
43 uint8_t paddingGreen, | |
44 uint8_t paddingBlue) : | |
45 SingleLevelDecodedPyramid(tileWidth, tileHeight) | |
46 { | |
47 TiffReader reader(path); | |
48 | |
49 // Look for the largest sub-image | |
50 bool first = true; | |
51 unsigned int width = 0; | |
52 unsigned int height = 0; | |
53 tdir_t largest = 0; | |
54 | |
55 tdir_t pos = 0; | |
56 | |
57 do | |
58 { | |
59 uint32_t w, h, tw, th; | |
60 | |
61 if (TIFFSetDirectory(reader.GetTiff(), pos) && | |
62 !TIFFGetField(reader.GetTiff(), TIFFTAG_TILEWIDTH, &tw) && // Must not be a tiled image | |
63 !TIFFGetField(reader.GetTiff(), TIFFTAG_TILELENGTH, &th) && // Must not be a tiled image | |
64 TIFFGetField(reader.GetTiff(), TIFFTAG_IMAGEWIDTH, &w) && | |
65 TIFFGetField(reader.GetTiff(), TIFFTAG_IMAGELENGTH, &h) && | |
66 w > 0 && | |
67 h > 0) | |
68 { | |
69 if (first) | |
70 { | |
71 first = false; | |
72 width = w; | |
73 height = h; | |
74 largest = pos; | |
75 } | |
76 else if (w > width && | |
77 h > height) | |
78 { | |
79 width = w; | |
80 height = h; | |
81 largest = pos; | |
82 } | |
83 } | |
84 | |
85 pos++; | |
86 } | |
87 while (TIFFReadDirectory(reader.GetTiff())); | |
88 | |
89 if (first) | |
90 { | |
91 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "This is an empty TIFF image"); | |
92 } | |
93 | |
94 // Back to the largest directory | |
95 if (!TIFFSetDirectory(reader.GetTiff(), largest)) | |
96 { | |
97 throw Orthanc::OrthancException(Orthanc::ErrorCode_CorruptedFile); | |
98 } | |
99 | |
100 ImageCompression compression; | |
101 Orthanc::PixelFormat pixelFormat; | |
102 Orthanc::PhotometricInterpretation photometric; | |
103 | |
104 if (!reader.GetCurrentDirectoryInformation(compression, pixelFormat, photometric)) | |
105 { | |
106 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
107 } | |
108 | |
109 if (pixelFormat != Orthanc::PixelFormat_RGB24) | |
110 { | |
111 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
112 } | |
113 | |
114 LOG(WARNING) << "Size of the source TIFF image: " << width << "x" << height; | |
115 | |
116 const unsigned int paddedWidth = paddingAlignement * CeilingDivision(width, paddingAlignement); | |
117 const unsigned int paddedHeight = paddingAlignement * CeilingDivision(height, paddingAlignement); | |
118 assert(paddedWidth >= width && | |
119 paddedHeight >= height); | |
120 | |
121 LOG(WARNING) << "Size of the padded TIFF image: " << paddedWidth << "x" << paddedHeight; | |
122 | |
123 decoded_.reset(new Orthanc::Image(pixelFormat, paddedWidth, paddedHeight, false)); | |
124 Orthanc::ImageProcessing::Set(*decoded_, paddingRed, paddingGreen, paddingBlue, 255); | |
125 | |
126 std::string strip; | |
127 strip.resize(TIFFStripSize(reader.GetTiff())); | |
128 | |
129 const size_t stripPitch = width * Orthanc::GetBytesPerPixel(pixelFormat); | |
130 | |
131 if (strip.empty() || | |
132 stripPitch == 0 || | |
133 strip.size() < stripPitch || | |
134 strip.size() % stripPitch != 0) | |
135 { | |
136 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
137 } | |
138 | |
139 const size_t stripHeight = (strip.size() / stripPitch); | |
140 const size_t stripCount = CeilingDivision(height, stripHeight); | |
141 | |
142 if (TIFFNumberOfStrips(reader.GetTiff()) != stripCount) | |
143 { | |
144 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
145 } | |
146 | |
147 for (unsigned int i = 0; i < stripCount; i++) | |
148 { | |
149 TIFFReadEncodedStrip(reader.GetTiff(), i, &strip[0], static_cast<tsize_t>(-1)); | |
150 | |
151 const unsigned int y = i * stripHeight; | |
152 | |
153 const uint8_t* p = reinterpret_cast<const uint8_t*>(&strip[0]); | |
154 uint8_t* q = reinterpret_cast<uint8_t*>(decoded_->GetRow(y)); | |
155 | |
156 for (unsigned j = 0; j < stripHeight && y + j < height; j++) | |
157 { | |
158 memcpy(q, p, stripPitch); | |
159 p += stripPitch; | |
160 q += decoded_->GetPitch(); | |
161 } | |
162 } | |
163 | |
164 SetImage(*decoded_); | |
165 } | |
166 } |