1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkJpegDecoderMgr.h"
9#include "SkJpegUtility.h"
10
11/*
12 * Print information, warning, and error messages
13 */
14static void print_message(const j_common_ptr info, const char caller[]) {
15    char buffer[JMSG_LENGTH_MAX];
16    info->err->format_message(info, buffer);
17    SkCodecPrintf("libjpeg error %d <%s> from %s\n", info->err->msg_code, buffer, caller);
18}
19
20/*
21 * Reporting functions for libjpeg
22 */
23static void emit_message(j_common_ptr info, int) {
24    print_message(info, "emit_message");
25}
26static void output_message(j_common_ptr info) {
27    print_message(info, "output_message");
28}
29
30/*
31 * Choose the size of the memory buffer on Android
32 */
33static void overwrite_mem_buffer_size(jpeg_decompress_struct* dinfo) {
34#ifdef SK_BUILD_FOR_ANDROID
35
36// Use 30 MB for devices with a large amount of system memory and 5MB otherwise
37// TODO: (msarett) This matches SkImageDecoder.  Why were these values chosen?
38#ifdef ANDROID_LARGE_MEMORY_DEVICE
39    dinfo->mem->max_memory_to_use = 30 * 1024 * 1024;
40#else
41    dinfo->mem->max_memory_to_use = 5 * 1024 * 1024;
42#endif
43
44#endif // SK_BUILD_FOR_ANDROID
45}
46
47bool JpegDecoderMgr::returnFalse(const char caller[]) {
48    print_message((j_common_ptr) &fDInfo, caller);
49    return false;
50}
51
52SkCodec::Result JpegDecoderMgr::returnFailure(const char caller[], SkCodec::Result result) {
53    print_message((j_common_ptr) &fDInfo, caller);
54    return result;
55}
56
57SkColorType JpegDecoderMgr::getColorType() {
58    switch (fDInfo.jpeg_color_space) {
59        case JCS_CMYK:
60        case JCS_YCCK:
61            // libjpeg cannot convert from CMYK or YCCK to RGB.
62            // Here, we ask libjpeg to give us CMYK samples back and
63            // we will later manually convert them to RGB.
64            fDInfo.out_color_space = JCS_CMYK;
65            return kN32_SkColorType;
66        case JCS_GRAYSCALE:
67            fDInfo.out_color_space = JCS_GRAYSCALE;
68            return kGray_8_SkColorType;
69        default:
70#ifdef ANDROID_RGB
71            fDInfo.out_color_space = JCS_RGBA_8888;
72#else
73            fDInfo.out_color_space = JCS_RGB;
74#endif
75            return kN32_SkColorType;
76    }
77}
78
79JpegDecoderMgr::JpegDecoderMgr(SkStream* stream)
80    : fSrcMgr(stream)
81    , fInit(false)
82{
83    // Error manager must be set before any calls to libjeg in order to handle failures
84    fDInfo.err = jpeg_std_error(&fErrorMgr);
85    fErrorMgr.error_exit = skjpeg_err_exit;
86}
87
88void JpegDecoderMgr::init() {
89    jpeg_create_decompress(&fDInfo);
90    fInit = true;
91    fDInfo.src = &fSrcMgr;
92    overwrite_mem_buffer_size(&fDInfo);
93    fDInfo.err->emit_message = &emit_message;
94    fDInfo.err->output_message = &output_message;
95}
96
97JpegDecoderMgr::~JpegDecoderMgr() {
98    if (fInit) {
99        jpeg_destroy_decompress(&fDInfo);
100    }
101}
102
103jmp_buf& JpegDecoderMgr::getJmpBuf() {
104    return fErrorMgr.fJmpBuf;
105}
106
107jpeg_decompress_struct* JpegDecoderMgr::dinfo() {
108    return &fDInfo;
109}
110