~alinuxninja/nginx-edge/trunk

« back to all changes in this revision

Viewing changes to debian/modules/ngx_pagespeed/psol/include/pagespeed/kernel/image/png_optimizer.h

  • Committer: Vivian
  • Date: 2015-12-04 18:20:11 UTC
  • Revision ID: git-v1:a36f2bc32e884f7473b3a47040e5411306144d7d
* Do not extract psol.tar.gz

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright 2009 Google Inc.
3
 
 *
4
 
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 
 * you may not use this file except in compliance with the License.
6
 
 * You may obtain a copy of the License at
7
 
 *
8
 
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 
 *
10
 
 * Unless required by applicable law or agreed to in writing, software
11
 
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 
 * See the License for the specific language governing permissions and
14
 
 * limitations under the License.
15
 
 */
16
 
 
17
 
// Author: Bryan McQuade, Satyanarayana Manyam
18
 
 
19
 
#ifndef PAGESPEED_KERNEL_IMAGE_PNG_OPTIMIZER_H_
20
 
#define PAGESPEED_KERNEL_IMAGE_PNG_OPTIMIZER_H_
21
 
 
22
 
// Note: we should not include setjmp.h here, since libpng 1.2 headers
23
 
// include it themselves, and get unhappy if we do it ourselves.
24
 
 
25
 
extern "C" {
26
 
#ifdef USE_SYSTEM_LIBPNG
27
 
#include "png.h"  // NOLINT
28
 
#else
29
 
#include "third_party/libpng/png.h"
30
 
#endif
31
 
}  // extern "C"
32
 
 
33
 
#include <setjmp.h>
34
 
#include <cstddef>
35
 
#include "third_party/optipng/src/opngreduc/opngreduc.h"
36
 
#include "pagespeed/kernel/base/basictypes.h"
37
 
#include "pagespeed/kernel/base/scoped_ptr.h"
38
 
#include "pagespeed/kernel/base/string.h"
39
 
#include "pagespeed/kernel/image/image_util.h"
40
 
#include "pagespeed/kernel/image/scanline_interface.h"
41
 
#include "pagespeed/kernel/image/scanline_status.h"
42
 
 
43
 
namespace net_instaweb {
44
 
class MessageHandler;
45
 
}
46
 
 
47
 
namespace pagespeed {
48
 
 
49
 
namespace image_compression {
50
 
 
51
 
using net_instaweb::MessageHandler;
52
 
 
53
 
class ScanlineStreamInput;
54
 
 
55
 
struct PngCompressParams {
56
 
  PngCompressParams(int level, int strategy, bool is_progressive);
57
 
  PngCompressParams(bool try_best_compression, bool is_progressive);
58
 
 
59
 
  // Indicates what png filter type to be used while compressing the image.
60
 
  // Valid values for this are
61
 
  //   PNG_FILTER_NONE
62
 
  //   PNG_FILTER_SUB
63
 
  //   PNG_FILTER_UP
64
 
  //   PNG_FILTER_AVG
65
 
  //   PNG_FILTER_PAETH
66
 
  //   PNG_ALL_FILTERS
67
 
  int filter_level;
68
 
  // Indicates which compression strategy to use while compressing the image.
69
 
  // Valid values for this are
70
 
  //   Z_FILTERED
71
 
  //   Z_HUFFMAN_ONLY
72
 
  //   Z_RLE
73
 
  //   Z_FIXED
74
 
  //   Z_DEFAULT_STRATEGY
75
 
  int compression_strategy;
76
 
  // Indicates whether to search for the smallest output by using Opti-PNG and
77
 
  // multiple runs of compression. This mode will use more computation.
78
 
  bool try_best_compression;
79
 
  // Indicates whether to encode the image in progressive / interlacing format.
80
 
  bool is_progressive;
81
 
};
82
 
 
83
 
// Helper that manages the lifetime of the png_ptr and info_ptr.
84
 
class ScopedPngStruct {
85
 
 public:
86
 
  enum Type {
87
 
    READ,
88
 
    WRITE
89
 
  };
90
 
 
91
 
  ScopedPngStruct(Type type, MessageHandler* handler);
92
 
  ~ScopedPngStruct();
93
 
 
94
 
  bool valid() const { return png_ptr_ != NULL && info_ptr_ != NULL; }
95
 
 
96
 
  // This will only return false as a result of a longjmp due to an
97
 
  // unhandled libpng error.
98
 
  bool reset();
99
 
 
100
 
  png_structp png_ptr() const { return png_ptr_; }
101
 
  png_infop info_ptr() const { return info_ptr_; }
102
 
 
103
 
 private:
104
 
  png_structp png_ptr_;
105
 
  png_infop info_ptr_;
106
 
  Type type_;
107
 
