1212
1313namespace cv
1414{
15+ // Callback functions for JpegXLDecoder
16+ static void cbRGBtoBGR_8U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
17+ static void cbRGBAtoBGRA_8U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
18+ static void cbRGBtoBGR_16U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
19+ static void cbRGBAtoBGRA_16U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
20+ static void cbRGBtoBGR_32F (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
21+ static void cbRGBAtoBGRA_32F (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
22+ static void cbRGBtoGRAY_8U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
23+ static void cbRGBAtoGRAY_8U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
24+ static void cbRGBtoGRAY_16U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
25+ static void cbRGBAtoGRAY_16U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
26+ static void cbRGBtoGRAY_32F (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
27+ static void cbRGBAtoGRAY_32F (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels);
1528
1629// ///////////////////// JpegXLDecoder ///////////////////
1730
@@ -20,7 +33,7 @@ JpegXLDecoder::JpegXLDecoder() : m_f(nullptr, &fclose)
2033 m_signature =" \xFF\x0A " ;
2134 m_decoder =nullptr ;
2235 m_buf_supported =false ;
23- m_type =m_convert = -1 ;
36+ m_type = -1 ;
2437 m_status = JXL_DEC_NEED_MORE_INPUT;
2538}
2639
@@ -37,7 +50,7 @@ void JpegXLDecoder::close()
3750 m_f.reset ();
3851 m_read_buffer = {};
3952 m_width = m_height =0 ;
40- m_type =m_convert = -1 ;
53+ m_type = -1 ;
4154 m_status = JXL_DEC_NEED_MORE_INPUT;
4255}
4356
@@ -76,7 +89,7 @@ ImageDecoder JpegXLDecoder::newDecoder() const
7689return makePtr<JpegXLDecoder>();
7790}
7891
79- bool JpegXLDecoder::read (Mat* pimg )
92+ bool JpegXLDecoder::readHeader ( )
8093{
8194// Open file
8295if (!m_f) {
@@ -106,24 +119,87 @@ bool JpegXLDecoder::read(Mat* pimg)
106119 }
107120 }
108121
109- // Create buffer for reading
110- const size_t read_buffer_size =16384 ;// 16KB chunks
111- if (m_read_buffer.capacity () < read_buffer_size)
112- m_read_buffer.resize (read_buffer_size);
122+ return read ();
123+ }
113124
114- // Create image if needed
115- if (m_type != -1 && pimg) {
116- pimg->create (m_height, m_width, m_type);
117- if (!pimg->isContinuous ())
125+ bool JpegXLDecoder::readData (Mat& img)
126+ {
127+ if (!m_decoder || m_width ==0 || m_height ==0 || m_type == -1 )
128+ return false ;
129+
130+ // Prepare to decode image
131+ const uint32_t scn =CV_MAT_CN (m_type);// from image
132+ const uint32_t dcn = (uint32_t )img.channels ();// to OpenCV
133+ const int depth =CV_MAT_DEPTH (img.type ());
134+ JxlImageOutCallback cbFunc =nullptr ;
135+
136+ CV_CheckChannels (scn, (scn ==1 || scn ==3 || scn ==4 )," Unsupported src channels" );
137+ CV_CheckChannels (dcn, (dcn ==1 || dcn ==3 || dcn ==4 )," Unsupported dst channels" );
138+ CV_CheckDepth (depth, (depth == CV_8U || depth == CV_16U || depth == CV_32F)," Unsupported depth" );
139+
140+ m_format = {
141+ dcn,
142+ JXL_TYPE_UINT8,// (temporary)
143+ JXL_NATIVE_ENDIAN,// endianness
144+ 0 // align stride to bytes
145+ };
146+ switch (depth) {
147+ case CV_8U: m_format.data_type = JXL_TYPE_UINT8;break ;
148+ case CV_16U: m_format.data_type = JXL_TYPE_UINT16;break ;
149+ case CV_32F: m_format.data_type = JXL_TYPE_FLOAT;break ;
150+ default :break ;
151+ }
152+ // libjxl cannot read to BGR pixel order directly.
153+ // So we have to use callback function to convert from RGB(A) to BGR(A).
154+ if (!m_use_rgb) {
155+ switch (dcn) {
156+ case 1 :break ;
157+ case 3 : cbFunc = (depth == CV_32F)? cbRGBtoBGR_32F: (depth == CV_16U)? cbRGBtoBGR_16U: cbRGBtoBGR_8U;break ;
158+ case 4 : cbFunc = (depth == CV_32F)? cbRGBAtoBGRA_32F: (depth == CV_16U)? cbRGBAtoBGRA_16U: cbRGBAtoBGRA_8U;break ;
159+ default :break ;
160+ }
161+ }
162+ // libjxl cannot convert from color image to gray image directly.
163+ // So we have to use callback function to convert from RGB(A) to GRAY.
164+ if ( (scn >=3 ) && (dcn ==1 ) )
165+ {
166+ m_format.num_channels = scn;
167+ switch (scn) {
168+ case 3 : cbFunc = (depth == CV_32F)? cbRGBtoGRAY_32F: (depth == CV_16U)? cbRGBtoGRAY_16U: cbRGBtoGRAY_8U;break ;
169+ case 4 : cbFunc = (depth == CV_32F)? cbRGBAtoGRAY_32F: (depth == CV_16U)? cbRGBAtoGRAY_16U: cbRGBAtoGRAY_8U;break ;
170+ default :break ;
171+ }
172+ }
173+ if (cbFunc !=nullptr )
174+ {
175+ if (JXL_DEC_SUCCESS !=JxlDecoderSetImageOutCallback (m_decoder.get (),
176+ &m_format,
177+ cbFunc,
178+ static_cast <void *>(&img)))
179+ {
118180return false ;
181+ }
182+ }else {
119183if (JXL_DEC_SUCCESS !=JxlDecoderSetImageOutBuffer (m_decoder.get (),
120184 &m_format,
121- pimg->ptr <uint8_t >(),
122- pimg->total () * pimg->elemSize ())) {
185+ img.ptr <uint8_t >(),
186+ img.total () * img.elemSize ()))
187+ {
123188return false ;
124189 }
125190 }
126191
192+ return read ();
193+ }
194+
195+ // Common reading routine for readHeader() and readBody()
196+ bool JpegXLDecoder::read ()
197+ {
198+ // Create buffer for reading
199+ const size_t read_buffer_size =16384 ;// 16KB chunks
200+ if (m_read_buffer.capacity () < read_buffer_size)
201+ m_read_buffer.resize (read_buffer_size);
202+
127203// Start decoding loop
128204do {
129205// Check if we need more input
@@ -163,6 +239,7 @@ bool JpegXLDecoder::read(Mat* pimg)
163239case JXL_DEC_BASIC_INFO: {
164240if (m_type != -1 )
165241return false ;
242+
166243 JxlBasicInfo info;
167244if (JXL_DEC_SUCCESS !=JxlDecoderGetBasicInfo (m_decoder.get (), &info))
168245return false ;
@@ -172,49 +249,18 @@ bool JpegXLDecoder::read(Mat* pimg)
172249
173250 m_width = info.xsize ;
174251 m_height = info.ysize ;
175- m_format = {
176- ncn,
177- JXL_TYPE_UINT8,// (temporary)
178- JXL_LITTLE_ENDIAN,// endianness
179- 0 // align stride to bytes
180- };
181- if (!m_use_rgb) {
182- switch (ncn) {
183- case 3 :
184- m_convert = cv::COLOR_RGB2BGR;
185- break ;
186- case 4 :
187- m_convert = cv::COLOR_RGBA2BGRA;
188- break ;
189- default :
190- m_convert = -1 ;
191- }
192- }
193- if (info.exponent_bits_per_sample >0 ) {
194- m_format.data_type = JXL_TYPE_FLOAT;
195- m_type =CV_MAKETYPE ( CV_32F, ncn );
196- }else {
197- switch (info.bits_per_sample ) {
198- case 8 :
199- m_format.data_type = JXL_TYPE_UINT8;
200- m_type =CV_MAKETYPE ( CV_8U, ncn );
201- break ;
202- case 16 :
203- m_format.data_type = JXL_TYPE_UINT16;
204- m_type =CV_MAKETYPE ( CV_16U, ncn );
205- break ;
206- default :
207- return false ;
208- }
252+ int depth = (info.exponent_bits_per_sample >0 )?CV_32F:
253+ (info.bits_per_sample ==16 )?CV_16U:
254+ (info.bits_per_sample ==8 )?CV_8U: -1 ;
255+ if (depth == -1 )
256+ {
257+ return false ;// Return to readHeader()
209258 }
210- if (!pimg)
211- return true ;
212- break ;
259+ m_type =CV_MAKETYPE ( depth, ncn );
260+ return true ;
213261 }
214262case JXL_DEC_FULL_IMAGE: {
215263// Image is ready
216- if (m_convert != -1 )
217- cv::cvtColor (*pimg, *pimg, m_convert);
218264break ;
219265 }
220266case JXL_DEC_ERROR: {
@@ -229,17 +275,172 @@ bool JpegXLDecoder::read(Mat* pimg)
229275return true ;
230276}
231277
232- bool JpegXLDecoder::readHeader ()
278+ // Callback functopms
279+ static void cbRGBtoBGR_8U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
233280{
234- close ();
235- return read (nullptr );
281+ const uint8_t * src =static_cast <const uint8_t *>(pixels);
282+
283+ constexpr int dstStep =3 ;
284+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
285+ uint8_t * dstBase =const_cast <uint8_t *>(pDst->ptr (y));
286+ uint8_t * dst = dstBase + x * dstStep;
287+
288+ icvCvt_RGB2BGR_8u_C3R ( src,0 , dst,0 ,Size (num_pixels ,1 ) );
236289}
290+ static void cbRGBAtoBGRA_8U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
291+ {
292+ const uint8_t * src =static_cast <const uint8_t *>(pixels);
237293
238- bool JpegXLDecoder::readData (Mat& img)
294+ constexpr int dstStep =4 ;
295+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
296+ uint8_t * dstBase =const_cast <uint8_t *>(reinterpret_cast <const uint8_t *>(pDst->ptr (y)));
297+ uint8_t * dst = dstBase + x * dstStep;
298+
299+ icvCvt_RGBA2BGRA_8u_C4R ( src,0 , dst,0 ,Size (num_pixels,1 ) );
300+ }
301+ static void cbRGBtoBGR_16U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
239302{
240- if (!m_decoder || m_width ==0 || m_height ==0 )
241- return false ;
242- return read (&img);
303+ const uint16_t * src =static_cast <const uint16_t *>(pixels);
304+
305+ constexpr int dstStep =3 ;
306+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
307+ uint16_t * dstBase =const_cast <uint16_t *>(reinterpret_cast <const uint16_t *>(pDst->ptr (y)));
308+ uint16_t * dst = dstBase + x * dstStep;
309+
310+ icvCvt_BGR2RGB_16u_C3R ( src,0 , dst,0 ,Size (num_pixels,1 ));
311+ }
312+ static void cbRGBAtoBGRA_16U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
313+ {
314+ const uint16_t * src =static_cast <const uint16_t *>(pixels);
315+
316+ constexpr int dstStep =4 ;
317+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
318+ uint16_t * dstBase =const_cast <uint16_t *>(reinterpret_cast <const uint16_t *>(pDst->ptr (y)));
319+ uint16_t * dst = dstBase + x * dstStep;
320+
321+ icvCvt_BGRA2RGBA_16u_C4R ( src,0 , dst,0 ,Size (num_pixels,1 ));
322+ }
323+ static void cbRGBtoBGR_32F (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
324+ {
325+ constexpr int srcStep =3 ;
326+ const uint32_t * src =static_cast <const uint32_t *>(pixels);
327+
328+ constexpr int dstStep =3 ;
329+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
330+ uint32_t * dstBase =const_cast <uint32_t *>(reinterpret_cast <const uint32_t *>(pDst->ptr (y)));
331+ uint32_t * dst = dstBase + x * dstStep;
332+
333+ for (size_t i =0 ; i < num_pixels; i++)
334+ {
335+ dst[ i * dstStep +0 ] = src[ i * srcStep +2 ];
336+ dst[ i * dstStep +1 ] = src[ i * srcStep +1 ];
337+ dst[ i * dstStep +2 ] = src[ i * srcStep +0 ];
338+ }
339+ }
340+ static void cbRGBAtoBGRA_32F (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
341+ {
342+ constexpr int srcStep =4 ;
343+ const uint32_t * src =static_cast <const uint32_t *>(pixels);
344+
345+ constexpr int dstStep =4 ;
346+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
347+ uint32_t * dstBase =const_cast <uint32_t *>(reinterpret_cast <const uint32_t *>(pDst->ptr (y)));
348+ uint32_t * dst = dstBase + x * dstStep;
349+
350+ for (size_t i =0 ; i < num_pixels; i++)
351+ {
352+ dst[ i * dstStep +0 ] = src[ i * srcStep +2 ];
353+ dst[ i * dstStep +1 ] = src[ i * srcStep +1 ];
354+ dst[ i * dstStep +2 ] = src[ i * srcStep +0 ];
355+ dst[ i * dstStep +3 ] = src[ i * srcStep +3 ];
356+ }
357+ }
358+
359+ static void cbRGBtoGRAY_8U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
360+ {
361+ const uint8_t * src =static_cast <const uint8_t *>(pixels);
362+
363+ constexpr int dstStep =1 ;
364+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
365+ uint8_t * dstBase =const_cast <uint8_t *>(reinterpret_cast <const uint8_t *>(pDst->ptr (y)));
366+ uint8_t * dst = dstBase + x * dstStep;
367+
368+ icvCvt_BGR2Gray_8u_C3C1R (src,0 , dst,0 ,Size (num_pixels,1 ) );
369+ }
370+ static void cbRGBAtoGRAY_8U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
371+ {
372+ const uint8_t * src =static_cast <const uint8_t *>(pixels);
373+
374+ constexpr int dstStep =1 ;
375+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
376+ uint8_t * dstBase =const_cast <uint8_t *>(reinterpret_cast <const uint8_t *>(pDst->ptr (y)));
377+ uint8_t * dst = dstBase + x * dstStep;
378+
379+ icvCvt_BGRA2Gray_8u_C4C1R (src,0 , dst,0 ,Size (num_pixels,1 ) );
380+ }
381+ static void cbRGBtoGRAY_16U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
382+ {
383+ const uint16_t * src =static_cast <const uint16_t *>(pixels);
384+
385+ constexpr int dstStep =1 ;
386+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
387+ uint16_t * dstBase =const_cast <uint16_t *>(reinterpret_cast <const uint16_t *>(pDst->ptr (y)));
388+ uint16_t * dst = dstBase + x * dstStep;
389+
390+ icvCvt_BGRA2Gray_16u_CnC1R (src,0 , dst,0 ,Size (num_pixels,1 ),/* ncn=*/ 3 );
391+ }
392+ static void cbRGBAtoGRAY_16U (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
393+ {
394+ const uint16_t * src =static_cast <const uint16_t *>(pixels);
395+
396+ constexpr int dstStep =1 ;
397+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
398+ uint16_t * dstBase =const_cast <uint16_t *>(reinterpret_cast <const uint16_t *>(pDst->ptr (y)));
399+ uint16_t * dst = dstBase + x * dstStep;
400+
401+ icvCvt_BGRA2Gray_16u_CnC1R (src,0 , dst,0 ,Size (num_pixels,1 ),/* ncn=*/ 4 );
402+ }
403+ static void cbRGBtoGRAY_32F (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
404+ {
405+ constexpr float cR =0 .299f ;
406+ constexpr float cG =0 .587f ;
407+ constexpr float cB =1 .000f - cR - cG;
408+
409+ constexpr int srcStep =3 ;
410+ const float * src =static_cast <const float *>(pixels);
411+
412+ constexpr int dstStep =1 ;
413+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
414+ float * dstBase =const_cast <float *>(reinterpret_cast <const float *>(pDst->ptr (y)));
415+ float * dst = dstBase + x * dstStep;
416+
417+ for (size_t i =0 ; i < num_pixels; i++)
418+ {
419+ dst[ i * dstStep ] = src[ i * srcStep +0 ] * cR +
420+ src[ i * srcStep +1 ] * cG +
421+ src[ i * srcStep +2 ] * cB;
422+ }
423+ }
424+ static void cbRGBAtoGRAY_32F (void *opaque,size_t x,size_t y,size_t num_pixels,const void *pixels)
425+ {
426+ constexpr float cR =0 .299f ;
427+ constexpr float cG =0 .587f ;
428+ constexpr float cB =1 .000f - cR - cG;
429+
430+ constexpr int srcStep =4 ;
431+ const float * src =static_cast <const float *>(pixels);
432+
433+ constexpr int dstStep =1 ;
434+ const cv::Mat *pDst =static_cast <cv::Mat*>(opaque);
435+ float * dstBase =const_cast <float *>(reinterpret_cast <const float *>(pDst->ptr (y)));
436+ float * dst = dstBase + x * dstStep;
437+
438+ for (size_t i =0 ; i < num_pixels; i++)
439+ {
440+ dst[ i * dstStep ] = src[ i * srcStep +0 ] * cR +
441+ src[ i * srcStep +1 ] * cG +
442+ src[ i * srcStep +2 ] * cB;
443+ }
243444}
244445
245446// ///////////////////// JpegXLEncoder ///////////////////