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); GetQuantMatrixEncoderParam199 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); ~SearchHookSearchHook306 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: ~ByteSinkByteSink328 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: ~MemoryManagerMemoryManager346 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_ 354