  MessageHandler* message_handler_;
108
 
};
109
 
 
110
 
// Helper class that provides an API to read a PNG image from some
111
 
// source.
112
 
class PngReaderInterface {
113
 
 public:
114
 
  PngReaderInterface();
115
 
  virtual ~PngReaderInterface();
116
 
 
117
 
  // Parse the contents of body, convert to a PNG, and populate the
118
 
  // PNG structures with the PNG representation. If 'require_opaque'
119
 
  // is true, returns an image without an alpha channel if the
120
 
  // original image has no transparent pixels, and fails
121
 
  // otherwise. Returns true on success, false on failure.
122
 
  virtual bool ReadPng(const GoogleString& body,
123
 
                       png_structp png_ptr,
124
 
                       png_infop info_ptr,
125
 
                       int transforms,
126
 
                       bool require_opaque) const = 0;
127
 
 
128
 
  // Parse the contents of body, convert to a PNG, and populate the
129
 
  // PNG structures with the PNG representation. Returns true on
130
 
  // success, false on failure.
131
 
  bool ReadPng(const GoogleString& body,
132
 
               png_structp png_ptr,
133
 
               png_infop info_ptr,
134
 
               int transforms) const {
135
 
    return ReadPng(body, png_ptr, info_ptr, transforms, false);
136
 
  }
137
 
 
138
 
  // Get just the attributes of the given image. out_bit_depth is the
139
 
  // number of bits per channel. out_color_type is one of the
140
 
  // PNG_COLOR_TYPE_* declared in png.h.
141
 
  // TODO(bmcquade): consider merging this with ImageAttributes.
142
 
  virtual bool GetAttributes(const GoogleString& body,
143
 
                             int* out_width,
144
 
                             int* out_height,
145
 
                             int* out_bit_depth,
146
 
                             int* out_color_type) const = 0;
147
 
 
148
 
  // Get the background color, in the form of 8-bit RGB triplets. Note
149
 
  // that if the underlying image uses a bit_depth other than 8, the
150
 
  // background color will be scaled to 8-bits per channel.
151
 
  static bool GetBackgroundColor(
152
 
      png_structp png_ptr, png_infop info_ptr,
153
 
      unsigned char *red, unsigned char* green, unsigned char* blue,
154
 
      MessageHandler* handler);
155
 
 
156
 
  // Returns true if the alpha channel is actually a opaque. Returns
157
 
  // false otherwise. It is an error to call this method for an image
158
 
  // that does not have an alpha channel.
159
 
  static bool IsAlphaChannelOpaque(png_structp png_ptr, png_infop info_ptr,
160
 
                                   MessageHandler* handler);
161
 
 
162
 
 private:
163
 
  DISALLOW_COPY_AND_ASSIGN(PngReaderInterface);
164
 
};
165
 
 
166
 
// Reader for PNG-encoded data.
167
 
// This is sample code on how someone can use the scanline reader
168
 
// interface.
169
 
// bool func() {
170
 
//   if (setjmp(*GetJmpBuf())) {
171
 
//     return false;
172
 
//   }
173
 
//
174
 
//   InitializeRead(...)
175
 
//   while (HasMoreScanlines()) {
176
 
//     Scanline line;
177
 
//     ReadNextScanline(line);
178
 
//     ....
179
 
//     ....
180
 
//   }
181
 
// }
182
 
class PngScanlineReader : public ScanlineReaderInterface {
183
 
 public:
184
 
  explicit PngScanlineReader(MessageHandler* handler);
185
 
  virtual ~PngScanlineReader();
186
 
 
187
 
  jmp_buf* GetJmpBuf();
188
 
 
189
 
  // This will only return false as a result of a longjmp due to an
190
 
  // unhandled libpng error.
191
 
  virtual bool Reset();
192
 
 
193
 
  // Initializes the read structures with the given input.
194
 
  bool InitializeRead(const PngReaderInterface& reader, const GoogleString& in);
195
 
  bool InitializeRead(const PngReaderInterface& reader, const GoogleString& in,
196
 
                      bool* is_opaque);
197
 
 
198
 
  virtual size_t GetBytesPerScanline();
199
 
  virtual bool HasMoreScanLines();
200
 
  virtual ScanlineStatus ReadNextScanlineWithStatus(void** out_scanline_bytes);
201
 
  virtual size_t GetImageHeight();
202
 
  virtual size_t GetImageWidth();
203
 
  virtual PixelFormat GetPixelFormat();
204
 
  virtual bool IsProgressive();
205
 
 
206
 
  void set_transform(int transform);
207
 
  void set_require_opaque(bool require_opaque);
208
 
  int GetColorType();
209
 
  bool GetBackgroundColor(
210
 
      unsigned char* red, unsigned char* green, unsigned char* blue);
211
 
 
212
 
  // This is a no-op and should not be called.
213
 
