}
surface.clear();
- if(!newimporter->get_frame(surface,Time(0)))
+ if(!newimporter->get_frame(surface,Time(0),trimmed,width,height,top,left))
{
synfig::warning(strprintf("Unable to get frame from \"%s\"",filename_with_path.c_str()));
}
void
Import::set_time(Context context, Time time)const
{
- if(get_amount() && importer && importer->is_animated())importer->get_frame(surface,time+time_offset);
- //else surface.clear();
+ if(get_amount() && importer &&
+ importer->is_animated())
+ importer->get_frame(surface,time+time_offset,trimmed,width,height,top,left);
+
context.set_time(time);
}
void
Import::set_time(Context context, Time time, const Point &pos)const
{
- if(get_amount() && importer && importer->is_animated())importer->get_frame(surface,time+time_offset);
- //else surface.clear();
+ if(get_amount() && importer &&
+ importer->is_animated())
+ importer->get_frame(surface,time+time_offset,trimmed,width,height,top,left);
+
context.set_time(time,pos);
}
png_read_image(png_ptr, row_pointers);
- int x;
- int y;
+ png_uint_32 x, y;
surface_buffer.set_wh(width,height);
switch(color_type)
{
case PNG_COLOR_TYPE_RGB:
- for(y=0;y<surface_buffer.get_h();y++)
- for(x=0;x<surface_buffer.get_w();x++)
+ for(y=0;y<height;y++)
+ for(x=0;x<width;x++)
{
float r=gamma().r_U8_to_F32((unsigned char)row_pointers[y][x*3+0]);
float g=gamma().g_U8_to_F32((unsigned char)row_pointers[y][x*3+1]);
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
- for(y=0;y<surface_buffer.get_h();y++)
- for(x=0;x<surface_buffer.get_w();x++)
+ for(y=0;y<height;y++)
+ for(x=0;x<width;x++)
{
float r=gamma().r_U8_to_F32((unsigned char)row_pointers[y][x*4+0]);
float g=gamma().g_U8_to_F32((unsigned char)row_pointers[y][x*4+1]);
break;
case PNG_COLOR_TYPE_GRAY:
- for(y=0;y<surface_buffer.get_h();y++)
- for(x=0;x<surface_buffer.get_w();x++)
+ for(y=0;y<height;y++)
+ for(x=0;x<width;x++)
{
float gray=gamma().g_U8_to_F32((unsigned char)row_pointers[y][x]);
//float gray=(float)(unsigned char)row_pointers[y][x]*(1.0/255.0);
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
- for(y=0;y<surface_buffer.get_h();y++)
- for(x=0;x<surface_buffer.get_w();x++)
+ for(y=0;y<height;y++)
+ for(x=0;x<width;x++)
{
float gray=gamma().g_U8_to_F32((unsigned char)row_pointers[y][x*2]);
// float gray=(float)(unsigned char)row_pointers[y][x*2]*(1.0/255.0);
case PNG_COLOR_TYPE_PALETTE:
synfig::warning("png_mptr: Paletted PNGs aren't yet fully supported.");
- for(y=0;y<surface_buffer.get_h();y++)
- for(x=0;x<surface_buffer.get_w();x++)
+ for(y=0;y<height;y++)
+ for(x=0;x<width;x++)
{
float r=gamma().r_U8_to_F32((unsigned char)png_ptr->palette[row_pointers[y][x]].red);
float g=gamma().g_U8_to_F32((unsigned char)png_ptr->palette[row_pointers[y][x]].green);
delete [] row_pointers;
delete [] data;
+
+ trim = false;
+
+ if (getenv("SYNFIG_DISABLE_CROP_IMPORTED_IMAGES"))
+ return;
+
+ switch(color_type)
+ {
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ case PNG_COLOR_TYPE_PALETTE:
+ for(y=0;y<height;y++)
+ {
+ for(x=0;x<width;x++)
+ if (surface_buffer[y][x].get_a()) break;
+ if (x != width) break;
+ }
+
+ if (y != height)
+ {
+#define BORDER 1 // don't chop off all the transparent space - leave a border this many pixels wide for the interpolation
+
+ png_uint_32 min_x, min_y, max_x, max_y;
+ if (y>BORDER) min_y = y-BORDER; else min_y = 0;
+
+ for(y=height-1;y>0;y--)
+ {
+ for(x=0;x<width;x++)
+ if (surface_buffer[y][x].get_a()) break;
+ if (x != width) break;
+ }
+ max_y = std::min(y+BORDER,height-1);
+
+ for(x=0;x<width;x++)
+ {
+ for(y=0;y<height;y++)
+ if (surface_buffer[y][x].get_a()) break;
+ if (y != height) break;
+ }
+ if (x>BORDER) min_x = x-BORDER; else min_x = 0;
+
+ for(x=width-1;x>0;x--)
+ {
+ for(y=0;y<height;y++)
+ if (surface_buffer[y][x].get_a()) break;
+ if (y != height) break;
+ }
+ max_x = std::min(x+BORDER,width-1);
+
+ if (min_x != 0 || max_x != width-1 ||
+ min_y != 0 || max_y != height-1)
+ {
+ trim = true;
+ orig_width = width;
+ orig_height = height;
+ trimmed_x = min_x;
+ trimmed_y = min_y;
+
+ width=max_x-min_x+1;
+ height=max_y-min_y+1;
+ synfig::Surface tmp_buffer;
+ tmp_buffer.set_wh(width,height);
+ for(y=0;y<height;y++)
+ for(x=0;x<width;x++)
+ tmp_buffer[y][x] = surface_buffer[y+min_y][x+min_x];
+ surface_buffer = tmp_buffer;
+ }
+ }
+ }
}
png_mptr::~png_mptr()
bool
png_mptr::get_frame(synfig::Surface &surface,Time, synfig::ProgressCallback */*cb*/)
{
+ assert(0); // shouldn't be called?
surface=surface_buffer;
return true;
}
+
+bool
+png_mptr::get_frame(synfig::Surface &surface,Time,
+ bool &trimmed, unsigned int &width, unsigned int &height, unsigned int &top, unsigned int &left,
+ synfig::ProgressCallback */*cb*/)
+{
+ surface=surface_buffer;
+ if ((trimmed = trim))
+ {
+ width = orig_width;
+ height = orig_height;
+ top = trimmed_y;
+ left = trimmed_x;
+ }
+ return true;
+}
png_infop info_ptr;
png_infop end_info;
+ bool trim;
+ unsigned int orig_width, orig_height, trimmed_x, trimmed_y;
+
static void png_out_error(png_struct *png_data,const char *msg);
static void png_out_warning(png_struct *png_data,const char *msg);
static int read_chunk_callback(png_struct *png_data, png_unknown_chunkp chunk);
~png_mptr();
virtual bool get_frame(synfig::Surface &surface,synfig::Time time, synfig::ProgressCallback *callback);
+ virtual bool get_frame(synfig::Surface &surface,synfig::Time time,
+ bool &trimmed, unsigned int &width, unsigned int &height, unsigned int &top, unsigned int &left,
+ synfig::ProgressCallback *callback);
};
/* === E N D =============================================================== */
+#include <cstdio>
/* === S Y N F I G ========================================================= */
/*! \file importer.h
** \brief writeme
** \see ProgressCallback, Surface
*/
virtual bool get_frame(Surface &surface,Time time, ProgressCallback *callback=NULL)=0;
+ virtual bool get_frame(Surface &surface,Time time,
+ bool &trimmed __attribute__ ((unused)),
+ unsigned int &width __attribute__ ((unused)), unsigned int &height __attribute__ ((unused)),
+ unsigned int &top __attribute__ ((unused)), unsigned int &left __attribute__ ((unused)),
+ ProgressCallback *callback=NULL) {
+ return get_frame(surface,time,callback);
+ }
//! Returns \c true if the importer pays attention to the \a time parameter of get_frame()
virtual bool is_animated() { return false; }
br (0.5,-0.5),
c (1),
surface (128,128),
+ trimmed (false),
gamma_adjust (1.0)
{
}
if(param=="_width")
{
+ if (trimmed) return int(width);
return surface.get_w();
}
if(param=="_height")
{
+ if (trimmed) return int(height);
return surface.get_h();
}
surface_pos[1]/=br[1]-tl[1];
if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0)
{
- surface_pos[0]*=surface.get_w();
- surface_pos[1]*=surface.get_h();
+ if (trimmed)
+ {
+ surface_pos[0]*=width;
+ surface_pos[1]*=height;
+
+ if (surface_pos[0] > left+surface.get_w() || surface_pos[0] < left || surface_pos[1] > top+surface.get_h() || surface_pos[1] < top)
+ return context.get_color(pos);
+
+ surface_pos[0] -= left;
+ surface_pos[1] -= top;
+ }
+ else
+ {
+ surface_pos[0]*=surface.get_w();
+ surface_pos[1]*=surface.get_h();
+ }
Color ret(Color::alpha());
if( get_amount()==1 &&
get_blend_method()==Color::BLEND_STRAIGHT &&
+ !trimmed &&
renddesc.get_tl()==tl &&
renddesc.get_br()==br)
{
//sa = scaling for input (0,1) -> (0,w/h)
//sb = scaling for output (0,1) -> (0,w/h)
- float inwf = br[0] - tl[0];
- float inhf = br[1] - tl[1];
-
float outwf = obr[0] - otl[0];
float outhf = obr[1] - otl[1];
int outw = renddesc.get_w();
int outh = renddesc.get_h();
+ float inwf, inhf;
+ Point itl, ibr;
+
+ if (trimmed)
+ {
+ inwf = (br[0] - tl[0])*surface.get_w()/width;
+ inhf = (br[1] - tl[1])*surface.get_h()/height;
+ itl = Point(tl[0] + (br[0]-tl[0])*left/width,
+ tl[1] + (br[1]-tl[1])*top/height);
+ ibr = Point(tl[0] + (br[0]-tl[0])*(left+inw)/width,
+ tl[1] + (br[1]-tl[1])*(top+inh)/height);
+ }
+ else
+ {
+ inwf = br[0] - tl[0];
+ inhf = br[1] - tl[1];
+ itl = tl;
+ ibr = br;
+ }
+
//need to get the input coords in output space, so we can clip
//get the desired corners of the bitmap (in increasing order) in integers
//floating point corners
- float x1f = (tl[0] - otl[0])*outw/outwf;
- float x2f = (br[0] - otl[0])*outw/outwf;
- float y1f = (tl[1] - otl[1])*outh/outhf;
- float y2f = (br[1] - otl[1])*outh/outhf;
+ float x1f = (itl[0] - otl[0])*outw/outwf;
+ float x2f = (ibr[0] - otl[0])*outw/outwf;
+ float y1f = (itl[1] - otl[1])*outh/outhf;
+ float y2f = (ibr[1] - otl[1])*outh/outhf;
if(x1f > x2f) swap(x1f,x2f);
if(y1f > y2f) swap(y1f,y2f);
// in int -> out float:
// Sb(B^-1)A(Sa^-1) x
- float inx_start = (((x_start/*+0.5f*/)*outwf/outw + otl[0]) - tl[0])*inw/inwf; //may want to bias this (center of pixel)???
- float iny_start = (((y_start/*+0.5f*/)*outhf/outh + otl[1]) - tl[1])*inh/inhf; //may want to bias this (center of pixel)???
+ float inx_start = (((x_start/*+0.5f*/)*outwf/outw + otl[0]) - itl[0])*inw/inwf; //may want to bias this (center of pixel)???
+ float iny_start = (((y_start/*+0.5f*/)*outhf/outh + otl[1]) - itl[1])*inh/inhf; //may want to bias this (center of pixel)???
//calculate the delta values in input space for one pixel movement in output space
//same matrix but with a vector instead of a point...
Point br;
int c;
mutable Surface surface;
+ mutable bool trimmed;
+ mutable unsigned int width, height, top, left;
Real gamma_adjust;
bool studio::App::single_threaded=false;
#endif
bool studio::App::restrict_radius_ducks=false;
+bool studio::App::resize_imported_images=false;
String studio::App::custom_filename_prefix(DEFAULT_FILENAME_PREFIX);
int studio::App::preferred_x_size=480;
int studio::App::preferred_y_size=270;
value=strprintf("%i",(int)App::restrict_radius_ducks);
return true;
}
+ if(key=="resize_imported_images")
+ {
+ value=strprintf("%i",(int)App::resize_imported_images);
+ return true;
+ }
if(key=="browser_command")
{
value=App::browser_command;
App::restrict_radius_ducks=i;
return true;
}
+ if(key=="resize_imported_images")
+ {
+ int i(atoi(value.c_str()));
+ App::resize_imported_images=i;
+ return true;
+ }
if(key=="browser_command")
{
App::browser_command=value;
#endif
ret.push_back("auto_recover_backup_interval");
ret.push_back("restrict_radius_ducks");
+ ret.push_back("resize_imported_images");
ret.push_back("browser_command");
ret.push_back("custom_filename_prefix");
ret.push_back("preferred_x_size");
synfigapp::Main::settings().set_value("pref.single_threaded","0");
#endif
synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
+ synfigapp::Main::settings().set_value("pref.resize_imported_images","0");
synfigapp::Main::settings().set_value("pref.custom_filename_prefix",DEFAULT_FILENAME_PREFIX);
synfigapp::Main::settings().set_value("pref.preferred_x_size","480");
synfigapp::Main::settings().set_value("pref.preferred_y_size","270");
#endif
static bool restrict_radius_ducks;
+ static bool resize_imported_images;
static synfig::String browser_command;
static synfig::String custom_filename_prefix;
}
else
{
- if(canvas_interface()->import(filename))
+ if(canvas_interface()->import(filename, App::resize_imported_images))
success=true;
}
// String filename(dirname(get_canvas()->get_file_name()));
String filename("*.*");
if(App::dialog_open_file(_("Import Image"), filename, IMAGE_DIR_PREFERENCE))
- canvas_interface()->import(filename);
+ canvas_interface()->import(filename, App::resize_imported_images);
}
Smach::event_result
toggle_single_threaded(_("Use Only a Single Thread")),
#endif
toggle_restrict_radius_ducks(_("Restrict Real-Valued Ducks to Top Right Quadrant")),
+ toggle_resize_imported_images(_("Scale New Imported Images to Fit Canvas")),
adj_pref_x_size(480,1,10000,1,10,0),
adj_pref_y_size(270,1,10000,1,10,0)
// Misc - restrict_radius_ducks
misc_table->attach(toggle_restrict_radius_ducks, 0, 2, 8, 9, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, xpadding, ypadding);
+ // Misc - resize_imported_images
+ misc_table->attach(toggle_resize_imported_images, 0, 2, 9, 10, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, xpadding, ypadding);
+
// Misc - browser_command
attach_label(misc_table, _("Browser Command"), 4, xpadding, ypadding);
misc_table->attach(textbox_browser_command, 1, 2, 4, 5, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, xpadding, ypadding);
// Set the restrict_radius_ducks flag
App::restrict_radius_ducks=toggle_restrict_radius_ducks.get_active();
+ // Set the resize_imported_images flag
+ App::resize_imported_images=toggle_resize_imported_images.get_active();
+
// Set the browser_command textbox
App::browser_command=textbox_browser_command.get_text();
// Refresh the status of the restrict_radius_ducks flag
toggle_restrict_radius_ducks.set_active(App::restrict_radius_ducks);
+ // Refresh the status of the resize_imported_images flag
+ toggle_resize_imported_images.set_active(App::resize_imported_images);
+
// Refresh the browser_command textbox
textbox_browser_command.set_text(App::browser_command);
Widget_Time auto_backup_interval;
Gtk::CheckButton toggle_restrict_radius_ducks;
+ Gtk::CheckButton toggle_resize_imported_images;
Gtk::Entry textbox_browser_command;
}
bool
-CanvasInterface::import(const synfig::String &filename, bool /*copy*/)
+CanvasInterface::import(const synfig::String &filename, bool resize_image)
{
Action::PassiveGrouper group(get_instance().get(),_("Import Image"));
h=layer->get_param("_height").get(int());
if(w&&h)
{
- Vector size=ValueBase(get_canvas()->rend_desc().get_br()-get_canvas()->rend_desc().get_tl());
- Vector x;
- if(size[0]<size[1])
+ Vector x, size=ValueBase(get_canvas()->rend_desc().get_br()-get_canvas()->rend_desc().get_tl());
+
+ // vector from top left of canvas to bottom right
+ if (resize_image)
{
- x[0]=size[0];
- x[1]=size[0]/w*h;
- if((size[0]<0) ^ (size[1]<0))
- x[1]=-x[1];
+ if(abs(size[0])<abs(size[1])) // if canvas is tall and thin
+ {
+ x[0]=size[0]; // use full width
+ x[1]=size[0]/w*h; // and scale for height
+ if((size[0]<0) ^ (size[1]<0))
+ x[1]=-x[1];
+ }
+ else // else canvas is short and fat (or maybe square)
+ {
+ x[1]=size[1]; // use full height
+ x[0]=size[1]/h*w; // and scale for width
+ if((size[0]<0) ^ (size[1]<0))
+ x[0]=-x[0];
+ }
}
else
{
- x[1]=size[1];
- x[0]=size[1]/h*w;
- if((size[0]<0) ^ (size[1]<0))
- x[0]=-x[0];
+ x[0] = w/60.0;
+ x[1] = h/60.0;
+ if((size[0]<0)) x[0]=-x[0];
+ if((size[1]<0)) x[1]=-x[1];
}
+
if(!layer->set_param("tl",ValueBase(-x/2)))
throw int();
if(!layer->set_param("br",ValueBase(x/2)))
void set_rend_desc(const synfig::RendDesc &rend_desc);
- bool import(const synfig::String &filename, bool copy=false);
+ bool import(const synfig::String &filename, bool resize_image=false);
void waypoint_duplicate(synfigapp::ValueDesc value_desc,synfig::Waypoint waypoint);