summaryrefslogtreecommitdiff
path: root/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h
blob: b86ce5f450b89395df1ab2da6b188f8637199120 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_ULTRAHDR_JPEGDECODERHELPER_H
#define ANDROID_ULTRAHDR_JPEGDECODERHELPER_H

// We must include cstdio before jpeglib.h. It is a requirement of libjpeg.
#include <cstdio>
extern "C" {
#include <jerror.h>
#include <jpeglib.h>
}
#include <utils/Errors.h>
#include <vector>

// constraint on max width and max height is only due to device alloc constraints
// Can tune these values basing on the target device
static const int kMaxWidth = 8192;
static const int kMaxHeight = 8192;

namespace android::ultrahdr {
/*
 * Encapsulates a converter from JPEG to raw image (YUV420planer or grey-scale) format.
 * This class is not thread-safe.
 */
class JpegDecoderHelper {
public:
    JpegDecoderHelper();
    ~JpegDecoderHelper();
    /*
     * Decompresses JPEG image to raw image (YUV420planer, grey-scale or RGBA) format. After
     * calling this method, call getDecompressedImage() to get the image.
     * Returns false if decompressing the image fails.
     */
    bool decompressImage(const void* image, int length, bool decodeToRGBA = false);
    /*
     * Returns the decompressed raw image buffer pointer. This method must be called only after
     * calling decompressImage().
     */
    void* getDecompressedImagePtr();
    /*
     * Returns the decompressed raw image buffer size. This method must be called only after
     * calling decompressImage().
     */
    size_t getDecompressedImageSize();
    /*
     * Returns the image width in pixels. This method must be called only after calling
     * decompressImage().
     */
    size_t getDecompressedImageWidth();
    /*
     * Returns the image width in pixels. This method must be called only after calling
     * decompressImage().
     */
    size_t getDecompressedImageHeight();
    /*
     * Returns the XMP data from the image.
     */
    void* getXMPPtr();
    /*
     * Returns the decompressed XMP buffer size. This method must be called only after
     * calling decompressImage() or getCompressedImageParameters().
     */
    size_t getXMPSize();
    /*
     * Extracts EXIF package and updates the EXIF position / length without decoding the image.
     */
    bool extractEXIF(const void* image, int length);
    /*
     * Returns the EXIF data from the image.
     * This method must be called after extractEXIF() or decompressImage().
     */
    void* getEXIFPtr();
    /*
     * Returns the decompressed EXIF buffer size. This method must be called only after
     * calling decompressImage(), extractEXIF() or getCompressedImageParameters().
     */
    size_t getEXIFSize();
    /*
     * Returns the position offset of EXIF package
     * (4 bypes offset to FF sign, the byte after FF E1 XX XX <this byte>),
     * or -1  if no EXIF exists.
     * This method must be called after extractEXIF() or decompressImage().
     */
    int getEXIFPos() { return mExifPos; }
    /*
     * Returns the ICC data from the image.
     */
    void* getICCPtr();
    /*
     * Returns the decompressed ICC buffer size. This method must be called only after
     * calling decompressImage() or getCompressedImageParameters().
     */
    size_t getICCSize();
    /*
     * Decompresses metadata of the image. All vectors are owned by the caller.
     */
    bool getCompressedImageParameters(const void* image, int length, size_t* pWidth,
                                      size_t* pHeight, std::vector<uint8_t>* iccData,
                                      std::vector<uint8_t>* exifData);

private:
    bool decode(const void* image, int length, bool decodeToRGBA);
    // Returns false if errors occur.
    bool decompress(jpeg_decompress_struct* cinfo, const uint8_t* dest, bool isSingleChannel);
    bool decompressYUV(jpeg_decompress_struct* cinfo, const uint8_t* dest);
    bool decompressRGBA(jpeg_decompress_struct* cinfo, const uint8_t* dest);
    bool decompressSingleChannel(jpeg_decompress_struct* cinfo, const uint8_t* dest);
    // Process 16 lines of Y and 16 lines of U/V each time.
    // We must pass at least 16 scanlines according to libjpeg documentation.
    static const int kCompressBatchSize = 16;
    // The buffer that holds the decompressed result.
    std::vector<JOCTET> mResultBuffer;
    // The buffer that holds XMP Data.
    std::vector<JOCTET> mXMPBuffer;
    // The buffer that holds EXIF Data.
    std::vector<JOCTET> mEXIFBuffer;
    // The buffer that holds ICC Data.
    std::vector<JOCTET> mICCBuffer;

    // Resolution of the decompressed image.
    size_t mWidth;
    size_t mHeight;

    // Position of EXIF package, default value is -1 which means no EXIF package appears.
    ssize_t mExifPos = -1;
};
} /* namespace android::ultrahdr  */

#endif // ANDROID_ULTRAHDR_JPEGDECODERHELPER_H