  virtual ScanlineStatus InitializeWithStatus(const void* image_buffer,
214
 
                                              size_t buffer_length);
215
 
 
216
 
 private:
217
 
  ScopedPngStruct read_;
218
 
  size_t current_scanline_;
219
 
  int transform_;
220
 
  bool require_opaque_;
221
 
  MessageHandler* message_handler_;
222
 
 
223
 
  DISALLOW_COPY_AND_ASSIGN(PngScanlineReader);
224
 
};
225
 
 
226
 
class PngOptimizer {
227
 
 public:
228
 
  static bool OptimizePng(const PngReaderInterface& reader,
229
 
                          const GoogleString& in,
230
 
                          GoogleString* out,
231
 
                          MessageHandler* handler);
232
 
 
233
 
  static bool OptimizePngBestCompression(const PngReaderInterface& reader,
234
 
                                         const GoogleString& in,
235
 
                                         GoogleString* out,
236
 
                                         MessageHandler* handler);
237
 
 
238
 
  static bool CopyPngStructs(const ScopedPngStruct& from, ScopedPngStruct* to);
239
 
 
240
 
 private:
241
 
  explicit PngOptimizer(MessageHandler* handler);
242
 
  ~PngOptimizer();
243
 
 
244
 
  // Take the given input and losslessly compress it by removing
245
 
  // all unnecessary chunks, and by choosing an optimal PNG encoding.
246
 
  // @return true on success, false on failure.
247
 
  bool CreateOptimizedPng(const PngReaderInterface& reader,
248
 
                          const GoogleString& in,
249
 
                          GoogleString* out,
250
 
                          MessageHandler* handler);
251
 
 
252
 
  // Turn on best compression. Requires additional CPU but produces
253
 
  // smaller files.
254
 
  void EnableBestCompression() { best_compression_ = true; }
255
 
 
256
 
  bool WritePng(ScopedPngStruct* write, GoogleString* buffer);
257
 
  bool CopyReadToWrite();
258
 
  bool CreateBestOptimizedPngForParams(const PngCompressParams* param_list,
259
 
                                       size_t param_list_size,
260
 
                                       GoogleString* out);
261
 
  bool CreateOptimizedPngWithParams(ScopedPngStruct* write,
262
 
                                    const PngCompressParams& params,
263
 
                                    GoogleString* out);
264
 
  ScopedPngStruct read_;
265
 
  ScopedPngStruct write_;
266
 
  bool best_compression_;
267
 
  MessageHandler* message_handler_;
268
 
 
269
 
  DISALLOW_COPY_AND_ASSIGN(PngOptimizer);
270
 
};
271
 
 
272
 
// Reader for PNG-encoded data.
273
 
class PngReader : public PngReaderInterface {
274
 
 public:
275
 
  explicit PngReader(MessageHandler* handler);
276
 
  virtual ~PngReader();
277
 
  virtual bool ReadPng(const GoogleString& body,
278
 
                       png_structp png_ptr,
279
 
                       png_infop info_ptr,
280
 
                       int transforms,
281
 
                       bool require_opaque) const;
282
 
 
283
 
  virtual bool GetAttributes(const GoogleString& body,
284
 
                             int* out_width,
285
 
                             int* out_height,
286
 
                             int* out_bit_depth,
287
 
                             int* out_color_type) const;
288
 
 
289
 
 private:
290
 
  MessageHandler* message_handler_;
291
 
  DISALLOW_COPY_AND_ASSIGN(PngReader);
292
 
};
293
 
 
294
 
// Class PngScanlineReaderRaw decodes PNG images and outputs the raw pixel data,
295
 
// image size, pixel type, etc. The class accepts all formats supported by
296
 
// libpng. The output is Gray_8, RGB_888, or RGBA_8888. The following
297
 
// transformations are used:
298
 
//   - Image with depth other than 8 bits/pixel is expanded or stripped to
299
 
//     8 bits/pixel.
300
 
//   - Paletted image is converted to RGB or RGBA depending on whether
301
 
//     transparency is specified.
302
 
//   - Gray_Alpha is converted to RGBA.
303
 
//
304
 
// Note: The input image stream must be valid throughout the life of the
305
 
//   object. In other words, the image_buffer input you set to the Initialize()
306
 
//   method cannot be changed until your last call to the ReadNextScanline()
307
 
//   method.
308
 
//
309
 
class PngScanlineReaderRaw : public ScanlineReaderInterface {
310
 
 public:
311
 
  explicit PngScanlineReaderRaw(MessageHandler* handler);
312
 
  virtual ~PngScanlineReaderRaw();
313
 
 
314
 
  // This will only return false as a result of a longjmp due to an
315
 
  // unhandled libpng error.
316
 
  virtual bool Reset();
317
 
 
318
 
  // Initialize the reader with the given image stream. Note that image_buffer
319
 
