29#include <com/sun/star/task/XStatusIndicator.hpp>
44#pragma warning (disable: 4324)
49struct ErrorManagerStruct
52 jmp_buf setjmp_buffer;
65 char buffer[JMSG_LENGTH_MAX];
66 (*cinfo->err->format_message) (cinfo, buffer);
67 SAL_WARN(
"vcl.filter",
"fatal failure reading JPEG: " << buffer);
68 ErrorManagerStruct * error =
reinterpret_cast<ErrorManagerStruct *
>(cinfo->err);
69 longjmp(error->setjmp_buffer, 1);
74 char buffer[JMSG_LENGTH_MAX];
75 (*cinfo->err->format_message) (cinfo, buffer);
76 SAL_WARN(
"vcl.filter",
"failure reading JPEG: " << buffer);
97 cinfo->err->error_exit(cinfo);
99 cinfo->err->output_message(cinfo);
101 else if (cinfo->err->trace_level >= msg_level)
102 cinfo->err->output_message(cinfo);
109class JpegDecompressOwner
112 void set(jpeg_decompress_struct *cinfo)
116 ~JpegDecompressOwner()
118 if (m_cinfo !=
nullptr)
120 jpeg_destroy_decompress(m_cinfo);
124 jpeg_decompress_struct *m_cinfo =
nullptr;
127class JpegCompressOwner
130 void set(jpeg_compress_struct *cinfo)
136 if (m_cinfo !=
nullptr)
138 jpeg_destroy_compress(m_cinfo);
142 jpeg_compress_struct *m_cinfo =
nullptr;
147 jpeg_decompress_struct cinfo;
148 ErrorManagerStruct jerr;
149 JpegDecompressOwner aOwner;
150 std::unique_ptr<BitmapScopedWriteAccess> pScopedAccess;
151 std::vector<sal_uInt8> pScanLineBuffer;
152 std::vector<sal_uInt8> pCYMKBuffer;
161 if (setjmp(rContext.jerr.setjmp_buffer))
166 rContext.cinfo.err = jpeg_std_error(&rContext.jerr.pub);
167 rContext.jerr.pub.error_exit =
errorExit;
171 jpeg_create_decompress(&rContext.cinfo);
172 rContext.aOwner.set(&rContext.cinfo);
175 jpeg_read_header(&rContext.cinfo,
TRUE);
177 rContext.cinfo.scale_num = 1;
178 rContext.cinfo.scale_denom = 1;
179 rContext.cinfo.output_gamma = 1.0;
180 rContext.cinfo.raw_data_out =
FALSE;
181 rContext.cinfo.quantize_colors =
FALSE;
183 jpeg_calc_output_dimensions(&rContext.cinfo);
186 tools::Long nHeight = rContext.cinfo.output_height;
193 if (rContext.cinfo.err->num_warnings && (nWidth > 8192 || nHeight > 8192))
197 bool bGray = (rContext.cinfo.output_components == 1);
201 aCreateBitmapParam.
nWidth = nWidth;
202 aCreateBitmapParam.
nHeight = nHeight;
204 aCreateBitmapParam.
density_unit = rContext.cinfo.density_unit;
205 aCreateBitmapParam.
X_density = rContext.cinfo.X_density;
206 aCreateBitmapParam.
Y_density = rContext.cinfo.Y_density;
207 aCreateBitmapParam.
bGray = bGray;
211 bool bBitmapCreated = bUseExistingBitmap;
213 bBitmapCreated = pJPEGReader->
CreateBitmap(aCreateBitmapParam);
215 if (bBitmapCreated && !bOnlyCreateBitmap)
228 J_COLOR_SPACE best_out_color_space = JCS_RGB;
234 best_out_color_space = JCS_GRAYSCALE;
238#if defined(JCS_EXTENSIONS)
241 best_out_color_space = JCS_EXT_BGR;
242 eScanlineFormat = eFinalFormat;
247 best_out_color_space = JCS_EXT_BGRA;
248 eScanlineFormat = eFinalFormat;
253 best_out_color_space = JCS_EXT_RGBA;
254 eScanlineFormat = eFinalFormat;
259 best_out_color_space = JCS_EXT_ARGB;
260 eScanlineFormat = eFinalFormat;
264 if (rContext.cinfo.jpeg_color_space == JCS_YCCK)
265 rContext.cinfo.out_color_space = JCS_CMYK;
267 if (rContext.cinfo.out_color_space != JCS_CMYK)
268 rContext.cinfo.out_color_space = best_out_color_space;
270 jpeg_start_decompress(&rContext.cinfo);
272 JSAMPLE* aRangeLimit = rContext.cinfo.sample_range_limit;
274 rContext.pScanLineBuffer.resize(nWidth * nPixelSize);
276 if (rContext.cinfo.out_color_space == JCS_CMYK)
278 rContext.pCYMKBuffer.resize(nWidth * 4);
284 size_t yIndex = *pLines;
286 sal_uInt8*
p = (rContext.cinfo.out_color_space == JCS_CMYK) ? rContext.pCYMKBuffer.data() : rContext.pScanLineBuffer.data();
287 jpeg_read_scanlines(&rContext.cinfo,
reinterpret_cast<JSAMPARRAY
>(&
p), 1);
289 if (rContext.cinfo.out_color_space == JCS_CMYK)
292 Scanline pScanline = pAccess->GetScanline(yIndex);
293 for (
tools::Long cmyk = 0,
x = 0; cmyk < nWidth * 4; cmyk += 4, ++
x)
295 int color_C = 255 - rContext.pCYMKBuffer[cmyk + 0];
296 int color_M = 255 - rContext.pCYMKBuffer[cmyk + 1];
297 int color_Y = 255 - rContext.pCYMKBuffer[cmyk + 2];
298 int color_K = 255 - rContext.pCYMKBuffer[cmyk + 3];
300 sal_uInt8 cRed = aRangeLimit[255L - (color_C + color_K)];
301 sal_uInt8 cGreen = aRangeLimit[255L - (color_M + color_K)];
302 sal_uInt8 cBlue = aRangeLimit[255L - (color_Y + color_K)];
304 pAccess->SetPixelOnData(pScanline,
x,
BitmapColor(cRed, cGreen, cBlue));
309 pAccess->CopyScanline(yIndex, rContext.pScanLineBuffer.data(), eScanlineFormat, rContext.pScanLineBuffer.size());
313 if (rContext.cinfo.err->msg_code == 113)
317 rContext.pScanLineBuffer.clear();
318 rContext.pCYMKBuffer.clear();
320 rContext.pScopedAccess.reset();
323 if (bBitmapCreated && !bOnlyCreateBitmap)
325 jpeg_finish_decompress(&rContext.cinfo);
329 jpeg_abort_decompress(&rContext.cinfo);
338 ReadJPEG(aContext, pJPEGReader, pInputStream, pLines, nImportFlags, ppAccess);
344 css::uno::Reference<css::task::XStatusIndicator>
const & status )
346 jpeg_compress_struct cinfo;
347 ErrorManagerStruct jerr;
351 JpegCompressOwner aOwner;
353 if ( setjmp( jerr.setjmp_buffer ) )
358 cinfo.err = jpeg_std_error( &jerr.pub );
362 jpeg_create_compress( &cinfo );
366 cinfo.image_width =
static_cast<JDIMENSION
>(nWidth);
367 cinfo.image_height =
static_cast<JDIMENSION
>(nHeight);
370 cinfo.input_components = 1;
371 cinfo.in_color_space = JCS_GRAYSCALE;
375 cinfo.input_components = 3;
376 cinfo.in_color_space = JCS_RGB;
379 jpeg_set_defaults( &cinfo );
380 jpeg_set_quality( &cinfo,
static_cast<int>(nQualityPercent),
FALSE );
384 cinfo.density_unit = 1;
385 cinfo.X_density = rPPI.
getX();
386 cinfo.Y_density = rPPI.
getY();
390 SAL_WARN(
"vcl.filter",
"ignoring too large PPI " << rPPI);
393 if ( ( nWidth > 128 ) || ( nHeight > 128 ) )
394 jpeg_simple_progression( &cinfo );
396 if (aChromaSubsampling == 1)
398 cinfo.comp_info[0].h_samp_factor = 1;
399 cinfo.comp_info[0].v_samp_factor = 1;
401 else if (aChromaSubsampling == 2)
403 cinfo.comp_info[0].h_samp_factor = 2;
404 cinfo.comp_info[0].v_samp_factor = 1;
406 else if (aChromaSubsampling == 3)
408 cinfo.comp_info[0].h_samp_factor = 2;
409 cinfo.comp_info[0].v_samp_factor = 2;
412 jpeg_start_compress( &cinfo,
TRUE );
414 for( nY = 0; nY < nHeight; nY++ )
420 jpeg_write_scanlines( &cinfo,
reinterpret_cast<JSAMPARRAY
>(&pScanline), 1 );
425 status->setValue( nY * 100L / nHeight );
429 jpeg_finish_compress(&cinfo);
439 jpeg_decompress_struct aSourceInfo;
440 jpeg_compress_struct aDestinationInfo;
441 ErrorManagerStruct aSourceError;
442 ErrorManagerStruct aDestinationError;
444 jvirt_barray_ptr* aSourceCoefArrays =
nullptr;
445 jvirt_barray_ptr* aDestinationCoefArrays =
nullptr;
454 switch (nAngle.
get())
470 aSourceInfo.err = jpeg_std_error(&aSourceError.pub);
475 aDestinationInfo.err = jpeg_std_error(&aDestinationError.pub);
476 aDestinationInfo.err->error_exit =
errorExit;
479 aDestinationInfo.optimize_coding =
TRUE;
481 JpegDecompressOwner aDecompressOwner;
482 JpegCompressOwner aCompressOwner;
484 if (setjmp(aSourceError.setjmp_buffer))
486 jpeg_destroy_decompress(&aSourceInfo);
487 jpeg_destroy_compress(&aDestinationInfo);
490 if (setjmp(aDestinationError.setjmp_buffer))
492 jpeg_destroy_decompress(&aSourceInfo);
493 jpeg_destroy_compress(&aDestinationInfo);
497 jpeg_create_decompress(&aSourceInfo);
498 aDecompressOwner.set(&aSourceInfo);
499 jpeg_create_compress(&aDestinationInfo);
500 aCompressOwner.set(&aDestinationInfo);
505 jpeg_read_header(&aSourceInfo,
TRUE);
506 jtransform_request_workspace(&aSourceInfo, &aTransformOption);
508 aSourceCoefArrays = jpeg_read_coefficients(&aSourceInfo);
509 jpeg_copy_critical_parameters(&aSourceInfo, &aDestinationInfo);
511 aDestinationCoefArrays = jtransform_adjust_parameters(&aSourceInfo, &aDestinationInfo, aSourceCoefArrays, &aTransformOption);
515 aDestinationInfo.optimize_coding =
TRUE;
516 jpeg_write_coefficients(&aDestinationInfo, aDestinationCoefArrays);
518 jtransform_execute_transformation(&aSourceInfo, &aDestinationInfo, aSourceCoefArrays, &aTransformOption);
520 jpeg_finish_compress(&aDestinationInfo);
522 jpeg_finish_decompress(&aSourceInfo);
vcl::ScopedBitmapAccess< BitmapWriteAccess, Bitmap, &Bitmap::AcquireWriteAccess > BitmapScopedWriteAccess
bool CreateBitmap(JPEGCreateBitmapParam const ¶m)
void * GetScanline(tools::Long nY)
This template handles BitmapAccess the RAII way.
@ UseExistingBitmap
Read pixel data into an existing bitmap.
@ OnlyCreateBitmap
Only create a bitmap, do not read pixel data.
void jpeg_svstream_dest(j_compress_ptr cinfo, void *outfile)
void jpeg_svstream_src(j_decompress_ptr cinfo, void *infile)
static void errorExit(j_common_ptr cinfo)
static void ReadJPEG(JpegStuff &rContext, JPEGReader *pJPEGReader, void *pInputStream, tools::Long *pLines, GraphicFilterImportFlags nImportFlags, BitmapScopedWriteAccess *ppAccess)
void Transform(void *pInputStream, void *pOutputStream, Degree10 nAngle)
static void emitMessage(j_common_ptr cinfo, int msg_level)
bool WriteJPEG(JPEGWriter *pJPEGWriter, void *pOutputStream, tools::Long nWidth, tools::Long nHeight, basegfx::B2DSize const &rPPI, bool bGreys, tools::Long nQualityPercent, tools::Long aChromaSubsampling, css::uno::Reference< css::task::XStatusIndicator > const &status)
static int GetWarningLimit()
static void outputMessage(j_common_ptr cinfo)
#define SAL_WARN(area, stream)
void set(css::uno::UnoInterfaceReference const &value)
std::enable_if< std::is_signed< T >::value, bool >::type checked_multiply(T a, T b, T &result)
constexpr std::enable_if_t< std::is_floating_point_v< F > &&std::is_integral_v< I >, bool > convertsToAtMost(F value, I max)
tools::ULong density_unit
int no_data_available_failures
UNDERLYING_TYPE get() const
jcopy_markers_setup(j_decompress_ptr srcinfo, JCOPY_OPTION option)
jcopy_markers_execute(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option)