libpsd続き その3
まとめとしてlibpsdを使って通常レイヤをpngにばらすコードを書いてlibpsd編は終わりにする。
// main.cpp // // $ g++ main.cpp -lpng -lpsd -ljpeg #include <libpsd.h> #define USE_PNG 1 #include "rgbaimage.h" #include <iostream> int main(int argc, char **argv) { if(argc <= 1){ std::cout << "usage: " << argv[0] << " {psd file}" << std::endl; return -1; } psd_context *context; psd_status status = psd_image_load(&context, argv[1]); if(status!=psd_status_done){ return 1; } char path[1024]; int write_count=1; psd_layer_record *end=context->layer_records+context->layer_count; for(psd_layer_record* layer=context->layer_records; layer!=end; ++layer){ // each layer if(layer->layer_type!=psd_layer_type_normal){ // groupとか捨てる continue; } RGBAImage image(layer->width, layer->height, (unsigned char*)layer->image_data); sprintf(path, "%03d.png", write_count++); image.write_png(path); std::cout << "write: " << path << std::endl; } psd_image_free(context); return 0; };
これだけでlayerを抜き出せる。
psdファイル(gimpで作ったやつとか?)によっては、psd_image_loadで失敗する場合がある様子。ヘッダのブロックの長さを偶数バイトに合わせる界隈とかでずれる時があるような気がするのでその辺直せば動くかも。
あと残りの
rgbaimage.hはpng書き出し用の使い回しコードでlibpsdとは関係ない。
こっちの方が長いけど。
// rgbaimage.h // #ifndef RGB_IMAGE_H #define RGB_IMAGE_H #ifdef USE_PNG #include <png.h> #endif #include <vector> #include <fstream> class RGBAImage { int width_; int height_; std::vector<unsigned char> data_; public: RGBAImage() : width_(0), height_(0) {} RGBAImage(int w, int h) { resize(w, h); } RGBAImage(int w, int h, unsigned char* data) { resize(w, h); data_.assign(data, data+w*h*4); } void resize(int w, int h) { width_=w; height_=h; data_.resize(w*h*4); } unsigned char* get() { return data_.empty() ? NULL : &data_[0]; } bool write_ppm(const char *path) { std::ofstream io(path, std::ios::binary); if(!io){ return false; } // header io << "P6\n" << width_ << ' ' << height_ << '\n' << 255 << '\n' ; // raw data char *current=(char*)&data_[0]; for(int y=0; y<height_; ++y){ for(int x=0; x<width_; ++x, current+=4){ io.write(current, 3); } } return true; } #ifdef USE_PNG bool write_png(const char *path, bool isInterlaced=false) { // output FILE* pFile=fopen(path, "wb"); if(pFile==NULL){ return false; } // png png_struct *pPngStruct=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_info *pPngInfo=png_create_info_struct(pPngStruct); // setjmp png_byte** ppRowTable=0; if(setjmp(pPngStruct->jmpbuf)){ if(ppRowTable){ delete[] ppRowTable; } png_destroy_write_struct(&pPngStruct, &pPngInfo); fclose(pFile); return false; } png_init_io(pPngStruct, pFile); png_set_compression_level(pPngStruct, Z_BEST_COMPRESSION); png_set_IHDR(pPngStruct, pPngInfo, width_, height_, 8, PNG_COLOR_TYPE_RGB_ALPHA, isInterlaced ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // gamma double CRT_exponent=2.2; double LUT_exponent=1.0; double default_display_exponent=LUT_exponent*CRT_exponent; double default_gamma=1.0/default_display_exponent; png_set_gAMA(pPngStruct, pPngInfo, default_gamma); png_write_info(pPngStruct, pPngInfo); png_set_bgr(pPngStruct); if(isInterlaced){ ppRowTable=new png_byte*[height_]; for(int y=0; y<height_; ++y){ ppRowTable[y]=&data_[y*width_*4]; } png_write_image(pPngStruct, ppRowTable); } else{ for(int y=0; y<height_; ++y){ png_write_row(pPngStruct, &data_[y*width_*4]); } } png_write_end(pPngStruct, NULL); if(ppRowTable){ delete[] ppRowTable; } png_destroy_write_struct(&pPngStruct, &pPngInfo); fclose(pFile); return true; } #endif }; #endif
元の作業に戻ろう・・・