  // must remain unchanged until the last call to ReadNextScanline().
320
 
  virtual ScanlineStatus InitializeWithStatus(const void* image_buffer,
321
 
                                              size_t buffer_length);
322
 
 
323
 
  // Return the next row of pixels. For non-progressive PNG,
324
 
  // ReadNextScanlineWithStatus will decode one row of pixels each
325
 
  // time when it is called, but for progressive PNG,
326
 
  // ReadNextScanlineWithStatus will decode the entire image at the
327
 
  // first time when it is called.
328
 
  virtual ScanlineStatus ReadNextScanlineWithStatus(void** out_scanline_bytes);
329
 
 
330
 
  // Return the number of bytes in a row (without padding).
331
 
  virtual size_t GetBytesPerScanline() { return bytes_per_row_; }
332
 
 
333
 
  virtual bool HasMoreScanLines() { return (row_ < height_); }
334
 
  virtual PixelFormat GetPixelFormat() { return pixel_format_; }
335
 
  virtual size_t GetImageHeight() { return height_; }
336
 
  virtual size_t GetImageWidth() {  return width_; }
337
 
  virtual bool IsProgressive() { return is_progressive_; }
338
 
 
339
 
 private:
340
 
  PixelFormat pixel_format_;
341
 
  bool is_progressive_;
342
 
  size_t height_;
343
 
  size_t width_;
344
 
  size_t bytes_per_row_;
345
 
  size_t row_;
346
 
  bool was_initialized_;
347
 
  net_instaweb::scoped_array<png_byte> image_buffer_;
348
 
  net_instaweb::scoped_array<png_bytep> row_pointers_;
349
 
  scoped_ptr<ScopedPngStruct> png_struct_;
350
 
  // png_input_ stores a pointer to the input image stream. It also keeps
351
 
  // tracking the length of data that libpng has read. It is initialized
352
 
  // in Initialize() and is updated in ReadNextScanline().
353
 
  scoped_ptr<ScanlineStreamInput> png_input_;
354
 
  MessageHandler* message_handler_;
355
 
 
356
 
  DISALLOW_COPY_AND_ASSIGN(PngScanlineReaderRaw);
357
 
};
358
 
 
359
 
// Class PngScanlineWriter writes a PNG image. It supports Gray_8, RGB_888,
360
 
// and RGBA_8888 formats.
361
 
class PngScanlineWriter : public ScanlineWriterInterface {
362
 
 public:
363
 
  explicit PngScanlineWriter(MessageHandler* handler);
364
 
  virtual ~PngScanlineWriter();
365
 
 
366
 
  // Initialize the basic parameters for writing the image. Size of the image
367
 
  // must be 1-by-1 or larger.
368
 
  virtual ScanlineStatus InitWithStatus(const size_t width, const size_t height,
369
 
                                        PixelFormat pixel_format);
370
 
 
371
 
  // Initialize additional parameters for writing the image using
372
 
  // 'params', which should be a PngCompressParams*. You can set
373
 
  // 'params' to NULL to use the default compression configuration.
374
 
  virtual ScanlineStatus InitializeWriteWithStatus(const void* params,
375
 
                                                   GoogleString* png_image);
376
 
 
377
 
  // Write a scanline with the data provided. Return false in case of error.
378
 
  virtual ScanlineStatus WriteNextScanlineWithStatus(
379
 
      const void *scanline_bytes);
380
 
 
381
 
  // Finalize write structure once all scanlines are written.
382
 
  // If FinalizeWriter() is called before all of the scanlines have been
383
 
  // written, the object will be reset to the initial state.
384
 
  virtual ScanlineStatus FinalizeWriteWithStatus();
385
 
 
386
 
 private:
387
 
  // Reset the object to the usable state.
388
 
  bool Reset();
389
 
 
390
 
  // Validate the input parameters.
391
 
  bool Validate(const PngCompressParams* params,
392
 
                GoogleString* png_image);
393
 
 
394
 
  bool DoBestCompression();
395
 
 
396
 
 private:
397
 
  size_t width_;
398
 
  size_t height_;
399
 
  size_t bytes_per_row_;
400
 
  size_t row_;
401
 
  PixelFormat pixel_format_;
402
 
  scoped_ptr<ScopedPngStruct> png_struct_;
403
 
  bool was_initialized_;
404
 
  bool try_best_compression_;
405
 
  net_instaweb::scoped_array<unsigned char> pixel_buffer_;
406
 
  MessageHandler* message_handler_;
407
 
 
408
 
  DISALLOW_COPY_AND_ASSIGN(PngScanlineWriter);
409
 
};
410
 
 
411
 
}  // namespace image_compression
412
 
 
413
 
}  // namespace pagespeed
414
 
 
415
 
#endif  // PAGESPEED_KERNEL_IMAGE_PNG_OPTIMIZER_H_