/* */ /* Copyright (C) 2014 Ferrero Andrea This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/ */ #include #include "file_util.hh" #include "operation.hh" #include "layer.hh" #include "../operations/image_to_map.hh" //#include "../vips/vips_layer.h" static int _phf_operation_serial_id = 0; int vips_layer( int n, VipsImage **out, PF::ProcessorBase* proc, VipsImage* imap, VipsImage* omap, VipsDemandStyle demand_hint, int width, int height, int nbands, int sid, ... ); void PF::OperationConfigUI::open() { get_layer()->get_processor()->get_par()->save_properties(initial_params); } PF::OpParBase::OpParBase(): output_caching_enabled(false), render_mode(PF_RENDER_PREVIEW), map_flag( false ), editing_flag( false ), modified_flag(false), intensity("intensity",this,1), grey_target_channel("grey_target_channel",this,-1,"Grey","Grey"), rgb_target_channel("rgb_target_channel",this,-1,"RGB","RGB"), lab_target_channel("lab_target_channel",this,-1,"Lab","Lab"), cmyk_target_channel("cmyk_target_channel",this,-1,"CMYK","CMYK"), mask_enabled("mask_enabled",this,true), file_format_version( PF_FILE_VERSION ), enable_padding( "enable_padding", this, false ), test_padding(64) { //blend_mode.set_internal(true); intensity.set_internal(true); //opacity.set_internal(true); grey_target_channel.set_internal(true); rgb_target_channel.set_internal(true); lab_target_channel.set_internal(true); cmyk_target_channel.set_internal(true); processor = NULL; //out = NULL; config_ui = NULL; //blend_mode = PF_BLEND_PASSTHROUGH; //blend_mode = PF_BLEND_NORMAL; //blend_mode.set_enum_value( PF_BLEND_PASSTHROUGH ); demand_hint = VIPS_DEMAND_STYLE_ANY; bands = 1; xsize = 100; ysize = 100; rgb_target_channel.add_enum_value(0,"R","R"); rgb_target_channel.add_enum_value(1,"G","G"); rgb_target_channel.add_enum_value(2,"B","B"); lab_target_channel.add_enum_value(0,"L","L"); lab_target_channel.add_enum_value(1,"a","a"); lab_target_channel.add_enum_value(2,"b","b"); cmyk_target_channel.add_enum_value(0,"C","C"); cmyk_target_channel.add_enum_value(1,"M","M"); cmyk_target_channel.add_enum_value(2,"Y","Y"); cmyk_target_channel.add_enum_value(3,"K","K"); to_map = NULL; //PF::PropertyBase* prop; //prop = new PF::Property("intensity",&intensity); } PF::OpParBase::~OpParBase() { //for(unsigned int i = 0; i < outvec.size(); i++ ) { // PF_UNREF( outvec[i], "~OpParBase(): previous outputs unref" ); //} //#ifndef NDEBUG //std::cout<<"~OpParBase(): deleting operation "<<(void*)this<<" ("<::iterator pi; // Look into mapped properties first for(pi = mapped_properties.begin(); pi != mapped_properties.end(); pi++) { //std::cout<<"(*pi)->get_name(): "<<(*pi)->get_name()<<" name: "<get_name() == name ) return( *pi ); } // If nothing is found, look into our own properties for(pi = properties.begin(); pi != properties.end(); pi++) { //std::cout<<"(*pi)->get_name(): "<<(*pi)->get_name()<<" name: "<get_name() == name ) return( *pi ); } return NULL; } void PF::OpParBase::save_properties(std::list& plist) { std::list::iterator pi; for(pi = mapped_properties.begin(); pi != mapped_properties.end(); pi++) { std::string str = (*pi)->get_str(); plist.push_back(str); } for(pi = properties.begin(); pi != properties.end(); pi++) { std::string str = (*pi)->get_str(); plist.push_back(str); } } void PF::OpParBase::restore_properties(const std::list& plist) { std::list::iterator pi; std::list::const_iterator si; for(pi = mapped_properties.begin(), si = plist.begin(); (pi != mapped_properties.end()) && (si != plist.end()); pi++, si++) { (*pi)->set_str(*si); } for(pi = properties.begin(); (pi != properties.end()) && (si != plist.end()); pi++, si++) { (*pi)->set_str(*si); } } void PF::OpParBase::compute_padding( VipsImage* full_res, unsigned int id, unsigned int level ) { int p = enable_padding.get() ? test_padding : 0; set_padding( p, id ); } void PF::OpParBase::modified() { //std::cout<<"OpParBase::modified() called for "<::iterator pi; for(pi = mapped_properties.begin(); pi != mapped_properties.end(); pi++) { (*pi)->clear_modified(); } for(pi = properties.begin(); pi != properties.end(); pi++) { (*pi)->clear_modified(); } } void PF::OpParBase::set_image_hints(int w, int h, VipsInterpretation interpr) { xsize = w; ysize = h; coding = VIPS_CODING_NONE; interpretation = interpr; } void PF::OpParBase::set_image_hints(int w, int h, colorspace_t cs) { xsize = w; ysize = h; coding = VIPS_CODING_NONE; switch(cs) { case PF_COLORSPACE_GRAYSCALE: interpretation = VIPS_INTERPRETATION_B_W; break; case PF_COLORSPACE_RGB: interpretation = VIPS_INTERPRETATION_RGB; break; case PF_COLORSPACE_LAB: interpretation = VIPS_INTERPRETATION_LAB; break; case PF_COLORSPACE_CMYK: interpretation = VIPS_INTERPRETATION_CMYK; break; default: interpretation = VIPS_INTERPRETATION_MULTIBAND; break; } } bool PF::OpParBase::import_settings( OpParBase* pin ) { if( !pin ) { std::cout<<"OpParBase::import_settings(): pin = NULL"<& propin = pin->get_properties(); std::list::iterator pi=propin.begin(), pj=properties.begin(); for( ; pi != propin.end(); pi++, pj++ ) { if( !(*pj)->import( *pi ) ) { std::cout<<"OpParBase::import_settings(): failed to import values for property \""<<(*pj)->get_name()<<"\""<get_name()<<"\" se to "<<(*pj)->get_str()<& mpropin = pin->get_mapped_properties(); std::list::iterator mpi=mpropin.begin(), mpj=mapped_properties.begin(); for( ; mpi != mpropin.end(); mpi++, mpj++ ) { if( !(*mpj)->import( *mpi ) ) { std::cout<<"OpParBase::import_settings(): failed to import values for property \""<<(*mpj)->get_name()<<"\""<is_map() ); //std::cout<<"OpParBase["<is_editing()<<")"<is_editing() ); //set_demand_hint( pin->get_demand_hint() ); //set_image_hints( pin->get_xsize(), pin->get_ysize(), // pin->get_interpretation() ); //set_nbands( pin->get_nbands() ); //set_coding( pin->get_coding() ); //set_format( pin->get_format() ); return true; } VipsImage* PF::OpParBase::build(std::vector& in, int first, VipsImage* imap, VipsImage* omap, unsigned int& level) { VipsImage* outnew = NULL; VipsImage* invec[100]; unsigned int n = 0; for(unsigned int i = 0; i < in.size(); i++) { if( !in[i] ) continue; invec[n] = in[i]; n++; } if(n > 100) n = 100; #ifndef NDEBUG //std::cout<<"OpParBase::build("< PF::OpParBase::build_many_internal(std::vector& in, int first, VipsImage* imap, VipsImage* omap, unsigned int& level) { std::vector in_temp; if( true && convert_inputs_on_map_build() && is_map() && interpretation == VIPS_INTERPRETATION_B_W ) { if( !to_map ) to_map = new_image_to_map(); std::vector in_temp2; std::vector* in_ptr = in_temp.empty() ? &in : &in_temp; for(unsigned int i = 0; i < in_ptr->size(); i++) { VipsImage* img = (*in_ptr)[i]; if( img == NULL || img->Type == interpretation ) { in_temp2.push_back(img); std::cout<<"OpParBase::build_many_internal: op_type="< in2; in2.push_back(img); std::cout<<"OpParBase::build_many_internal: to_map="<get_par(); to_map_op->set_format(get_format()); //to_map_op->set_image_hints(img); //to_map_op->grayscale_image( img->Xsize, img->Ysize ); VipsImage* bwimg = to_map_op->build(in2, 0, NULL, NULL, level); std::cout<<"OpParBase::build_many_internal: bwimg built"< result; if( in_temp.empty() ) result = build_many( in, first, imap, omap, level ); else result = build_many( in_temp, first, imap, omap, level ); #ifndef NDEBUG std::cout<<"OpParBase::build_many_internal(): filling hierarchy with padding "< result_cached; for( unsigned int i = 0; i < result.size(); i++ ) { bool is_dup = false; VipsImage* out = result[i]; for( unsigned int j = 0; j < in.size(); j++ ) { if( out == in[j] ) { is_dup = true; break; } } if( is_dup ) { result_cached.push_back( out ); continue; } int p = get_output_padding( i ); if( p > 32 || needs_caching() ) { VipsAccess acc = VIPS_ACCESS_RANDOM; int threaded = 1, persistent = 1; VipsImage* cached; std::cout<<"OpParBase::build_many_internal(): adding tilecache for output image #" <* in_ptr = in_temp.empty() ? &in : &in_temp; for(unsigned int i = 0; i < in_ptr->size(); i++) { VipsImage* img = (*in_ptr)[i]; PF_UNREF( img, "build_many_internal: img unref" ); std::cout<<"OpParBase::build_many_internal: op_type="<& in, VipsImage* imap, VipsImage* omap, std::vector& out) { for( unsigned int i = 0; i < out.size(); i++ ) { bool is_dup = false; for( unsigned int j = 0; j < in.size(); j++ ) { if( out[i] == in[j] ) { is_dup = true; break; } } if( is_dup ) continue; #ifndef NDEBUG if( get_padding() > 0 ) { std::cout<<"OpParBase::fill_image_hierarchy(): filling hierarchy for image "< maps; if( imap ) maps.push_back(imap); if( omap ) maps.push_back(omap); if( !maps.empty() ) PF::image_hierarchy_fill( out[i], 0, maps ); } } bool PF::OpParBase::save( std::ostream& ostr, int level ) { for(int i = 0; i < level; i++) ostr<<" "; ostr<<""<::iterator pi = properties.begin(); pi != properties.end(); pi++ ) { if( (*pi)->is_persistent() == false ) continue; std::string pvalue = (*pi)->get_str(); for(int i = 0; i < level+1; i++) ostr<<" "; ostr<<"get_name()<<"\" value=\""; //(*pi)->to_stream( ostr ); ostr<"<"<::iterator pi = mapped_properties.begin(); pi != mapped_properties.end(); pi++ ) { if( (*pi)->is_persistent() == false ) continue; std::string pvalue = (*pi)->get_str(); for(int i = 0; i < level+1; i++) ostr<<" "; ostr<<"get_name()<<"\" value=\""; //(*pi)->to_stream( ostr ); ostr<"<"<"<Xsize; int Ysize = out->Ysize; int bands = out->Bands; VipsBandFormat fmt = out->BandFmt; VipsCoding coding = out->Coding; VipsInterpretation type = out->Type; gdouble xres = out->Xres; gdouble yres = out->Yres; VipsImage* invec[2] = {in, NULL}; vips__image_copy_fields_array( out, invec ); vips_image_init_fields( out, Xsize, Ysize, bands, fmt, coding, type, xres, yres ); return 0; } void PF::print_embedded_profile( VipsImage* image ) { PF::ICCProfile* icc_data = PF::get_icc_profile( image ); if(icc_data) { cmsHPROFILE in_profile = icc_data->get_profile(); if( in_profile ) { char tstr[1024]; cmsGetProfileInfoASCII(in_profile, cmsInfoDescription, "en", "US", tstr, 1024); std::cout<<"\""<