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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +40 -0
- data/LICENSE.txt +21 -0
- data/README.md +40 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/sjpeg/bit_writer.cc +122 -0
- data/ext/sjpeg/bit_writer.h +169 -0
- data/ext/sjpeg/colors_rgb.cc +691 -0
- data/ext/sjpeg/dichotomy.cc +290 -0
- data/ext/sjpeg/enc.cc +2132 -0
- data/ext/sjpeg/extconf.rb +3 -0
- data/ext/sjpeg/fdct.cc +627 -0
- data/ext/sjpeg/headers.cc +218 -0
- data/ext/sjpeg/jpeg_tools.cc +274 -0
- data/ext/sjpeg/libsjpeg.pc.in +11 -0
- data/ext/sjpeg/score_7.cc +6220 -0
- data/ext/sjpeg/sjpeg.h +353 -0
- data/ext/sjpeg/sjpegi.h +427 -0
- data/ext/sjpeg/yuv_convert.cc +698 -0
- data/lib/sjpeg/version.rb +3 -0
- data/lib/sjpeg.rb +35 -0
- data/sjpeg.gemspec +36 -0
- metadata +143 -0
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_
|