Ejemplo n.º 1
0
void PNGImageWriter::beginOfImage(int cols, int rows) {
    _png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    _info_ptr = png_create_info_struct(_png_ptr);
    if (!_info_ptr) {
        png_destroy_write_struct(&_png_ptr, NULL);
        exit(1);
    }

    png_set_IHDR(_png_ptr,
		 _info_ptr,
		 cols,
		 rows,
		 16,
		 PNG_COLOR_TYPE_GRAY,
		 PNG_INTERLACE_NONE,
		 NULL/*PNG_COMPRESSION_TYPE_DEFAULT*/,
		 PNG_FILTER_TYPE_DEFAULT);
    //png_set_filter(_png_ptr, 0, PNG_FILTER_NONE);
    //png_set_packing(_png_ptr);
    png_set_compression_level(_png_ptr, 0); // No compression
    png_set_filter(_png_ptr, 0 /* method */, PNG_NO_FILTERS);

    png_color_8 sig_bit;
    sig_bit.gray  = 16;
    sig_bit.red   = 0;
    sig_bit.green = 0;
    sig_bit.blue  = 0;
    sig_bit.alpha = 0;
    png_set_sBIT(_png_ptr, _info_ptr, &sig_bit);
    //png_set_shift(_png_ptr, &sig_bit);

    //png_set_gamma(_png_ptr, 1., 1.);
    png_set_strip_16(_png_ptr);

    //if (lsb)
    //png_set_swap(_png_ptr);

    // flush output after every row
    if (_lineBuffered)
	png_set_flush(_png_ptr, 1);

    //png_set_filler(_png_ptr, 0, PNG_FILLER_BEFORE);

    // Represent black as 1 and white as 0 instead of the PNG default.
    //png_set_invert_mono(_png_ptr);

    png_init_io(_png_ptr, _output);

    /* write the file information */
    png_write_info(_png_ptr, _info_ptr);
}
Ejemplo n.º 2
0
void write_png_file(const char* file_name, int32 width, int32 height, uint8 * data)
{
	if (CommandLineParser::Instance()->GetVerbose())
		printf("* Writing PNG file (%d x %d): %s\n", width, height, file_name);
	
	png_byte color_type = PNG_COLOR_TYPE_RGBA;
	png_byte bit_depth = 8;
	png_color_8 sig_bit;
	
	png_structp png_ptr;
	png_infop info_ptr;
	
	png_bytep * row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
	for (int y = 0; y < height; y++)
	{
		row_pointers[y] = (png_byte*) &data[y * width * 4];
	}
	
	
	/* create file */
	FILE *fp = fopen(file_name, "wb");
	if (!fp)
		abort_("[write_png_file] File %s could not be opened for writing", file_name);
	
	
	/* initialize stuff */
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	
	if (!png_ptr)
		abort_("[write_png_file] png_create_write_struct failed");
	
	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
		abort_("[write_png_file] png_create_info_struct failed");
	
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during init_io");
	
	png_init_io(png_ptr, fp);
	
	
	/* write header */
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during writing header");
	
	png_set_IHDR(png_ptr, info_ptr, width, height,
				 bit_depth, color_type, PNG_INTERLACE_NONE,
				 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
	
	
	sig_bit.red = 8;
	sig_bit.green = 8;
	sig_bit.blue = 8;
	sig_bit.alpha = 8;

	png_set_sBIT(png_ptr, info_ptr, &sig_bit);
		
	png_write_info(png_ptr, info_ptr);
	png_set_shift(png_ptr, &sig_bit);
	png_set_packing(png_ptr);
	
	/* write bytes */
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during writing bytes");
	
	png_write_image(png_ptr, row_pointers);
	
	
	/* end write */
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during end of write");
	
	png_write_end(png_ptr, NULL);
	
	free(row_pointers);
	
	fclose(fp);
}
Ejemplo n.º 3
0
    void write_header( const View& view )
    {
        using png_rw_info_t = detail::png_write_support
            <
                typename channel_type<typename get_pixel_type<View>::type>::type,
                typename color_space_type<View>::type
            >;

        // Set the image information here.  Width and height are up to 2^31,
        // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
        // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
        // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
        // or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
        // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
        // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
        png_set_IHDR( get_struct()
                    , get_info()
                    , static_cast< png_image_width::type  >( view.width()  )
                    , static_cast< png_image_height::type >( view.height() )
                    , static_cast< png_bitdepth::type     >( png_rw_info_t::_bit_depth )
                    , static_cast< png_color_type::type   >( png_rw_info_t::_color_type )
                    , _info._interlace_method
                    , _info._compression_type
                    , _info._filter_method
                    );

#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
        if( _info._valid_cie_colors )
        {
            png_set_cHRM( get_struct()
                        , get_info()
                        , _info._white_x
                        , _info._white_y
                        , _info._red_x
                        , _info._red_y
                        , _info._green_x
                        , _info._green_y
                        , _info._blue_x
                        , _info._blue_y
                        );
        }

        if( _info._valid_file_gamma )
        {
            png_set_gAMA( get_struct()
                        , get_info()
                        , _info._file_gamma
                        );
        }
#else
        if( _info._valid_cie_colors )
        {
            png_set_cHRM_fixed( get_struct()
                              , get_info()
                              , _info._white_x
                              , _info._white_y
                              , _info._red_x
                              , _info._red_y
                              , _info._green_x
                              , _info._green_y
                              , _info._blue_x
                              , _info._blue_y
                              );
        }

        if( _info._valid_file_gamma )
        {
            png_set_gAMA_fixed( get_struct()
                              , get_info()
                              , _info._file_gamma
                              );
        }
#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED

        if( _info._valid_icc_profile )
        {
#if PNG_LIBPNG_VER_MINOR >= 5
            png_set_iCCP( get_struct()
                        , get_info()
                        , const_cast< png_charp >( _info._icc_name.c_str() )
                        , _info._iccp_compression_type
                        , reinterpret_cast< png_const_bytep >( & (_info._profile.front ()) )
                        , _info._profile_length
                        );
#else
            png_set_iCCP( get_struct()
                        , get_info()
                        , const_cast< png_charp >( _info._icc_name.c_str() )
                        , _info._iccp_compression_type
                        , const_cast< png_charp >( & (_info._profile.front()) )
                        , _info._profile_length
                        );
#endif
        }

        if( _info._valid_intent )
        {
            png_set_sRGB( get_struct()
                        , get_info()
                        , _info._intent
                        );
        }

        if( _info._valid_palette )
        {
            png_set_PLTE( get_struct()
                        , get_info()
                        , const_cast< png_colorp >( &_info._palette.front() )
                        , _info._num_palette
                        );
        }

        if( _info._valid_background )
        {
            png_set_bKGD( get_struct()
                        , get_info()
                        , const_cast< png_color_16p >( &_info._background )
                        );
        }

        if( _info._valid_histogram )
        {
            png_set_hIST( get_struct()
                        , get_info()
                        , const_cast< png_uint_16p >( &_info._histogram.front() )
                        );
        }

        if( _info._valid_offset )
        {
            png_set_oFFs( get_struct()
                        , get_info()
                        , _info._offset_x
                        , _info._offset_y
                        , _info._off_unit_type
                        );
        }

        if( _info._valid_pixel_calibration )
        {
            std::vector< const char* > params( _info._num_params );
            for( std::size_t i = 0; i < params.size(); ++i )
            {
                params[i] = _info._params[ i ].c_str();
            }

            png_set_pCAL( get_struct()
                        , get_info()
                        , const_cast< png_charp >( _info._purpose.c_str() )
                        , _info._X0
                        , _info._X1
                        , _info._cal_type
                        , _info._num_params
                        , const_cast< png_charp  >( _info._units.c_str() )
                        , const_cast< png_charpp >( &params.front()     )
                        );
        }

        if( _info._valid_resolution )
        {
            png_set_pHYs( get_struct()
                        , get_info()
                        , _info._res_x
                        , _info._res_y
                        , _info._phy_unit_type
                        );
        }

        if( _info._valid_significant_bits )
        {
            png_set_sBIT( get_struct()
                        , get_info()
                        , const_cast< png_color_8p >( &_info._sig_bits )
                        );
        }

#ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER

#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
        if( _info._valid_scale_factors )
        {
            png_set_sCAL( get_struct()
                        , get_info()
                        , this->_info._scale_unit
                        , this->_info._scale_width
                        , this->_info._scale_height
                        );
        }
#else
#ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
        if( _info._valid_scale_factors )
        {
            png_set_sCAL_fixed( get_struct()
                              , get_info()
                              , this->_info._scale_unit
                              , this->_info._scale_width
                              , this->_info._scale_height
                              );
        }
#else
        if( _info._valid_scale_factors )
        {
            png_set_sCAL_s( get_struct()
                          , get_info()
                          , this->_info._scale_unit
                          , const_cast< png_charp >( this->_info._scale_width.c_str()  )
                          , const_cast< png_charp >( this->_info._scale_height.c_str() )
                          );
        }

#endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
#endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER

        if( _info._valid_text )
        {
            std::vector< png_text > texts( _info._num_text );
            for( std::size_t i = 0; i < texts.size(); ++i )
            {
                png_text pt;
                pt.compression = _info._text[i]._compression;
                pt.key         = const_cast< png_charp >( this->_info._text[i]._key.c_str()  );
                pt.text        = const_cast< png_charp >( this->_info._text[i]._text.c_str() );
                pt.text_length = _info._text[i]._text.length();

                texts[i] = pt;
            }

            png_set_text( get_struct()
                        , get_info()
                        , &texts.front()
                        , _info._num_text
                        );
        }

        if( _info._valid_modification_time )
        {
            png_set_tIME( get_struct()
                        , get_info()
                        , const_cast< png_timep >( &_info._mod_time )
                        );
        }

        if( _info._valid_transparency_factors )
        {
            int sample_max = ( 1u << _info._bit_depth );

            /* libpng doesn't reject a tRNS chunk with out-of-range samples */
            if( !(  (  _info._color_type == PNG_COLOR_TYPE_GRAY
                    && (int) _info._trans_values[0].gray > sample_max
                    )
                 || (  _info._color_type == PNG_COLOR_TYPE_RGB
                    &&(  (int) _info._trans_values[0].red   > sample_max
                      || (int) _info._trans_values[0].green > sample_max
                      || (int) _info._trans_values[0].blue  > sample_max
                      )
                    )
                 )
              )
            {
                //@todo Fix that once reading transparency values works
/*
                png_set_tRNS( get_struct()
                            , get_info()
                            , trans
                            , num_trans
                            , trans_values
                            );
*/
            }
        }

        // Compression Levels - valid values are [0,9]
        png_set_compression_level( get_struct()
                                 , _info._compression_level
                                 );

        png_set_compression_mem_level( get_struct()
                                     , _info._compression_mem_level
                                     );

        png_set_compression_strategy( get_struct()
                                    , _info._compression_strategy
                                    );

        png_set_compression_window_bits( get_struct()
                                       , _info._compression_window_bits
                                       );

        png_set_compression_method( get_struct()
                                  , _info._compression_method
                                  );

        png_set_compression_buffer_size( get_struct()
                                       , _info._compression_buffer_size
                                       );

#ifdef BOOST_GIL_IO_PNG_DITHERING_SUPPORTED
        // Dithering
        if( _info._set_dithering )
        {
            png_set_dither( get_struct()
                          , &_info._dithering_palette.front()
                          , _info._dithering_num_palette
                          , _info._dithering_maximum_colors
                          , &_info._dithering_histogram.front()
                          , _info._full_dither
                          );
        }
#endif // BOOST_GIL_IO_PNG_DITHERING_SUPPORTED

        // Filter
        if( _info._set_filter )
        {
            png_set_filter( get_struct()
                          , 0
                          , _info._filter
                          );
        }

        // Invert Mono
        if( _info._invert_mono )
        {
            png_set_invert_mono( get_struct() );
        }

        // True Bits
        if( _info._set_true_bits )
        {
            png_set_sBIT( get_struct()
                        , get_info()
                        , &_info._true_bits.front()
                        );
        }

        // sRGB Intent
        if( _info._set_srgb_intent )
        {
            png_set_sRGB( get_struct()
                        , get_info()
                        , _info._srgb_intent
                        );
        }

        // Strip Alpha
        if( _info._strip_alpha )
        {
            png_set_strip_alpha( get_struct() );
        }

        // Swap Alpha
        if( _info._swap_alpha )
        {
            png_set_swap_alpha( get_struct() );
        }


        png_write_info( get_struct()
                      , get_info()
                      );
    }
Ejemplo n.º 4
0
/**
 * Generic .PNG file image writer.
 * @param name        Filename, including extension.
 * @param callb       Callback function for generating lines of pixels.
 * @param userdata    User data, passed on to \a callb.
 * @param w           Width of the image in pixels.
 * @param h           Height of the image in pixels.
 * @param pixelformat Bits per pixel (bpp), either 8 or 32.
 * @param palette     %Colour palette (for 8bpp images).
 * @return File was written successfully.
 * @see ScreenshotHandlerProc
 */
static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
{
	png_color rq[256];
	FILE *f;
	uint i, y, n;
	uint maxlines;
	uint bpp = pixelformat / 8;
	png_structp png_ptr;
	png_infop info_ptr;

	/* only implemented for 8bit and 32bit images so far. */
	if (pixelformat != 8 && pixelformat != 32) return false;

	f = fopen(name, "wb");
	if (f == NULL) return false;

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, const_cast<char *>(name), png_my_error, png_my_warning);

	if (png_ptr == NULL) {
		fclose(f);
		return false;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		fclose(f);
		return false;
	}

	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(f);
		return false;
	}

	png_init_io(png_ptr, f);

	png_set_filter(png_ptr, 0, PNG_FILTER_NONE);

	png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

