void software::Contour::render_contour( synfig::Surface &target_surface, const rendering::Contour::ChunkList &chunks, bool invert, bool antialias, rendering::Contour::WindingStyle winding_style, const Matrix &transform_matrix, const Color &color, Color::value_type opacity, Color::BlendMethod blend_method ) { Polyspan polyspan; polyspan.init(0, 0, target_surface.get_w(), target_surface.get_h()); build_polyspan(chunks, transform_matrix, polyspan); polyspan.sort_marks(); return render_polyspan( target_surface, polyspan, invert, antialias, winding_style, color, opacity, blend_method ); }
void Instance::save_surface(const synfig::Surface &surface, const synfig::String &filename) { if (surface.get_h() <= 0 || surface.get_w() <= 0) return; String ext = filename_extension(filename); if (ext.empty()) return; ext.erase(0, 1); String tmpfile = FileContainerTemporary::generate_temporary_filename(); etl::handle<Target_Scanline> target = etl::handle<Target_Scanline>(Target::create(Target::ext_book()[ext],tmpfile,TargetParam())); if (!target) return; target->set_canvas(get_canvas()); RendDesc desc; desc.set_w(surface.get_w()); desc.set_h(surface.get_h()); desc.set_x_res(1); desc.set_y_res(1); desc.set_frame_rate(1); desc.set_frame(0); desc.set_frame_start(0); desc.set_frame_end(0); target->set_rend_desc(&desc); target->add_frame(&surface); target = NULL; FileSystem::copy(FileSystemNative::instance(), tmpfile, get_file_system(), filename); FileSystemNative::instance()->file_remove(tmpfile); }
bool exr_mptr::get_frame(synfig::Surface &out_surface, const synfig::RendDesc &/*renddesc*/, Time, synfig::ProgressCallback *cb) { try { Imf::RgbaInputFile in(identifier.filename.c_str()); int w = in.dataWindow().max.x - in.dataWindow().min.x + 1; int h = in.dataWindow().max.y - in.dataWindow().min.y + 1; //int dx = in.dataWindow().min.x; //int dy = in.dataWindow().min.y; etl::surface<Imf::Rgba> in_surface; in_surface.set_wh(w,h); in.setFrameBuffer (reinterpret_cast<Imf::Rgba *>(in_surface[0]), 1, w); in.readPixels (in.dataWindow().min.y, in.dataWindow().max.y); int x; int y; out_surface.set_wh(w,h); for(y=0;y<out_surface.get_h();y++) for(x=0;x<out_surface.get_w();x++) { Color &color(out_surface[y][x]); Imf::Rgba &rgba(in_surface[y][x]); color.set_r(rgba.r); color.set_g(rgba.g); color.set_b(rgba.b); color.set_a(rgba.a); } } catch (const std::exception& e) { if(cb)cb->error(e.what()); else synfig::error(e.what()); return false; } return true; }
void Action::LayerPaint::PaintStroke::copy_to_cairo_surface(const synfig::Surface &surface, synfig::CairoSurface &csurface) { int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, surface.get_w()); unsigned char *data = (unsigned char*)malloc(stride * surface.get_h()); unsigned char *p = data; for(int y = 0; y < surface.get_h(); ++y, p += stride) { CairoColor *c = (CairoColor*)p; for(int x = 0; x < surface.get_w(); ++x, ++c) *c = CairoColor(surface[y][x]); } cairo_surface_t *cs = cairo_image_surface_create_for_data( data, CAIRO_FORMAT_ARGB32, surface.get_w(), surface.get_h(), stride ); csurface.set_cairo_surface(cs); csurface.map_cairo_image(); cairo_surface_destroy(cs); }
bool bmp_mptr::get_frame(synfig::Surface &surface, const synfig::RendDesc &/*renddesc*/, Time /*time*/, synfig::ProgressCallback *cb) { FILE *file=fopen(filename.c_str(),"rb"); if(!file) { if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),filename.c_str())); else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),filename.c_str())); return false; } synfig::BITMAPFILEHEADER fileheader; synfig::BITMAPINFOHEADER infoheader; char b_char=fgetc(file); char m_char=fgetc(file); if(b_char!='B' || m_char!='M') { if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("%s is not in BMP format"),filename.c_str())); else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("%s is not in BMP format"),filename.c_str())); return false; } if(fread(&fileheader.bfSize, 1, sizeof(synfig::BITMAPFILEHEADER)-4, file)!=sizeof(synfig::BITMAPFILEHEADER)-4) { String str("bmp_mptr::get_frame(): "+strprintf(_("Failure while reading BITMAPFILEHEADER from %s"),filename.c_str())); if(cb)cb->error(str); else synfig::error(str); return false; } if(fread(&infoheader, 1, sizeof(synfig::BITMAPINFOHEADER), file)!=sizeof(synfig::BITMAPINFOHEADER)) { String str("bmp_mptr::get_frame(): "+strprintf(_("Failure while reading BITMAPINFOHEADER from %s"),filename.c_str())); if(cb)cb->error(str); else synfig::error(str); return false; } int offset=little_endian(fileheader.bfOffsetBits); if(offset!=sizeof(synfig::BITMAPFILEHEADER)+sizeof(synfig::BITMAPINFOHEADER)-2) { String str("bmp_mptr::get_frame(): "+strprintf(_("Bad BITMAPFILEHEADER in %s. (bfOffsetBits=%d, should be %d)"),filename.c_str(),offset,sizeof(synfig::BITMAPFILEHEADER)+sizeof(synfig::BITMAPINFOHEADER)-2)); if(cb)cb->error(str); else synfig::error(str); return false; } if(little_endian(infoheader.biSize)!=little_endian(40)) { String str("bmp_mptr::get_frame(): "+strprintf(_("Bad BITMAPINFOHEADER in %s. (biSize=%d, should be 40)"),filename.c_str(),little_endian(infoheader.biSize))); if(cb)cb->error(str); else synfig::error(str); return false; } int w,h,bit_count; w=little_endian(infoheader.biWidth); h=little_endian(infoheader.biHeight); bit_count=little_endian_short(infoheader.biBitCount); synfig::warning("w:%d\n",w); synfig::warning("h:%d\n",h); synfig::warning("bit_count:%d\n",bit_count); if(little_endian(infoheader.biCompression)) { if(cb)cb->error("bmp_mptr::GetFrame(): "+string(_("Reading compressed bitmaps is not supported"))); else synfig::error("bmp_mptr::GetFrame(): "+string(_("Reading compressed bitmaps is not supported"))); return false; } if(bit_count!=24 && bit_count!=32) { if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("Unsupported bit depth (bit_count=%d, should be 24 or 32)"),bit_count)); else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("Unsupported bit depth (bit_count=%d, should be 24 or 32)"),bit_count)); return false; } int x; int y; surface.set_wh(w,h); for(y=0;y<surface.get_h();y++) for(x=0;x<surface.get_w();x++) { // float b=(float)(unsigned char)fgetc(file)*(1.0/255.0); // float g=(float)(unsigned char)fgetc(file)*(1.0/255.0); // float r=(float)(unsigned char)fgetc(file)*(1.0/255.0); float b=gamma().b_U8_to_F32((unsigned char)fgetc(file)); float g=gamma().g_U8_to_F32((unsigned char)fgetc(file)); float r=gamma().r_U8_to_F32((unsigned char)fgetc(file)); surface[h-y-1][x]=Color( r, g, b, 1.0 ); if(bit_count==32) fgetc(file); } fclose(file); return true; }
bool imagemagick_mptr::get_frame(synfig::Surface &surface, const synfig::RendDesc &renddesc, Time /*time*/, synfig::ProgressCallback *cb) { //#define HAS_LIBPNG 1 #if 1 if(identifier.filename.empty()) { if(cb)cb->error(_("No file to load")); else synfig::error(_("No file to load")); return false; } string temp_file="/tmp/deleteme.png"; string temp_container_file=""; // todo: "container:" and "images" literals if (identifier.filename.substr(0, String("#images/").size())=="#images/") { temp_container_file = "/tmp/synfigtmp.png"; // try to copy file to a temp file if (!FileSystem::copy(identifier.file_system, identifier.filename, identifier.file_system, temp_container_file)) { if(cb)cb->error(_("Cannot create temporary file of ")+ identifier.filename); else synfig::error(_("Cannot create temporary file of ")+ identifier.filename); return false; } } string filename = temp_container_file.size() == 0 ? identifier.filename : temp_container_file; #if defined(WIN32_PIPE_TO_PROCESSES) if(file) pclose(file); string command; if(identifier.filename.find("psd")!=String::npos) command=strprintf("convert \"%s\" -flatten \"png32:%s\"\n",filename.c_str(),temp_file.c_str()); else command=strprintf("convert \"%s\" \"png32:%s\"\n",filename.c_str(),temp_file.c_str()); if(system(command.c_str())!=0) return false; #elif defined(UNIX_PIPE_TO_PROCESSES) string output="png32:"+temp_file; pid_t pid = fork(); if (pid == -1) { return false; } if (pid == 0){ // Child process if(identifier.filename.find("psd")!=String::npos) execlp("convert", "convert", filename.c_str(), "-flatten", output.c_str(), (const char *)NULL); else execlp("convert", "convert", filename.c_str(), output.c_str(), (const char *)NULL); // We should never reach here unless the exec failed return false; } int status; waitpid(pid, &status, 0); if( (WIFEXITED(status) && WEXITSTATUS(status) != 0) || !WIFEXITED(status) ) return false; #else #error There are no known APIs for creating child processes #endif //if any delete container tmp file if(temp_container_file.size()) identifier.file_system->file_remove(temp_container_file); Importer::Handle importer(Importer::open(synfig::FileSystem::Identifier(synfig::FileSystemNative::instance(), temp_file))); if(!importer) { if(cb)cb->error(_("Unable to open ")+temp_file); else synfig::error(_("Unable to open ")+temp_file); return false; } if(!importer->get_frame(surface,renddesc,0,cb)) { if(cb)cb->error(_("Unable to get frame from ")+temp_file); else synfig::error(_("Unable to get frame from ")+temp_file); return false; } if(!surface) { if(cb)cb->error(_("Bad surface from ")+temp_file); else synfig::error(_("Bad surface from ")+temp_file); return false; } if(1) { // remove odd premultiplication for(int i=0;i<surface.get_w()*surface.get_h();i++) { Color c(surface[0][i]); if(c.get_a()) { surface[0][i].set_r(c.get_r()/c.get_a()/c.get_a()); surface[0][i].set_g(c.get_g()/c.get_a()/c.get_a()); surface[0][i].set_b(c.get_b()/c.get_a()/c.get_a()); } else { surface[0][i].set_r(0); surface[0][i].set_g(0); surface[0][i].set_b(0); } surface[0][i].set_a(c.get_a()); } } Surface bleh(surface); surface=bleh; //remove(temp_file.c_str()); return true; #else #error This code contains tempfile and arbitrary shell command execution vulnerabilities if(file) pclose(file); string command; if(identifier.filename.empty()) { if(cb)cb->error(_("No file to load")); else synfig::error(_("No file to load")); return false; } command=strprintf("convert \"%s\" -flatten ppm:-\n",identifier.filename.c_str()); file=popen(command.c_str(),POPEN_BINARY_READ_TYPE); if(!file) { if(cb)cb->error(_("Unable to open pipe to imagemagick")); else synfig::error(_("Unable to open pipe to imagemagick")); return false; } int w,h; float divisor; char cookie[2]; while((cookie[0]=fgetc(file))!='P' && !feof(file)); if(feof(file)) { if(cb)cb->error(_("Reached end of stream without finding PPM header")); else synfig::error(_("Reached end of stream without finding PPM header")); return false; } cookie[1]=fgetc(file); if(cookie[0]!='P' || cookie[1]!='6') { if(cb)cb->error(string(_("stream not in PPM format"))+" \""+cookie[0]+cookie[1]+'"'); else synfig::error(string(_("stream not in PPM format"))+" \""+cookie[0]+cookie[1]+'"'); return false; } fgetc(file); fscanf(file,"%d %d\n",&w,&h); fscanf(file,"%f",&divisor); fgetc(file); if(feof(file)) { if(cb)cb->error(_("Premature end of file (after header)")); else synfig::error(_("Premature end of file (after header)")); return false; } int x; int y; frame.set_wh(w,h); for(y=0;y<frame.get_h();y++) for(x=0;x<frame.get_w();x++) { if(feof(file)) { if(cb)cb->error(_("Premature end of file")); else synfig::error(_("Premature end of file")); return false; } float b=gamma().r_U8_to_F32((unsigned char)fgetc(file)); float g=gamma().g_U8_to_F32((unsigned char)fgetc(file)); float r=gamma().b_U8_to_F32((unsigned char)fgetc(file)); /* float b=(float)(unsigned char)fgetc(file)/divisor; float g=(float)(unsigned char)fgetc(file)/divisor; float r=(float)(unsigned char)fgetc(file)/divisor; */ frame[y][x]=Color( b, g, r, 1.0 ); } surface=frame; return true; #endif }
void software::Contour::render_polyspan( synfig::Surface &target_surface, const Polyspan &polyspan, bool invert, bool antialias, rendering::Contour::WindingStyle winding_style, const Color &color, Color::value_type opacity, Color::BlendMethod blend_method ) { bool simple_fill = (Color::BLEND_METHODS_OVERWRITE_ON_ALPHA_ONE & (1 << blend_method)) && fabsf(1.f - opacity*color.get_a()) <= 1e-6; synfig::Surface::alpha_pen p(target_surface.begin(), opacity, blend_method); synfig::Surface::pen sp(target_surface.begin()); const RectInt &window = polyspan.get_window(); const Polyspan::cover_array &covers = polyspan.get_covers(); Polyspan::cover_array::const_iterator cur_mark = covers.begin(); Polyspan::cover_array::const_iterator end_mark = covers.end(); Real cover = 0, area = 0, alpha = 0; int y = 0, x = 0; p.set_value(color); sp.set_value(color); cover = 0; if (cur_mark == end_mark) { // no marks at all if (invert) { if (simple_fill) { sp.move_to(window.minx, window.miny); sp.put_block(window.maxy - window.miny, window.maxx - window.minx); } else { p.move_to(window.minx, window.miny); p.put_block(window.maxy - window.miny, window.maxx - window.minx); } } return; } // fill initial rect / line if (invert) { if (simple_fill) { // fill all the area above the first vertex sp.move_to(window.minx, window.miny); y = window.miny; int l = window.maxx - window.minx; sp.put_block(cur_mark->y - window.miny, l); // fill the area to the left of the first vertex on that line l = cur_mark->x - window.minx; sp.move_to(window.minx, cur_mark->y); if (l) sp.put_hline(l); } else { // fill all the area above the first vertex p.move_to(window.minx, window.miny); y = window.miny; int l = window.maxx - window.minx; p.put_block(cur_mark->y - window.miny, l); // fill the area to the left of the first vertex on that line l = cur_mark->x - window.minx; p.move_to(window.minx, cur_mark->y); if (l) p.put_hline(l); } } while(true) { y = cur_mark->y; x = cur_mark->x; p.move_to(x,y); area = cur_mark->area; cover += cur_mark->cover; // accumulate for the current pixel while(++cur_mark != covers.end()) { if (y != cur_mark->y || x != cur_mark->x) break; area += cur_mark->area; cover += cur_mark->cover; } // draw pixel - based on covered area if (area) // if we're ok, draw the current pixel { alpha = polyspan.extract_alpha(cover - area, winding_style); if (invert) alpha = 1 - alpha; if (antialias) { if (alpha) p.put_value_alpha(alpha); } else { if (alpha >= .5) p.put_value(); } p.inc_x(); ++x; } // if we're done, don't use iterator and exit if (cur_mark == end_mark) break; // if there is no more live pixels on this line, goto next if (y != cur_mark->y) { if (invert) { // fill the area at the end of the line if (simple_fill) { sp.move_to(p); sp.put_hline(window.maxx - x); } else { p.put_hline(window.maxx - x); } // fill area at the beginning of the next line if (simple_fill) { sp.move_to(window.minx, cur_mark->y); sp.put_hline(cur_mark->x - window.minx); } else { p.move_to(window.minx, cur_mark->y); p.put_hline(cur_mark->x - window.minx); } } cover = 0; continue; } // draw span to next pixel - based on total amount of pixel cover if (x < cur_mark->x) { alpha = polyspan.extract_alpha(cover, winding_style); if (invert) alpha = 1 - alpha; if (alpha >= .5) { if (simple_fill) { sp.move_to(p); sp.put_hline(cur_mark->x - x); p.move_to(sp); } else { p.put_hline(cur_mark->x - x); } } /* if (antialias) { if (alpha) p.put_hline(cur_mark->x - x, alpha); } else { if (alpha >= .5) p.put_hline(cur_mark->x - x); } */ } } // fill the after stuff if (invert) { if (simple_fill) { sp.move_to(p); //fill the area at the end of the line sp.put_hline(window.maxx - x); //fill area at the beginning of the next line sp.move_to(window.minx, y+1); sp.put_block(window.maxy - y - 1, window.maxx - window.minx); } else { //fill the area at the end of the line p.put_hline(window.maxx - x); //fill area at the beginning of the next line p.move_to(window.minx, y+1); p.put_block(window.maxy - y - 1, window.maxx - window.minx); } } }
bool bmp_mptr::get_frame(synfig::Surface &surface, const synfig::RendDesc &/*renddesc*/, Time /*time*/, synfig::ProgressCallback *cb) { FileSystem::ReadStreamHandle stream = identifier.get_read_stream(); if(!stream) { if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),identifier.filename.c_str())); else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),identifier.filename.c_str())); return false; } synfig::BITMAP::FILEHEADER fileheader; synfig::BITMAP::INFOHEADER infoheader; if (!stream->read_variable(fileheader.bfType) || fileheader.bfType[0] != 'B' || fileheader.bfType[1] != 'M') { if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("%s is not in BMP format"),identifier.filename.c_str())); else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("%s is not in BMP format"),identifier.filename.c_str())); return false; } if(!stream->read_whole_block(&fileheader.bfSize, sizeof(synfig::BITMAP::FILEHEADER)-2)) { String str("bmp_mptr::get_frame(): "+strprintf(_("Failure while reading BITMAP::FILEHEADER from %s"),identifier.filename.c_str())); if(cb)cb->error(str); else synfig::error(str); return false; } if(!stream->read_whole_block(&infoheader, sizeof(synfig::BITMAP::INFOHEADER))) { String str("bmp_mptr::get_frame(): "+strprintf(_("Failure while reading BITMAP::INFOHEADER from %s"),identifier.filename.c_str())); if(cb)cb->error(str); else synfig::error(str); return false; } int offset=little_endian(fileheader.bfOffsetBits); if(offset!=sizeof(synfig::BITMAP::FILEHEADER)+sizeof(synfig::BITMAP::INFOHEADER)) { String str("bmp_mptr::get_frame(): "+strprintf(_("Bad BITMAP::FILEHEADER in %s. (bfOffsetBits=%d, should be %d)"),identifier.filename.c_str(),offset,sizeof(synfig::BITMAP::FILEHEADER)+sizeof(synfig::BITMAP::INFOHEADER))); if(cb)cb->error(str); else synfig::error(str); return false; } if(little_endian(infoheader.biSize)!=sizeof(synfig::BITMAP::INFOHEADER)) { String str("bmp_mptr::get_frame(): "+strprintf(_("Bad BITMAP::INFOHEADER in %s. (biSize=%d, should be %d)"),identifier.filename.c_str(),little_endian(infoheader.biSize),sizeof(synfig::BITMAP::INFOHEADER))); if(cb)cb->error(str); else synfig::error(str); return false; } int w,h,bit_count; w=little_endian(infoheader.biWidth); h=little_endian(infoheader.biHeight); bit_count=little_endian_short(infoheader.biBitCount); synfig::warning("w:%d\n",w); synfig::warning("h:%d\n",h); synfig::warning("bit_count:%d\n",bit_count); if(little_endian(infoheader.biCompression)) { if(cb)cb->error("bmp_mptr::GetFrame(): "+string(_("Reading compressed bitmaps is not supported"))); else synfig::error("bmp_mptr::GetFrame(): "+string(_("Reading compressed bitmaps is not supported"))); return false; } if(bit_count!=24 && bit_count!=32) { if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("Unsupported bit depth (bit_count=%d, should be 24 or 32)"),bit_count)); else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("Unsupported bit depth (bit_count=%d, should be 24 or 32)"),bit_count)); return false; } int x; int y; surface.set_wh(w,h); for(y=0;y<surface.get_h();y++) for(x=0;x<surface.get_w();x++) { // float b=(float)(unsigned char)stream->getc()*(1.0/255.0); // float g=(float)(unsigned char)stream->getc()*(1.0/255.0); // float r=(float)(unsigned char)stream->getc()*(1.0/255.0); float b=gamma().b_U8_to_F32((unsigned char)stream->get()); float g=gamma().g_U8_to_F32((unsigned char)stream->get()); float r=gamma().r_U8_to_F32((unsigned char)stream->get()); surface[h-y-1][x]=Color( r, g, b, 1.0 ); if(bit_count==32) stream->get(); } return true; }
static inline Color cubic(const synfig::Surface &surface, const Vector &pos) { return surface.cubic_sample(pos[0] - 0.5, pos[1] - 0.5); }
static inline Color nearest(const synfig::Surface &surface, const Vector &pos) { return surface[ std::max(std::min((int)floor(pos[1]), surface.get_h()-1), 0) ] [ std::max(std::min((int)floor(pos[0]), surface.get_w()-1), 0) ]; }
bool mplayer_mptr::get_frame(synfig::Surface &surface, const synfig::RendDesc &renddesc, synfig::Time time, synfig::ProgressCallback *callback) { #error This code has vulnerabilites: arbitrary shell command execution and tmpfile issues int ret; ret=system( strprintf("/usr/local/bin/mencoder \"%s\" -ovc rawrgb -ss %f -endpos 0 -nosound -o /tmp/tmp.synfig.rgbdata | grep \"VIDEO\" > /tmp/tmp.synfig.size", identifier.filename.c_str(), time ).c_str() ); /* if(ret!=0) { cerr<<"mencoder execution failed."<<endl; return false; } */ FILE *sizefile=fopen("/tmp/tmp.synfig.size","rt"); FILE *rgbfile=fopen("/tmp/tmp.synfig.rgbdata","rb"); if(!rgbfile) { cerr<<"unable to open /tmp/tmp.synfig.rgbdata"<<endl; return false; } if(!sizefile) { cerr<<"unable to open /tmp/tmp.synfig.size"<<endl; return false; } int w=4,h=4,x,y; char bleh[500]; fscanf(sizefile,"%499s %499s %dx%d",bleh,bleh,&w,&h); cerr<<strprintf("w:%d, h:%d, time:%f",w,h,time)<<endl; fseek(rgbfile,2047+3*8,SEEK_CUR); surface.set_wh(w,h); for(y=0;y<h;y++) for(x=0;x<w;x++) { unsigned char b=(unsigned char)fgetc(rgbfile), g=(unsigned char)fgetc(rgbfile), r=(unsigned char)fgetc(rgbfile); surface[h-y-1][x]=Color( (float)r/255.0, (float)g/255.0, (float)b/255.0, 1.0 ); } fclose(rgbfile); fclose(sizefile); return true; }
bool png_mptr::get_frame(synfig::Surface &surface, const synfig::RendDesc &/*renddesc*/, Time, synfig::ProgressCallback */*cb*/) { /* Open the file pointer */ FileSystem::ReadStream::Handle stream = identifier.get_read_stream(); if (!stream) { //! \todo THROW SOMETHING throw strprintf("Unable to physically open %s",identifier.filename.c_str()); return false; } /* Make sure we are dealing with a PNG format file */ png_byte header[PNG_CHECK_BYTES]; if (!stream->read_variable(header)) { //! \todo THROW SOMETHING throw strprintf("Cannot read header from \"%s\"",identifier.filename.c_str()); return false; } if (0 != png_sig_cmp(header, 0, PNG_CHECK_BYTES)) { //! \todo THROW SOMETHING throw strprintf("This (\"%s\") doesn't appear to be a PNG file",identifier.filename.c_str()); return false; } png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, (png_voidp)this, &png_mptr::png_out_error, &png_mptr::png_out_warning); if (!png_ptr) { //! \todo THROW SOMETHING throw String("error on importer construction, *WRITEME*3"); return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); //! \todo THROW SOMETHING throw String("error on importer construction, *WRITEME*4"); return false; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); //! \todo THROW SOMETHING throw String("error on importer construction, *WRITEME*4"); return false; } png_set_read_fn(png_ptr, stream.get(), read_callback); png_set_sig_bytes(png_ptr,PNG_CHECK_BYTES); png_read_info(png_ptr, info_ptr); int bit_depth,color_type,interlace_type, compression_type,filter_method; png_uint_32 width,height; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); if (bit_depth == 16) png_set_strip_16(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); double fgamma; if (png_get_gAMA(png_ptr, info_ptr, &fgamma)) { synfig::info("PNG: Image gamma is %f",fgamma); png_set_gamma(png_ptr, gamma().get_gamma(), fgamma); } /* if (setjmp(png_jmpbuf(png_ptr))) { synfig::error("Unable to setup longjump"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(file); //! \todo THROW SOMETHING throw String("error on importer construction, *WRITEME*5"); return; } */ // man libpng tells me: // You must use png_transforms and not call any // png_set_transform() functions when you use png_read_png(). // but we used png_set_gamma(), which may be why we were seeing a crash at the end // png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING|PNG_TRANSFORM_STRIP_16, NULL); png_read_update_info(png_ptr, info_ptr); png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr); // allocate buffer to read image data into png_bytep *row_pointers=new png_bytep[height]; png_byte *data = new png_byte[rowbytes*height]; for (png_uint_32 i = 0; i < height; i++) row_pointers[i] = &(data[rowbytes*i]); png_read_image(png_ptr, row_pointers); png_uint_32 x, y; surface.set_wh(width,height); switch(color_type) { case PNG_COLOR_TYPE_RGB: 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]); float b=gamma().b_U8_to_F32((unsigned char)row_pointers[y][x*3+2]); surface[y][x]=Color( r, g, b, 1.0 ); /* surface[y][x]=Color( (float)(unsigned char)row_pointers[y][x*3+0]*(1.0/255.0), (float)(unsigned char)row_pointers[y][x*3+1]*(1.0/255.0), (float)(unsigned char)row_pointers[y][x*3+2]*(1.0/255.0), 1.0 ); */ } break; case PNG_COLOR_TYPE_RGB_ALPHA: 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]); float b=gamma().b_U8_to_F32((unsigned char)row_pointers[y][x*4+2]); surface[y][x]=Color( r, g, b, (float)(unsigned char)row_pointers[y][x*4+3]*(1.0/255.0) ); /* surface[y][x]=Color( (float)(unsigned char)row_pointers[y][x*4+0]*(1.0/255.0), (float)(unsigned char)row_pointers[y][x*4+1]*(1.0/255.0), (float)(unsigned char)row_pointers[y][x*4+2]*(1.0/255.0), (float)(unsigned char)row_pointers[y][x*4+3]*(1.0/255.0) ); */ } break; case PNG_COLOR_TYPE_GRAY: 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); surface[y][x]=Color( gray, gray, gray, 1.0 ); } break; case PNG_COLOR_TYPE_GRAY_ALPHA: 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); surface[y][x]=Color( gray, gray, gray, (float)(unsigned char)row_pointers[y][x*2+1]*(1.0/255.0) ); } break; case PNG_COLOR_TYPE_PALETTE: { png_colorp palette; int num_palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); png_bytep trans_alpha = NULL; int num_trans = 0; bool has_alpha = (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, NULL) & PNG_INFO_tRNS); for(y=0; y<height; y++) for(x=0; x<width; x++) { float r=gamma().r_U8_to_F32((unsigned char)palette[row_pointers[y][x]].red); float g=gamma().g_U8_to_F32((unsigned char)palette[row_pointers[y][x]].green); float b=gamma().b_U8_to_F32((unsigned char)palette[row_pointers[y][x]].blue); float a=1.0; if (has_alpha && num_trans > 0 && trans_alpha != NULL) { a = row_pointers[y][x] < num_trans ? (trans_alpha[row_pointers[y][x]]*(1.0/255.0)) : 1.0; } surface[y][x]=Color( r, g, b, a ); } break; } default: png_read_end(png_ptr, end_info); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); synfig::error("png_mptr: error: Unsupported color type"); //! \todo THROW SOMETHING throw String("error on importer construction, *WRITEME*6"); return false; } png_read_end(png_ptr, end_info); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return true; }