Beispiel #1
0
	void PNGFile::save(std::ostream &stream) {
		if (pixels.empty()) {
			throw std::runtime_error("Trying to save an empty PNG");
		}
		
		// Initializations needed by libpng
		png_structp PngPointer = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
		if (!PngPointer)
		{
			throw std::runtime_error("Cannot allocate memory");
		}

		png_infop InfoPointer = png_create_info_struct(PngPointer);
		if (!InfoPointer)
		{
			png_destroy_write_struct(&PngPointer, nullptr);
			throw std::runtime_error("Cannot allocate memory");
		}

		if (setjmp(png_jmpbuf(PngPointer)))
		{
			png_destroy_write_struct(&PngPointer, &InfoPointer);
			throw std::runtime_error("Cannot set jump pointer");
		}

		// Set PNG parameters
		png_set_IHDR(PngPointer, InfoPointer, params.width, params.height, params.BitDepth, params.BitsPerPixel == 24 ?
		       PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, params.InterlaceType, params.CompressionType, params.FilterType);

		/*
		  Instead of storing the image in a 2D-array, I store it in a 1D-array.
		  Since png_set_rows() accepts a pointer to a pointer as an argument,
		  I need to create a temporary std::vector storing pointers
		  to addresses of 1st pixels for each row.
		*/
		std::vector<unsigned char*> RowPointers(params.height);
		size_t BytesPerLine = params.width << 2; // (x << 2) == (x * 4). 4 channels: RGB and Alpha.
		unsigned char *ptr = reinterpret_cast<unsigned char*>(pixels.data());
		for (size_t i = 0; i < params.height; ++i, ptr += BytesPerLine)
			RowPointers[i] = ptr;

		// Write data to file
		png_set_bgr(PngPointer);
		png_set_write_fn(PngPointer, reinterpret_cast<void*>(&stream), WriteToStream, nullptr);
		// png_set_rows() takes a pointer to a non-const data as its
		// 3rd argument, making it not possible to declare save() as const
		// without using const_cast on pixels.data(), I'd rather not do that.
		png_set_rows(PngPointer, InfoPointer, RowPointers.data());
		png_write_png(PngPointer, InfoPointer, params.BitsPerPixel == 24 ?
		         PNG_TRANSFORM_STRIP_FILLER_AFTER : PNG_TRANSFORM_IDENTITY, NULL);
		png_destroy_write_struct(&PngPointer, &InfoPointer);
	}