#ifdef PNG_TEXT_SUPPORTED
	/* Try to add some game metadata to the PNG screenshot so
	 * it's more useful for debugging and archival purposes. */
	png_text_struct text[2];
	memset(text, 0, sizeof(text));
	text[0].key = const_cast<char *>("Software");
	text[0].text = const_cast<char *>(_openttd_revision);
	text[0].text_length = strlen(_openttd_revision);
	text[0].compression = PNG_TEXT_COMPRESSION_NONE;

	char buf[8192];
	char *p = buf;
	p += seprintf(p, lastof(buf), "Graphics set: %s (%u)\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version);
	p = strecpy(p, "NewGRFs:\n", lastof(buf));
	for (const GRFConfig *c = _game_mode == GM_MENU ? NULL : _grfconfig; c != NULL; c = c->next) {
		p += seprintf(p, lastof(buf), "%08X ", BSWAP32(c->ident.grfid));
		p = md5sumToString(p, lastof(buf), c->ident.md5sum);
		p += seprintf(p, lastof(buf), " %s\n", c->filename);
	}
	p = strecpy(p, "\nCompanies:\n", lastof(buf));
	const Company *c;
	FOR_ALL_COMPANIES(c) {
		if (c->ai_info == NULL) {
			p += seprintf(p, lastof(buf), "%2i: Human\n", (int)c->index);
		} else {
			p += seprintf(p, lastof(buf), "%2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion());
		}
	}
	text[1].key = const_cast<char *>("Description");
	text[1].text = buf;
	text[1].text_length = p - buf;
	text[1].compression = PNG_TEXT_COMPRESSION_zTXt;
	png_set_text(png_ptr, info_ptr, text, 2);
#endif /* PNG_TEXT_SUPPORTED */

	if (pixelformat == 8) {
		/* convert the palette to the .PNG format. */
		for (i = 0; i != 256; i++) {
			rq[i].red   = palette[i].r;
			rq[i].green = palette[i].g;
			rq[i].blue  = palette[i].b;
		}

		png_set_PLTE(png_ptr, info_ptr, rq, 256);
	}

	png_write_info(png_ptr, info_ptr);
	png_set_flush(png_ptr, 512);

	if (pixelformat == 32) {
		png_color_8 sig_bit;

		/* Save exact colour/alpha resolution */
		sig_bit.alpha = 0;
		sig_bit.blue  = 8;
		sig_bit.green = 8;
		sig_bit.red   = 8;
		sig_bit.gray  = 8;
		png_set_sBIT(png_ptr, info_ptr, &sig_bit);

#if TTD_ENDIAN == TTD_LITTLE_ENDIAN
		png_set_bgr(png_ptr);
		png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
#else
		png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
#endif /* TTD_ENDIAN == TTD_LITTLE_ENDIAN */
	}

	/* use by default 64k temp memory */
	maxlines = Clamp(65536 / w, 16, 128);

	/* now generate the bitmap bits */
	void *buff = CallocT<uint8>(w * maxlines * bpp); // by default generate 128 lines at a time.

	y = 0;
	do {
		/* determine # lines to write */
		n = min(h - y, maxlines);

		/* render the pixels into the buffer */
		callb(userdata, buff, y, w, n);
		y += n;

		/* write them to png */
		for (i = 0; i != n; i++) {
			png_write_row(png_ptr, (png_bytep)buff + i * w * bpp);
		}
	} while (y != h);

	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);

	free(buff);
	fclose(f);
	return true;
}
Ejemplo n.º 5
0
void PNGImageFileWriter::write(
    const char*             filename,
    const ICanvas&          image,
    const ImageAttributes&  image_attributes)
{
    // Retrieve canvas properties.
    const CanvasProperties& props = image.properties();

    // todo: lift these limitations.
    assert(props.m_channel_count == 3 || props.m_channel_count == 4);

    // Open the file in write mode.
    FILE* fp = fopen(filename, "wb");
    if (fp == 0)
        throw ExceptionIOError();

    // Allocate and initialize the png_struct structure.
    png_structp png_ptr =
        png_create_write_struct(
            PNG_LIBPNG_VER_STRING,
            fp,
            error_callback,
            warning_callback);
    if (png_ptr == 0)
    {
        fclose(fp);
        throw ExceptionMemoryError();
    }

    // Allocate the png_info structure.
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == 0)
    {
        png_destroy_write_struct(&png_ptr, 0);
        fclose(fp);
        throw ExceptionMemoryError();
    }

    // Set up the output control.
    png_init_io(png_ptr, fp);

    // Set image information.
    png_set_IHDR(
        png_ptr,
        info_ptr,
        static_cast<png_uint_32>(props.m_canvas_width),
        static_cast<png_uint_32>(props.m_canvas_height),
        8,                                  // bit depth -- todo: allow higher bit depths
        props.m_channel_count == 4
            ? PNG_COLOR_TYPE_RGB_ALPHA
            : PNG_COLOR_TYPE_RGB,
        PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_DEFAULT,
        PNG_FILTER_TYPE_DEFAULT);

    // Mark the image as being sRGB (implying specific gamma and color matching functions).
    // See http://www.vias.org/pngguide/chapter10_07.html for details about intents.
    png_set_sRGB_gAMA_and_cHRM(
        png_ptr,
        info_ptr,
        PNG_sRGB_INTENT_PERCEPTUAL);        // todo: allow the user to select different intents

    // Set the number of significant bits for each of the R, G, B and A channels.
    // todo: are we required to provide these information?
    png_color_8 sig_bit;
    sig_bit.red = 8;
    sig_bit.green = 8;
    sig_bit.blue = 8;
    sig_bit.alpha = 8;
    sig_bit.gray = 8;                       // for completeness
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

    // Add image attributes.
    vector<png_text_struct> text_chunks;
    add_attributes(
        png_ptr,
        info_ptr,
        text_chunks,
        image_attributes);
    if (!text_chunks.empty())
    {
        png_set_text(
            png_ptr,
            info_ptr,
            &text_chunks[0],
            static_cast<int>(text_chunks.size()));
    }

    // Write the file header information.
    png_write_info(png_ptr, info_ptr);

    // Create the temporary buffer holding one row of tiles in target format.
    vector<uint8> buffer(
          props.m_canvas_width
        * props.m_tile_height
        * props.m_channel_count);

    // Construct pointers to each row of the temporary buffer.
    vector<uint8*> buffer_rows(props.m_tile_height);
    for (size_t y = 0; y < props.m_tile_height; ++y)
        buffer_rows[y] = &buffer[y * props.m_canvas_width * props.m_channel_count];

    // Loop over the rows of tiles.
    for (size_t tile_y = 0; tile_y < props.m_tile_count_y; ++tile_y)
    {
        // Convert this row of tiles to target format.
        for (size_t tile_x = 0; tile_x < props.m_tile_count_x; ++tile_x)
        {
            const Tile& tile = image.tile(tile_x, tile_y);
            assert(tile.get_height() <= props.m_tile_height);
            for (size_t y = 0; y < tile.get_height(); ++y)
            {
                for (size_t x = 0; x < tile.get_width(); ++x)
                {
                    // Horizontal coordinate of the pixel in the temporary buffer.
                    const size_t buffer_x = tile_x * props.m_tile_width + x;

                    // Index of the pixel in the temporary buffer.
                    const size_t buffer_index =
                        (y * props.m_canvas_width + buffer_x) * props.m_channel_count;

                    // Fetch the pixel at coordinates (x, y) in the tile,
                    // perform format conversion if necessary, and store
                    // the converted pixel into the temporary buffer.
                    if (tile.get_channel_count() == 3)
                    {
                        Color3i pixel;
                        tile.get_pixel(x, y, pixel);
                        buffer[buffer_index + 0] = pixel[0];
                        buffer[buffer_index + 1] = pixel[1];
                        buffer[buffer_index + 2] = pixel[2];
                    }
                    else
                    {
                        assert(tile.get_channel_count() == 4);
                        Color4i pixel;
                        tile.get_pixel(x, y, pixel);
                        buffer[buffer_index + 0] = pixel[0];
                        buffer[buffer_index + 1] = pixel[1];
                        buffer[buffer_index + 2] = pixel[2];
                        buffer[buffer_index + 3] = pixel[3];
                    }
                }
            }
        }

        // Write this row of tiles to the file.
        const size_t row_count = image.tile(0, tile_y).get_height();
        png_write_rows(
            png_ptr,
            &buffer_rows[0],
            static_cast<png_uint_32>(row_count));
    }

    // Finish writing the file.
    png_write_end(png_ptr, 0);

    // Deallocate the png_struct and png_info structures.
    png_destroy_write_struct(&png_ptr, &info_ptr);

    // Deallocate text chunks.
    destroy_text_chunks(text_chunks);

    // Close the file.
    fclose(fp);
}
Ejemplo n.º 6
0
bool KIPIWriteImage::write2PNG(const QString& destPath)
{
    /*
    check this out for b/w support:
    http://lxr.kde.org/source/playground/graphics/krita-exp/kis_png_converter.cpp#607
    */
    QFile file(destPath);

    if (!file.open(QIODevice::ReadWrite))
    {
        qDebug() << "Failed to open PNG file for writing" ;
        return false;
    }

    uchar*       data       = 0;
    int          bitsDepth  = d->sixteenBit ? 16 : 8;
    png_color_8  sig_bit;
    png_bytep    row_ptr;
    png_structp  png_ptr    = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_infop    info_ptr   = png_create_info_struct(png_ptr);

    png_set_write_fn(png_ptr, (void*)&file, kipi_png_write_fn, kipi_png_flush_fn);

    if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)      // Intel
        png_set_bgr(png_ptr);
    else                                                    // PPC
        png_set_swap_alpha(png_ptr);

    if (d->hasAlpha)
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB_ALPHA,  PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 8 * sizeof(uchar)];
        else
            data = new uchar[d->width * 4 * sizeof(uchar)];
    }
    else
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB,        PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 6 * sizeof(uchar)];
        else
            data = new uchar[d->width * 3 * sizeof(uchar)];
    }

    sig_bit.red   = bitsDepth;
    sig_bit.green = bitsDepth;
    sig_bit.blue  = bitsDepth;
    sig_bit.alpha = bitsDepth;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
    png_set_compression_level(png_ptr, 9);

    // Write Software info.
    QString libpngver(QLatin1String(PNG_HEADER_VERSION_STRING));
    libpngver.replace(QLatin1Char('\n'), QLatin1Char(' '));
    QByteArray softAscii = libpngver.toLatin1();
    png_text text;
    text.key         = (png_charp)"Software";
    text.text        = softAscii.data();
    text.compression = PNG_TEXT_COMPRESSION_zTXt;
    png_set_text(png_ptr, info_ptr, &(text), 1);

    png_write_info(png_ptr, info_ptr);
    png_set_shift(png_ptr, &sig_bit);
    png_set_packing(png_ptr);

    uchar* ptr = (uchar*)d->data.data();
    uint   x, y, j;

    for (y = 0; y < d->height; ++y)
    {
        if (cancel())
        {
            delete [] data;
            file.close();
            png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
            png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
            return false;
        }

        j = 0;

        for (x = 0; x < d->width*bytesDepth(); x+=bytesDepth())
        {
            if (d->sixteenBit)
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                    data[j++] = ptr[x+7];  // Alpha
                    data[j++] = ptr[x+6];
                }
                else
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                }
            }
            else
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                    data[j++] = ptr[x+3];  // Alpha
                }
                else
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                }
            }
        }

        row_ptr = (png_bytep) data;

        png_write_rows(png_ptr, &row_ptr, 1);
        ptr += (d->width * bytesDepth());
    }

    delete [] data;

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
    png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
    file.close();

    return true;
}
Ejemplo n.º 7
0
static bool
sp_png_write_rgba_striped(SPDocument *doc,
                          gchar const *filename, unsigned long int width, unsigned long int height, double xdpi, double ydpi,
                          int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data),
                          void *data)
{
    struct SPEBP *ebp = (struct SPEBP *) data;
    FILE *fp;
    png_structp png_ptr;
    png_infop info_ptr;
    png_color_8 sig_bit;
    png_uint_32 r;

    g_return_val_if_fail(filename != NULL, false);
    g_return_val_if_fail(data != NULL, false);

    /* open the file */

    Inkscape::IO::dump_fopen_call(filename, "M");
    fp = Inkscape::IO::fopen_utf8name(filename, "wb");
    g_return_val_if_fail(fp != NULL, false);

    /* Create and initialize the png_struct with the desired error handler
     * functions.  If you want to use the default stderr and longjump method,
     * you can supply NULL for the last three parameters.  We also check that
     * the library version is compatible with the one used at compile time,
     * in case we are using dynamically linked libraries.  REQUIRED.
     */
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    if (png_ptr == NULL) {
        fclose(fp);
        return false;
    }

    /* Allocate/initialize the image information data.  REQUIRED */
    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        fclose(fp);
        png_destroy_write_struct(&png_ptr, NULL);
        return false;
    }

    /* Set error handling.  REQUIRED if you aren't supplying your own
     * error hadnling functions in the png_create_write_struct() call.
     */
    if (setjmp(png_jmpbuf(png_ptr))) {
        // If we get here, we had a problem reading the file
        fclose(fp);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return false;
    }

    /* set up the output control if you are using standard C streams */
    png_init_io(png_ptr, fp);

    /* Set the image information here.  Width and height are up to 2^31,
     * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
     * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
     * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
     * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
     * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
     * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
     */
    png_set_IHDR(png_ptr, info_ptr,
                 width,
                 height,
                 8, /* bit_depth */
                 PNG_COLOR_TYPE_RGB_ALPHA,
                 PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_BASE,
                 PNG_FILTER_TYPE_BASE);

    /* otherwise, if we are dealing with a color image then */
    sig_bit.red = 8;
    sig_bit.green = 8;
    sig_bit.blue = 8;
    /* if the image has an alpha channel then */
    sig_bit.alpha = 8;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

    PngTextList textList;

    textList.add("Software", "www.inkscape.org"); // Made by Inkscape comment
    {
        const gchar* pngToDc[] = {"Title", "title",
                               "Author", "creator",
                               "Description", "description",
                               //"Copyright", "",
                               "Creation Time", "date",
                               //"Disclaimer", "",
                               //"Warning", "",
                               "Source", "source"
                               //"Comment", ""
        };
        for (size_t i = 0; i < G_N_ELEMENTS(pngToDc); i += 2) {
            struct rdf_work_entity_t * entity = rdf_find_entity ( pngToDc[i + 1] );
            if (entity) {
                gchar const* data = rdf_get_work_entity(doc, entity);
                if (data && *data) {
                    textList.add(pngToDc[i], data);
                }
            } else {
                g_warning("Unable to find entity [%s]", pngToDc[i + 1]);
            }
        }


        struct rdf_license_t *license =  rdf_get_license(doc);
        if (license) {
            if (license->name && license->uri) {
                gchar* tmp = g_strdup_printf("%s %s", license->name, license->uri);
                textList.add("Copyright", tmp);
                g_free(tmp);
            } else if (license->name) {
                textList.add("Copyright", license->name);
            } else if (license->uri) {
                textList.add("Copyright", license->uri);
            }
        }
    }
    if (textList.getCount() > 0) {
        png_set_text(png_ptr, info_ptr, textList.getPtext(), textList.getCount());
    }

    /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
    /* note that if sRGB is present the cHRM chunk must be ignored
     * on read and must be written in accordance with the sRGB profile */
    png_set_pHYs(png_ptr, info_ptr, unsigned(xdpi / 0.0254 + 0.5), unsigned(ydpi / 0.0254 + 0.5), PNG_RESOLUTION_METER);

    /* Write the file header information.  REQUIRED */
    png_write_info(png_ptr, info_ptr);

    /* Once we write out the header, the compression type on the text
     * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
     * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
     * at the end.
     */

    /* set up the transformations you want.  Note that these are
     * all optional.  Only call them if you want them.
     */

    /* --- CUT --- */

    /* The easiest way to write the image (you may have a different memory
     * layout, however, so choose what fits your needs best).  You need to
     * use the first method if you aren't handling interlacing yourself.
     */

    png_bytep* row_pointers = new png_bytep[ebp->sheight];

    r = 0;
    while (r < static_cast<png_uint_32>(height)) {
        void *to_free;
        int n = get_rows((unsigned char const **) row_pointers, &to_free, r, height-r, data);
        if (!n) break;
        png_write_rows(png_ptr, row_pointers, n);
        g_free(to_free);
        r += n;
    }

    delete[] row_pointers;

    /* You can write optional chunks like tEXt, zTXt, and tIME at the end
     * as well.
     */

    /* It is REQUIRED to call this to finish writing the rest of the file */
    png_write_end(png_ptr, info_ptr);

    /* if you allocated any text comments, free them here */

    /* clean up after the write, and free any memory allocated */
    png_destroy_write_struct(&png_ptr, &info_ptr);

    /* close the file */
    fclose(fp);

    /* that's it */
    return true;
}
Ejemplo n.º 8
0
bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
{
    wxPNGInfoStruct wxinfo;

    wxinfo.verbose = verbose;
    wxinfo.stream.out = &stream;

    png_structp png_ptr = png_create_write_struct
                          (
                              PNG_LIBPNG_VER_STRING,
                              NULL,
                              wx_png_error,
                              wx_png_warning
                          );
    if (!png_ptr)
    {
        if (verbose)
        {
            wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL)
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
            wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    if (setjmp(wxinfo.jmpbuf))
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
            wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    // NB: please see the comment near wxPNGInfoStruct declaration for
    //     explanation why this line is mandatory
    png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL);

    const int iColorType = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT)
                           ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT)
                           : wxPNG_TYPE_COLOUR;
    const int iBitDepth = image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH)
                          ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH)
                          : 8;

    bool bHasAlpha = image->HasAlpha();
    bool bHasMask = image->HasMask();
    bool bUseAlpha = bHasAlpha || bHasMask;

    int iPngColorType;
    if ( iColorType==wxPNG_TYPE_COLOUR )
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA
                        : PNG_COLOR_TYPE_RGB;
    }
    else
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA
                        : PNG_COLOR_TYPE_GRAY;
    }

    if (image->HasOption(wxIMAGE_OPTION_PNG_FILTER))
        png_set_filter( png_ptr, PNG_FILTER_TYPE_BASE, image->GetOptionInt(wxIMAGE_OPTION_PNG_FILTER) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL))
        png_set_compression_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL))
        png_set_compression_mem_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY))
        png_set_compression_strategy( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE))
        png_set_compression_buffer_size( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE) );

    png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(),
                  iBitDepth, iPngColorType,
                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                  PNG_FILTER_TYPE_BASE);

    int iElements;
    png_color_8 sig_bit;

    if ( iPngColorType & PNG_COLOR_MASK_COLOR )
    {
        sig_bit.red =
            sig_bit.green =
                sig_bit.blue = (png_byte)iBitDepth;
        iElements = 3;
    }
    else // grey
    {
        sig_bit.gray = (png_byte)iBitDepth;
        iElements = 1;
    }

    if ( iPngColorType & PNG_COLOR_MASK_ALPHA )
    {
        sig_bit.alpha = (png_byte)iBitDepth;
        iElements++;
    }

    if ( iBitDepth == 16 )
        iElements *= 2;

    // save the image resolution if we have it
    int resX, resY;
    switch ( GetResolutionFromOptions(*image, &resX, &resY) )
    {
    case wxIMAGE_RESOLUTION_INCHES:
    {
        const double INCHES_IN_METER = 10000.0 / 254;
        resX = int(resX * INCHES_IN_METER);
        resY = int(resY * INCHES_IN_METER);
    }
    break;

    case wxIMAGE_RESOLUTION_CM:
        resX *= 100;
        resY *= 100;
        break;

    case wxIMAGE_RESOLUTION_NONE:
        break;

    default:
        wxFAIL_MSG( wxT("unsupported image resolution units") );
    }

    if ( resX && resY )
        png_set_pHYs( png_ptr, info_ptr, resX, resY, PNG_RESOLUTION_METER );

    png_set_sBIT( png_ptr, info_ptr, &sig_bit );
    png_write_info( png_ptr, info_ptr );
    png_set_shift( png_ptr, &sig_bit );
    png_set_packing( png_ptr );

    unsigned char *
    data = (unsigned char *)malloc( image->GetWidth() * iElements );
    if ( !data )
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        return false;
    }

    unsigned char *
    pAlpha = (unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL);
    int iHeight = image->GetHeight();
    int iWidth = image->GetWidth();

    unsigned char uchMaskRed = 0, uchMaskGreen = 0, uchMaskBlue = 0;

    if ( bHasMask )
    {
        uchMaskRed = image->GetMaskRed();
        uchMaskGreen = image->GetMaskGreen();
        uchMaskBlue = image->GetMaskBlue();
    }

    unsigned char *pColors = image->GetData();

    for (int y = 0; y != iHeight; ++y)
    {
        unsigned char *pData = data;
        for (int x = 0; x != iWidth; x++)
        {
            unsigned char uchRed = *pColors++;
            unsigned char uchGreen = *pColors++;
            unsigned char uchBlue = *pColors++;

            switch ( iColorType )
            {
            default:
                wxFAIL_MSG( wxT("unknown wxPNG_TYPE_XXX") );
            // fall through

            case wxPNG_TYPE_COLOUR:
                *pData++ = uchRed;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                *pData++ = uchGreen;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                *pData++ = uchBlue;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                break;

            case wxPNG_TYPE_GREY:
            {
                // where do these coefficients come from? maybe we
                // should have image options for them as well?
                unsigned uiColor =
                    (unsigned) (76.544*(unsigned)uchRed +
                                150.272*(unsigned)uchGreen +
                                36.864*(unsigned)uchBlue);

                *pData++ = (unsigned char)((uiColor >> 8) & 0xFF);
                if ( iBitDepth == 16 )
                    *pData++ = (unsigned char)(uiColor & 0xFF);
            }
            break;

            case wxPNG_TYPE_GREY_RED:
                *pData++ = uchRed;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                break;
            }

            if ( bUseAlpha )
            {
                unsigned char uchAlpha = 255;
                if ( bHasAlpha )
                    uchAlpha = *pAlpha++;

                if ( bHasMask )
                {
                    if ( (uchRed == uchMaskRed)
                            && (uchGreen == uchMaskGreen)
                            && (uchBlue == uchMaskBlue) )
                        uchAlpha = 0;
                }

                *pData++ = uchAlpha;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
            }
        }

        png_bytep row_ptr = data;
        png_write_rows( png_ptr, &row_ptr, 1 );
    }

    free(data);
    png_write_end( png_ptr, info_ptr );
    png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );

    return true;
}
Ejemplo n.º 9
0
static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
{
	png_color rq[256];
	FILE *f;
	uint i, y, n;
	uint maxlines;
	uint bpp = pixelformat / 8;
	png_structp png_ptr;
	png_infop info_ptr;

	/* only implemented for 8bit and 32bit images so far. */
	if (pixelformat != 8 && pixelformat != 32) return false;

	f = fopen(name, "wb");
	if (f == NULL) return false;

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *)name, png_my_error, png_my_warning);

	if (png_ptr == NULL) {
		fclose(f);
		return false;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		fclose(f);
		return false;
	}

	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(f);
		return false;
	}

	png_init_io(png_ptr, f);

	png_set_filter(png_ptr, 0, PNG_FILTER_NONE);

	png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	if (pixelformat == 8) {
		/* convert the palette to the .PNG format. */
		for (i = 0; i != 256; i++) {
			rq[i].red   = palette[i].r;
			rq[i].green = palette[i].g;
			rq[i].blue  = palette[i].b;
		}

		png_set_PLTE(png_ptr, info_ptr, rq, 256);
	}

	png_write_info(png_ptr, info_ptr);
	png_set_flush(png_ptr, 512);

	if (pixelformat == 32) {
		png_color_8 sig_bit;

		/* Save exact colour/alpha resolution */
		sig_bit.alpha = 0;
		sig_bit.blue  = 8;
		sig_bit.green = 8;
		sig_bit.red   = 8;
		sig_bit.gray  = 8;
		png_set_sBIT(png_ptr, info_ptr, &sig_bit);

#if TTD_ENDIAN == TTD_LITTLE_ENDIAN
		png_set_bgr(png_ptr);
		png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
#else
		png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
#endif /* TTD_ENDIAN == TTD_LITTLE_ENDIAN */
	}

	/* use by default 64k temp memory */
	maxlines = Clamp(65536 / w, 16, 128);

	/* now generate the bitmap bits */
	void *buff = CallocT<uint8>(w * maxlines * bpp); // by default generate 128 lines at a time.

	y = 0;
	do {
		/* determine # lines to write */
		n = min(h - y, maxlines);

		/* render the pixels into the buffer */
		callb(userdata, buff, y, w, n);
		y += n;

		/* write them to png */
		for (i = 0; i != n; i++)
			png_write_row(png_ptr, (png_bytep)buff + i * w * bpp);
	} while (y != h);

	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);

	free(buff);
	fclose(f);
	return true;
}
Ejemplo n.º 10
0
int imagetopng(opj_image_t * image, const char *write_idf)
{
    FILE * volatile writer = NULL;
    png_structp png = NULL;
    png_infop info = NULL;
    png_bytep volatile row_buf = NULL;
    int nr_comp, color_type;
    volatile int prec;
    png_color_8 sig_bit;
    int32_t const* planes[4];
    int i;
    int32_t* volatile buffer32s = NULL;

    volatile int fails = 1;

    memset(&sig_bit, 0, sizeof(sig_bit));
    prec = (int)image->comps[0].prec;
    planes[0] = image->comps[0].data;
    nr_comp = (int)image->numcomps;

    if (nr_comp > 4) {
        nr_comp = 4;
    }
    for (i = 1; i < nr_comp; ++i) {
        if (image->comps[0].dx != image->comps[i].dx) {
            break;
        }
        if (image->comps[0].dy != image->comps[i].dy) {
            break;
        }
        if (image->comps[0].prec != image->comps[i].prec) {
            break;
        }
        if (image->comps[0].sgnd != image->comps[i].sgnd) {
            break;
        }
        planes[i] = image->comps[i].data;
    }
    if (i != nr_comp) {
        fprintf(stderr,"imagetopng: All components shall have the same subsampling, same bit depth, same sign.\n");
        fprintf(stderr,"\tAborting\n");
        return 1;
    }
    for (i = 0; i < nr_comp; ++i) {
        clip_component(&(image->comps[i]), image->comps[0].prec);
    }
    if(prec > 8 && prec < 16) {
        for (i = 0; i < nr_comp; ++i) {
            scale_component(&(image->comps[i]), 16);
        }
        prec = 16;
    } else if(prec < 8 && nr_comp > 1) { /* GRAY_ALPHA, RGB, RGB_ALPHA */
        for (i = 0; i < nr_comp; ++i) {
            scale_component(&(image->comps[i]), 8);
        }
        prec = 8;
    } else if((prec > 1) && (prec < 8) && ((prec == 6) || ((prec & 1)==1))) { /* GRAY with non native precision */
        if ((prec == 5) || (prec == 6)) {
            prec = 8;
        } else {
            prec++;
        }
        for (i = 0; i < nr_comp; ++i) {
            scale_component(&(image->comps[i]), (uint32_t)prec);
        }
    }

    if(prec != 1 && prec != 2 && prec != 4 && prec != 8 && prec != 16) {
        fprintf(stderr,"imagetopng: can not create %s\n\twrong bit_depth %d\n", write_idf, prec);
        return fails;
    }

    writer = fopen(write_idf, "wb");

    if(writer == NULL) return fails;

    /* Create and initialize the png_struct with the desired error handler
     * functions.  If you want to use the default stderr and longjump method,
     * you can supply NULL for the last three parameters.  We also check that
     * the library version is compatible with the one used at compile time,
     * in case we are using dynamically linked libraries.  REQUIRED.
     */
    png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                  NULL, NULL, NULL);
    /*png_voidp user_error_ptr, user_error_fn, user_warning_fn); */

    if(png == NULL) goto fin;

    /* Allocate/initialize the image information data.  REQUIRED
     */
    info = png_create_info_struct(png);

    if(info == NULL) goto fin;

    /* Set error handling.  REQUIRED if you are not supplying your own
     * error handling functions in the png_create_write_struct() call.
     */
    if(setjmp(png_jmpbuf(png))) goto fin;

    /* I/O initialization functions is REQUIRED
     */
    png_init_io(png, writer);

    /* Set the image information here.  Width and height are up to 2^31,
     * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
     * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
     * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
     * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
     * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
     * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE.
     * REQUIRED
     *
     * ERRORS:
     *
     * color_type == PNG_COLOR_TYPE_PALETTE && bit_depth > 8
     * color_type == PNG_COLOR_TYPE_RGB && bit_depth < 8
     * color_type == PNG_COLOR_TYPE_GRAY_ALPHA && bit_depth < 8
     * color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8
     *
     */
    png_set_compression_level(png, Z_BEST_COMPRESSION);

    if(nr_comp >= 3) { /* RGB(A) */
        color_type = PNG_COLOR_TYPE_RGB;
        sig_bit.red = sig_bit.green = sig_bit.blue = (png_byte)prec;
    } else { /* GRAY(A) */
        color_type = PNG_COLOR_TYPE_GRAY;
        sig_bit.gray = (png_byte)prec;
    }
    if((nr_comp & 1) == 0) { /* ALPHA */
        color_type |= PNG_COLOR_MASK_ALPHA;
        sig_bit.alpha = (png_byte)prec;
    }

    png_set_IHDR(png, info, image->comps[0].w, image->comps[0].h, prec, color_type,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,  PNG_FILTER_TYPE_BASE);

    png_set_sBIT(png, info, &sig_bit);
    /* png_set_gamma(png, 2.2, 1./2.2); */
    /* png_set_sRGB(png, info, PNG_sRGB_INTENT_PERCEPTUAL); */
    png_write_info(png, info);

    /* setup conversion */
    {
        size_t rowStride;
        png_size_t png_row_size;

        png_row_size = png_get_rowbytes(png, info);
        rowStride = ((size_t)image->comps[0].w * (size_t)nr_comp * (size_t)prec + 7U) / 8U;
        if (rowStride != (size_t)png_row_size) {
            fprintf(stderr, "Invalid PNG row size\n");
            goto fin;
        }
        row_buf = (png_bytep)malloc(png_row_size);
        if (row_buf == NULL) {
            fprintf(stderr, "Can't allocate memory for PNG row\n");
            goto fin;
        }
        buffer32s = (int32_t*)malloc((size_t)image->comps[0].w * (size_t)nr_comp * sizeof(int32_t));
        if (buffer32s == NULL) {
            fprintf(stderr, "Can't allocate memory for interleaved 32s row\n");
            goto fin;
        }
    }

    /* convert */
    {
        size_t width= image->comps[0].w;
        uint32_t y;
        convert_32s_PXCX cvtPxToCx = convert_32s_PXCX_LUT[nr_comp];
        convert_32sXXx_C1R cvt32sToPack = NULL;
        int32_t adjust = image->comps[0].sgnd ? 1 << (prec - 1) : 0;
        png_bytep row_buf_cpy = row_buf;
        int32_t* buffer32s_cpy = buffer32s;

        switch (prec) {
        case 1:
        case 2:
        case 4:
        case 8:
            cvt32sToPack = convert_32sXXu_C1R_LUT[prec];
            break;
        case 16:
            cvt32sToPack = convert_32s16u_C1R;
            break;
        default:
            /* never here */
			return 1;
            break;
        }

        for(y = 0; y < image->comps[0].h; ++y) {
            cvtPxToCx(planes, buffer32s_cpy, width, adjust);
            cvt32sToPack(buffer32s_cpy, row_buf_cpy, width * (size_t)nr_comp);
            png_write_row(png, row_buf_cpy);
            planes[0] += width;
            planes[1] += width;
            planes[2] += width;
            planes[3] += width;
        }
    }

    png_write_end(png, info);

    fails = 0;

