Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
jpeg_progressive_decoder.cpp
Go to the documentation of this file.
1// Copyright 2020 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "core/fxcodec/jpeg/jpeg_progressive_decoder.h"
8
9#include <optional>
10#include <utility>
11
12#include "core/fxcodec/cfx_codec_memory.h"
13#include "core/fxcodec/fx_codec.h"
14#include "core/fxcodec/jpeg/jpeg_common.h"
15#include "core/fxcodec/scanlinedecoder.h"
16#include "core/fxcrt/check.h"
17#include "core/fxcrt/compiler_specific.h"
18#include "core/fxcrt/fx_safe_types.h"
19#include "core/fxge/dib/cfx_dibbase.h"
20#include "core/fxge/dib/fx_dib.h"
21
22class CJpegContext final : public ProgressiveDecoderIface::Context {
23 public:
25 ~CJpegContext() override;
26
27 jmp_buf& GetJumpMark() { return m_Common.jmpbuf; }
28
29 JpegCommon m_Common = {};
30 unsigned int m_SkipSize = 0;
31};
32
33extern "C" {
34
35static void error_fatal(j_common_ptr cinfo) {
36 auto* pContext = reinterpret_cast<CJpegContext*>(cinfo->client_data);
37 longjmp(pContext->m_Common.jmpbuf, -1);
38}
39
40static void src_skip_data(jpeg_decompress_struct* cinfo, long num) {
41 if (cinfo->src->bytes_in_buffer < static_cast<size_t>(num)) {
42 auto* pContext = reinterpret_cast<CJpegContext*>(cinfo->client_data);
43 pContext->m_SkipSize = (unsigned int)(num - cinfo->src->bytes_in_buffer);
44 cinfo->src->bytes_in_buffer = 0;
45 } else {
46 // SAFETY: required from library during callback.
47 UNSAFE_BUFFERS(cinfo->src->next_input_byte += num);
48 cinfo->src->bytes_in_buffer -= num;
49 }
50}
51
52} // extern "C"
53
54static void JpegLoadAttribute(const jpeg_decompress_struct& info,
55 CFX_DIBAttribute* pAttribute) {
56 pAttribute->m_nXDPI = info.X_density;
57 pAttribute->m_nYDPI = info.Y_density;
58 pAttribute->m_wDPIUnit =
59 static_cast<CFX_DIBAttribute::ResUnit>(info.density_unit);
60}
61
62CJpegContext::CJpegContext() {
63 m_Common.cinfo.client_data = this;
64 m_Common.cinfo.err = &m_Common.error_mgr;
65
66 m_Common.error_mgr.error_exit = error_fatal;
67 m_Common.error_mgr.emit_message = jpeg_common_error_do_nothing_int;
68 m_Common.error_mgr.output_message = jpeg_common_error_do_nothing;
69 m_Common.error_mgr.format_message = jpeg_common_error_do_nothing_char;
70 m_Common.error_mgr.reset_error_mgr = jpeg_common_error_do_nothing;
71
72 m_Common.source_mgr.init_source = jpeg_common_src_do_nothing;
73 m_Common.source_mgr.term_source = jpeg_common_src_do_nothing;
74 m_Common.source_mgr.skip_input_data = src_skip_data;
75 m_Common.source_mgr.fill_input_buffer = jpeg_common_src_fill_buffer;
76 m_Common.source_mgr.resync_to_restart = jpeg_common_src_resync;
77}
78
79CJpegContext::~CJpegContext() {
80 jpeg_destroy_decompress(&m_Common.cinfo);
81}
82
83namespace fxcodec {
84
85namespace {
86
87JpegProgressiveDecoder* g_jpeg_decoder = nullptr;
88
89} // namespace
90
91// static
92void JpegProgressiveDecoder::InitializeGlobals() {
93 CHECK(!g_jpeg_decoder);
94 g_jpeg_decoder = new JpegProgressiveDecoder();
95}
96
97// static
98void JpegProgressiveDecoder::DestroyGlobals() {
99 delete g_jpeg_decoder;
100 g_jpeg_decoder = nullptr;
101}
102
103// static
104JpegProgressiveDecoder* JpegProgressiveDecoder::GetInstance() {
105 return g_jpeg_decoder;
106}
107
108// static
109std::unique_ptr<ProgressiveDecoderIface::Context>
110JpegProgressiveDecoder::Start() {
111 auto pContext = std::make_unique<CJpegContext>();
112 if (!jpeg_common_create_decompress(&pContext->m_Common)) {
113 return nullptr;
114 }
115 pContext->m_Common.cinfo.src = &pContext->m_Common.source_mgr;
116 pContext->m_SkipSize = 0;
117 return pContext;
118}
119
120// static
121jmp_buf& JpegProgressiveDecoder::GetJumpMark(Context* pContext) {
122 return static_cast<CJpegContext*>(pContext)->GetJumpMark();
123}
124
125// static
126int JpegProgressiveDecoder::ReadHeader(Context* pContext,
127 int* width,
128 int* height,
129 int* nComps,
130 CFX_DIBAttribute* pAttribute) {
131 DCHECK(pAttribute);
132
133 auto* ctx = static_cast<CJpegContext*>(pContext);
134 int ret = jpeg_read_header(&ctx->m_Common.cinfo, TRUE);
135 if (ret == JPEG_SUSPENDED)
136 return 2;
137 if (ret != JPEG_HEADER_OK)
138 return 1;
139
140 *width = ctx->m_Common.cinfo.image_width;
141 *height = ctx->m_Common.cinfo.image_height;
142 *nComps = ctx->m_Common.cinfo.num_components;
143 JpegLoadAttribute(ctx->m_Common.cinfo, pAttribute);
144 return 0;
145}
146
147// static
148bool JpegProgressiveDecoder::StartScanline(Context* pContext) {
149 auto* ctx = static_cast<CJpegContext*>(pContext);
150 ctx->m_Common.cinfo.scale_denom = 1;
151 return !!jpeg_start_decompress(&ctx->m_Common.cinfo);
152}
153
154// static
155bool JpegProgressiveDecoder::ReadScanline(Context* pContext,
156 unsigned char* dest_buf) {
157 auto* ctx = static_cast<CJpegContext*>(pContext);
158 unsigned int nlines = jpeg_read_scanlines(&ctx->m_Common.cinfo, &dest_buf, 1);
159 return nlines == 1;
160}
161
162FX_FILESIZE JpegProgressiveDecoder::GetAvailInput(Context* pContext) const {
163 auto* ctx = static_cast<CJpegContext*>(pContext);
164 return static_cast<FX_FILESIZE>(ctx->m_Common.source_mgr.bytes_in_buffer);
165}
166
167bool JpegProgressiveDecoder::Input(Context* pContext,
168 RetainPtr<CFX_CodecMemory> codec_memory) {
169 pdfium::span<uint8_t> src_buf = codec_memory->GetUnconsumedSpan();
170 auto* ctx = static_cast<CJpegContext*>(pContext);
171 if (ctx->m_SkipSize) {
172 if (ctx->m_SkipSize > src_buf.size()) {
173 ctx->m_Common.source_mgr.bytes_in_buffer = 0;
174 ctx->m_SkipSize -= src_buf.size();
175 return true;
176 }
177 src_buf = src_buf.subspan(ctx->m_SkipSize);
178 ctx->m_SkipSize = 0;
179 }
180 ctx->m_Common.source_mgr.next_input_byte = src_buf.data();
181 ctx->m_Common.source_mgr.bytes_in_buffer = src_buf.size();
182 return true;
183}
184
185JpegProgressiveDecoder::JpegProgressiveDecoder() = default;
186
187JpegProgressiveDecoder::~JpegProgressiveDecoder() = default;
188
189} // namespace fxcodec
#define DCHECK
Definition check.h:33
static bool ReadScanline(Context *pContext, uint8_t *dest_buf)
static jmp_buf & GetJumpMark(Context *pContext)
static int ReadHeader(Context *pContext, int *width, int *height, int *nComps, CFX_DIBAttribute *pAttribute)
static JpegProgressiveDecoder * GetInstance()
static bool StartScanline(Context *pContext)
FX_FILESIZE GetAvailInput(Context *pContext) const override
bool Input(Context *pContext, RetainPtr< CFX_CodecMemory > codec_memory) override
#define UNSAFE_BUFFERS(...)
#define FX_FILESIZE
Definition fx_types.h:19
static void JpegLoadAttribute(const jpeg_decompress_struct &info, CFX_DIBAttribute *pAttribute)
static void src_skip_data(jpeg_decompress_struct *cinfo, long num)
static void error_fatal(j_common_ptr cinfo)
#define CHECK(cvref)