Beispiel #2
0
void PngFile::SetFromImage(const class Image2D &image, const class ColorMap &colorMap, long double normalizeFactor, long double zeroLevel) throw(IOException)
{
	png_bytep *row_pointers = RowPointers();
	for(unsigned long y=0;y<image.Height();y++) {
		for(unsigned long x=0;x<image.Width();x++) {
			int xa = x * PixelSize();
			row_pointers[y][xa]=colorMap.ValueToColorR((image.Value(x, y) - zeroLevel) * normalizeFactor);
			row_pointers[y][xa+1]=colorMap.ValueToColorG((image.Value(x, y) - zeroLevel) * normalizeFactor);
			row_pointers[y][xa+2]=colorMap.ValueToColorB((image.Value(x, y) - zeroLevel) * normalizeFactor);
			row_pointers[y][xa+3]=colorMap.ValueToColorA((image.Value(x, y) - zeroLevel) * normalizeFactor);
		}
	}
}
Beispiel #3
0
void PngFile::Save(const Image2D &image, const ColorMap &colorMap) throw(IOException)
{
	long double normalizeFactor = image.GetMaxMinNormalizationFactor();
	
	png_bytep *row_pointers = RowPointers();
	
	for(unsigned long y=0;y<image.Height();++y) {
		for(unsigned long x=0;x<image.Width();++x) {
			int xa = x * PixelSize();
			row_pointers[y][xa]=colorMap.ValueToColorR(image.Value(x, y) * normalizeFactor);
			row_pointers[y][xa+1]=colorMap.ValueToColorG(image.Value(x, y) * normalizeFactor);
			row_pointers[y][xa+2]=colorMap.ValueToColorB(image.Value(x, y) * normalizeFactor);
			row_pointers[y][xa+3]=colorMap.ValueToColorA(image.Value(x, y) * normalizeFactor);
		}
	}
}
Beispiel #4
0
	void PNGFile::load(std::istream &stream) {
		const int signatureLength = 8;
		uint8_t header[signatureLength];

		// Check the file's signature
		stream.read(reinterpret_cast<char*>(&header), signatureLength);
		if (png_sig_cmp(header, 0, signatureLength))
		{
			throw std::invalid_argument("Invalid file format");
		}

		// Initializations needed by libpng
		png_structp PngPointer = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
		if (!PngPointer)
		{
			throw std::runtime_error("Cannot allocate memory");
		}
		
		png_infop InfoPointer = png_create_info_struct(PngPointer);
		if (!InfoPointer)
		{
			png_destroy_read_struct(&PngPointer, nullptr, nullptr);
			throw std::runtime_error("Cannot allocate memory");
		}

		if (setjmp(png_jmpbuf(PngPointer)))
		{
			png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr);
			throw std::runtime_error("Cannot set jump pointer");
		}

		png_set_sig_bytes(PngPointer, sizeof(header));
		png_set_read_fn(PngPointer, reinterpret_cast<void*>(&stream), ReadFromStream);

		// Get the image's parameters
		png_read_info(PngPointer, InfoPointer);
		params.Channels = png_get_channels(PngPointer, InfoPointer);
		png_get_IHDR(PngPointer, InfoPointer, &params.width, &params.height, &params.BitDepth,
		                         &params.ColorType, &params.InterlaceType, &params.CompressionType, &params.FilterType);
		
		// Convert to 32-bits if needed
		png_set_strip_16(PngPointer);
		png_set_packing(PngPointer);
		switch (params.ColorType)
		{
		case PNG_COLOR_TYPE_GRAY:
		{
			png_set_gray_to_rgb(PngPointer);
			png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER);
			png_set_bgr(PngPointer);
			params.BitsPerPixel = 24;
			break;
		}

		case PNG_COLOR_TYPE_PALETTE:
		{
			// Check whether there's a tRNS chunk
			png_bytep transparency_vals = nullptr;
			png_get_tRNS(PngPointer, InfoPointer, &transparency_vals, nullptr, nullptr);

			// Convert to RGB
			png_set_palette_to_rgb(PngPointer);
			png_set_bgr(PngPointer);

			// If there was no tRNS chunk,
			// add an alpha channel
			if (transparency_vals != nullptr) {
				params.BitsPerPixel = 32;
			}
			else {
				png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER);
				params.BitsPerPixel = 24;
			}			
			break;
		}

		case PNG_COLOR_TYPE_RGB:
		{
			png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER);
			png_set_bgr(PngPointer);
			params.BitsPerPixel = 24;			
			break;
		}

		case PNG_COLOR_TYPE_GRAY_ALPHA:
		{
			png_set_gray_to_rgb(PngPointer);
			png_set_bgr(PngPointer);
			params.BitsPerPixel = 32;
			break;
		}

		case PNG_COLOR_TYPE_RGBA:
		{
			png_set_bgr(PngPointer);
			params.BitsPerPixel = 32;
			break;
		}

		default:
			png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr);
			throw std::runtime_error("Not supported PNG Type");
			break;
		}
		
		// Update the image's parameters
		png_read_update_info(PngPointer, InfoPointer);
		params.Channels = png_get_channels(PngPointer, InfoPointer);
		png_get_IHDR(PngPointer, InfoPointer, &params.width, &params.height, &params.BitDepth,
		                         &params.ColorType, &params.InterlaceType, &params.CompressionType, &params.FilterType);

		/*
		  Instead of storing the image in a 2D-array, I store it in a 1D-array.
		  Since png_read_image() accepts a pointer to a pointer as an argument,
		  I need to create a temporary std::vector storing pointers
		  to addresses of 1st pixels for each row.
		*/
		pixels.resize(params.width * params.height);
		std::vector<unsigned char*> RowPointers(params.height);
		size_t BytesPerLine = params.width << 2; // (x << 2) == (x * 4). 4 channels: RGB and Alpha.
		unsigned char *ptr = reinterpret_cast<unsigned char*>(pixels.data());
		for (size_t i = 0; i < params.height; ++i, ptr += BytesPerLine)
			RowPointers[i] = ptr;

		// Read pixels
		png_read_image(PngPointer, RowPointers.data());
		png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr);

		// Read cryptographic stuff
		this->ReadIV();
		this->ReadSalt();		
	}