fin:
    if(png) {
        png_destroy_write_struct(&png, &info);
    }
    if(row_buf) {
        free(row_buf);
    }
    if(buffer32s) {
        free(buffer32s);
    }
    fclose(writer);

    if(fails) (void)remove(write_idf); /* ignore return value */

    return fails;
}/* imagetopng() */
Ejemplo n.º 11
0
//==============================================================
void PngWrite(char *file, int w, int h, u_char *ptr)
//--------------------------------------------------------------
// データ出力
// 32bit → 32bit
//--------------------------------------------------------------
// in:	file = ファイル名
//		w, h = データサイズ
//		ptr  = データポインタ
//--------------------------------------------------------------
// out:	なし
//==============================================================
{
	sFILE *fp;
	png_structp png_ptr;
	png_infop info_ptr;
	png_color_8 sig_bit;
	png_text text_ptr[1];
	png_bytep *row_pointers;
	int k;

#ifdef USE_USER_MEMORY
	png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, libpng_Malloc, libpng_Free);
#else
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
#endif
	if(!png_ptr)
	{
		return;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if(!info_ptr)
	{
		png_destroy_write_struct(&png_ptr, png_infopp_NULL);
		return;
	}

	// ファイルの新規作成
	//--------------------
	fp = FsCreate(file);
	ASSERT(fp);

	png_set_write_fn(png_ptr, (png_voidp)fp, writeFunc, flushFunc);
	png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE);

	sig_bit.red = 8;
	sig_bit.green = 8;
	sig_bit.blue = 8;
	sig_bit.alpha = 0;
	png_set_sBIT(png_ptr, info_ptr, &sig_bit);

	text_ptr[0].key = "Description";
	text_ptr[0].text = "ktcDIB::Save() Data";
	text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
	png_set_text(png_ptr, info_ptr, text_ptr, 1);

	png_write_info(png_ptr, info_ptr);
	png_set_bgr(png_ptr);

	row_pointers = (png_bytep *)fsMalloc(sizeof(png_bytep *) * h, "png_bytep");
	ASSERT(row_pointers);
	for(k = 0; k < h; ++k)
	{
		png_byte *p;

		p = (png_byte *)fsMalloc(sizeof(png_byte) * w * 3, "png_byte");
		ASSERT(p);
		row_pointers[k] = (png_bytep)p;
		memcpy(p, ptr, w * 3);
		ptr += w * 3;
	}

	png_write_image(png_ptr, row_pointers);
	png_write_end(png_ptr, info_ptr);

	for(k = 0; k < h; ++k)
	{
		Free(row_pointers[k]);
	}
	Free(row_pointers);

	png_destroy_write_struct(&png_ptr, &info_ptr);
	FsClose(fp);
}
Ejemplo n.º 12
0
Archivo: image.cpp Proyecto: KAlO2/blog
bool snapshot_png(int width, int height, const char* path)
{
	FILE *file = fopen(path, "wb");
	if(!file)
	{
		printf("can't open file %s for writing\n", path);
		return false;
	}

	png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
		NULL/*user_error_ptr*/, NULL/*user_error_fn*/, NULL/*user_warning_fn*/);
	if(!png_ptr)
	{
		printf("error: png_create_read_struct returned 0.\n");
		fclose(file);
		return false;
	}
	
	png_info* info_ptr = png_create_info_struct(png_ptr);
	if(!info_ptr || setjmp(png_jmpbuf(png_ptr)))
	{
		printf("error: png_create_read_struct returned 0 or set error handling failed.\n");
		png_destroy_write_struct(&png_ptr, (info_ptr==NULL)?NULL:&info_ptr);
		fclose(file);
		return false;
	}
    
    png_init_io(png_ptr, file);
    
	/* Set the image information here. Width and height are up to 2^31,
	 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
	 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
	 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
	 * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
	 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
	 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
	 */
	const int bit_depth = 8;
	png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGB,
		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
	
	/* Optional significant bit (sBIT) chunk */
	png_color_8 sig_bit;
	sig_bit.red = bit_depth;
	sig_bit.green = bit_depth;
	sig_bit.blue = bit_depth;
	sig_bit.alpha = 0; // no alpha channel
	png_set_sBIT(png_ptr, info_ptr, &sig_bit);

	// Write the file header information.
	png_write_info(png_ptr, info_ptr);
	
	if((png_uint_32)height > PNG_UINT_32_MAX/(sizeof(png_byte*)))
		png_error(png_ptr, "Image is too tall to process in memory");
	
	png_byte** row_ptrs = (png_byte**)malloc(height * sizeof(png_byte*));
	if(!row_ptrs)
		printf("malloc failed for row_ptrs.\n");
	else
	{
		const size_t line = sizeof(GLubyte) * width * 3; // RGB components
		GLubyte *data = (GLubyte*)malloc(line * height);

		if(data)
		{
			/* Make sure the rows are packed as tight as possible (no row padding),
			 * set the pack alignment to 1.
			 */
			glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
			glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);

			/* Set the individual row_ptrs to point at the correct offsets of image 
			 * data, note that it's upside down to keep consistent with the screen
			 * coordinate system.
			 */
			for(int row = 0; row < height; ++row)
				row_ptrs[row] = (png_byte*)data + line * row;

			png_write_image(png_ptr, row_ptrs);
			png_write_end(png_ptr, info_ptr);

			free(data);
		}
	}

	png_destroy_write_struct(&png_ptr, &info_ptr);
	fclose(file);
	free(row_ptrs);
	
	return(row_ptrs != NULL);
}
Ejemplo n.º 13
0
int /* PRIVATE */
pngx_read_pnm(png_structp png_ptr, png_infop info_ptr, FILE *stream)
{
   pnm_struct pnminfo;
   unsigned int format, depth, width, height, maxval;
   unsigned int max_width, num_samples, sample_size;
   unsigned int *pnmrow;
   size_t row_size;
   png_bytepp row_pointers;
   png_color_8 sig_bit;
   unsigned int i, j;
   int failed, overflow;

   /* Read the PNM header. */
   if (pnm_fget_header(&pnminfo, stream) != 1)
      return 0;  /* not PNM */
   format = pnminfo.format;
   depth = pnminfo.depth;
   width = pnminfo.width;
   height = pnminfo.height;
   maxval = pnminfo.maxval;
   if (format > PNM_P6)
      png_error(png_ptr, "Can't handle PNM formats newer than PPM (\"P6\")");
   max_width =
      (sizeof(size_t) <= sizeof(unsigned int)) ?
         UINT_MAX / sizeof(unsigned int) / depth : UINT_MAX;
#if UINT_MAX > PNGX_PNM_LENGTH_MAX
   if (max_width > PNGX_PNM_LENGTH_MAX)
      max_width = PNGX_PNM_LENGTH_MAX;
#endif
   if (width > max_width)
      png_error(png_ptr, "Can't handle exceedingly large PNM dimensions");
   sample_size = 1;
   row_size = num_samples = depth * width;
   if (maxval > 65535)
      png_error(png_ptr, "Can't handle PNM samples larger than 16 bits");
   else if (maxval > 255)
   {
      sample_size = 2;
      row_size *= 2;
   }

   /* Set the PNG image type. */
   png_set_IHDR(png_ptr, info_ptr,
      width, height,
      (maxval <= 255) ? 8 : 16,
      (depth == 1) ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_RGB,
      PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
   for (i = 1, j = 2; j - 1 < maxval; ++i, j <<= 1) { }
   if (j - 1 != maxval)
      png_warning(png_ptr,
         "Possibly inexact sample conversion from PNM to PNG");
   else if (i % 8 != 0 && (depth > 1 || 8 % i != 0))
   {
      sig_bit.red = sig_bit.green = sig_bit.blue = sig_bit.gray = (png_byte)i;
      sig_bit.alpha = 0;
      png_set_sBIT(png_ptr, info_ptr, &sig_bit);
   }

   /* Allocate memory. */
   row_pointers = pngx_malloc_rows(png_ptr, info_ptr, -1);
   if ((format >= PNM_P4) && (maxval == 255 || maxval == 65535))
      pnmrow = NULL;  /* can read raw data directly into row_pointers */
   else
      pnmrow = (unsigned int *)
         png_malloc(png_ptr, num_samples * sizeof(unsigned int));

   /* Read the image data. */
   failed = 0;
   overflow = 0;
   if (pnmrow != NULL)
   {
      for (i = 0; i < height; ++i)
      {
         if (pnm_fget_values(&pnminfo, pnmrow, 1, stream) <= 0)
            failed = 1;
         /* Transfer the samples, even on partial (unsuccessful) reads. */
         if (maxval <= 255)
         {
            for (j = 0; j < num_samples; ++j)
            {
               unsigned int val = pnmrow[j];
               if (val > maxval)
               {
                  val = 255;
                  overflow = 1;
               }
               else if (maxval != 255)
                  val = (val * 255 + maxval/2) / maxval;
               row_pointers[i][j] = (png_byte)val;
            }
         }
         else  /* maxval > 255 */
         {
            for (j = 0; j < num_samples; ++j)
            {
               png_uint_32 val = pnmrow[j];
               if (val > maxval)
               {
                  val = 65535;
                  overflow = 1;
               }
               else if (maxval != 65535)
                  val = (val * 65535 + maxval/2) / maxval;
               row_pointers[i][2 * j] = (png_byte)(val >> 8);
               row_pointers[i][2 * j + 1] = (png_byte)(val & 0xff);
            }
         }
         if (failed)
            break;
      }
   }
   else  /* read the raw data directly */
   {
      for (i = 0; i < height; ++i)
Ejemplo n.º 14
0
bool KPWriteImage::write2PNG(const QString& destPath)
{
    FILE* file = fopen(QFile::encodeName(destPath), "wb");
    if (!file)
    {
        kDebug( 51000 ) << "Failed to open PNG file for writing" << endl;
        return false;
    }

    uchar       *data       = 0;
    int          bitsDepth  = d->sixteenBit ? 16 : 8;
    png_color_8  sig_bit;
    png_bytep    row_ptr;
    png_structp  png_ptr    = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_infop    info_ptr   = png_create_info_struct(png_ptr);
    png_init_io(png_ptr, file);

    if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)      // Intel
        png_set_bgr(png_ptr);
    else                                                    // PPC
        png_set_swap_alpha(png_ptr);

    if (d->hasAlpha)
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB_ALPHA,  PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 8 * sizeof(uchar)];
        else
            data = new uchar[d->width * 4 * sizeof(uchar)];
    }
    else
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB,        PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 6 * sizeof(uchar)];
        else
            data = new uchar[d->width * 3 * sizeof(uchar)];
    }

    sig_bit.red   = bitsDepth;
    sig_bit.green = bitsDepth;
    sig_bit.blue  = bitsDepth;
    sig_bit.alpha = bitsDepth;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
    png_set_compression_level(png_ptr, 9);

    // Write ICC profil.
    if (!d->iccProfile.isEmpty())
    {
        png_set_iCCP(png_ptr, info_ptr, (png_charp)"icc", PNG_COMPRESSION_TYPE_BASE,
                     d->iccProfile.data(), d->iccProfile.size());
    }

    // Write Software info.
    QString libpngver(PNG_HEADER_VERSION_STRING);
    libpngver.replace('\n', ' ');
    QString soft = d->kipipluginsVer;
    soft.append(QString(" (%1)").arg(libpngver));
    png_text text;
    text.key  = (png_charp)"Software";
    text.text = soft.toAscii().data();
    text.compression = PNG_TEXT_COMPRESSION_zTXt;
    png_set_text(png_ptr, info_ptr, &(text), 1);

    // Store Exif data.
    QByteArray ba = d->metadata.getExif(true);
    writeRawProfile(png_ptr, info_ptr, (png_charp)"exif", ba.data(), (png_uint_32) ba.size());

    // Store Iptc data.
    QByteArray ba2 = d->metadata.getIptc();
    writeRawProfile(png_ptr, info_ptr, (png_charp)"iptc", ba2.data(), (png_uint_32) ba2.size());

    // Store Xmp data.
    QByteArray ba3 = d->metadata.getXmp();
    writeRawProfile(png_ptr, info_ptr, (png_charp)("xmp"), ba3.data(), (png_uint_32) ba3.size());

    png_write_info(png_ptr, info_ptr);
    png_set_shift(png_ptr, &sig_bit);
    png_set_packing(png_ptr);

    uchar* ptr = (uchar*)d->data.data();
    uint   x, y, j;

    for (y = 0; y < d->height; y++)
    {
        if (cancel())
        {
            delete [] data;
            fclose(file);
            png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
            png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
            return false;
        }

        j = 0;

        for (x = 0; x < d->width*bytesDepth(); x+=bytesDepth())
        {
            if (d->sixteenBit)
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                    data[j++] = ptr[x+7];  // Alpha
                    data[j++] = ptr[x+6];
                }
                else
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                }
            }
            else
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                    data[j++] = ptr[x+3];  // Alpha
                }
                else
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                }
            }
        }

        row_ptr = (png_bytep) data;

        png_write_rows(png_ptr, &row_ptr, 1);
        ptr += (d->width * bytesDepth());
    }

    delete [] data;

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
    png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
    fclose(file);

    return true;
}
Ejemplo n.º 15
0
int pngWrite( char *file_name, int width, int height, unsigned char *buffer )
{
	FILE *fp;
	png_structp png_ptr;
	png_infop info_ptr;
	//png_uint_32 width, height;
	int bit_depth, color_type, interlace_type;
	png_color_8 sig_bit;
	int i;
	int j;
	int k;
	int line;
	png_bytep *row_pointers;
	
	fp = fopen(file_name, "wb");
	png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING,NULL,NULL,NULL );
	if( png_ptr == NULL )
	{
		fclose(fp);
		return 0;
	}
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL)
	{
		fclose(fp);
		png_destroy_write_struct(&png_ptr, NULL);
		return 0;
	}

	if (setjmp(png_ptr->jmpbuf))
	{
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(fp);
		return 0;
	}
	
	png_init_io(png_ptr, fp);
	//width = 64;
	//height = 64;
	bit_depth = 8;
	color_type = PNG_COLOR_TYPE_RGB_ALPHA;
	
	png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGB_ALPHA,
      PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
		
	sig_bit.red = bit_depth;
	sig_bit.green = bit_depth;
	sig_bit.blue = bit_depth;
	sig_bit.alpha = bit_depth;
	png_set_sBIT(png_ptr, info_ptr, &sig_bit);
	
	png_write_info(png_ptr, info_ptr);
	png_set_packing(png_ptr);
	
	row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height);
	for (unsigned row = 0; row < height; row++)
	{
		if(color_type == PNG_COLOR_TYPE_RGB_ALPHA)
		{
			row_pointers[row] = (png_bytep)malloc(width * 4);
		}
		else
		{
  			row_pointers[row] = (png_bytep)malloc(width * 3);
		}
	}
	
	if ( row_pointers == NULL )
	{
		return 0;
	}
	
	k = 0;
	i = 0;
	while( i < height )
	{
		j = 0;
		while( j < width * 4 )
		{
			row_pointers[i][j+0] = buffer[k];
			k++;
			row_pointers[i][j+1] = buffer[k];
			k++;
			row_pointers[i][j+2] = buffer[k];
			k++;
			row_pointers[i][j+3] = buffer[k];
			k++;
			
			//row_pointers[i][j+3] = (int)((float)(row_pointers[i][j+0] + row_pointers[i][j+1] + row_pointers[i][j+2])/3.0);
			//row_pointers[i][j+3] = 255;
			j += 4;
		}
		i++;
	}
	
	png_write_image(png_ptr, row_pointers);
	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);
	fclose(fp);
	return 1;
}
Ejemplo n.º 16
0
Archivo: Image.cpp Proyecto: 9heart/DT3
bool Image::save (const std::string &s)
{
	// Open the file
	std::ofstream outfile;
	outfile.open(s.c_str(), std::ifstream::out | std::ifstream::binary);

	png_structp png_ptr;
	png_infop info_ptr;

	// Create and initialize the png_struct with the desired error handler
	// functions.  If you want to use the default stderr and longjump method,
	// you can supply NULL for the last three parameters.  We also check that
	// the library version is compatible with the one used at compile time,
	// in case we are using dynamically linked libraries.  REQUIRED.
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) {
		return false;
	}

	// Allocate/initialize the image information data. 
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		::png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		return false;
	}

	// Set error handling.  REQUIRED if you aren't supplying your own
	// error handling functions in the png_create_write_struct() call.
	if (setjmp(png_jmpbuf(png_ptr))) {
		// If we get here, we had a problem reading the file
		png_destroy_write_struct(&png_ptr, &info_ptr);
		return false;
	}

	// Set custom write routine
	png_set_write_fn(png_ptr, &outfile, &png_write_data, &png_flush_data);

	// Set the image information here.  Width and height are up to 2^31,
    // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
    // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
    // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
    // or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
    // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
    // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
	png_set_IHDR(png_ptr, info_ptr, _window_width, _window_height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	// We are dealing with a color image then
	png_color_8 sig_bit;
	sig_bit.red = 8;
	sig_bit.green = 8;
	sig_bit.blue = 8;
	sig_bit.alpha = 8;
	png_set_sBIT(png_ptr, info_ptr, &sig_bit);


	// Optional gamma chunk is strongly suggested if you have any guess
	// as to the correct gamma of the image.
	//
	png_set_gAMA(png_ptr, info_ptr, 0.0);

	// Write the file header information.
	png_write_info(png_ptr, info_ptr);

	// Shift the pixels up to a legal bit depth and fill in
	// as appropriate to correctly scale the image.
	png_set_shift(png_ptr, &sig_bit);

	// pack pixels into bytes
	png_set_packing(png_ptr);

	// swap location of alpha bytes from ARGB to RGBA
	//png_set_swap_alpha(png_ptr);

	// Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
	// RGB (4 channels -> 3 channels). The second parameter is not used.
	//png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);

	// flip BGR pixels to RGB 
	//png_set_bgr(png_ptr);

	// swap bytes of 16-bit files to most significant byte first
	//png_set_swap(png_ptr);

	// swap bits of 1, 2, 4 bit packed pixel formats
	//png_set_packswap(png_ptr);

	// The easiest way to write the image (you may have a different memory
	// layout, however, so choose what fits your needs best).  You need to
	// use the first method if you aren't handling interlacing yourself.

	// Setup row pointers
	png_bytep *row_pointers = new png_bytep[_window_height];

	for (png_uint_32 k = 0; k < _window_height; k++)
		row_pointers[k] = (png_bytep) &getPixel(0,k);

	png_write_image(png_ptr, row_pointers);
	
	delete row_pointers;

	// It is REQUIRED to call this to finish writing the rest of the file
	png_write_end(png_ptr, info_ptr);

	// Similarly, if you png_malloced any data that you passed in with
	// png_set_something(), such as a hist or trans array, free it here,
	// when you can be sure that libpng is through with it.
	png_free(png_ptr, NULL);

	// clean up after the write, and free any memory allocated
	png_destroy_write_struct(&png_ptr, &info_ptr);

	return false;
}
Ejemplo n.º 17
0
int main( int argc, char *argv[] ) {
	int f, rowbytes;
	char buf[256];
	static FILE *fpout;  /* "static" prevents setjmp corruption */
	png_structp write_ptr;
	png_infop write_info_ptr, end_info_ptr;
	png_bytep row_buf, here;
	png_uint_32 y;
	png_textp text_ptr, new_text_ptr;
	int num_text;

	int interlace_type, compression_type, filter_type, bit_depth, color_type;
	int it, ct, ft, bd, clrt;
	png_uint_32 width, height, w, h;

	int duration;

	if( argc < 4 ) {
		printf( "makeanim v0.2\nusage: makeanim <duration in milliseconds> <input files ...> <output file>\n" );
		printf( "example: makeanim 1500 a00.png a01.png a02.png a03.png a04.png a.anim\n" );
		return 1;
		}

	duration = atoi( argv[1] );
	if( duration < 1 ) {
		printf( "duration is incorrect\n" );
		return 1;
		}

	numfiles = argc - 3;
	input = (struct inputstruct *)malloc( sizeof( struct inputstruct ) * numfiles );
	if( !input ) return 1;

	for( f = 0; f < numfiles; f++ ) {
		input[f].name = argv[f + 2];
		printf( "opening file %d, \"%s\"\n", f, input[f].name );

		/* open the file handle */
		input[f].file = fopen( input[f].name, "rb" );
		if( input[f].file == NULL ) {
			printf( "fopen() failed\n" );
			return 1;
			}

		/* check if it's PNG */
		if( fread( buf, 1, 8, input[f].file ) != 8 ) {
			printf( "fread() failed for file \"%s\"\n", input[f].name );
			return 1;
			}
		if( png_sig_cmp( buf, (png_size_t)0, 8 ) ) {
			printf( "not a PNG file\n" );
			return 1;
			}
		fseek( input[f].file, 0, SEEK_SET );

		/* allocate read structure */
		input[f].read_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL );
		if( input[f].read_ptr == NULL ) {
			printf( "png_create_read_struct() failed\n" );
			return 1;
			}
		
		/* allocate read info structure */
		input[f].read_info_ptr = png_create_info_struct( input[f].read_ptr );
		if( input[f].read_info_ptr == NULL ) {
			printf( "png_create_info_struct() failed\n" );
			return 1;
			}


		/* set error handler code */
		if( setjmp( input[f].read_ptr->jmpbuf ) ) {
			printf( "libpng read error\n" );
			return 1;
			}

		/* initialize stream */
		png_init_io( input[f].read_ptr, input[f].file );
		png_set_read_status_fn( input[f].read_ptr, NULL );

		/* read png info struct */
		png_read_info( input[f].read_ptr, input[f].read_info_ptr );

		/* get the info */
		if( !png_get_IHDR( input[f].read_ptr, input[f].read_info_ptr, &w, &h, &bd, &clrt, &it, &ct, &ft ) ) {
			printf( "png_get_IHDR() failed\n" );
			return 1;
			}

		/* save the info of the first frame */
		if( f == 0 ) {
			width = w;
			height = h;
			bit_depth = bd;
			color_type = clrt;
			interlace_type = it;
			compression_type = ct;
			filter_type = ft;
			}
		/* compare all other frames to first frame */
		else if( (w != width) ||
				(h != height) ||
				(bd != bit_depth) ||
				(clrt != color_type) ||
				(it != interlace_type) ||
				(ct != compression_type) ||
				(ft != filter_type) ) {
			if( w != width ) printf( "width is different\n" );
			if( h != height ) printf( "height  is different\n" );
			if( bd != bit_depth ) printf( "bit depth is different\n" );
			if( clrt != color_type ) printf( "color type is different\n" );
			if( it != interlace_type ) printf( "interlace type is different\n" );
			if( ct != compression_type ) printf( "compression type is different\n" );
			if( ft != filter_type ) printf( "filter type is different\n" );
			return 1;
			}
		}
	
	row_buf = (png_bytep)NULL;
	
	/* open output file */
	printf( "opening file \"%s\"\n", argv[numfiles + 2] );
	fpout = fopen( argv[numfiles + 2], "wb" );
	if( fpout == NULL ) {
		printf( "fopen() failed\n" );
		return 1;
		}

	/* allocate write structure */
	write_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL );

	/* allocate info structures */
	write_info_ptr = png_create_info_struct( write_ptr );
	end_info_ptr = png_create_info_struct( write_ptr );

	/* error handling */
	if( setjmp( write_ptr->jmpbuf ) ) {
		printf( "libpng write error\n" );
		return 1;
		}

	/* initialize output stream */
	png_init_io( write_ptr, fpout );
	png_set_write_status_fn( write_ptr, NULL );

	/* set info */
	png_set_IHDR( write_ptr, write_info_ptr, width * numfiles, height, bit_depth, color_type, PNG_INTERLACE_NONE, compression_type, filter_type);

	/* image characteristics */
	{
		png_color_16p background;
		double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
		double gamma;
		int intent;
		png_uint_16p hist;
		png_uint_32 offset_x, offset_y;
		int unit_type;
		png_charp purpose, units;
		png_charpp params;
		png_int_32 X0, X1;
		int type, nparams;
		png_uint_32 res_x, res_y;
		png_colorp palette;
		int num_palette;
		png_color_8p sig_bit;
		png_bytep trans;
		int num_trans;
		png_color_16p trans_values;

		/* background color */
		if( png_get_bKGD( input[0].read_ptr, input[0].read_info_ptr, &background ) ) {
			png_set_bKGD( write_ptr, write_info_ptr, background );
			}

		if( png_get_cHRM( input[0].read_ptr, input[0].read_info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y ) ) {
			png_set_cHRM( write_ptr, write_info_ptr, white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y );
			}

		/* gamma */
		if( png_get_gAMA( input[0].read_ptr, input[0].read_info_ptr, &gamma ) ) {
			png_set_gAMA( write_ptr, write_info_ptr, gamma );
			}

		/* rendering intent */
		if( png_get_sRGB( input[0].read_ptr, input[0].read_info_ptr, &intent ) ) {
			png_set_sRGB( write_ptr, write_info_ptr, intent );
			}

		/* Histogram */
		if( png_get_hIST( input[0].read_ptr, input[0].read_info_ptr, &hist ) ) {
			png_set_hIST( write_ptr, write_info_ptr, hist );
			}

		/* offsets */
		if( png_get_oFFs( input[0].read_ptr, input[0].read_info_ptr, &offset_x, &offset_y, &unit_type ) ) {
			png_set_oFFs( write_ptr, write_info_ptr, offset_x, offset_y, unit_type );
			}

		if( png_get_pCAL( input[0].read_ptr, input[0].read_info_ptr, &purpose, &X0, &X1, &type, &nparams, &units, &params ) ) {
			png_set_pCAL( write_ptr, write_info_ptr, purpose, X0, X1, type, nparams, units, params );
			}

		/* pixel density */
		if( png_get_pHYs( input[0].read_ptr, input[0].read_info_ptr, &res_x, &res_y, &unit_type ) ) {
			png_set_pHYs( write_ptr, write_info_ptr, res_x, res_y, unit_type );
			}

		/* text chunks */
/*		if( png_get_text( input[0].read_ptr, input[0].read_info_ptr, &text_ptr, &num_text ) > 0 ) {
			printf( "Handling %d tEXt/zTXt chunks\n", num_text );
			png_set_text( write_ptr, write_info_ptr, text_ptr, num_text );
			}
*/
		/* palette */
		if( png_get_PLTE( input[0].read_ptr, input[0].read_info_ptr, &palette, &num_palette ) ) {
			png_set_PLTE( write_ptr, write_info_ptr, palette, num_palette );
			}

		/* significant bits */
		if( png_get_sBIT( input[0].read_ptr, input[0].read_info_ptr, &sig_bit ) ) {
			png_set_sBIT( write_ptr, write_info_ptr, sig_bit );
			}

		/* transparency */
		if( png_get_tRNS( input[0].read_ptr, input[0].read_info_ptr, &trans, &num_trans, &trans_values ) ) {
			png_set_tRNS( write_ptr, write_info_ptr, trans, num_trans, trans_values );
			}
		}

	/* text chunks */
	num_text = 0;
	if( !png_get_text( input[0].read_ptr, input[0].read_info_ptr, &text_ptr, &num_text ) ) num_text = 0;
	new_text_ptr = (struct png_text_struct *)malloc( sizeof( struct png_text_struct ) * num_text + 1 );
	if( !new_text_ptr ) {
		printf( "malloc() failed\n" );
		return 1;
		}
	
	memcpy( new_text_ptr, text_ptr, sizeof( struct png_text_struct ) * num_text );

	snprintf( buf, 255, "SDL_anim %d %d %d", duration, width, numfiles );
	buf[255] = 0;
	new_text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
	new_text_ptr[num_text].key = "format";
	new_text_ptr[num_text].text = buf;
	new_text_ptr[num_text].text_length = strlen( buf );
	num_text++;
	png_set_text( write_ptr, write_info_ptr, new_text_ptr, num_text );

	/* write info */
	png_write_info( write_ptr, write_info_ptr );

	/* allocate buffer */
	rowbytes = png_get_rowbytes( input[0].read_ptr, input[0].read_info_ptr );
	row_buf = (png_bytep)png_malloc( write_ptr, rowbytes * numfiles );
	if( row_buf == NULL ) {
		printf( "png_malloc() failed\n" );
		return 1;
		}

	/* copy raw data */
	for( y = 0; y < height; y++ ) {
		/* grab a scanline from each file */
		here = row_buf;
		for( f = 0; f < numfiles; f++ ) {
			png_read_rows( input[f].read_ptr, (png_bytepp)&here, (png_bytepp)NULL, 1 );
			here += rowbytes;
			}
		/* write the long scanline */
		png_write_rows( write_ptr, (png_bytepp)&row_buf, 1 );
		}

	/* end io */
	for( f = 0; f < numfiles; f++ ) png_read_end( input[f].read_ptr, end_info_ptr );
	png_write_end( write_ptr, end_info_ptr );

	/* cleanup */
	png_free( write_ptr, row_buf );
	for( f = 0; f < numfiles; f++ ) {
		png_destroy_read_struct( &input[f].read_ptr, &input[f].read_info_ptr, &end_info_ptr);
		fclose( input[f].file );
		}
	png_destroy_write_struct( &write_ptr, &write_info_ptr );
	fclose( fpout );

	return 0;
	}
