sjpeg 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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_
|