如何用libpng輸出一個編輯後的png圖片?

Koma_Wong發表於2018-06-13

如何用libpng輸出一個png圖片?

/* Copyright (c) 2013 Frank Ham and Phuc Quang */
#include <iostream>
#include <string>
#include <png.h>

using namespace std;

#ifndef PNG_WRITER_HPP
#define PNG_WRITER_HPP

// Sample usage:
//    PngWriter png(nx,ny);
//    // then one or more calls to...
//    png.set(i, j, red, green, blue); // 0 <= red,green,blue <= 255
//    png.write("myfile.png");
//      at this point you can change the image and write again...
//    png.set(i, j, red, green, blue);
//    png.write("myfile2.png");
class PngWriter {
private:
    unsigned char (*buffer)[3]; // 0 <= r,g,b < 255 
    int nx,ny;
public:
    PngWriter(const int width,const int height) {
        nx = width;
        ny = height;
        buffer = new unsigned char[nx*ny][3];

        for (int i = 0; i < nx*ny; ++i) {
            //cyan
            buffer[i][0] = 73;
            buffer[i][1] = 175;
            buffer[i][2] = 205;
        }
    }
    ~PngWriter() {
        delete[] buffer;
    }
    /*給某一點的畫素賦值*/
    void set(const int i,
           const int j,
           const unsigned char r,
           const unsigned char g,         
           const unsigned char b) 
    {
        buffer[(ny-j-1)*nx+i][0] = r;
        buffer[(ny-j-1)*nx+i][1] = g;
        buffer[(ny-j-1)*nx+i][2] = b;
    }
    /*修復原作者的char **/
    void write(string filename) {

        FILE * fp = fopen(filename.c_str(),"wb");
        if (!fp) {
            std::cout << "Warning: could not open png file: " 
                    << filename 
                    << std::endl;
            return;
        }
        
        png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                              (png_voidp)NULL,NULL,NULL);
        if (!png_ptr) {
            fclose(fp);
            std::cout << "Warning: could not create png_ptr" << std::endl;
            return;
        }
        
        png_infop info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr) {
            png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
            std::cout << "Warning: could not create info_ptr" << std::endl;
            return;
        }
        png_init_io(png_ptr, fp);
        png_set_IHDR(png_ptr, info_ptr,
             nx, ny,             // width, height
             8,                  // bits per pixel -- 16 does not work with blockbuster
             PNG_COLOR_TYPE_RGB, // non-alpha options are PNG_COLOR_TYPE_RGB,PNG_COLOR_TYPE_GRAY,
             PNG_INTERLACE_NONE,
             PNG_COMPRESSION_TYPE_DEFAULT,
             PNG_FILTER_TYPE_DEFAULT);

        /* Some bits per pixel notes: 16 does not work with blockbuster, and there are also 
         issues with PNG_COLOR_TYPE_GRAY interpretation, so stick to 8 and PNG_COLOR_TYPE_RGB
         for now. Note that if you do use 16, pay attention to MSB/LSB order. Endian is 
         flipped on my linux workstation... */
        
        png_write_info(png_ptr, info_ptr);
        
        // set up row pointers to point into the raw image data in buffer...
        
        png_byte * row_pointers[ny];
        for (int i = 0; i < ny; ++i)
          row_pointers[i] = (png_byte*)(buffer + i*nx);
        
        png_write_image(png_ptr, row_pointers);
        png_write_end(png_ptr, NULL);
        png_destroy_write_struct(&png_ptr, &info_ptr);

        fclose(fp);
    }
};
#endif

// g++ main.cpp -lpng 
int main(int argc,char * argv[]) 
{
    PngWriter png(800,600);
    // set some pixels....
    for (int i = 0; i < 800; ++i)
        for (int j = 0; j < 600; ++j)
            png.set(i,j,i+j,i-j,j-i); 
    // then write...
    png.write("sample1.png");
    for (int i = 400; i < 500; ++i)
        for (int j = 200; j < 300; ++j)
            png.set(i,j,10,10,10);
    png.write("sample2.png");
}

我的環境:cygwin,g++ (GCC) 7.3.0

編譯,執行

$ g++ main.cpp -lpng

$ ./a.exe

結果


相關文章