Ejemplo n.º 18
0
Py::Object 
Image::write_png(const Py::Tuple& args)
{
  //small memory leak in this function - JDH 2004-06-08
  _VERBOSE("Image::write_png");
  
  args.verify_length(1);
  
  std::string fileName = Py::String(args[0]);
  const char *file_name = fileName.c_str();
  FILE *fp;
  png_structp png_ptr;
  png_infop info_ptr;
  struct        png_color_8_struct sig_bit;
  png_uint_32 row;
  
  //todo: allocate on heap
  png_bytep row_pointers[rowsOut];
  for (row = 0; row < rowsOut; ++row) {
    row_pointers[row] = bufferOut + row * colsOut * 4;
  }
  
  fp = fopen(file_name, "wb");
  if (fp == NULL) 
    throw Py::RuntimeError(Printf("Could not open file %s", file_name).str());
  
  
  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL) {
    fclose(fp);
    throw Py::RuntimeError("Could not create write struct");
  }
  
  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL) {
    fclose(fp);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    throw Py::RuntimeError("Could not create info struct");
  }
  
  if (setjmp(png_ptr->jmpbuf)) {
    fclose(fp);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    throw Py::RuntimeError("Error building image");
  }
  
  png_init_io(png_ptr, fp);
  png_set_IHDR(png_ptr, info_ptr,
	       colsOut, rowsOut, 8,
	       PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
	       PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
  
  // this a a color image!
  sig_bit.gray = 0;
  sig_bit.red = 8;
  sig_bit.green = 8;
  sig_bit.blue = 8;
  /* if the image has an alpha channel then */
  sig_bit.alpha = 8;
  png_set_sBIT(png_ptr, info_ptr, &sig_bit);
  
  png_write_info(png_ptr, info_ptr);
  png_write_image(png_ptr, row_pointers);
  png_write_end(png_ptr, info_ptr);
  png_destroy_write_struct(&png_ptr, &info_ptr);
  fclose(fp);
  
  return Py::Object();
}
bool PNGImageFileType::write(const Image        *OSG_PNG_ARG(pImage  ), 
                                   std::ostream &OSG_PNG_ARG(os      ),
                             const std::string  &OSG_PNG_ARG(mimetype))
{
#ifdef OSG_WITH_PNG

    png_structp png_ptr;
    png_infop info_ptr;

    if(pImage->getDimension() < 1 || pImage->getDimension() > 2)
    {
        FWARNING(("PNGImageFileType::write: invalid dimension %d!\n",
                  pImage->getDimension()));

        return false;
    }
    
    /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also check that
    * the library version is compatible with the one used at compile time,
    * in case we are using dynamically linked libraries.  REQUIRED.
     */
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                      0, &errorOutput, &warningOutput);

    if(png_ptr == NULL)
        return false;

    /* Allocate/initialize the image information data.  REQUIRED */
    info_ptr = png_create_info_struct(png_ptr);

    if(info_ptr == NULL)
    {
        png_destroy_write_struct(&png_ptr,  NULL);
        return false;
    }
    
    /* set up the output handlers */
    png_set_write_fn(png_ptr, &os, &osWriteFunc, &osFlushFunc);

    /* This is the hard way */

    /* Set the image information here.  Width and height are up to 2^31,
    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
    */

    Int32 ctype;
    switch(pImage->getPixelFormat())
    {
        case Image::OSG_L_PF:       
            ctype = PNG_COLOR_TYPE_GRAY;        
            break;
            
        case Image::OSG_LA_PF:      
            ctype = PNG_COLOR_TYPE_GRAY_ALPHA;          
            break;
            
#if defined(GL_BGR) || defined(GL_BGR_EXT)
        case Image::OSG_BGR_PF:
#endif
        case Image::OSG_RGB_PF:     
            ctype = PNG_COLOR_TYPE_RGB;                 
            break;
            
#if defined(GL_BGRA) || defined(GL_BGRA_EXT)
        case Image::OSG_BGRA_PF:
#endif
        case Image::OSG_RGBA_PF:    
            ctype = PNG_COLOR_TYPE_RGB_ALPHA;           
            break;
            
        default:
            FWARNING(("PNGImageFileType::write: unknown pixel format %d!\n",
                      pImage->getPixelFormat()));
            png_destroy_write_struct(&png_ptr,  NULL);
            return false;
            
    }
    
    Int32 bit_depth;
    switch(pImage->getDataType()) 
    {
        case Image::OSG_UINT8_IMAGEDATA:
            bit_depth = 8;
            break;
        case Image::OSG_UINT16_IMAGEDATA:
            bit_depth = 16;
            break;
        default:
            FWARNING (("Invalid pixeldepth, cannot store data\n"));
            return false;
    };

    png_set_IHDR(png_ptr, info_ptr, pImage->getWidth(), pImage->getHeight(),
                 bit_depth,ctype,      
                 PNG_INTERLACE_NONE, 
                 PNG_COMPRESSION_TYPE_BASE, 
                 PNG_FILTER_TYPE_BASE);

    // set resolution png supports only meter per pixel,
    // so we do a conversion from dpi with some rounding.
    png_uint_32 res_x = png_uint_32(pImage->getResX());
    png_uint_32 res_y = png_uint_32(pImage->getResY());
    if(pImage->getResUnit() == Image::OSG_RESUNIT_INCH)
    {
        res_x = png_uint_32((pImage->getResX() * 39.37007874f) < 0.0f ?
                            (pImage->getResX() * 39.37007874f) - 0.5f :
                            (pImage->getResX() * 39.37007874f) + 0.5f);
        res_y = png_uint_32((pImage->getResY() * 39.37007874f) < 0.0f ?
                            (pImage->getResY() * 39.37007874f) - 0.5f :
                            (pImage->getResY() * 39.37007874f) + 0.5f);
    }

    png_set_pHYs(png_ptr, info_ptr, res_x, res_y,
                 PNG_RESOLUTION_METER);

