PNGImageEncoder.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * Copyright (C) 2011, 2012 Research In Motion Limited. All rights reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. *
  18. * Portions of this file are Copyright 2005 Google Inc.
  19. */
  20. #include "config.h"
  21. #include "PNGImageEncoder.h"
  22. extern "C" {
  23. #include "png.h"
  24. }
  25. #include <wtf/OwnArrayPtr.h>
  26. // This code is almost a mirror of the code in WebCore/platform/image-encoders/skia/PNGImageEncoder.cpp
  27. // since we can't include this private WebCore file in a WebKit-client application.
  28. // Keep the premultipied for as it is the most faithful information
  29. static void BGRAtoRGBA(const unsigned char* input, int numberOfPixels, unsigned char* output)
  30. {
  31. for (int x = 0; x < numberOfPixels; x++) {
  32. output[0] = input[2];
  33. output[1] = input[1];
  34. output[2] = input[0];
  35. output[3] = input[3];
  36. input += 4;
  37. output += 4;
  38. }
  39. }
  40. // Passed around as the io_ptr in the png structs so our callbacks know where
  41. // to write data.
  42. struct PNGEncoderState {
  43. PNGEncoderState(Vector<unsigned char>* o) : m_out(o) { }
  44. Vector<unsigned char>* m_out;
  45. };
  46. // Called by libpng to flush its internal buffer to ours.
  47. void encoderWriteCallback(png_structp png, png_bytep data, png_size_t size)
  48. {
  49. PNGEncoderState* state = static_cast<PNGEncoderState*>(png_get_io_ptr(png));
  50. ASSERT(state->m_out);
  51. size_t oldSize = state->m_out->size();
  52. state->m_out->resize(oldSize + size);
  53. memcpy(&(*state->m_out)[oldSize], data, size);
  54. }
  55. // Automatically destroys the given write structs on destruction to make
  56. // cleanup and error handling code cleaner.
  57. class PNGWriteStructDestroyer {
  58. public:
  59. PNGWriteStructDestroyer(png_struct** ps, png_info** pi)
  60. : m_pngStruct(ps)
  61. , m_pngInfo(pi)
  62. {
  63. }
  64. ~PNGWriteStructDestroyer()
  65. {
  66. png_destroy_write_struct(m_pngStruct, m_pngInfo);
  67. }
  68. private:
  69. png_struct** m_pngStruct;
  70. png_info** m_pngInfo;
  71. };
  72. typedef void (*PixelConversionFunc)(const unsigned char*, int, unsigned char*);
  73. static bool encodeImpl(const unsigned char* input, int imageWidth, int imageHeight, int bytesPerRow, Vector<unsigned char>* output, PixelConversionFunc conversionFunc)
  74. {
  75. int inputColorComponents = 4;
  76. int outputColorComponents = 4;
  77. int pngOutputColorType = PNG_COLOR_TYPE_RGB_ALPHA;
  78. if (imageWidth < 0)
  79. imageWidth = 0;
  80. if (imageHeight < 0)
  81. imageHeight = 0;
  82. // Row stride should be at least as long as the length of the data.
  83. if (inputColorComponents * imageWidth > bytesPerRow) {
  84. ASSERT(false);
  85. return false;
  86. }
  87. png_struct* pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
  88. if (!pngPtr)
  89. return false;
  90. png_info* infoPtr = png_create_info_struct(pngPtr);
  91. if (!infoPtr) {
  92. png_destroy_write_struct(&pngPtr, 0);
  93. return false;
  94. }
  95. PNGWriteStructDestroyer destroyer(&pngPtr, &infoPtr);
  96. if (setjmp(png_jmpbuf(pngPtr))) {
  97. // The destroyer will ensure that the structures are cleaned up in this
  98. // case, even though we may get here as a jump from random parts of the
  99. // PNG library called below.
  100. return false;
  101. }
  102. // Set our callback for libpng to give us the data.
  103. PNGEncoderState state(output);
  104. png_set_write_fn(pngPtr, &state, encoderWriteCallback, 0);
  105. png_set_IHDR(pngPtr, infoPtr, imageWidth, imageHeight, 8, pngOutputColorType,
  106. PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
  107. PNG_FILTER_TYPE_DEFAULT);
  108. png_write_info(pngPtr, infoPtr);
  109. OwnArrayPtr<unsigned char> rowPixels = adoptArrayPtr(new unsigned char[imageWidth * outputColorComponents]);
  110. for (int y = 0; y < imageHeight; y ++) {
  111. conversionFunc(&input[y * bytesPerRow], imageWidth, rowPixels.get());
  112. png_write_row(pngPtr, rowPixels.get());
  113. }
  114. png_write_end(pngPtr, infoPtr);
  115. return true;
  116. }
  117. bool encodeBitmapToPNG(unsigned char* data, int width, int height, Vector<unsigned char>* output)
  118. {
  119. bool result = encodeImpl(data, width, height, width * 4, output, BGRAtoRGBA);
  120. return result;
  121. }