void SaveExr(const Image<unsigned char>& image_in, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first) { PANGOLIN_UNUSED(image_in); PANGOLIN_UNUSED(fmt); PANGOLIN_UNUSED(filename); PANGOLIN_UNUSED(top_line_first); #ifdef HAVE_OPENEXR ManagedImage<unsigned char> flip_image; Image<unsigned char> image; if(top_line_first) { image = image_in; }else{ flip_image.Reinitialise(image_in.pitch,image_in.h); for(size_t y=0; y<image_in.h; ++y) { std::memcpy(flip_image.RowPtr(y), image_in.RowPtr(y), image_in.pitch); } image = flip_image; } Imf::Header header (image.w, image.h); SetOpenEXRChannels(header.channels(), fmt); Imf::OutputFile file (filename.c_str(), header); Imf::FrameBuffer frameBuffer; int ch=0; size_t ch_bits = 0; for(Imf::ChannelList::Iterator it = header.channels().begin(); it != header.channels().end(); ++it) { frameBuffer.insert( it.name(), Imf::Slice( it.channel().type, (char*)image.ptr + ch_bits/8, fmt.channel_bits[ch]/8, image.pitch ) ); ch_bits += fmt.channel_bits[ch++]; } file.setFrameBuffer(frameBuffer); file.writePixels(image.h); #else throw std::runtime_error("EXR Support not enabled. Please rebuild Pangolin."); #endif // HAVE_OPENEXR }
TypedImage LoadLz4(std::istream& in) { #ifdef HAVE_LZ4 // Read in header, uncompressed lz4_image_header header; in.read( (char*)&header, sizeof(header)); TypedImage img(header.w, header.h, PixelFormatFromString(header.fmt)); std::unique_ptr<char[]> input_buffer(new char[header.compressed_size]); in.read(input_buffer.get(), header.compressed_size); const int decompressed_size = LZ4_decompress_safe(input_buffer.get(), (char*)img.ptr, header.compressed_size, img.SizeBytes()); if (decompressed_size < 0) throw std::runtime_error(FormatString("A negative result from LZ4_decompress_safe indicates a failure trying to decompress the data. See exit code (%) for value returned.", decompressed_size)); if (decompressed_size == 0) throw std::runtime_error("I'm not sure this function can ever return 0. Documentation in lz4.h doesn't indicate so."); if (decompressed_size != (int)img.SizeBytes()) throw std::runtime_error(FormatString("decompressed size % is not equal to predicted size %", decompressed_size, img.SizeBytes())); return img; #else PANGOLIN_UNUSED(in); throw std::runtime_error("Rebuild Pangolin for LZ4 support."); #endif // HAVE_LZ4 }
void SaveFramebuffer(std::string prefix, const Viewport& v) { PANGOLIN_UNUSED(prefix); PANGOLIN_UNUSED(v); #ifndef HAVE_GLES #ifdef HAVE_PNG PixelFormat fmt = PixelFormatFromString("RGBA32"); TypedImage buffer(v.w, v.h, fmt ); glReadBuffer(GL_BACK); glPixelStorei(GL_PACK_ALIGNMENT, 1); // TODO: Avoid this? glReadPixels(v.l, v.b, v.w, v.h, GL_RGBA, GL_UNSIGNED_BYTE, buffer.ptr ); SaveImage(buffer, fmt, prefix + ".png", false); #endif // HAVE_PNG #endif // HAVE_GLES }
void SaveViewFromFbo(std::string prefix, View& view, float scale) { PANGOLIN_UNUSED(prefix); #ifndef HAVE_GLES const Viewport orig = view.v; view.v.l = 0; view.v.b = 0; view.v.w = (int)(view.v.w * scale); view.v.h = (int)(view.v.h * scale); const int w = view.v.w; const int h = view.v.h; float origLineWidth; glGetFloatv(GL_LINE_WIDTH, &origLineWidth); glLineWidth(origLineWidth * scale); float origPointSize; glGetFloatv(GL_POINT_SIZE, &origPointSize); glPointSize(origPointSize * scale); // Create FBO GlTexture color(w,h); GlRenderBuffer depth(w,h); GlFramebuffer fbo(color, depth); // Render into FBO fbo.Bind(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); view.Render(); glFlush(); #ifdef HAVE_PNG const PixelFormat fmt = PixelFormatFromString("RGBA32"); TypedImage buffer(w, h, fmt ); glReadBuffer(GL_BACK); glPixelStorei(GL_PACK_ALIGNMENT, 1); // TODO: Avoid this? glReadPixels(0,0,w,h, GL_RGBA, GL_UNSIGNED_BYTE, buffer.ptr ); SaveImage(buffer, fmt, prefix + ".png", false); #endif // HAVE_PNG // unbind FBO fbo.Unbind(); // restore viewport / line width view.v = orig; glLineWidth(origLineWidth); glPointSize(origPointSize); #endif // HAVE_GLES }
void SaveLz4(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level) { #ifdef HAVE_LZ4 const int64_t src_size = image.SizeBytes(); const int64_t max_dst_size = LZ4_compressBound(src_size); std::unique_ptr<char[]> output_buffer(new char[max_dst_size]); // Same as LZ4_compress_default(), but allows to select an "acceleration" factor. // The larger the acceleration value, the faster the algorithm, but also the lesser the compression. // It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. // An acceleration value of "1" is the same as regular LZ4_compress_default() // Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. const int64_t compressed_data_size = LZ4_compress_fast((char*)image.ptr, output_buffer.get(), src_size, max_dst_size, compression_level); if (compressed_data_size < 0) throw std::runtime_error("A negative result from LZ4_compress_default indicates a failure trying to compress the data."); if (compressed_data_size == 0) throw std::runtime_error("A result of 0 for LZ4 means compression worked, but was stopped because the destination buffer couldn't hold all the information."); lz4_image_header header; strncpy(header.magic,"LZ4",3); strncpy(header.fmt, fmt.format.c_str(), sizeof(header.fmt)); header.w = image.w; header.h = image.h; header.compressed_size = compressed_data_size; out.write((char*)&header, sizeof(header)); out.write(output_buffer.get(), compressed_data_size); #else PANGOLIN_UNUSED(image); PANGOLIN_UNUSED(fmt); PANGOLIN_UNUSED(out); PANGOLIN_UNUSED(compression_level); throw std::runtime_error("Rebuild Pangolin for LZ4 support."); #endif // HAVE_LZ4 }
TypedImage LoadJpg(const std::string& filename) { PANGOLIN_UNUSED(filename); #ifdef HAVE_JPEG FILE * infile = fopen(filename.c_str(), "rb"); if(infile) { struct my_error_mgr jerr; jerr.pub.error_exit = my_error_exit; struct jpeg_decompress_struct cinfo; cinfo.err = jpeg_std_error(&jerr.pub); if (setjmp(jerr.setjmp_buffer)) { // If we get here, the JPEG code has signaled an error. jpeg_destroy_decompress(&cinfo); fclose(infile); throw std::runtime_error("Error whilst loading JPEG image, '" + filename + "'"); } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, infile); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); const int row_stride = cinfo.output_width * cinfo.output_components; TypedImage img(cinfo.output_width, cinfo.output_height, JpgFormat(cinfo), row_stride); JSAMPARRAY row_buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); while (cinfo.output_scanline < cinfo.output_height) { const int scanline = cinfo.output_scanline; jpeg_read_scanlines(&cinfo, row_buffer, 1); memcpy(img.ptr + scanline * img.pitch, row_buffer[0], img.pitch ); } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(infile); return img; } throw std::runtime_error("Unable to load JPEG file, '" + filename + "'"); #else throw std::runtime_error("JPEG Support not enabled. Please rebuild Pangolin."); #endif }
void View::RecordOnRender(const std::string& record_uri) { PANGOLIN_UNUSED(record_uri); #ifdef BUILD_PANGOLIN_VIDEO if(!context->recorder.IsOpen()) { Viewport area = GetBounds(); context->record_view = this; context->recorder.Open(record_uri); std::vector<StreamInfo> streams; const PixelFormat fmt = PixelFormatFromString("RGB24"); streams.push_back( StreamInfo(fmt, area.w, area.h, area.w * fmt.bpp / 8) ); context->recorder.SetStreams(streams); }else{ context->recorder.Close(); } #else std::cerr << "Error: Video Support hasn't been built into this library." << std::endl; #endif // BUILD_PANGOLIN_VIDEO }
void SavePng(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first) { PANGOLIN_UNUSED(image); PANGOLIN_UNUSED(filename); PANGOLIN_UNUSED(top_line_first); // Check image has supported bit depth for(unsigned int i=1; i < fmt.channels; ++i) { if( fmt.channel_bits[i] != fmt.channel_bits[0] ) { throw std::runtime_error("PNG Saving only supported for images where each channel has the same bit depth."); } } #ifdef HAVE_PNG FILE *fp; png_structp png_ptr; png_infop info_ptr; // Open file for writing (binary mode) fp = fopen(filename.c_str(), "wb"); if (fp == NULL) { throw std::runtime_error( "PNG Error: Could not open file '" + filename + "' for writing" ); } // Initialize write structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); throw std::runtime_error( "PNG Error: Could not allocate write struct." ); } // Initialize info structure info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); fclose(fp); throw std::runtime_error( "PNG Error: Could not allocate info struct." ); } // Setup Exception handling if (setjmp(png_jmpbuf(png_ptr))) { png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); png_destroy_write_struct(&png_ptr, (png_infopp)NULL); fclose(fp); throw std::runtime_error( "PNG Error: Error during png creation." ); } png_init_io(png_ptr, fp); const int bit_depth = fmt.channel_bits[0]; int colour_type; switch (fmt.channels) { case 1: colour_type = PNG_COLOR_TYPE_GRAY; break; case 2: colour_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: colour_type = PNG_COLOR_TYPE_RGB; break; case 4: colour_type = PNG_COLOR_TYPE_RGBA; break; default: throw std::runtime_error( "PNG Error: unexpected image channel number"); } // Write header png_set_IHDR( png_ptr, info_ptr, (png_uint_32)image.w, (png_uint_32)image.h, bit_depth, colour_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); // Setup rows to write: std::vector<png_bytep> rows(image.h); if(top_line_first) { for (unsigned int y = 0; y< image.h; y++) { rows[y] = image.ptr + y*image.pitch; } }else{ for (unsigned int y = 0; y< image.h; y++) { rows[y] = image.ptr + (image.h-1-y)*image.pitch; } } png_set_rows(png_ptr,info_ptr, &rows[0]); // Write image data: switch to little-endian byte order, to match host. png_write_png(png_ptr,info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, 0); // Free resources fclose(fp); png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); png_destroy_write_struct(&png_ptr, (png_infopp)NULL); #else throw std::runtime_error("PNG Support not enabled. Please rebuild Pangolin."); #endif }
TypedImage LoadPng(const std::string& filename) { PANGOLIN_UNUSED(filename); #ifdef HAVE_PNG FILE *in = fopen(filename.c_str(), "rb"); if( in ) { //check the header const size_t nBytes = 8; png_byte header[nBytes]; size_t nread = fread(header, 1, nBytes, in); int nIsPNG = png_sig_cmp(header, 0, nread); if ( nIsPNG != 0 ) { throw std::runtime_error( filename + " is not a PNG file" ); } //set up initial png structs png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, &PngWarningsCallback); if (!png_ptr) { throw std::runtime_error( "PNG Init error 1" ); } 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); throw std::runtime_error( "PNG Init error 2" ); } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); throw std::runtime_error( "PNG Init error 3" ); } png_init_io(png_ptr, in); png_set_sig_bytes(png_ptr, nBytes); //read the file png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, NULL); if( png_get_bit_depth(png_ptr, info_ptr) == 1) { //Unpack bools to bytes to ease loading. png_set_packing(png_ptr); } else if( png_get_bit_depth(png_ptr, info_ptr) < 8) { //Expand nonbool colour depths up to 8bpp png_set_expand_gray_1_2_4_to_8(png_ptr); } //Get rid of palette, by transforming it to RGB if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if( png_get_interlace_type(png_ptr,info_ptr) != PNG_INTERLACE_NONE) { throw std::runtime_error( "Interlace not yet supported" ); } const size_t w = png_get_image_width(png_ptr,info_ptr); const size_t h = png_get_image_height(png_ptr,info_ptr); const size_t pitch = png_get_rowbytes(png_ptr, info_ptr); TypedImage img(w, h, PngFormat(png_ptr, info_ptr), pitch); png_bytepp rows = png_get_rows(png_ptr, info_ptr); for( unsigned int r = 0; r < h; r++) { memcpy( img.ptr + pitch*r, rows[r], pitch ); } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(in); return img; } throw std::runtime_error("Unable to load PNG file, '" + filename + "'"); #else throw std::runtime_error("PNG Support not enabled. Please rebuild Pangolin."); #endif }
TypedImage LoadPng(std::istream& source) { #ifdef HAVE_PNG //so First, we validate our stream with the validate function I just mentioned if (!pango_png_validate(source)) { throw std::runtime_error("Not valid PNG header"); } //set up initial png structs png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, &PngWarningsCallback); if (!png_ptr) { throw std::runtime_error( "PNG Init error 1" ); } 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); throw std::runtime_error( "PNG Init error 2" ); } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); throw std::runtime_error( "PNG Init error 3" ); } png_set_read_fn(png_ptr,(png_voidp)&source, pango_png_stream_read); png_set_sig_bytes(png_ptr, PNGSIGSIZE); // Setup transformation options if( png_get_bit_depth(png_ptr, info_ptr) == 1) { //Unpack bools to bytes to ease loading. png_set_packing(png_ptr); } else if( png_get_bit_depth(png_ptr, info_ptr) < 8) { //Expand nonbool colour depths up to 8bpp png_set_expand_gray_1_2_4_to_8(png_ptr); } //Get rid of palette, by transforming it to RGB if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } //read the file png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, NULL); if( png_get_interlace_type(png_ptr,info_ptr) != PNG_INTERLACE_NONE) { throw std::runtime_error( "Interlace not yet supported" ); } const size_t w = png_get_image_width(png_ptr,info_ptr); const size_t h = png_get_image_height(png_ptr,info_ptr); const size_t pitch = png_get_rowbytes(png_ptr, info_ptr); TypedImage img(w, h, PngFormat(png_ptr, info_ptr), pitch); png_bytepp rows = png_get_rows(png_ptr, info_ptr); for( unsigned int r = 0; r < h; r++) { memcpy( img.ptr + pitch*r, rows[r], pitch ); } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return img; #else PANGOLIN_UNUSED(source); throw std::runtime_error("Rebuild Pangolin for PNG support."); #endif // HAVE_PNG }