#if 0
    /* optional significant bit chunk */
    /* if we are dealing with a grayscale image then */
    sig_bit.gray = true_bit_depth;
    /* otherwise, if we are dealing with a color image then */
    sig_bit.red = true_red_bit_depth;
    sig_bit.green = true_green_bit_depth;
    sig_bit.blue = true_blue_bit_depth;
    /* if the image has an alpha channel then */
    sig_bit.alpha = true_alpha_bit_depth;
    png_set_sBIT(png_ptr, info_ptr, sig_bit);


    /* Optional gamma chunk is strongly suggested if you have any guess
    * as to the correct gamma of the image.
    */
    png_set_gAMA(png_ptr, info_ptr, gamma);

    /* Optionally write comments into the image */
    text_ptr[0].key = "Title";
    text_ptr[0].text = "Mona Lisa";
    text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
    text_ptr[1].key = "Author";
    text_ptr[1].text = "Leonardo DaVinci";
    text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
    text_ptr[2].key = "Description";
    text_ptr[2].text = "<long text>";
    text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
#ifdef PNG_iTXt_SUPPORTED
    text_ptr[0].lang = NULL;
    text_ptr[1].lang = NULL;
    text_ptr[2].lang = NULL;
#endif
    png_set_text(png_ptr, info_ptr, text_ptr, 3);
#endif
    /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
    /* note that if sRGB is present the gAMA and cHRM chunks must be ignored
    * on read and must be written in accordance with the sRGB profile */

    /* Write the file header information.  REQUIRED */
    png_write_info(png_ptr, info_ptr);

#if BYTE_ORDER == LITTLE_ENDIAN
    if (bit_depth == 16) 
      png_set_swap(png_ptr);
#endif

#if 0
    /* invert monochrome pixels */
    png_set_invert_mono(png_ptr);

    /* Shift the pixels up to a legal bit depth and fill in
    * as appropriate to correctly scale the image.
    */
    png_set_shift(png_ptr, &sig_bit);

    /* pack pixels into bytes */
    png_set_packing(png_ptr);

    /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
    * RGB (4 channels -> 3 channels). The second parameter is not used.
    */
    png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);

    /* swap bytes of 16-bit files to most significant byte first */
    png_set_swap(png_ptr);

    /* swap bits of 1, 2, 4 bit packed pixel formats */
    png_set_packswap(png_ptr);
#endif

    if(pImage->getPixelFormat() == Image::OSG_BGR_PF ||
       pImage->getPixelFormat() == Image::OSG_BGRA_PF )
    {
        /* flip BGR pixels to RGB */
        png_set_bgr(png_ptr);
        
        /* swap location of alpha bytes from ARGB to RGBA */
        png_set_swap_alpha(png_ptr);
    }
    
    /* The easiest way to write the image (you may have a different memory
     * layout, however, so choose what fits your needs best).  You need to
     * use the first method if you aren't handling interlacing yourself.
     */
    png_bytep *row_pointers = new png_bytep [pImage->getHeight()];
    
    for(Int32 k = 0; k < pImage->getHeight(); k++)
    {
        row_pointers[k] = 
            (const_cast<UInt8 *>(pImage->getData())) + 
            (pImage->getHeight() - 1 - k) * 
            pImage->getWidth() * pImage->getBpp();
    }
    
    /* write out the entire image data in one call */
    png_write_image(png_ptr, row_pointers);

    /* It is REQUIRED to call this to finish writing the rest of the file */
    png_write_end(png_ptr, info_ptr);
    
    /* clean up after the write, and free any memory allocated */
    png_destroy_write_struct(&png_ptr, &info_ptr);

    delete [] row_pointers;

    /* that's it */
    return true;

#else
    SWARNING << getMimeType() 
             << " write is not compiled into the current binary " 
             << endLog;

    return false;
#endif
}
Ejemplo n.º 20
0
//--------------------------------------------------------------------------
static bool _writePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel, U32 strategy, U32 filter)
{
   GFXFormat   format = bitmap->getFormat();

   // ONLY RGB bitmap writing supported at this time!
   AssertFatal(   format == GFXFormatR8G8B8 || 
                  format == GFXFormatR8G8B8A8 || 
                  format == GFXFormatR8G8B8X8 || 
                  format == GFXFormatA8 ||
                  format == GFXFormatR5G6B5, "_writePNG: ONLY RGB bitmap writing supported at this time.");

   if (  format != GFXFormatR8G8B8 && 
         format != GFXFormatR8G8B8A8 && 
         format != GFXFormatR8G8B8X8 && 
         format != GFXFormatA8 &&
         format != GFXFormatR5G6B5 )
      return false;

   png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
      NULL,
      pngFatalErrorFn,
      pngWarningFn,
      NULL,
      pngMallocFn,
      pngFreeFn);
   if (png_ptr == NULL)
      return (false);

   png_infop info_ptr = png_create_info_struct(png_ptr);
   if (info_ptr == NULL)
   {
      png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
      return false;
   }

   png_set_write_fn(png_ptr, &stream, pngWriteDataFn, pngFlushDataFn);

   // Set the compression level and image filters
   png_set_compression_window_bits(png_ptr, 15);
   png_set_compression_level(png_ptr, compressionLevel);
   png_set_filter(png_ptr, 0, filter);

   // Set the image information here.  Width and height are up to 2^31,
   // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
   // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
   // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
   // or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
   // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
   // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED

   U32   width = bitmap->getWidth();
   U32   height = bitmap->getHeight();

   if (format == GFXFormatR8G8B8)
   {
      png_set_IHDR(png_ptr, info_ptr,
         width, height,               // the width & height
         8, PNG_COLOR_TYPE_RGB,       // bit_depth, color_type,
         NULL,                        // no interlace
         NULL,                        // compression type
         NULL);                       // filter type
   }
   else if (format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8)
   {
      png_set_IHDR(png_ptr, info_ptr,
         width, height,               // the width & height
         8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type,
         NULL,                        // no interlace
         NULL,                        // compression type
         NULL);                       // filter type
   }
   else if (format == GFXFormatA8)
   {
      png_set_IHDR(png_ptr, info_ptr,
         width, height,               // the width & height
         8, PNG_COLOR_TYPE_GRAY,      // bit_depth, color_type,
         NULL,                        // no interlace
         NULL,                        // compression type
         NULL);                       // filter type
   }
   else if (format == GFXFormatR5G6B5) 
   {
      png_set_IHDR(png_ptr, info_ptr,
         width, height,               // the width & height
         16, PNG_COLOR_TYPE_GRAY,     // bit_depth, color_type,
         PNG_INTERLACE_NONE,          // no interlace
         PNG_COMPRESSION_TYPE_DEFAULT,   // compression type
         PNG_FILTER_TYPE_DEFAULT);       // filter type
      
      png_color_8_struct sigBit = { 0 };
      sigBit.gray = 16;
      png_set_sBIT(png_ptr, info_ptr, &sigBit );

      png_set_swap( png_ptr );
   }

   png_write_info(png_ptr, info_ptr);
   FrameAllocatorMarker marker;
   png_bytep* row_pointers = (png_bytep*)marker.alloc( height * sizeof( png_bytep ) );
   for (U32 i=0; i<height; i++)
      row_pointers[i] = const_cast<png_bytep>(bitmap->getAddress(0, i));

   png_write_image(png_ptr, row_pointers);

   // Write S3TC data if present...
   // Write FXT1 data if present...

   png_write_end(png_ptr, info_ptr);
   png_destroy_write_struct(&png_ptr, (png_infopp)NULL);

   return true;
}
Ejemplo n.º 21
0
bool8 S9xDoScreenshot(int width, int height){
#ifdef HAVE_LIBPNG
    FILE *fp;
    png_structp png_ptr;
    png_infop info_ptr;
    png_color_8 sig_bit;
    png_color pngpal[256];
    int imgwidth;
    int imgheight;
    const char *fname=S9xGetFilename( FILE_SCREENSHOT );
    
#if 0
    Settings.TakeScreenshot=FALSE;
#endif

    if((fp=fopen(fname, "wb"))==NULL){
        perror("Screenshot failed");
        return FALSE;
    }

    png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(!png_ptr){
        fclose(fp);
        unlink(fname);
        return FALSE;
    }
    info_ptr=png_create_info_struct(png_ptr);
    if(!info_ptr){
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        fclose(fp);
        unlink(fname);
        return FALSE;
    }

    if(setjmp(png_jmpbuf(png_ptr))){
        perror("Screenshot: setjmp");
        png_destroy_write_struct(&png_ptr, &info_ptr);
        fclose(fp);
        unlink(fname);
        return FALSE;
    }

    imgwidth=width;
    imgheight=height;
#if 0
    if(Settings.StretchScreenshots==1){
        if(width<=256 && height>SNES_HEIGHT_EXTENDED) imgwidth=width<<1;
        if(width>256 && height<=SNES_HEIGHT_EXTENDED) imgheight=height<<1;
    } else if(Settings.StretchScreenshots==2){
#endif
        if(width<=256) imgwidth=width<<1;
        if(height<=SNES_HEIGHT_EXTENDED) imgheight=height<<1;
#if 0
    }
#endif
    
    png_init_io(png_ptr, fp);
    png_set_IHDR(png_ptr, info_ptr, imgwidth, imgheight, 8, 
                 (PNG_COLOR_TYPE_RGB),
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);

    /* 5 bits per color */
    sig_bit.red=5;
    sig_bit.green=5;
    sig_bit.blue=5;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
    png_set_shift(png_ptr, &sig_bit);

    png_write_info(png_ptr, info_ptr);
    
    png_set_packing(png_ptr);

    png_byte *row_pointer=new png_byte [png_get_rowbytes(png_ptr, info_ptr)];
    uint8 *screen=GFX.Screen;
    for(int y=0; y<height; y++, screen+=GFX.Pitch){
        png_byte *rowpix = row_pointer;
        for(int x=0; x<width; x++){
                uint32 r, g, b;
                DECOMPOSE_PIXEL((*(uint16 *)(screen+2*x)), r, g, b);
                *(rowpix++) = r;
                *(rowpix++) = g;
                *(rowpix++) = b;
                if(imgwidth!=width){
                    *(rowpix++) = r;
                    *(rowpix++) = g;
                    *(rowpix++) = b;
                }
        }
        png_write_row(png_ptr, row_pointer);
        if(imgheight!=height)
            png_write_row(png_ptr, row_pointer);
    }

    delete [] row_pointer;
        
    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, &info_ptr);

    fclose(fp);
    fprintf(stderr, "%s saved.\n", fname);
    return TRUE;
#else
    perror("Screenshot support not available (libpng was not found at build time)");
	return FALSE;
#endif
}
Ejemplo n.º 22
0
bool DeferredPNGWriter::begin( GFXFormat format, S32 width, S32 height, Stream &stream, U32 compressionLevel )
{   
   // ONLY RGB bitmap writing supported at this time!
   AssertFatal(   format == GFXFormatR8G8B8 || 
                  format == GFXFormatR8G8B8A8 || 
                  format == GFXFormatR8G8B8X8 || 
                  format == GFXFormatA8 ||
                  format == GFXFormatR5G6B5, "_writePNG: ONLY RGB bitmap writing supported at this time.");

   if (  format != GFXFormatR8G8B8 && 
         format != GFXFormatR8G8B8A8 && 
         format != GFXFormatR8G8B8X8 && 
         format != GFXFormatA8 &&
         format != GFXFormatR5G6B5 )
      return false;

   mData->png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
      NULL,
      pngFatalErrorFn,
      pngWarningFn,
      NULL,
      pngRealMallocFn,
      pngRealFreeFn);
   if (mData->png_ptr == NULL)
      return (false);

   mData->info_ptr = png_create_info_struct(mData->png_ptr);
   if (mData->info_ptr == NULL)
   {
      png_destroy_write_struct(&mData->png_ptr, (png_infopp)NULL);
      return false;
   }

   png_set_write_fn(mData->png_ptr, &stream, pngWriteDataFn, pngFlushDataFn);

   // Set the compression level and image filters
   png_set_compression_window_bits(mData->png_ptr, 15);
   png_set_compression_level(mData->png_ptr, compressionLevel);
   png_set_filter(mData->png_ptr, 0, PNG_ALL_FILTERS);

   // Set the image information here.  Width and height are up to 2^31,
   // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
   // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
   // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
   // or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
   // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
   // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
   
   if (format == GFXFormatR8G8B8)
   {
      png_set_IHDR(mData->png_ptr, mData->info_ptr,
         width, height,               // the width & height
         8, PNG_COLOR_TYPE_RGB,       // bit_depth, color_type,
         NULL,                        // no interlace
         NULL,                        // compression type
         NULL);                       // filter type
   }
   else if (format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8)
   {
      png_set_IHDR(mData->png_ptr, mData->info_ptr,
         width, height,               // the width & height
         8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type,
         NULL,                        // no interlace
         NULL,                        // compression type
         NULL);                       // filter type
   }
   else if (format == GFXFormatA8)
   {
      png_set_IHDR(mData->png_ptr, mData->info_ptr,
         width, height,               // the width & height
         8, PNG_COLOR_TYPE_GRAY,      // bit_depth, color_type,
         NULL,                        // no interlace
         NULL,                        // compression type
         NULL);                       // filter type
   }
   else if (format == GFXFormatR5G6B5) 
   {
      png_set_IHDR(mData->png_ptr, mData->info_ptr,
         width, height,               // the width & height
         16, PNG_COLOR_TYPE_GRAY,     // bit_depth, color_type,
         PNG_INTERLACE_NONE,          // no interlace
         PNG_COMPRESSION_TYPE_DEFAULT,   // compression type
         PNG_FILTER_TYPE_DEFAULT);       // filter type
      
      png_color_8_struct sigBit = { 0 };
      sigBit.gray = 16;
      png_set_sBIT(mData->png_ptr, mData->info_ptr, &sigBit );

      png_set_swap( mData->png_ptr );
   }

   png_write_info(mData->png_ptr, mData->info_ptr);
   
   mActive = true;

   return true;
}
Ejemplo n.º 23
0
/*
 * write audio block to png file
*/
void frame_loop(size_t frame, char* output_dir, SNDFILE* audio_file, s_dimension d) {

    size_t x, y;
    size_t area = d.width * d.height;
    size_t wsec = ceil(d.width / d.channels);
    sf_count_t req, cnt;
    sf_count_t copy_frames = ceil(area / d.channels);
    png_uint_32 i;
    png_infop info_ptr;
    png_structp png_ptr;
    png_color_8 sig_bit;
    png_byte  pixelbuffer[d.height][d.width * BYTES_PER_PIXEL];
    png_bytep row_pointers[d.height];
    short int audiobuffer[d.channels * area];

    char file_name[11 + strlen(output_dir)];

    // open file for writing
    set_filename(file_name, output_dir, frame);
    FILE *fp = fopen(file_name, "wb");
    if (!fp) {
        exit(ERROR);
    }
    printf("%s\n", file_name);

    // clear pixelbuffer
    memset(&pixelbuffer, 0, area * BYTES_PER_PIXEL);
    // assign row pointers
    for (i = 0; i < d.height; i++) {
        row_pointers[i] = &(pixelbuffer[i][0]);
    }

    req = (size_t)sf_seek(audio_file, d.audio_frames * frame, SEEK_SET);
    if(req == -1) {
        puts("[!] audiofile seek error");
        // skip frame
        return;
    }
    cnt = sf_readf_short(audio_file, audiobuffer, copy_frames);

    // copy block
    for(x=0; x<cnt; x++) {
        //pixelbuffer[ (int) floor(x / width) ][x % width] = (char) audiobuffer[x * channels];
        for(y=0; y<d.channels; y++) {
            size_t ix = min(floor(x / wsec), d.height-1);
            size_t iy = x % wsec + y * wsec;
            pixelbuffer[ix][iy] = abs((audiobuffer[x * d.channels + y]) / 128);
            //printf("%lu ", (audiobuffer[x * channels + y] + sizeof(short int)) / 2);
            //printf("%i ", abs((audiobuffer[x * channels + y]) / 128));
        }
        //printf("\n");
    }


    // generate png from pixelbuffer
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    if (!png_ptr) {
        fclose(fp);
        exit(ERROR);
    }

    info_ptr = png_create_info_struct(png_ptr);

    if (!info_ptr) {
        png_destroy_write_struct(&png_ptr, NULL);
        fclose(fp);
        exit(ERROR);
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        puts("png error");
        png_destroy_write_struct(&png_ptr, &info_ptr);
        fclose(fp);
        exit(ERROR);
    }

    // write png
    png_init_io(png_ptr, fp);
    png_set_IHDR(png_ptr,
                 info_ptr,
                 d.width,
                 d.height,
                 d.bit_depth,
                 PNG_COLOR_TYPE_GRAY,
                 PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);
    sig_bit.gray = d.bit_depth;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

    png_write_info(png_ptr, info_ptr);
    png_write_image(png_ptr, row_pointers);
    png_write_end(png_ptr, info_ptr);

    png_destroy_write_struct(&png_ptr, &info_ptr);
    fclose(fp);
}
Ejemplo n.º 24
0
RADRT_API bool RADRT_CALL Encode(const Image &in, const Mipmap &mip, bool interlaced, void *&outData, AddrSize &outSize)
{
	RAD_ASSERT(in.format == Format_A8 || in.format == Format_RGB888 || in.format == Format_RGBA8888);

	if (in.format != Format_A8 &&
		in.format != Format_RGB888 &&
		in.format != Format_RGBA8888) return false;

	png_structp png;
	png_infop   info;

	png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, 0, PNGErrorHandler, PNGWarningHandler, 0,
		PNGMalloc, PNGFree);

	if (!png) return false;

	info = png_create_info_struct(png);

	if (!info)
	{
		png_destroy_write_struct(&png, 0);
		return false;
	}

	stream::DynamicMemOutputBuffer ob(ZImageCodec);
	stream::OutputStream os(ob);

	png_set_write_fn(png, &os, PNGWrite, PNGFlush);
	png_set_IHDR(png, info, mip.width, mip.height, 8,
		(in.format == Format_A8) ? PNG_COLOR_TYPE_GRAY :
		(in.format == Format_RGB888) ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
		interlaced ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	png_color_8 sig;
	memset(&sig, 0, sizeof(sig));
	
	if (in.format == Format_A8)
	{
		sig.gray = 8;
	}
	else
	{
		sig.red = 8;
		sig.green = 8;
		sig.blue = 8;
		sig.alpha = (in.format == Format_RGBA8888) ? 8 : 0;
	}

	png_set_sBIT(png, info, &sig);

	try
	{
		png_write_info(png, info);
	}
	catch (PNGException&)
	{
		png_destroy_write_struct(&png, &info);
		return false;
	}

	png_set_shift(png, &sig);

	int passes = 1;

	if (interlaced)
	{
		passes = png_set_interlace_handling(png);
	}

	for (int pass = 0; pass < passes; ++pass)
	{
		png_bytep src = (png_bytep)mip.data;

		for (int y = 0; y < mip.height; ++y)
		{
			png_write_rows(png, (png_bytepp)&src, 1);
			src += mip.stride;
		}
	}

	png_write_end(png, info);
	png_destroy_write_struct(&png, &info);

	outData = ob.OutputBuffer().Ptr();
	outSize = ob.OutputBuffer().Size();
	ob.OutputBuffer().Set(0, 0); // don't let the output buffer release the memory.

	return true;

}
Ejemplo n.º 25
0
bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
{
    wxPNGInfoStruct wxinfo;

    wxinfo.verbose = verbose;
    wxinfo.stream.out = &stream;

    png_structp png_ptr = png_create_write_struct
                          (
                            PNG_LIBPNG_VER_STRING,
                            NULL,
                            wx_PNG_error,
                            wx_PNG_warning
                          );
    if (!png_ptr)
    {
        if (verbose)
        {
           wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL)
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
           wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    if (setjmp(wxinfo.jmpbuf))
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
           wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    // NB: please see the comment near wxPNGInfoStruct declaration for
    //     explanation why this line is mandatory
    png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL);

    const int iHeight = image->GetHeight();
    const int iWidth = image->GetWidth();

    const bool bHasPngFormatOption
        = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT);

    int iColorType = bHasPngFormatOption
                            ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT)
                            : wxPNG_TYPE_COLOUR;

    bool bHasAlpha = image->HasAlpha();
    bool bHasMask = image->HasMask();

    bool bUsePalette = iColorType == wxPNG_TYPE_PALETTE
#if wxUSE_PALETTE
        || (!bHasPngFormatOption && image->HasPalette() )
#endif
    ;

    png_color_8 mask = { 0, 0, 0, 0, 0 };

    if (bHasMask)
    {
        mask.red   = image->GetMaskRed();
        mask.green = image->GetMaskGreen();
        mask.blue  = image->GetMaskBlue();
    }

    PaletteMap palette;

    if (bUsePalette)
    {
        png_color png_rgb  [PNG_MAX_PALETTE_LENGTH];
        png_byte  png_trans[PNG_MAX_PALETTE_LENGTH];

        const unsigned char *pColors = image->GetData();
        const unsigned char* pAlpha  = image->GetAlpha();

        if (bHasMask && !pAlpha)
        {
            // Mask must be first
            PaletteAdd(&palette, mask);
        }

        for (int y = 0; y < iHeight; y++)
        {
            for (int x = 0; x < iWidth; x++)
            {
                png_color_8 rgba;

                rgba.red   = *pColors++;
                rgba.green = *pColors++;
                rgba.blue  = *pColors++;
                rgba.gray  = 0;
                rgba.alpha = (pAlpha && !bHasMask) ? *pAlpha++ : 0;

                // save in our palette
                long index = PaletteAdd(&palette, rgba);

                if (index < PNG_MAX_PALETTE_LENGTH)
                {
                    // save in libpng's palette
                    png_rgb[index].red   = rgba.red;
                    png_rgb[index].green = rgba.green;
                    png_rgb[index].blue  = rgba.blue;
                    png_trans[index]     = rgba.alpha;
                }
                else
                {
                    bUsePalette = false;
                    break;
                }
            }
        }

        if (bUsePalette)
        {
            png_set_PLTE(png_ptr, info_ptr, png_rgb, palette.size());

            if (bHasMask && !pAlpha)
            {
                wxASSERT(PaletteFind(palette, mask) == 0);
                png_trans[0] = 0;
                png_set_tRNS(png_ptr, info_ptr, png_trans, 1, NULL);
            }
            else if (pAlpha && !bHasMask)
            {
                png_set_tRNS(png_ptr, info_ptr, png_trans, palette.size(), NULL);
            }
        }
    }

    /*
    If saving palettised was requested but it was decided we can't use a
    palette then reset the colour type to RGB.
    */
    if (!bUsePalette && iColorType == wxPNG_TYPE_PALETTE)
    {
        iColorType = wxPNG_TYPE_COLOUR;
    }

    bool bUseAlpha = !bUsePalette && (bHasAlpha || bHasMask);

    int iPngColorType;

    if (bUsePalette)
    {
        iPngColorType = PNG_COLOR_TYPE_PALETTE;
        iColorType = wxPNG_TYPE_PALETTE;
    }
    else if ( iColorType==wxPNG_TYPE_COLOUR )
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA
                                  : PNG_COLOR_TYPE_RGB;
    }
    else
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA
                                  : PNG_COLOR_TYPE_GRAY;
    }

    if (image->HasOption(wxIMAGE_OPTION_PNG_FILTER))
        png_set_filter( png_ptr, PNG_FILTER_TYPE_BASE, image->GetOptionInt(wxIMAGE_OPTION_PNG_FILTER) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL))
        png_set_compression_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL))
        png_set_compression_mem_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY))
        png_set_compression_strategy( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE))
        png_set_compression_buffer_size( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE) );

    int iBitDepth = !bUsePalette && image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH)
                            ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH)
                            : 8;

    png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(),
                  iBitDepth, iPngColorType,
                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                  PNG_FILTER_TYPE_BASE);

    int iElements;
    png_color_8 sig_bit;

    if ( iPngColorType & PNG_COLOR_MASK_COLOR )
    {
        sig_bit.red =
        sig_bit.green =
        sig_bit.blue = (png_byte)iBitDepth;
        iElements = 3;
    }
    else // grey
    {
        sig_bit.gray = (png_byte)iBitDepth;
        iElements = 1;
    }

    if ( bUseAlpha )
    {
        sig_bit.alpha = (png_byte)iBitDepth;
        iElements++;
    }

    if ( iBitDepth == 16 )
        iElements *= 2;

    // save the image resolution if we have it
    int resX, resY;
    switch ( GetResolutionFromOptions(*image, &resX, &resY) )
    {
        case wxIMAGE_RESOLUTION_INCHES:
            {
                const double INCHES_IN_METER = 10000.0 / 254;
                resX = int(resX * INCHES_IN_METER);
                resY = int(resY * INCHES_IN_METER);
            }
            break;

        case wxIMAGE_RESOLUTION_CM:
            resX *= 100;
            resY *= 100;
            break;

        case wxIMAGE_RESOLUTION_NONE:
            break;

        default:
            wxFAIL_MSG( wxT("unsupported image resolution units") );
    }

    if ( resX && resY )
        png_set_pHYs( png_ptr, info_ptr, resX, resY, PNG_RESOLUTION_METER );

    png_set_sBIT( png_ptr, info_ptr, &sig_bit );
    png_write_info( png_ptr, info_ptr );
    png_set_shift( png_ptr, &sig_bit );
    png_set_packing( png_ptr );

    unsigned char *
        data = (unsigned char *)malloc( image->GetWidth() * iElements );
    if ( !data )
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        return false;
    }

    const unsigned char *
        pAlpha = (const unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL);

    const unsigned char *pColors = image->GetData();

    for (int y = 0; y != iHeight; ++y)
    {
        unsigned char *pData = data;
        for (int x = 0; x != iWidth; x++)
        {
            png_color_8 clr;
            clr.red   = *pColors++;
            clr.green = *pColors++;
            clr.blue  = *pColors++;
            clr.gray  = 0;
            clr.alpha = (bUsePalette && pAlpha) ? *pAlpha++ : 0; // use with wxPNG_TYPE_PALETTE only

            switch ( iColorType )
            {
                default:
                    wxFAIL_MSG( wxT("unknown wxPNG_TYPE_XXX") );
                    // fall through

                case wxPNG_TYPE_COLOUR:
                    *pData++ = clr.red;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    *pData++ = clr.green;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    *pData++ = clr.blue;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    break;

                case wxPNG_TYPE_GREY:
                    {
                        // where do these coefficients come from? maybe we
                        // should have image options for them as well?
                        unsigned uiColor =
                            (unsigned) (76.544*(unsigned)clr.red +
                                        150.272*(unsigned)clr.green +
                                        36.864*(unsigned)clr.blue);

                        *pData++ = (unsigned char)((uiColor >> 8) & 0xFF);
                        if ( iBitDepth == 16 )
                            *pData++ = (unsigned char)(uiColor & 0xFF);
                    }
                    break;

                case wxPNG_TYPE_GREY_RED:
                    *pData++ = clr.red;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    break;

                case wxPNG_TYPE_PALETTE:
                    *pData++ = (unsigned char) PaletteFind(palette, clr);
                    break;
            }

            if ( bUseAlpha )
            {
                unsigned char uchAlpha = 255;
                if ( bHasAlpha )
                    uchAlpha = *pAlpha++;

                if ( bHasMask )
                {
                    if ( (clr.red == mask.red)
                            && (clr.green == mask.green)
                                && (clr.blue == mask.blue) )
                        uchAlpha = 0;
                }

                *pData++ = uchAlpha;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
            }
        }

        png_bytep row_ptr = data;
        png_write_rows( png_ptr, &row_ptr, 1 );
    }

    free(data);
    png_write_end( png_ptr, info_ptr );
    png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );

    return true;
}
Ejemplo n.º 26
0
/* write a png file */
GF_EXPORT
GF_Err gf_img_png_enc(char *data, u32 width, u32 height, s32 stride, u32 pixel_format, char *dst, u32 *dst_size)
{
	GFpng udta;
	png_color_8 sig_bit;
	png_int_32 k;
	png_bytep *row_pointers;
	png_structp png_ptr;
	png_infop info_ptr;
	u32 type, nb_comp;

	type = 0;
	nb_comp = 0;
	switch (pixel_format) {
	case GF_PIXEL_GREYSCALE:
		nb_comp = 1;
		type = PNG_COLOR_TYPE_GRAY;
		break;
	case GF_PIXEL_ALPHAGREY:
		nb_comp = 1;
		type = PNG_COLOR_TYPE_GRAY_ALPHA;
		break;
	case GF_PIXEL_RGB_24:
	case GF_PIXEL_BGR_24:
	case GF_PIXEL_RGB_32:
	case GF_PIXEL_BGR_32:
		nb_comp = 3;
		type = PNG_COLOR_TYPE_RGB;
		break;
	case GF_PIXEL_RGBA:
	case GF_PIXEL_ARGB:
		nb_comp = 4;
		type = PNG_COLOR_TYPE_RGB_ALPHA;
		break;
	default:
		return GF_NOT_SUPPORTED;
	}
	if (*dst_size < width*height*nb_comp) return GF_BUFFER_TOO_SMALL;


	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	//      png_voidp user_error_ptr, user_error_fn, user_warning_fn);

	if (png_ptr == NULL) return GF_IO_ERR;

	/* Allocate/initialize the image information data.  REQUIRED */
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_write_struct(&png_ptr, NULL);
		return GF_IO_ERR;
	}

	/* Set error handling.  REQUIRED if you aren't supplying your own
    * error handling functions in the png_create_write_struct() call.
    */
	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		return GF_NON_COMPLIANT_BITSTREAM;
	}

	udta.buffer = dst;
	udta.pos = 0;
	png_set_write_fn(png_ptr, &udta, gf_png_write, gf_png_flush);

	png_set_IHDR(png_ptr, info_ptr, width, height, 8, type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	/* otherwise, if we are dealing with a color image then */
	sig_bit.red = 8;
	sig_bit.green = 8;
	sig_bit.blue = 8;
	sig_bit.gray = 8;
	sig_bit.alpha = 8;
	png_set_sBIT(png_ptr, info_ptr, &sig_bit);

#if 0
	/* Optionally write comments into the image */
	text_ptr[0].key = "Title";
	text_ptr[0].text = "Mona Lisa";
	text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
	text_ptr[1].key = "Author";
	text_ptr[1].text = "Leonardo DaVinci";
	text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
	text_ptr[2].key = "Description";
	text_ptr[2].text = "<long text>";
	text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
#ifdef PNG_iTXt_SUPPORTED
	text_ptr[0].lang = NULL;
	text_ptr[1].lang = NULL;
	text_ptr[2].lang = NULL;
#endif
	png_set_text(png_ptr, info_ptr, text_ptr, 3);
#endif

	png_write_info(png_ptr, info_ptr);

	/* Shift the pixels up to a legal bit depth and fill in
    * as appropriate to correctly scale the image.
    */
	png_set_shift(png_ptr, &sig_bit);

	/* pack pixels into bytes */
	png_set_packing(png_ptr);

	if (pixel_format==GF_PIXEL_ARGB) {
//		png_set_swap_alpha(png_ptr);
		png_set_bgr(png_ptr);
	}
	switch (pixel_format) {
	case GF_PIXEL_RGB_32:
		png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
		png_set_bgr(png_ptr);
		break;
	case GF_PIXEL_BGR_32:
	   png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
		break;
	case GF_PIXEL_BGR_24:
		png_set_bgr(png_ptr);
		break;
	}
	row_pointers = gf_malloc(sizeof(png_bytep)*height);
	for (k = 0; k < (s32)height; k++)
		row_pointers[k] = data + k*stride;

	png_write_image(png_ptr, row_pointers);
	png_write_end(png_ptr, info_ptr);
	gf_free(row_pointers);
	/* clean up after the write, and free any memory allocated */
	png_destroy_write_struct(&png_ptr, &info_ptr);

	*dst_size = udta.pos;
	return GF_OK;
}
Ejemplo n.º 27
0
// this code is heavily adapted from the paint license, which is in
// the file paint.license (BSD compatible) included in this
// distribution.  TODO, add license file to MANIFEST.in and CVS
Py::Object _png_module::write_png(const Py::Tuple& args)
{
    args.verify_length(4, 5);

    FILE *fp = NULL;
    bool close_file = false;
    bool close_dup_file = false;
    Py::Object buffer_obj = Py::Object(args[0]);
    PyObject* buffer = buffer_obj.ptr();
    if (!PyObject_CheckReadBuffer(buffer))
    {
        throw Py::TypeError("First argument must be an rgba buffer.");
    }

    const void* pixBufferPtr = NULL;
    Py_ssize_t pixBufferLength = 0;
    if (PyObject_AsReadBuffer(buffer, &pixBufferPtr, &pixBufferLength))
    {
        throw Py::ValueError("Couldn't get data from read buffer.");
    }

    png_byte* pixBuffer = (png_byte*)pixBufferPtr;
    int width = (int)Py::Int(args[1]);
    int height = (int)Py::Int(args[2]);

    if (pixBufferLength < width * height * 4)
    {
        throw Py::ValueError("Buffer and width, height don't seem to match.");
    }

    Py::Object py_fileobj = Py::Object(args[3]);
    PyObject* py_file = NULL;
    if (py_fileobj.isString())
    {
        if ((py_file = npy_PyFile_OpenFile(py_fileobj.ptr(), (char *)"wb")) == NULL) {
            throw Py::Exception();
        }
        close_file = true;
    }
    else
    {
        py_file = py_fileobj.ptr();
    }

    if ((fp = npy_PyFile_Dup(py_file, (char *)"wb")))
    {
        close_dup_file = true;
    }
    else
    {
        PyErr_Clear();
        PyObject* write_method = PyObject_GetAttrString(
                py_file, "write");
        if (!(write_method && PyCallable_Check(write_method)))
        {
            Py_XDECREF(write_method);
            throw Py::TypeError(
                    "Object does not appear to be a 8-bit string path or "
                    "a Python file-like object");
        }
        Py_XDECREF(write_method);
    }

    png_bytep *row_pointers = NULL;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;

    try
    {
        struct png_color_8_struct sig_bit;
        png_uint_32 row;

        row_pointers = new png_bytep[height];
        for (row = 0; row < (png_uint_32)height; ++row)
        {
            row_pointers[row] = pixBuffer + row * width * 4;
        }

        png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
        if (png_ptr == NULL)
        {
            throw Py::RuntimeError("Could not create write struct");
        }

        info_ptr = png_create_info_struct(png_ptr);
        if (info_ptr == NULL)
        {
            throw Py::RuntimeError("Could not create info struct");
        }

        if (setjmp(png_jmpbuf(png_ptr)))
        {
            throw Py::RuntimeError("Error building image");
        }

        if (fp)
        {
            png_init_io(png_ptr, fp);
        }
        else
        {
            png_set_write_fn(png_ptr, (void*)py_file,
                             &write_png_data, &flush_png_data);
        }
        png_set_IHDR(png_ptr, info_ptr,
                     width, height, 8,
                     PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        // Save the dpi of the image in the file
        if (args.size() == 5)
        {
            double dpi = Py::Float(args[4]);
            size_t dots_per_meter = (size_t)(dpi / (2.54 / 100.0));
            png_set_pHYs(png_ptr, info_ptr, dots_per_meter, dots_per_meter, PNG_RESOLUTION_METER);
        }

        // this a a color image!
        sig_bit.gray = 0;
        sig_bit.red = 8;
        sig_bit.green = 8;
        sig_bit.blue = 8;
        /* if the image has an alpha channel then */
        sig_bit.alpha = 8;
        png_set_sBIT(png_ptr, info_ptr, &sig_bit);

        png_write_info(png_ptr, info_ptr);
        png_write_image(png_ptr, row_pointers);
        png_write_end(png_ptr, info_ptr);
    }
    catch (...)
    {
        if (png_ptr && info_ptr)
        {
            png_destroy_write_struct(&png_ptr, &info_ptr);
        }
        delete [] row_pointers;

        if (close_dup_file)
        {
            if (npy_PyFile_DupClose(py_file, fp)) {
              throw Py::RuntimeError("Error closing dupe file handle");
            }
        }

        if (close_file)
        {
            npy_PyFile_CloseFile(py_file);
            Py_DECREF(py_file);
        }
        /* Changed calls to png_destroy_write_struct to follow
           http://www.libpng.org/pub/png/libpng-manual.txt.
           This ensures the info_ptr memory is released.
        */
        throw;
    }

    png_destroy_write_struct(&png_ptr, &info_ptr);
    delete [] row_pointers;
    if (close_dup_file)
    {
        if (npy_PyFile_DupClose(py_file, fp)) {
          throw Py::RuntimeError("Error closing dupe file handle");
        }
    }

    if (close_file)
    {
        npy_PyFile_CloseFile(py_file);
        Py_DECREF(py_file);
    }

    if (PyErr_Occurred()) {
        throw Py::Exception();
    } else {
        return Py::Object();
    }
}
Ejemplo n.º 28
0
static gboolean real_save_png (GdkPixbuf        *pixbuf, 
                               gchar           **keys,
                               gchar           **values,
                               GError          **error,
                               gboolean          to_callback,
                               FILE             *f,
                               GdkPixbufSaveFunc save_func,
                               gpointer          user_data)
{
       png_structp png_ptr = NULL;
       png_infop info_ptr;
       png_textp text_ptr = NULL;
       guchar *ptr;
       guchar *pixels;
       int y;
       int i;
       png_bytep row_ptr;
       png_color_8 sig_bit;
       int w, h, rowstride;
       int has_alpha;
       int bpc;
       int num_keys;
       int compression = -1;
       gboolean success = TRUE;
       guchar *icc_profile = NULL;
       gsize icc_profile_size = 0;
       SaveToFunctionIoPtr to_callback_ioptr;

       num_keys = 0;

       if (keys && *keys) {
               gchar **kiter = keys;
               gchar **viter = values;

               while (*kiter) {
                       if (strncmp (*kiter, "tEXt::", 6) == 0) {
                               gchar  *key = *kiter + 6;
                               int     len = strlen (key);
                               if (len < 1 || len > 79) {
                                       g_set_error_literal (error,
                                                            GDK_PIXBUF_ERROR,
                                                            GDK_PIXBUF_ERROR_BAD_OPTION,
                                                            _("Keys for PNG text chunks must have at least 1 and at most 79 characters."));
                                       success = FALSE;
                                       goto cleanup;
                               }
                               for (i = 0; i < len; i++) {
                                       if ((guchar) key[i] > 127) {
                                               g_set_error_literal (error,
                                                                    GDK_PIXBUF_ERROR,
                                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                                    _("Keys for PNG text chunks must be ASCII characters."));
                                               success = FALSE;
                                               goto cleanup;
                                       }
                               }
                               num_keys++;
                       } else if (strcmp (*kiter, "icc-profile") == 0) {
                               /* decode from base64 */
                               icc_profile = g_base64_decode (*viter, &icc_profile_size);
                               if (icc_profile_size < 127) {
                                       /* This is a user-visible error */
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("Color profile has invalid length %d."),
                                                    (gint)icc_profile_size);
                                       success = FALSE;
                                       goto cleanup;
                               }
                       } else if (strcmp (*kiter, "compression") == 0) {
                               char *endptr = NULL;
                               compression = strtol (*viter, &endptr, 10);

                               if (endptr == *viter) {
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("PNG compression level must be a value between 0 and 9; value '%s' could not be parsed."),
                                                    *viter);
                                       success = FALSE;
                                       goto cleanup;
                               }
                               if (compression < 0 || compression > 9) {
                                       /* This is a user-visible error;
                                        * lets people skip the range-checking
                                        * in their app.
                                        */
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("PNG compression level must be a value between 0 and 9; value '%d' is not allowed."),
                                                    compression);
                                       success = FALSE;
                                       goto cleanup;
                               }
                       } else {
                               g_warning ("Unrecognized parameter (%s) passed to PNG saver.", *kiter);
                       }

                       ++kiter;
                       ++viter;
               }
       }

       if (num_keys > 0) {
               gchar **kiter = keys;
               gchar **viter = values;

               text_ptr = g_new0 (png_text, num_keys);
               for (i = 0; i < num_keys; i++) {
                       if (strncmp (*kiter, "tEXt::", 6) != 0) {
                                kiter++;
                                viter++;
                       }

                       text_ptr[i].compression = PNG_TEXT_COMPRESSION_NONE;
                       text_ptr[i].key  = *kiter + 6;
                       text_ptr[i].text = g_convert (*viter, -1, 
                                                     "ISO-8859-1", "UTF-8", 
                                                     NULL, &text_ptr[i].text_length, 
                                                     NULL);

#ifdef PNG_iTXt_SUPPORTED 
                       if (!text_ptr[i].text) {
                               text_ptr[i].compression = PNG_ITXT_COMPRESSION_NONE;
                               text_ptr[i].text = g_strdup (*viter);
                               text_ptr[i].text_length = 0;
                               text_ptr[i].itxt_length = strlen (text_ptr[i].text);
                               text_ptr[i].lang = NULL;
                               text_ptr[i].lang_key = NULL;
                       }
#endif

                       if (!text_ptr[i].text) {
                               gint j;
                               g_set_error (error,
                                            GDK_PIXBUF_ERROR,
                                            GDK_PIXBUF_ERROR_BAD_OPTION,
                                            _("Value for PNG text chunk %s cannot be converted to ISO-8859-1 encoding."), *kiter + 6);
                               for (j = 0; j < i; j++)
                                       g_free (text_ptr[j].text);
                               g_free (text_ptr);
                               return FALSE;
                       }

                        kiter++;
                        viter++;
               }
       }

       bpc = gdk_pixbuf_get_bits_per_sample (pixbuf);
       w = gdk_pixbuf_get_width (pixbuf);
       h = gdk_pixbuf_get_height (pixbuf);
       rowstride = gdk_pixbuf_get_rowstride (pixbuf);
       has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
       pixels = gdk_pixbuf_get_pixels (pixbuf);

       png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
                                          error,
                                          png_simple_error_callback,
                                          png_simple_warning_callback);
       if (png_ptr == NULL) {
	       success = FALSE;
	       goto cleanup;
       }

       info_ptr = png_create_info_struct (png_ptr);
       if (info_ptr == NULL) {
	       success = FALSE;
	       goto cleanup;
       }
       if (setjmp (png_jmpbuf(png_ptr))) {
	       success = FALSE;
	       goto cleanup;
       }

       if (num_keys > 0) {
               png_set_text (png_ptr, info_ptr, text_ptr, num_keys);
       }

       if (to_callback) {
               to_callback_ioptr.save_func = save_func;
               to_callback_ioptr.user_data = user_data;
               to_callback_ioptr.error = error;
               png_set_write_fn (png_ptr, &to_callback_ioptr,
                                 png_save_to_callback_write_func,
                                 png_save_to_callback_flush_func);
       } else {
               png_init_io (png_ptr, f);
       }

       if (compression >= 0)
               png_set_compression_level (png_ptr, compression);

