sjpeg 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/sjpeg/sjpeg.h ADDED
@@ -0,0 +1,353 @@
1
+ // Copyright 2017 Google Inc.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // Fast & simple JPEG encoder.
16
+ //
17
+ // Author: Skal (pascal.massimino@gmail.com)
18
+
19
+ #ifndef SJPEG_JPEG_H_
20
+ #define SJPEG_JPEG_H_
21
+
22
+ #include <inttypes.h>
23
+ #include <memory>
24
+ #include <string>
25
+ #include <vector>
26
+
27
+ #define SJPEG_VERSION 0x000100 // 0.1.0
28
+
29
+ #if defined(__cplusplus) || defined(c_plusplus)
30
+ extern "C" {
31
+ #endif
32
+
33
+ // Returns the library's version.
34
+ uint32_t SjpegVersion();
35
+
36
+ // Main function
37
+ // This is the simplest possible call. There is only one parameter (quality)
38
+ // and most decisions will be made automatically (YUV420/YUV444/etc...).
39
+ // Returns the compressed size, and fills *out_data with the bitstream.
40
+ // This returned buffer is allocated with 'new[]' operator. It must be
41
+ // deallocated by using 'delete[]' or SjpegFreeBuffer() calls.
42
+ // Input data 'rgb' are the samples in sRGB format, in R/G/B memory order.
43
+ // Picture dimension is width x height.
44
+ // Returns 0 in case of error.
45
+ size_t SjpegCompress(const uint8_t* rgb, int width, int height, float quality,
46
+ uint8_t** out_data);
47
+
48
+ // Parameter 'yuv_mode': decides which colorspace to use. Possible values:
49
+ // * YUV_AUTO (0): automated decision between YUV 4:2:0 / sharp / 4:4:4
50
+ // * YUV_420 (1): YUV 4:2:0
51
+ // * YUV_SHARP (2): YUV 4:2:0 with 'sharp' conversion
52
+ // * YUV_444 (3): YUV 4:4:4
53
+ typedef enum {
54
+ SJPEG_YUV_AUTO = 0,
55
+ SJPEG_YUV_420,
56
+ SJPEG_YUV_SHARP,
57
+ SJPEG_YUV_444
58
+ } SjpegYUVMode;
59
+
60
+ // Encodes an RGB picture to JPEG.
61
+ //
62
+ // the dimension of the picture pointed to by 'rgb', is W * H, with stride
63
+ // 'stride' (must be greater or equal to 3*W). The dimensions must be strictly
64
+ // positive.
65
+ //
66
+ // The compressed bytes are made available in *out_data, which is a buffer
67
+ // allocated with new []. This buffer must be disallocated using 'delete []',
68
+ // or by calling SjpegFreeBuffer().
69
+ //
70
+ // Return parameter -if positive- is the size of the JPEG string,
71
+ // or 0 if an error occurred.
72
+ //
73
+ // Parameter 'quality' correspond to the usual quality factor in JPEG:
74
+ // 0=very bad, 100=very good.
75
+ // Parameter 'compression_method' refer to the efforts and resources spent
76
+ // trying to compress better. Default (fastest) method should be 0. Method 1
77
+ // will optimize the size at the expense of using more RAM. Method 2 does
78
+ // the same as method #1, but but without any additional RAM (but using twice
79
+ // more CPU). Methods 3, 4, 5, and 6 behave like methods 0, 1, and 2, except
80
+ // that the quantization matrices are fine-tuned to the source's content using
81
+ // histogram. This requires an additional pass, and is hence slower, but can
82
+ // give substantial filesize reduction, especially for hi-quality settings.
83
+ // Method 5 will try to not use extra RAM to store the Fourier-transformed
84
+ // coefficients, at the expense of being ~15% slower, but will still use some
85
+ // memory for the Huffman size-optimization. Eventually, method 6 will use
86
+ // a minimal amount of RAM, but will be must slower.
87
+ // To recap:
88
+ // method | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
89
+ // ---------------------------+---+---+---+---+---+---+---+---+---|
90
+ // Huffman size-optimization | | x | x | | x | x | x | x | x |
91
+ // Adaptive quantization | | | | x | x | x | x | x | x |
92
+ // Extra RAM for Huffman pass | | x | | | x | x | | x | |
93
+ // Extra RAM for histogram | | | | x | x | | | x | |
94
+ // Trellis-based quantization | | | | | | | | x | x |
95
+ //
96
+ // Methods sorted by decreasing speed: 0 > 1 > 2 > 3 > 4 > 5 > 6
97
+ // Sorted by increasing efficiency: 0 < [1|2] < 3 < [4|5|6]
98
+ //
99
+ // If you don't have any strict requirements on CPU and memory, you should
100
+ // probably use method #4.
101
+ //
102
+ size_t SjpegEncode(const uint8_t* rgb,
103
+ int width, int height, int stride,
104
+ uint8_t** out_data,
105
+ float quality,
106
+ int compression_method,
107
+ SjpegYUVMode yuv_mode);
108
+
109
+ // Deallocate a compressed bitstream that were returned by SjpegEncode(),
110
+ // SjpegCompress() or sjpeg::Encode(). Useful for non-C++ bindings.
111
+ void SjpegFreeBuffer(const uint8_t* buffer);
112
+
113
+ ////////////////////////////////////////////////////////////////////////////////
114
+ // JPEG-parsing tools
115
+
116
+ // Decode the dimensions of a JPEG bitstream, doing as few read operations as
117
+ // possible. Return false if an error occurred (invalid bitstream, invalid
118
+ // parameter...).
119
+ // The pointers 'width', 'height', 'is_yuv420' can be passed NULL.
120
+ bool SjpegDimensions(const uint8_t* data, size_t size,
121
+ int* width, int* height, int* is_yuv420);
122
+
123
+ // Finds the location of the first two quantization matrices within a JPEG
124
+ // 'data' bitstream. Matrices are 64 coefficients stored as uint8_t.
125
+ // The matrices are returned in natural order (not zigzag order).
126
+ // Note that the input can be truncated to include the headers only, but still
127
+ // must start as a valid JPEG with an 0xffd8 marker.
128
+ // Returns the number of matrices detected.
129
+ // Returns 0 in case of bitstream error, or if the DQT chunk is missing.
130
+ int SjpegFindQuantizer(const uint8_t* data, size_t size,
131
+ uint8_t quant[2][64]);
132
+
133
+ // Returns an estimation of the quality factor that would best approximate
134
+ // the quantization coefficients in matrix[].
135
+ // Note that matrix[] must be in natural order (not the zigzag order used
136
+ // in the byte stream). With this restriction, one can then pass the result
137
+ // of SjpegFindQuantizer() directly to SjpegEstimateQuality().
138
+ float SjpegEstimateQuality(const uint8_t matrix[64], bool for_chroma);
139
+
140
+ // Generate a default quantization matrix for the given quality factor,
141
+ // in a libjpeg-6b fashion.
142
+ void SjpegQuantMatrix(float quality, bool for_chroma, uint8_t matrix[64]);
143
+
144
+ // Returns the favored conversion mode to use (YUV420 / sharp-YUV420 / YUV444)
145
+ // Return values: SJPEG_YUV_420, SJPEG_YUV_SHARP or SJPEG_YUV_444
146
+ // If risk is not NULL, the riskiness score (between 0 and 100) is returned.
147
+ SjpegYUVMode SjpegRiskiness(const uint8_t* rgb, int width, int height,
148
+ int stride, float* risk);
149
+
150
+ #if defined(__cplusplus) || defined(c_plusplus)
151
+ } // extern "C"
152
+ #endif
153
+
154
+ ////////////////////////////////////////////////////////////////////////////////
155
+ // Variant of the function above, but using std::string as interface.
156
+
157
+ bool SjpegCompress(const uint8_t* rgb,
158
+ int width, int height, float quality, std::string* output);
159
+
160
+ bool SjpegDimensions(const std::string& jpeg_data,
161
+ int* width, int* height, int* is_yuv420);
162
+
163
+ int SjpegFindQuantizer(const std::string& jpeg_data, uint8_t quant[2][64]);
164
+
165
+
166
+ ////////////////////////////////////////////////////////////////////////////////
167
+ // Advanced API, C++ only.
168
+ // . Fine control over the encoding parameters using EncoderParam
169
+ // . Interfaces to customize the codec
170
+ ////////////////////////////////////////////////////////////////////////////////
171
+
172
+ namespace sjpeg {
173
+
174
+ // Forward declaration of internal struct:
175
+ struct Encoder;
176
+
177
+ // interfaces to customize the codec:
178
+ struct SearchHook;
179
+ struct ByteSink;
180
+ struct MemoryManager;
181
+
182
+ // Structure for holding encoding parameter, to be passed to the unique
183
+ // call to SjpegEncode() below. For a more detailed description of some fields,
184
+ // see SjpegEncode()'s doc above.
185
+ struct EncoderParam {
186
+ EncoderParam();
187
+ explicit EncoderParam(float quality_factor);
188
+
189
+ // Sets the compression factor. 0 = lowest quality, 100 = best quality.
190
+ // The call will actually initialize quant[][].
191
+ void SetQuality(float quality_factor);
192
+
193
+ // Reduce the output size by a factor 'reduction' in [0, 100]:
194
+ // reduction ~= 100 -> small size reduction
195
+ // reduction ~= 1 -> large size reduction
196
+ // Note: 'reduction' can be larger than 100.
197
+ // This function is incompatible with SetQuality()
198
+ void SetQuantization(const uint8_t m[2][64], float reduction = 100.f);
199
+ const uint8_t* GetQuantMatrix(int idx) const { return quant_[idx]; }
200
+
201
+ // Limit the quantization by setting up some minimal quantization matrices
202
+ // based on the current content of quant_[][] matrices.
203
+ // Hence, this function must be called after SetQuality() or SetQuantMatrix().
204
+ void SetLimitQuantization(bool limit_quantization = true, int tolerance = 0);
205
+
206
+ // Set the minimal quantization matrices directly, irrespective of the value
207
+ // of quant_[][].
208
+ void SetMinQuantization(const uint8_t m[2][64], int min_quant_tolerance = 0);
209
+
210
+ // main compression parameters
211
+ SjpegYUVMode yuv_mode; // YUV-420...444 decisions
212
+ bool Huffman_compress; // if true, use optimized Huffman tables.
213
+ bool adaptive_quantization; // if true, use optimized quantizer matrices.
214
+ bool adaptive_bias; // if true, use perceptual bias adaptation
215
+ bool use_trellis; // if true, use trellis-based optimization
216
+
217
+ // target size or distortion
218
+ typedef enum {
219
+ TARGET_NONE = 0,
220
+ TARGET_SIZE = 1,
221
+ TARGET_PSNR = 2,
222
+ } TargetMode;
223
+ TargetMode target_mode;
224
+ float target_value; // size, psnr or SSIM
225
+ int passes; // max number of passes to try and converge
226
+ float tolerance; // percentage of distance-to-target allowed
227
+ float qmin, qmax; // Limits for the search quality values.
228
+ // If set, min_quant_[] matrices will take
229
+ // precedence and limit qmax further.
230
+
231
+ // fine-grained control over compression parameters
232
+ int quantization_bias; // [0..255] Rounding bias for quantization.
233
+ int qdelta_max_luma; // [0..12] How much to hurt luma in adaptive quant
234
+ int qdelta_max_chroma; // [0..12] How much to hurt chroma in adaptive quant
235
+ // A higher value might be useful for images
236
+ // encoded without chroma subsampling.
237
+
238
+ // if null, a default implementation will be used
239
+ sjpeg::SearchHook* search_hook;
240
+
241
+ // metadata: extra EXIF/XMP/ICCP data that will be embedded in
242
+ // APP1 or APP2 markers. They should contain only the raw payload and not
243
+ // the prefixes ("Exif\0", "ICC_PROFILE", etc...). These will be added
244
+ // automatically during encoding.
245
+ // Conversely, the content of app_markers is written as is, right after APP0.
246
+ std::string exif;
247
+ std::string xmp;
248
+ std::string iccp;
249
+ std::string app_markers;
250
+ void ResetMetadata(); // clears the above
251
+
252
+ // Memory manager used by the codec. If null, default one will be used.
253
+ sjpeg::MemoryManager* memory;
254
+
255
+ protected:
256
+ uint8_t quant_[2][64]; // quantization matrices to use
257
+ uint8_t min_quant_[2][64]; // If limit_quantization is true, these
258
+ // pointers should direct to the minimum
259
+ // quantizer values allowed for luma / chroma.
260
+ bool use_min_quant_; // True if min_quant_[][] has been set.
261
+ int min_quant_tolerance_; // Tolerance going over min_quant_ ([0..100])
262
+
263
+ protected:
264
+ void Init(float quality_factor);
265
+ friend struct sjpeg::Encoder;
266
+ };
267
+
268
+ // Same as the first version of SjpegEncode(), except encoding parameters are
269
+ // passed in a EncoderParam. Upon failure (memory allocation or
270
+ // invalid parameter), the function returns false.
271
+ bool Encode(const uint8_t* rgb, int width, int height, int stride,
272
+ const EncoderParam& param, std::string* output);
273
+
274
+ // This version returns data in *out_data. Returns 0 in case of error.
275
+ size_t Encode(const uint8_t* rgb, int width, int height, int stride,
276
+ const EncoderParam& param, uint8_t** out_data);
277
+
278
+ // Generic call taking a byte-sink for emitting the compressed data.
279
+ // Same as SjpegEncode(), except encoding parameters are passed in a
280
+ // EncoderParam. Upon failure (memory allocation or invalid parameter),
281
+ // the function returns false.
282
+ bool Encode(const uint8_t* rgb, int width, int height, int stride,
283
+ const EncoderParam& param, sjpeg::ByteSink* sink);
284
+
285
+ ////////////////////////////////////////////////////////////////////////////////
286
+ // Some interfaces for customizing the core codec
287
+
288
+ // Custom search loop
289
+ struct SearchHook {
290
+ float q; // this is the current parameter used
291
+ float qmin, qmax; // this is the current bracket for q
292
+ float target; // target value (PSNR or size)
293
+ float tolerance; // relative tolerance for reaching the 'target' value
294
+ bool for_size; // true if we're searching for size
295
+ float value; // result for the search after Update() is called
296
+ int pass; // pass number (0-based) during search (informative)
297
+
298
+ // Returns false in case of initialization error.
299
+ // Should always be called by sub-classes.
300
+ virtual bool Setup(const EncoderParam& param);
301
+ // Set up the next matrices to try, corresponding to the current q value.
302
+ // 'idx' is 0 for luma, 1 for chroma
303
+ virtual void NextMatrix(int idx, uint8_t dst[64]);
304
+ // return true if the search is finished
305
+ virtual bool Update(float result);
306
+ virtual ~SearchHook() {}
307
+ };
308
+
309
+ ////////////////////////////////////////////////////////////////////////////////
310
+ // Generic byte-sink: custom streaming output of compressed data
311
+ //
312
+ // Protocol:
313
+ // . Commit(used_size, extra_size, buffer): specify that 'used_size' bytes
314
+ // were used since the last call to Commit(). Also reserve 'extra_size'
315
+ // bytes for the next cycle and make *data point to the corresponding
316
+ // memory. 'extra_size' can be 0, in which case *buffer does not need
317
+ // to point to a valid memory area. Most of the time (except during
318
+ // header writing), 'extra_size' will be less than 2048.
319
+ // Returns false in case of error (both flushing used_size, or allocating
320
+ // extra_size).
321
+ // . Finalize(): indicates that calls to Commit() are finished until the
322
+ // destruction (and the assembled byte-stream can be grabbed).
323
+ // Returns false in case of I/O error.
324
+ // . Reset(): releases resources (called in case of error or at destruction).
325
+
326
+ struct ByteSink {
327
+ public:
328
+ virtual ~ByteSink() {}
329
+ virtual bool Commit(size_t used_size, size_t extra_size, uint8_t** data) = 0;
330
+ virtual bool Finalize() = 0;
331
+ virtual void Reset() = 0;
332
+ };
333
+
334
+ // Some useful factories
335
+ std::shared_ptr<ByteSink> MakeByteSink(std::string* output);
336
+ // Vector-based template, specialized for uint8_t
337
+ template<typename T>
338
+ std::shared_ptr<ByteSink> MakeByteSink(std::vector<T>* output);
339
+ template<> std::shared_ptr<ByteSink> MakeByteSink(std::vector<uint8_t>* output);
340
+
341
+ ////////////////////////////////////////////////////////////////////////////////
342
+ // Memory manager (for internal allocation)
343
+
344
+ struct MemoryManager {
345
+ public:
346
+ virtual ~MemoryManager() {}
347
+ virtual void* Alloc(size_t size) = 0; // same semantic as malloc()
348
+ virtual void Free(void* const ptr) = 0; // same semantic as free()
349
+ };
350
+
351
+ } // namespace sjpeg
352
+
353
+ #endif // SJPEG_JPEG_H_