Beispiel #5
0
// load in the image data
Picture PictureLoaderPng::load( io::NFile file ) const
{
  if(!file.isOpen())
  {
    Logger::warning( "LOAD PNG: can't open file %s", file.getFileName().toString().c_str() );
    return Picture::getInvalid();
  }

  png_byte buffer[8];
  // Read the first few bytes of the PNG file
  if( file.read(buffer, 8) != 8 )
  {
    Logger::warning( "LOAD PNG: can't read file %s", file.getFileName().toString().c_str() );
    return Picture::getInvalid();
  }

  // Check if it really is a PNG file
  if( png_sig_cmp(buffer, 0, 8) )
  {
    Logger::warning( "LOAD PNG: not really a png %s", file.getFileName().toString().c_str() );
    return Picture::getInvalid();
  }

  // Allocate the png read struct
  png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
                                                NULL, (png_error_ptr)png_cpexcept_error,
                                                (png_error_ptr)png_cpexcept_warn);
  if( !png_ptr )
  {
    Logger::warning( "LOAD PNG: Internal PNG create read struct failure %s", file.getFileName().toString().c_str() );
    return Picture::getInvalid();
  }

  // Allocate the png info struct
  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
  {
    Logger::warning( "LOAD PNG: Internal PNG create info struct failure 5s", file.getFileName().toString().c_str() );
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    return Picture::getInvalid();
  }

  // for proper error handling
  if (setjmp(png_jmpbuf(png_ptr)))
  {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        /*
        if( RowPointers )
                                delete [] RowPointers;
                        */
        return Picture::getInvalid();
  }

  // changed by zola so we don't need to have public FILE pointers
  png_set_read_fn(png_ptr, &file, user_read_data_fcn);

  png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature

  png_read_info(png_ptr, info_ptr); // Read the info section of the png file

  unsigned int Width;
  unsigned int Height;
  int BitDepth;
  int ColorType;
  {
        // Use temporary variables to avoid passing casted pointers
        png_uint_32 w,h;
        // Extract info
        png_get_IHDR(png_ptr, info_ptr,
                &w, &h,
                &BitDepth, &ColorType, NULL, NULL, NULL);
        Width=w;
        Height=h;
  }

  // Convert palette color to true color
  if (ColorType==PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);

  // Convert low bit colors to 8 bit colors
  if (BitDepth < 8)
  {
        if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
                png_set_expand_gray_1_2_4_to_8(png_ptr);
        else
                png_set_packing(png_ptr);
  }

  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
        png_set_tRNS_to_alpha(png_ptr);

  // Convert high bit colors to 8 bit colors
  if (BitDepth == 16)
        png_set_strip_16(png_ptr);

  // Convert gray color to true color
  if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);

  int intent;
  const double screen_gamma = 2.2;

  if (png_get_sRGB(png_ptr, info_ptr, &intent))
        png_set_gamma(png_ptr, screen_gamma, 0.45455);
  else
  {
        double image_gamma;
        if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
                png_set_gamma(png_ptr, screen_gamma, image_gamma);
        else
                png_set_gamma(png_ptr, screen_gamma, 0.45455);
  }

  // Update the changes in between, as we need to get the new color type
  // for proper processing of the RGBA type
  png_read_update_info(png_ptr, info_ptr);
  {
     // Use temporary variables to avoid passing casted pointers
     png_uint_32 w,h;
     // Extract info
     png_get_IHDR(png_ptr, info_ptr,
             &w, &h,
             &BitDepth, &ColorType, NULL, NULL, NULL);
     Width=w;
     Height=h;
  }

  // Convert RGBA to BGRA
  if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA)
  {
    png_set_bgr(png_ptr);
  }

  // Create the image structure to be filled by png data
  Picture* pic = GfxEngine::instance().createPicture( Size( Width, Height ) );
  GfxEngine::instance().loadPicture( *pic );

  if( pic->getSize().getArea() == 0 )
  {
    Logger::warning( "LOAD PNG: Internal PNG create image struct failure %s", file.getFileName().toString().c_str() );
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    return Picture::getInvalid();
  }

  if( !Height )
  {
    Logger::warning( "LOAD PNG: Internal PNG create row pointers failure %s", file.getFileName().toString().c_str() );
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    return Picture::getInvalid();
  }

  // Create array of pointers to rows in image data
  ScopedPtr<unsigned char*> RowPointers( (unsigned char**)new png_bytep[ Height ] );

  // Fill array of pointers to rows in image data
  SDL_LockSurface( pic->getSurface() );
  unsigned char* data = (unsigned char*)pic->getSurface()->pixels;
  for(unsigned int i=0; i<Height; ++i)
  {
    RowPointers.data()[i] = data;
    data += pic->getSurface()->pitch;
  }

  // for proper error handling
  if( setjmp( png_jmpbuf( png_ptr ) ) )
  {
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    GfxEngine::instance().deletePicture( pic );
    return Picture::getInvalid();
  }

  // Read data using the library function that handles all transformations including interlacing
  png_read_image( png_ptr, RowPointers.data() );

  png_read_end( png_ptr, NULL );
  png_destroy_read_struct( &png_ptr, &info_ptr, 0 ); // Clean up memory

  SDL_UnlockSurface(pic->getSurface());

  return *pic;
}