#if defined(PNG_iCCP_SUPPORTED)
        /* the proper ICC profile title is encoded in the profile */
        if (icc_profile != NULL) {
                png_set_iCCP (png_ptr, info_ptr,
                              "ICC profile", PNG_COMPRESSION_TYPE_BASE,
                              (png_bytep) icc_profile, icc_profile_size);
        }
#endif

       if (has_alpha) {
               png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
                             PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
       } else {
               png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
                             PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
       }
       sig_bit.red = bpc;
       sig_bit.green = bpc;
       sig_bit.blue = bpc;
       sig_bit.alpha = bpc;
       png_set_sBIT (png_ptr, info_ptr, &sig_bit);
       png_write_info (png_ptr, info_ptr);
       png_set_shift (png_ptr, &sig_bit);
       png_set_packing (png_ptr);

       ptr = pixels;
       for (y = 0; y < h; y++) {
               row_ptr = (png_bytep)ptr;
               png_write_rows (png_ptr, &row_ptr, 1);
               ptr += rowstride;
       }

       png_write_end (png_ptr, info_ptr);

cleanup:
        if (png_ptr != NULL)
                png_destroy_write_struct (&png_ptr, &info_ptr);

        g_free (icc_profile);

        if (text_ptr != NULL) {
                for (i = 0; i < num_keys; i++)
                        g_free (text_ptr[i].text);
                g_free (text_ptr);
        }

       return success;
}
Ejemplo n.º 29
0
static gboolean
_cairo_surface_write_as_png (cairo_surface_t  *image,
			     char            **buffer,
			     gsize            *buffer_size,
			     char            **keys,
			     char            **values,
			     GError          **error)
{
	int            compression_level;
	int            width, height;
	gboolean       alpha;
	guchar        *pixels, *ptr, *buf;
	int            rowstride;
	CairoPngData  *cairo_png_data;
	png_color_8    sig_bit;
	int            bpp;
	int            row;

	compression_level = 6;

	if (keys && *keys) {
		char **kiter = keys;
		char **viter = values;

		while (*kiter) {
			if (strcmp (*kiter, "compression") == 0) {
				if (*viter == NULL) {
					g_set_error (error,
						     G_IO_ERROR,
						     G_IO_ERROR_INVALID_DATA,
						     "Must specify a compression level");
					return FALSE;
				}

				compression_level = atoi (*viter);

				if (compression_level < 0 || compression_level > 9) {
					g_set_error (error,
						     G_IO_ERROR,
						     G_IO_ERROR_INVALID_DATA,
						     "Unsupported compression level passed to the PNG saver");
					return FALSE;
				}
			}
			else {
				g_warning ("Bad option name '%s' passed to the PNG saver", *kiter);
				return FALSE;
			}

			++kiter;
			++viter;
		}
	}

	width     = cairo_image_surface_get_width (image);
	height    = cairo_image_surface_get_height (image);
	alpha     = _cairo_image_surface_get_has_alpha (image);
	pixels    = _cairo_image_surface_flush_and_get_data (image);
	rowstride = cairo_image_surface_get_stride (image);

	cairo_png_data = g_new0 (CairoPngData, 1);
	cairo_png_data->error = error;
	cairo_png_data->buffer_data = gth_buffer_data_new ();

	cairo_png_data->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
							   &cairo_png_data->error,
							   gerror_error_func,
							   gerror_warning_func);
	if (cairo_png_data->png_ptr == NULL) {
		_cairo_png_data_destroy (cairo_png_data);
	        return FALSE;
	}

	cairo_png_data->png_info_ptr = png_create_info_struct (cairo_png_data->png_ptr);
	if (cairo_png_data->png_info_ptr == NULL) {
		_cairo_png_data_destroy (cairo_png_data);
	        return FALSE;
	}

	if (PNG_SETJMP (cairo_png_data->png_ptr)) {
		_cairo_png_data_destroy (cairo_png_data);
	        return FALSE;
	}

	png_set_write_fn (cairo_png_data->png_ptr,
			  cairo_png_data,
			  cairo_png_write_data_func,
			  cairo_png_flush_data_func);

	/* Set the image information here */

	png_set_IHDR (cairo_png_data->png_ptr,
		      cairo_png_data->png_info_ptr,
		      width,
		      height,
		      8,
		      (alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB),
		      PNG_INTERLACE_NONE,
		      PNG_COMPRESSION_TYPE_BASE,
		      PNG_FILTER_TYPE_BASE);

	/* Options */

	sig_bit.red = 8;
	sig_bit.green = 8;
	sig_bit.blue = 8;
	if (alpha)
		sig_bit.alpha = 8;
	png_set_sBIT (cairo_png_data->png_ptr, cairo_png_data->png_info_ptr, &sig_bit);

	png_set_compression_level (cairo_png_data->png_ptr, compression_level);

	/* Write the file header information. */

	png_write_info (cairo_png_data->png_ptr, cairo_png_data->png_info_ptr);

	/* Write the image */

	bpp = alpha ? 4 : 3;
	buf = g_new (guchar, width * bpp);
	ptr = pixels;
	for (row = 0; row < height; ++row) {
		_cairo_copy_line_as_rgba_big_endian (buf, ptr, width, alpha);
		png_write_rows (cairo_png_data->png_ptr, &buf, 1);

		ptr += rowstride;
	}
	g_free (buf);

	png_write_end (cairo_png_data->png_ptr, cairo_png_data->png_info_ptr);
	gth_buffer_data_get (cairo_png_data->buffer_data, buffer, buffer_size);

	_cairo_png_data_destroy (cairo_png_data);

	return TRUE;
}
Ejemplo n.º 30
0
bool8 S9xDoScreenshot (int width, int height)
{
	Settings.TakeScreenshot = FALSE;

#ifdef HAVE_LIBPNG
	FILE		*fp;
	png_structp	png_ptr;
	png_infop	info_ptr;
	png_color_8	sig_bit;
	int			imgwidth, imgheight;
	const char	*fname;

	fname = S9xGetFilenameInc(".png", SCREENSHOT_DIR);

	fp = fopen(fname, "wb");
	if (!fp)
	{
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!png_ptr)
	{
		fclose(fp);
		remove(fname);
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
		fclose(fp);
		remove(fname);
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	if (setjmp(png_jmpbuf(png_ptr)))
	{
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(fp);
		remove(fname);
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	imgwidth  = width;
	imgheight = height;

	if (Settings.StretchScreenshots == 1)
	{
		if (width > SNES_WIDTH && height <= SNES_HEIGHT_EXTENDED)
			imgheight = height << 1;
	}
	else
	if (Settings.StretchScreenshots == 2)
	{
		if (width  <= SNES_WIDTH)
			imgwidth  = width  << 1;
		if (height <= SNES_HEIGHT_EXTENDED)
			imgheight = height << 1;
	}

	png_init_io(png_ptr, fp);

	png_set_IHDR(png_ptr, info_ptr, imgwidth, imgheight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	sig_bit.red   = 5;
	sig_bit.green = 5;
	sig_bit.blue  = 5;
	png_set_sBIT(png_ptr, info_ptr, &sig_bit);
	png_set_shift(png_ptr, &sig_bit);

	png_write_info(png_ptr, info_ptr);

	png_set_packing(png_ptr);

	png_byte	*row_pointer = new png_byte[png_get_rowbytes(png_ptr, info_ptr)];
	uint16		*screen = GFX.Screen;

	for (int y = 0; y < height; y++, screen += GFX.RealPPL)
	{
		png_byte	*rowpix = row_pointer;

		for (int x = 0; x < width; x++)
		{
			uint32	r, g, b;

			DECOMPOSE_PIXEL(screen[x], r, g, b);

			*(rowpix++) = r;
			*(rowpix++) = g;
			*(rowpix++) = b;

			if (imgwidth != width)
			{
				*(rowpix++) = r;
				*(rowpix++) = g;
				*(rowpix++) = b;
			}
		}

		png_write_row(png_ptr, row_pointer);
		if (imgheight != height)
			png_write_row(png_ptr, row_pointer);
	}

	delete [] row_pointer;

	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);

	fclose(fp);

	fprintf(stderr, "%s saved.\n", fname);

	const char	*base = S9xBasename(fname);
	sprintf(String, "Saved screenshot %s", base);
	S9xMessage(S9X_INFO, 0, String);

	return (TRUE);
#else
	fprintf(stderr, "Screenshot support not available (libpng was not found at build time).\n");
	return (FALSE);
#endif
}