File: | dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp |
Warning: | line 113, column 17 Opened stream never closed. Potential resource leak |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* ============================================================ | |||
2 | * | |||
3 | * This file is a part of digiKam project | |||
4 | * https://www.digikam.org | |||
5 | * | |||
6 | * Date : 2006-06-14 | |||
7 | * Description : A JPEG-2000 IO file for DImg framework- load operations | |||
8 | * | |||
9 | * SPDX-FileCopyrightText: 2006-2025 by Gilles Caulier <caulier dot gilles at gmail dot com> | |||
10 | * | |||
11 | * SPDX-License-Identifier: GPL-2.0-or-later | |||
12 | * | |||
13 | * ============================================================ */ | |||
14 | ||||
15 | #include "dimgjpeg2000loader_p.h" | |||
16 | ||||
17 | namespace DigikamJPEG2000DImgPlugin | |||
18 | { | |||
19 | ||||
20 | bool DImgJPEG2000Loader::load(const QString& filePath, DImgLoaderObserver* const observer) | |||
21 | { | |||
22 | readMetadata(filePath); | |||
23 | ||||
24 | #ifdef Q_OS_WIN | |||
25 | ||||
26 | FILE* const file = _wfopen((const wchar_t*)filePath.utf16(), L"rb"); | |||
27 | ||||
28 | #else | |||
29 | ||||
30 | FILE* const file = fopen(filePath.toUtf8().constData(), "rb"); | |||
| ||||
31 | ||||
32 | #endif | |||
33 | ||||
34 | if (!file
| |||
35 | { | |||
36 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 36, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category .name()).warning() << "Unable to open JPEG2000 file"; | |||
37 | loadingFailed(); | |||
38 | ||||
39 | return false; | |||
40 | } | |||
41 | ||||
42 | imageSetAttribute(QLatin1String("format"), QLatin1String("JP2")); | |||
43 | ||||
44 | #if defined JAS_VERSION_MAJOR4 && JAS_VERSION_MAJOR4 >= 3 | |||
45 | ||||
46 | // NOTE: nothing to do. | |||
47 | ||||
48 | #else | |||
49 | ||||
50 | QScopedPointer<DMetadata> metadata(new DMetadata(filePath)); | |||
51 | QSize size = metadata->getItemDimensions(); | |||
52 | QString decoderOptions = QLatin1String("max_samples=100000000"); | |||
53 | ||||
54 | if (size.isValid()) | |||
55 | { | |||
56 | imageWidth() = size.width(); | |||
57 | imageHeight() = size.height(); | |||
58 | decoderOptions = QString::fromLatin1("max_samples=%1").arg(size.width() * size.height() * 4); | |||
59 | qCDebug(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 59, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category .name()).debug() << "JP2 image size:" << size; | |||
60 | } | |||
61 | ||||
62 | if (!(m_loadFlags & LoadImageData) && !(m_loadFlags & LoadICCData)) | |||
63 | { | |||
64 | // libjasper will load the full image in memory already when calling jas_image_decode. | |||
65 | // This is bad when scanning. See bugs 215458 and 195583. | |||
66 | // Exiv2 is used to extract this info. | |||
67 | ||||
68 | fclose(file); | |||
69 | ||||
70 | return true; | |||
71 | } | |||
72 | ||||
73 | #endif | |||
74 | ||||
75 | // ------------------------------------------------------------------- | |||
76 | // Initialize JPEG 2000 API. | |||
77 | ||||
78 | long i = 0; | |||
79 | long x = 0; | |||
80 | long y = 0; | |||
81 | int components[4] = { 0 }; | |||
82 | unsigned int maximum_component_depth = 0; | |||
83 | unsigned int scale[4] = { 0 }; | |||
84 | unsigned int x_step[4] = { 0 }; | |||
85 | unsigned int y_step[4] = { 0 }; | |||
86 | unsigned long number_components = 0; | |||
87 | jas_image_t* jp2_image = nullptr; | |||
88 | jas_stream_t* jp2_stream = nullptr; | |||
89 | jas_matrix_t* pixels[4] = { nullptr }; | |||
90 | ||||
91 | if (initJasper() != 0) | |||
92 | { | |||
93 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 93, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category .name()).warning() << "Unable to init JPEG2000 decoder"; | |||
94 | loadingFailed(); | |||
95 | fclose(file); | |||
96 | ||||
97 | return false; | |||
98 | } | |||
99 | ||||
100 | jp2_stream = jas_stream_freopen(filePath.toUtf8().constData(), "rb", file); | |||
101 | ||||
102 | if (jp2_stream == nullptr) | |||
103 | { | |||
104 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 104, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Unable to open JPEG2000 stream"; | |||
105 | fclose(file); | |||
106 | ||||
107 | cleanupJasper(); | |||
108 | loadingFailed(); | |||
109 | ||||
110 | return false; | |||
111 | } | |||
112 | ||||
113 | int fmt = jas_image_strtofmt(QByteArray("jp2").data()); | |||
| ||||
114 | ||||
115 | #if defined JAS_VERSION_MAJOR4 && JAS_VERSION_MAJOR4 >= 3 | |||
116 | ||||
117 | jp2_image = jas_image_decode(jp2_stream, fmt, nullptr); | |||
118 | ||||
119 | #else | |||
120 | ||||
121 | // See bug 447240 and UPSTREAM https://github.com/jasper-software/jasper/issues/315#issuecomment-1007872809 | |||
122 | ||||
123 | qCDebug(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtDebugMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 123, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).debug() << "jas_image_decode decoder options string:" << decoderOptions; | |||
124 | ||||
125 | jp2_image = jas_image_decode(jp2_stream, fmt, decoderOptions.toLatin1().data()); | |||
126 | ||||
127 | #endif | |||
128 | ||||
129 | if (jp2_image == nullptr) | |||
130 | { | |||
131 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 131, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Unable to decode JPEG2000 image"; | |||
132 | jas_stream_close(jp2_stream); | |||
133 | ||||
134 | cleanupJasper(); | |||
135 | loadingFailed(); | |||
136 | ||||
137 | return false; | |||
138 | } | |||
139 | ||||
140 | jas_stream_close(jp2_stream); | |||
141 | ||||
142 | // some pseudo-progress | |||
143 | ||||
144 | if (observer) | |||
145 | { | |||
146 | observer->progressInfo(0.1F); | |||
147 | } | |||
148 | ||||
149 | // ------------------------------------------------------------------- | |||
150 | // Check color space. | |||
151 | ||||
152 | int colorModel = DImg::COLORMODELUNKNOWN; | |||
153 | ||||
154 | switch (jas_clrspc_fam(jas_image_clrspc(jp2_image))((((jp2_image)->clrspc_)) >> 8)) | |||
155 | { | |||
156 | case JAS_CLRSPC_FAM_RGB4: | |||
157 | { | |||
158 | components[0] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_RGB_R0); | |||
159 | components[1] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_RGB_G1); | |||
160 | components[2] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_RGB_B2); | |||
161 | ||||
162 | if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0)) | |||
163 | { | |||
164 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 164, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Error parsing JPEG2000 image : Missing Image Channel"; | |||
165 | jas_image_destroy(jp2_image); | |||
166 | ||||
167 | cleanupJasper(); | |||
168 | loadingFailed(); | |||
169 | ||||
170 | return false; | |||
171 | } | |||
172 | ||||
173 | number_components = 3; | |||
174 | components[3] = jas_image_getcmptbytype(jp2_image, 3); | |||
175 | ||||
176 | if (components[3] > 0) | |||
177 | { | |||
178 | m_hasAlpha = true; | |||
179 | ++number_components; | |||
180 | } | |||
181 | ||||
182 | colorModel = DImg::RGB; | |||
183 | ||||
184 | break; | |||
185 | } | |||
186 | ||||
187 | case JAS_CLRSPC_FAM_GRAY3: | |||
188 | { | |||
189 | components[0] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_GRAY_Y0); | |||
190 | ||||
191 | // cppcheck-suppress knownConditionTrueFalse | |||
192 | if (components[0] < 0) | |||
193 | { | |||
194 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 194, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Error parsing JP2000 image : Missing Image Channel"; | |||
195 | jas_image_destroy(jp2_image); | |||
196 | ||||
197 | cleanupJasper(); | |||
198 | loadingFailed(); | |||
199 | ||||
200 | return false; | |||
201 | } | |||
202 | ||||
203 | number_components = 1; | |||
204 | colorModel = DImg::GRAYSCALE; | |||
205 | ||||
206 | break; | |||
207 | } | |||
208 | ||||
209 | case JAS_CLRSPC_FAM_YCBCR5: | |||
210 | { | |||
211 | components[0] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_YCBCR_Y0); | |||
212 | components[1] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_YCBCR_CB1); | |||
213 | components[2] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_YCBCR_CR2); | |||
214 | ||||
215 | // cppcheck-suppress knownConditionTrueFalse | |||
216 | if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0)) | |||
217 | { | |||
218 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 218, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Error parsing JP2000 image : Missing Image Channel"; | |||
219 | jas_image_destroy(jp2_image); | |||
220 | ||||
221 | cleanupJasper(); | |||
222 | loadingFailed(); | |||
223 | ||||
224 | return false; | |||
225 | } | |||
226 | ||||
227 | number_components = 3; | |||
228 | components[3] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_UNKNOWN0x10000); | |||
229 | ||||
230 | if (components[3] > 0) | |||
231 | { | |||
232 | m_hasAlpha = true; | |||
233 | ++number_components; | |||
234 | } | |||
235 | ||||
236 | // FIXME: image->colorspace = YCbCrColorspace; | |||
237 | ||||
238 | colorModel = DImg::YCBCR; | |||
239 | ||||
240 | break; | |||
241 | } | |||
242 | ||||
243 | default: | |||
244 | { | |||
245 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 245, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Error parsing JP2000 image : Colorspace Model Is Not Supported"; | |||
246 | jas_image_destroy(jp2_image); | |||
247 | ||||
248 | cleanupJasper(); | |||
249 | loadingFailed(); | |||
250 | ||||
251 | return false; | |||
252 | } | |||
253 | } | |||
254 | ||||
255 | // ------------------------------------------------------------------- | |||
256 | // Check image geometry. | |||
257 | ||||
258 | imageWidth() = jas_image_width(jp2_image)((jp2_image)->brx_ - (jp2_image)->tlx_); | |||
259 | imageHeight() = jas_image_height(jp2_image)((jp2_image)->bry_ - (jp2_image)->tly_); | |||
260 | ||||
261 | for (i = 0 ; i < (long)number_components ; ++i) | |||
262 | { | |||
263 | if ( | |||
264 | ( | |||
265 | ((jas_image_cmptwidth(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->width_)* | |||
266 | jas_image_cmpthstep(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->hstep_)) != (long)imageWidth()) | |||
267 | ) || | |||
268 | ( | |||
269 | ((jas_image_cmptheight(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->height_)* | |||
270 | jas_image_cmptvstep(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->vstep_)) != (long)imageHeight()) | |||
271 | ) || | |||
272 | (jas_image_cmpttlx(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->tlx_) != 0) || | |||
273 | (jas_image_cmpttly(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->tly_) != 0) || | |||
274 | (jas_image_cmptsgnd(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->sgnd_) != false) | |||
275 | ) | |||
276 | { | |||
277 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 277, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Error parsing JPEG2000 image : Irregular Channel Geometry Not Supported"; | |||
278 | jas_image_destroy(jp2_image); | |||
279 | ||||
280 | cleanupJasper(); | |||
281 | loadingFailed(); | |||
282 | ||||
283 | return false; | |||
284 | } | |||
285 | ||||
286 | x_step[i] = jas_image_cmpthstep(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->hstep_); | |||
287 | y_step[i] = jas_image_cmptvstep(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->vstep_); | |||
288 | } | |||
289 | ||||
290 | // ------------------------------------------------------------------- | |||
291 | // Get image format. | |||
292 | ||||
293 | maximum_component_depth = 0; | |||
294 | ||||
295 | for (i = 0 ; i < (long)number_components ; ++i) | |||
296 | { | |||
297 | maximum_component_depth = qMax((long)jas_image_cmptprec(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->prec_), | |||
298 | (long)maximum_component_depth); | |||
299 | ||||
300 | pixels[i] = jas_matrix_create(1, ((unsigned int)imageWidth()) / x_step[i]); | |||
301 | ||||
302 | if (!pixels[i]) | |||
303 | { | |||
304 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 304, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Error decoding JPEG2000 image data : Memory Allocation Failed"; | |||
305 | jas_image_destroy(jp2_image); | |||
306 | ||||
307 | cleanupJasper(); | |||
308 | loadingFailed(); | |||
309 | ||||
310 | return false; | |||
311 | } | |||
312 | } | |||
313 | ||||
314 | #if defined JAS_VERSION_MAJOR4 && JAS_VERSION_MAJOR4 >= 3 | |||
315 | ||||
316 | if (!(m_loadFlags & LoadImageData) && !(m_loadFlags & LoadICCData)) | |||
317 | { | |||
318 | imageSetAttribute(QLatin1String("originalColorModel"), colorModel); | |||
319 | imageSetAttribute(QLatin1String("originalBitDepth"), maximum_component_depth); | |||
320 | imageSetAttribute(QLatin1String("originalSize"), QSize(imageWidth(), imageHeight())); | |||
321 | ||||
322 | jas_image_destroy(jp2_image); | |||
323 | cleanupJasper(); | |||
324 | ||||
325 | return true; | |||
326 | } | |||
327 | ||||
328 | #endif | |||
329 | ||||
330 | if (maximum_component_depth > 8) | |||
331 | { | |||
332 | m_sixteenBit = true; | |||
333 | } | |||
334 | ||||
335 | for (i = 0 ; i < (long)number_components ; ++i) | |||
336 | { | |||
337 | scale[i] = 1; | |||
338 | int prec = jas_image_cmptprec(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->prec_); | |||
339 | ||||
340 | if (m_sixteenBit && (prec < 16)) | |||
341 | { | |||
342 | scale[i] = (1 << (16 - jas_image_cmptprec(jp2_image, components[i])((jp2_image)->cmpts_[components[i]]->prec_))); | |||
343 | } | |||
344 | } | |||
345 | ||||
346 | // ------------------------------------------------------------------- | |||
347 | // Get image data. | |||
348 | ||||
349 | QScopedArrayPointer<uchar> data; | |||
350 | ||||
351 | if (m_loadFlags & LoadImageData) | |||
352 | { | |||
353 | if (m_sixteenBit) // 16 bits image. | |||
354 | { | |||
355 | data.reset(new_failureTolerant(imageWidth(), imageHeight(), 8)); | |||
356 | } | |||
357 | else | |||
358 | { | |||
359 | data.reset(new_failureTolerant(imageWidth(), imageHeight(), 4)); | |||
360 | } | |||
361 | ||||
362 | if (!data) | |||
363 | { | |||
364 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 364, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Error decoding JPEG2000 image data : Memory Allocation Failed"; | |||
365 | jas_image_destroy(jp2_image); | |||
366 | ||||
367 | for (i = 0 ; i < (long)number_components ; ++i) | |||
368 | { | |||
369 | jas_matrix_destroy(pixels[i]); | |||
370 | } | |||
371 | ||||
372 | cleanupJasper(); | |||
373 | loadingFailed(); | |||
374 | ||||
375 | return false; | |||
376 | } | |||
377 | ||||
378 | uint checkPoint = 0; | |||
379 | uchar* dst = data.data(); | |||
380 | unsigned short* dst16 = reinterpret_cast<unsigned short*>(data.data()); | |||
381 | ||||
382 | for (y = 0 ; y < (long)imageHeight() ; ++y) | |||
383 | { | |||
384 | for (i = 0 ; i < (long)number_components ; ++i) | |||
385 | { | |||
386 | int ret = jas_image_readcmpt(jp2_image, (short)components[i], 0, | |||
387 | ((unsigned int) y) / y_step[i], | |||
388 | ((unsigned int) imageWidth()) / x_step[i], | |||
389 | 1, pixels[i]); | |||
390 | ||||
391 | if (ret != 0) | |||
392 | { | |||
393 | qCWarning(DIGIKAM_DIMG_LOG_JP2K)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG_JP2K)()); qt_category; qt_category.control = false) QMessageLogger(static_cast<const char *>("/home/gilles/devel/8.x/core/dplugins/dimg/jpeg2000/dimgjpeg2000loader_load.cpp" ), 393, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Error decoding JPEG2000 image data"; | |||
394 | jas_image_destroy(jp2_image); | |||
395 | ||||
396 | for (i = 0 ; i < (long)number_components ; ++i) | |||
397 | { | |||
398 | jas_matrix_destroy(pixels[i]); | |||
399 | } | |||
400 | ||||
401 | cleanupJasper(); | |||
402 | loadingFailed(); | |||
403 | ||||
404 | return false; | |||
405 | } | |||
406 | } | |||
407 | ||||
408 | switch (number_components) | |||
409 | { | |||
410 | case 1: // Grayscale. | |||
411 | { | |||
412 | if (!m_sixteenBit) // 8 bits image. | |||
413 | { | |||
414 | for (x = 0 ; x < (long)imageWidth() ; ++x) | |||
415 | { | |||
416 | dst[0] = (uchar)(scale[0] * jas_matrix_getv(pixels[0], x / x_step[0])); | |||
417 | dst[1] = dst[0]; | |||
418 | dst[2] = dst[0]; | |||
419 | dst[3] = 0xFF; | |||
420 | ||||
421 | dst += 4; | |||
422 | } | |||
423 | } | |||
424 | else // 16 bits image. | |||
425 | { | |||
426 | for (x = 0 ; x < (long)imageWidth() ; ++x) | |||
427 | { | |||
428 | dst16[0] = (unsigned short)(scale[0] * jas_matrix_getv(pixels[0], x / x_step[0])); | |||
429 | dst16[1] = dst16[0]; | |||
430 | dst16[2] = dst16[0]; | |||
431 | dst16[3] = 0xFFFF; | |||
432 | ||||
433 | dst16 += 4; | |||
434 | } | |||
435 | } | |||
436 | ||||
437 | break; | |||
438 | } | |||
439 | ||||
440 | case 3: // RGB. | |||
441 | { | |||
442 | if (!m_sixteenBit) // 8 bits image. | |||
443 | { | |||
444 | for (x = 0 ; x < (long)imageWidth() ; ++x) | |||
445 | { | |||
446 | // Blue | |||
447 | dst[0] = (uchar)(scale[2] * jas_matrix_getv(pixels[2], x / x_step[2])); | |||
448 | // Green | |||
449 | dst[1] = (uchar)(scale[1] * jas_matrix_getv(pixels[1], x / x_step[1])); | |||
450 | // Red | |||
451 | dst[2] = (uchar)(scale[0] * jas_matrix_getv(pixels[0], x / x_step[0])); | |||
452 | // Alpha | |||
453 | dst[3] = 0xFF; | |||
454 | ||||
455 | dst += 4; | |||
456 | } | |||
457 | } | |||
458 | else // 16 bits image. | |||
459 | { | |||
460 | for (x = 0 ; x < (long)imageWidth() ; ++x) | |||
461 | { | |||
462 | // Blue | |||
463 | dst16[0] = (unsigned short)(scale[2] * jas_matrix_getv(pixels[2], x / x_step[2])); | |||
464 | // Green | |||
465 | dst16[1] = (unsigned short)(scale[1] * jas_matrix_getv(pixels[1], x / x_step[1])); | |||
466 | // Red | |||
467 | dst16[2] = (unsigned short)(scale[0] * jas_matrix_getv(pixels[0], x / x_step[0])); | |||
468 | // Alpha | |||
469 | dst16[3] = 0xFFFF; | |||
470 | ||||
471 | dst16 += 4; | |||
472 | } | |||
473 | } | |||
474 | ||||
475 | break; | |||
476 | } | |||
477 | ||||
478 | case 4: // RGBA. | |||
479 | { | |||
480 | if (!m_sixteenBit) // 8 bits image. | |||
481 | { | |||
482 | for (x = 0 ; x < (long)imageWidth() ; ++x) | |||
483 | { | |||
484 | // Blue | |||
485 | dst[0] = (uchar)(scale[2] * jas_matrix_getv(pixels[2], x / x_step[2])); | |||
486 | // Green | |||
487 | dst[1] = (uchar)(scale[1] * jas_matrix_getv(pixels[1], x / x_step[1])); | |||
488 | // Red | |||
489 | dst[2] = (uchar)(scale[0] * jas_matrix_getv(pixels[0], x / x_step[0])); | |||
490 | // Alpha | |||
491 | dst[3] = (uchar)(scale[3] * jas_matrix_getv(pixels[3], x / x_step[3])); | |||
492 | ||||
493 | dst += 4; | |||
494 | } | |||
495 | } | |||
496 | else // 16 bits image. | |||
497 | { | |||
498 | for (x = 0 ; x < (long)imageWidth() ; ++x) | |||
499 | { | |||
500 | // Blue | |||
501 | dst16[0] = (unsigned short)(scale[2] * jas_matrix_getv(pixels[2], x / x_step[2])); | |||
502 | // Green | |||
503 | dst16[1] = (unsigned short)(scale[1] * jas_matrix_getv(pixels[1], x / x_step[1])); | |||
504 | // Red | |||
505 | dst16[2] = (unsigned short)(scale[0] * jas_matrix_getv(pixels[0], x / x_step[0])); | |||
506 | // Alpha | |||
507 | dst16[3] = (unsigned short)(scale[3] * jas_matrix_getv(pixels[3], x / x_step[3])); | |||
508 | ||||
509 | dst16 += 4; | |||
510 | } | |||
511 | } | |||
512 | ||||
513 | break; | |||
514 | } | |||
515 | } | |||
516 | ||||
517 | // Use 0-10% and 90-100% for pseudo-progress | |||
518 | ||||
519 | if (observer && (y >= (long)checkPoint)) | |||
520 | { | |||
521 | checkPoint += granularity(observer, y, 0.8F); | |||
522 | ||||
523 | if (!observer->continueQuery()) | |||
524 | { | |||
525 | jas_image_destroy(jp2_image); | |||
526 | ||||
527 | for (i = 0 ; i < (long)number_components ; ++i) | |||
528 | { | |||
529 | jas_matrix_destroy(pixels[i]); | |||
530 | } | |||
531 | ||||
532 | cleanupJasper(); | |||
533 | loadingFailed(); | |||
534 | ||||
535 | return false; | |||
536 | } | |||
537 | ||||
538 | observer->progressInfo(0.1F + (0.8F * (((float)y) / ((float)imageHeight())))); | |||
539 | } | |||
540 | } | |||
541 | } | |||
542 | ||||
543 | // ------------------------------------------------------------------- | |||
544 | // Get ICC color profile. | |||
545 | ||||
546 | if (m_loadFlags & LoadICCData) | |||
547 | { | |||
548 | jas_iccprof_t* icc_profile = nullptr; | |||
549 | jas_stream_t* icc_stream = nullptr; | |||
550 | jas_cmprof_t* cm_profile = nullptr; | |||
551 | ||||
552 | // To prevent cppcheck warnings. | |||
553 | ||||
554 | (void)icc_profile; | |||
555 | (void)icc_stream; | |||
556 | (void)cm_profile; | |||
557 | ||||
558 | cm_profile = jas_image_cmprof(jp2_image)((jp2_image)->cmprof_); | |||
559 | ||||
560 | if (cm_profile != nullptr) | |||
561 | { | |||
562 | icc_profile = jas_iccprof_createfromcmprof(cm_profile); | |||
563 | } | |||
564 | ||||
565 | if (icc_profile != nullptr) | |||
566 | { | |||
567 | icc_stream = jas_stream_memopen(nullptr, 0); | |||
568 | ||||
569 | if (icc_stream != nullptr) | |||
570 | { | |||
571 | if (jas_iccprof_save(icc_profile, icc_stream) == 0) | |||
572 | { | |||
573 | if (jas_stream_flush(icc_stream) == 0) | |||
574 | { | |||
575 | jas_stream_memobj_t* const blob = reinterpret_cast<jas_stream_memobj_t*>(icc_stream->obj_); | |||
576 | QByteArray profile_rawdata; | |||
577 | profile_rawdata.resize(blob->len_); | |||
578 | memcpy(profile_rawdata.data(), blob->buf_, blob->len_); | |||
579 | imageSetIccProfile(IccProfile(profile_rawdata)); | |||
580 | jas_stream_close(icc_stream); | |||
581 | } | |||
582 | } | |||
583 | } | |||
584 | } | |||
585 | else | |||
586 | { | |||
587 | // If ICC profile is null, check Exif metadata. | |||
588 | ||||
589 | checkExifWorkingColorSpace(); | |||
590 | } | |||
591 | } | |||
592 | ||||
593 | if (observer) | |||
594 | { | |||
595 | observer->progressInfo(1.0F); | |||
596 | } | |||
597 | ||||
598 | imageData() = data.take(); | |||
599 | imageSetAttribute(QLatin1String("originalColorModel"), colorModel); | |||
600 | imageSetAttribute(QLatin1String("originalBitDepth"), maximum_component_depth); | |||
601 | imageSetAttribute(QLatin1String("originalSize"), QSize(imageWidth(), imageHeight())); | |||
602 | ||||
603 | jas_image_destroy(jp2_image); | |||
604 | ||||
605 | for (i = 0 ; i < (long)number_components ; ++i) | |||
606 | { | |||
607 | jas_matrix_destroy(pixels[i]); | |||
608 | } | |||
609 | ||||
610 | cleanupJasper(); | |||
611 | ||||
612 | return true; | |||
613 | } | |||
614 | ||||
615 | } // namespace DigikamJPEG2000DImgPlugin |