Advertisement
donpasquale

PNG Encoder based on libpng

May 30th, 2012
988
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.30 KB | None | 0 0
  1. //============================================================================
  2. // Name     : pngencoder.cpp
  3. // Author     : Pascal Beyeler
  4. // Version   :
  5. // Copyright   : This content is released under the http://www.opensource.org/licenses/mit-license.php MIT License.
  6. // Description : PNG encoder with OpenMP support
  7. //============================================================================
  8.  
  9. typedef unsigned char byte;
  10. typedef unsigned short u16;
  11.  
  12. #include <boost/program_options.hpp>
  13. #include <iostream>
  14. #include <iterator>
  15. #include <fstream>
  16. #include <Magick++/Include.h>
  17. #include <Magick++/Image.h>
  18. #include <Magick++/Pixels.h>
  19. #include <png.h>
  20. #include <math.h>
  21. #include <time.h>
  22. #include <bits/time.h>
  23. #include <omp.h>
  24.  
  25. using namespace std;
  26. using namespace Magick;
  27. namespace po = boost::program_options;
  28.  
  29. double diffclock(clock_t clock1, clock_t clock2) {
  30.     double diffticks = clock1 - clock2;
  31.     double diffms = (diffticks * 1000) / CLOCKS_PER_SEC;
  32.     return diffms;
  33. }
  34.  
  35. void png_write(png_structp png_ptr, png_bytep data, png_size_t length) {
  36.     ofstream* file = (ofstream*) png_get_io_ptr(png_ptr);
  37.     file->write((char*) data, length);
  38.     if (file->bad()) {
  39.         cout << (char*) data << endl << endl << length << endl << file->badbit << endl;
  40.         png_error(png_ptr, "Write error");
  41.     }
  42. }
  43.  
  44. void png_flush(png_structp png_ptr) {
  45.     ofstream* file = (ofstream*) png_get_io_ptr(png_ptr);
  46.     file->flush();
  47. }
  48.  
  49. void png_encode(Image::Image &input_file, ofstream &output_file) {
  50.  
  51.     //Init PNG write struct
  52.     png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  53.     if (!png_ptr) {
  54.         cout << "PNG write struct could not be initialized" << endl;
  55.         return;
  56.     }
  57.  
  58.     //Init PNG info struct
  59.     png_infop info_ptr = png_create_info_struct(png_ptr);
  60.     if (!info_ptr) {
  61.         png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
  62.         cout << "PNG info struct could not be initialized" << endl;
  63.         return;
  64.     }
  65.  
  66.     //Tell the pnglib where to save the image
  67.     png_set_write_fn(png_ptr, &output_file, png_write, png_flush);
  68.  
  69.     //Change from RGB to BGR as Magick++ uses this format
  70.     png_set_bgr(png_ptr);
  71.  
  72.     //Write IHDR chunk
  73.     Geometry::Geometry ig = input_file.size();
  74.     int height = ig.height();
  75.     int width = ig.width();
  76.     png_set_IHDR(png_ptr, info_ptr, width, height, QuantumDepth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
  77.             PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  78.  
  79.     //Depending on the magick++ build, different amount of bytes for the pixel representation is used
  80. #if QuantumDepth==8
  81.     int color_format_bpp = 4;
  82. #elif QuantumDepth==16
  83.     int color_format_bpp = 8;
  84. #endif
  85.  
  86.     //Build rows
  87.     PixelPacket* pixels = input_file.getPixels(0, 0, width, height);
  88.     void** rows = (void**) png_malloc(png_ptr, height * color_format_bpp * width);
  89.     PixelPacket* pixels_row;
  90.     PixelPacket* pixels_op;
  91.     //#pragma omp parallel for private(pixels_row,pixels_op) shared(height,width,rows,pixels,color_format_bpp,png_ptr)
  92.     for (int i = 0; i < height; i++) {
  93.         pixels_row = pixels + i * width;
  94.         pixels_op = pixels_row;
  95.         for (int j = 0; j < width; j++) {
  96.             //change opacity
  97.             pixels_op->opacity = TransparentOpacity;
  98.             pixels_op += 1;
  99.         }
  100.         rows[i] = png_malloc(png_ptr, color_format_bpp * width);
  101.         memcpy(rows[i], pixels_row, color_format_bpp * width);
  102.     }
  103.     png_set_rows(png_ptr, info_ptr, (png_bytepp) rows);
  104.  
  105.     //Write the file header information.
  106.     png_write_info(png_ptr, info_ptr);
  107.  
  108.     //Write the bits
  109.     if (info_ptr->valid & PNG_INFO_IDAT) {
  110.  
  111.         png_uint_32 i; /* row index */
  112.         png_bytepp rp; /* points to current row */
  113.  
  114.         //Loop through image
  115.         for (i = 0, rp = info_ptr->row_pointers; i < png_ptr->height; i++, rp++) {
  116.             png_write_row(png_ptr, *rp);
  117.         }
  118.  
  119.     }
  120.  
  121.     //Write the rest of the file
  122.     png_write_end(png_ptr, info_ptr);
  123.  
  124.     //Cleanup
  125.     png_destroy_write_struct(&png_ptr, &info_ptr);
  126.     for (int i = 0; i < height; ++i) {
  127.         png_free(png_ptr, rows[i]);
  128.     }
  129.     png_free(png_ptr, rows);
  130.  
  131. }
  132.  
  133. int main(int argc, char *argv[]) {
  134.  
  135.     clock_t begin = clock();
  136.  
  137.     Image::Image input_file;
  138.     ofstream output_file;
  139.  
  140.     try {
  141.  
  142.         //Command line argument handling
  143.         po::options_description desc("Allowed options");
  144.         desc.add_options()("help", "produce help message")("input,i", po::value<string>(), "path to input file")(
  145.                 "output,o", po::value<string>(), "path to output file");
  146.  
  147.         po::variables_map vm;
  148.         po::store(po::parse_command_line(argc, argv, desc), vm);
  149.         po::notify(vm);
  150.  
  151.         if (vm.count("help")) {
  152.             cout << desc << "\n";
  153.             return 1;
  154.         }
  155.  
  156.         if (vm.count("input")) {
  157.             input_file.read(vm["input"].as<string>());
  158.  
  159.         } else {
  160.             cout << "Input file was not set.\n";
  161.             return 1;
  162.         }
  163.  
  164.         if (vm.count("output")) {
  165.             output_file.open(vm["output"].as<string>().c_str());
  166.             if (!output_file.good()) {
  167.                 cout << "Output file could not be opened" << endl;
  168.                 return 1;
  169.             }
  170.         } else {
  171.             cout << "Output file was not set.\n";
  172.             return 1;
  173.         }
  174.  
  175.         //Encode the file if everything is okay
  176.         if (input_file.isValid() && output_file.good()) {
  177.             png_encode(input_file, output_file);
  178.         }
  179.         output_file.close();
  180.  
  181.     } catch (exception& e) {
  182.         cerr << "error: " << e.what() << "\n";
  183.         return 1;
  184.     } catch (...) {
  185.         cerr << "Exception of unknown type!\n";
  186.     }
  187.  
  188.     clock_t end = clock();
  189.     cout << "Time elapsed: " << double(diffclock(end, begin)) << " ms" << endl;
  190.  
  191.     return 0;
  192.  
  193. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement