Example #1
0
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
}
Example #2
0
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
}
Example #3
0
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
}
Example #4
0
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
}
Example #5
0
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
}
Example #6
0
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
}
Example #7
0
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
}
Example #8
0
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
}
Example #9
0
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
}
Example #10
0
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
}