コード例 #1
0
bool FPMWritePNGCustom(FloatPixMapRef srcPM, png_voidp ioPtr, png_rw_ptr writeDataFn, png_flush_ptr flushDataFn, FPMWritePNGFlags options, FPMGammaFactor sourceGamma, FPMGammaFactor fileGamma, FPMPNGErrorHandler errorHandler)
{
    if (srcPM != NULL)
    {
        bool				success = false;
        png_structp			png = NULL;
        png_infop			pngInfo = NULL;
        FloatPixMapRef		pm = NULL;

        // Prepare data.
        FPMDimension width = FPMGetWidth(srcPM);
        FPMDimension height = FPMGetHeight(srcPM);
        if (width > UINT32_MAX || height > UINT32_MAX)
        {
            if (errorHandler != NULL)  errorHandler("image is too large for PNG format.", true);
            return false;
        }

        pm = FPMCopy(srcPM);
        if (pm == NULL)  return false;

        unsigned steps = (options & kFPMWritePNG16BPC) ? 0x10000 : 0x100;
        FPMApplyGamma(pm, sourceGamma, fileGamma, steps);
        FPMQuantize(pm, 0.0f, 1.0f, 0.0f, steps - 1, steps, (options & kFPMQuantizeDither & kFPMQuantizeJitter) | kFMPQuantizeClip | kFMPQuantizeAlpha);

        png = png_create_write_struct(PNG_LIBPNG_VER_STRING, errorHandler, PNGError, PNGWarning);
        if (png == NULL)  goto FAIL;

        pngInfo = png_create_info_struct(png);
        if (pngInfo == NULL)  goto FAIL;

        if (setjmp(png_jmpbuf(png)))
        {
            // libpng will jump here on error.
            goto FAIL;
        }

        png_set_write_fn(png, ioPtr, writeDataFn, flushDataFn);

        png_set_IHDR(png, pngInfo, width, height, (options & kFPMWritePNG16BPC) ? 16 : 8,PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

        if (fileGamma == kFPMGammaSRGB)
        {
            png_set_sRGB_gAMA_and_cHRM(png, pngInfo, PNG_sRGB_INTENT_PERCEPTUAL);
        }
        else
        {
            png_set_gAMA(png, pngInfo, fileGamma);
        }

        /*	Select function used to transform a row of data to PNG-friendly
        	format. NOTE: these work in place,and overwrite the data in pm,
        	which is OK since we copied it.
        */
        RowTransformer transformer = NULL;
        if (options & kFPMWritePNG16BPC)
        {
            transformer = TransformRow16;
        }
        else
        {
            transformer = TransformRow8;
        }

        png_write_info(png, pngInfo);

        size_t i;
        size_t rowOffset = FPMGetRowByteCount(pm);
        png_bytep row = (png_bytep)FPMGetBufferPointer(pm);
        for (i = 0; i < height; i++)
        {
            transformer(row, width);
            png_write_row(png, row);
            row += rowOffset;
        }
        png_write_end(png, pngInfo);
        success = true;

FAIL:
        if (png != NULL)  png_destroy_write_struct(&png, &pngInfo);
        FPMRelease(&pm);

        return success;
    }
    else
    {
        return false;
    }
}
コード例 #2
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);
}
コード例 #3
0
ファイル: png-save.c プロジェクト: jonnor/gegl
static gint
export_png (GeglOperation       *operation,
            GeglBuffer          *input,
            const GeglRectangle *result,
            png_structp          png,
            png_infop            info,
            gint                 compression,
            gint                 bit_depth)
{
  gint           i, src_x, src_y;
  png_uint_32    width, height;
  guchar        *pixels;
  png_color_16   white;
  int            png_color_type;
  gchar          format_string[16];
  const Babl    *format;

  src_x = result->x;
  src_y = result->y;
  width = result->width;
  height = result->height;

  {
    const Babl *babl = gegl_buffer_get_format (input);

    if (bit_depth != 16)
      bit_depth = 8;

    if (babl_format_has_alpha (babl))
      if (babl_format_get_n_components (babl) != 2)
        {
          png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
          strcpy (format_string, "R'G'B'A ");
        }
      else
        {
          png_color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
          strcpy (format_string, "Y'A ");
        }
    else
      if (babl_format_get_n_components (babl) != 1)
        {
          png_color_type = PNG_COLOR_TYPE_RGB;
          strcpy (format_string, "R'G'B' ");
        }
      else
        {
          png_color_type = PNG_COLOR_TYPE_GRAY;
          strcpy (format_string, "Y' ");
        }
  }

  if (bit_depth == 16)
    strcat (format_string, "u16");
  else
    strcat (format_string, "u8");

  if (setjmp (png_jmpbuf (png)))
    return -1;

  png_set_compression_level (png, compression);

  png_set_IHDR (png, info,
     width, height, bit_depth, png_color_type,
     PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT);

  if (png_color_type == PNG_COLOR_TYPE_RGB || png_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    {
      white.red = 0xff;
      white.blue = 0xff;
      white.green = 0xff;
      png_set_sRGB_gAMA_and_cHRM (png, info, PNG_sRGB_INTENT_RELATIVE);
    }
  else
    white.gray = 0xff;
  png_set_bKGD (png, info, &white);

  png_write_info (png, info);

#if BYTE_ORDER == LITTLE_ENDIAN
  if (bit_depth > 8)
    png_set_swap (png);
#endif

  format = babl_format (format_string);
  pixels = g_malloc0 (width * babl_format_get_bytes_per_pixel (format));

  for (i=0; i< height; i++)
    {
      GeglRectangle rect;

      rect.x = src_x;
      rect.y = src_y+i;
      rect.width = width;
      rect.height = 1;

      gegl_buffer_get (input, &rect, 1.0, babl_format (format_string), pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

      png_write_rows (png, &pixels, 1);
    }

  png_write_end (png, info);

  g_free (pixels);

  return 0;
}
コード例 #4
0
ファイル: fastpng.hpp プロジェクト: dvberkel/mypaint
PyObject *
save_png_fast_progressive (char *filename,
                           int w, int h,
                           bool has_alpha,
                           PyObject *data_generator,
                           bool write_legacy_png)
{
  png_structp png_ptr = NULL;
  png_infop info_ptr = NULL;
  PyObject * result = NULL;
  int bpc;
  FILE * fp = NULL;
  PyObject *iterator = NULL;

  /* TODO: try if this silliness helps
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
  png_uint_32 mask, flags;
  
  flags = png_get_asm_flags(png_ptr);
  mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
  png_set_asm_flags(png_ptr, flags | mask);
#endif
  */

  bpc = 8;
  
  fp = fopen(filename, "wb");
  if (!fp) {
    PyErr_SetFromErrno(PyExc_IOError);
    //PyErr_Format(PyExc_IOError, "Could not open PNG file for writing: %s", filename);
    goto cleanup;
  }

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, png_write_error_callback, NULL);
  if (!png_ptr) {
    PyErr_SetString(PyExc_MemoryError, "png_create_write_struct() failed");
    goto cleanup;
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
    PyErr_SetString(PyExc_MemoryError, "png_create_info_struct() failed");
    goto cleanup;
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
    goto cleanup;
  }

  png_init_io(png_ptr, fp);

  png_set_IHDR (png_ptr, info_ptr,
                w, h, bpc,
                has_alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
                PNG_INTERLACE_NONE,
                PNG_COMPRESSION_TYPE_BASE,
                PNG_FILTER_TYPE_BASE);

  if (! write_legacy_png) {
    // Internal data is sRGB by the time it gets here.
    // Explicitly save with the recommended chunks to advertise that fact.
    png_set_sRGB_gAMA_and_cHRM (png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
  }

  // default (all filters enabled):                 1350ms, 3.4MB
  //png_set_filter(png_ptr, 0, PNG_FILTER_NONE);  // 790ms, 3.8MB
  //png_set_filter(png_ptr, 0, PNG_FILTER_PAETH); // 980ms, 3.5MB
  png_set_filter(png_ptr, 0, PNG_FILTER_SUB);     // 760ms, 3.4MB

  //png_set_compression_level(png_ptr, 0); // 0.49s, 32MB
  //png_set_compression_level(png_ptr, 1); // 0.98s, 9.6MB
  png_set_compression_level(png_ptr, 2);   // 1.08s, 9.4MB
  //png_set_compression_level(png_ptr, 9); // 18.6s, 9.3MB

  png_write_info(png_ptr, info_ptr);

  if (!has_alpha) {
    // input array format format is rgbu
    png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
  }

  {
    iterator = PyObject_GetIter(data_generator);
    if (!iterator) goto cleanup;

    int y = 0;
    while (y < h) {
      int rows;
      PyObject * arr = PyIter_Next(iterator);
      if (PyErr_Occurred()) goto cleanup;
      assert(arr); // iterator should have data
      assert(PyArray_ISALIGNED(arr));
      assert(PyArray_NDIM(arr) == 3);
      assert(PyArray_DIM(arr, 1) == w);
      assert(PyArray_DIM(arr, 2) == 4); // rgbu
      assert(PyArray_TYPE(arr) == NPY_UINT8);
      assert(PyArray_STRIDE(arr, 1) == 4);
      assert(PyArray_STRIDE(arr, 2) == 1);

      rows = PyArray_DIM(arr, 0);
      assert(rows > 0);
      y += rows;
      png_bytep p = (png_bytep)PyArray_DATA(arr);
      for (int row=0; row<rows; row++) {
        png_write_row (png_ptr, p);
        p += PyArray_STRIDE(arr, 0);
      }
      Py_DECREF(arr);
    }
    assert(y == h);
    PyObject * obj = PyIter_Next(iterator);
    assert(!obj); // iterator should be finished
    if (PyErr_Occurred()) goto cleanup;
  }

  png_write_end (png_ptr, NULL);

  result = Py_BuildValue("{}");

 cleanup:
  if (iterator) Py_DECREF(iterator);
  if (info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
  if (fp) fclose(fp);
  return result;
}
コード例 #5
0
ファイル: file_png.cpp プロジェクト: DominikDeak/KFX
/*---------------------------------------------------------------------------
   Saves a PNG file.

   Image    : Image to save.
   Path     : Path to image file, relative to the current working directory.
   Compress : Specifies the compression level to use for encoding.
  ---------------------------------------------------------------------------*/
void PNG::Save(const Texture &Image, const std::string &Path, CompLevel Compress)
   {
   Destroy();

   //Important - set class to writing mode
   Mode = PNG::ModeWrite;

   vector2u Res = Image.Resolution();
   if (Res.U < 1 || Res.V < 1) {return;}

   #if defined (WINDOWS)
      if (fopen_s(&File, Path.c_str(), "wb") != 0)
         {throw dexception("Failed to open file: %s.", Path.c_str());}
   #else
      File = fopen(Path.c_str(), "wb");
      if (File == nullptr) {throw dexception("Failed to open file: %s.", Path.c_str());}
   #endif

   PngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
   if (PngPtr == nullptr) {throw dexception("png_create_write_struct( ) failed.");}

   InfoPtr = png_create_info_struct(PngPtr);
   if (InfoPtr == nullptr) {throw dexception("png_create_info_struct( ) failed.");}

   if (setjmp(png_jmpbuf(PngPtr)))
      {throw dexception("setjmp( ) failed.");}

   png_init_io(PngPtr, File);

   png_set_compression_level(PngPtr, (int)Compress);

   int BitDepth, ColourType;
   switch (Image.DataType())
      {
      case Texture::TypeAlpha : BitDepth = 8;  ColourType = PNG_COLOR_TYPE_GRAY; break;
      case Texture::TypeLum   : BitDepth = 8;  ColourType = PNG_COLOR_TYPE_GRAY; break;
      case Texture::TypeDepth : BitDepth = 16; ColourType = PNG_COLOR_TYPE_GRAY; break;
      case Texture::TypeRGB   : BitDepth = 8;  ColourType = PNG_COLOR_TYPE_RGB; break;
      case Texture::TypeRGBA  : BitDepth = 8;  ColourType = PNG_COLOR_TYPE_RGB_ALPHA; break;
      default : throw dexception("Unsupported image type."); break;
      }

   png_set_IHDR(PngPtr, InfoPtr, (png_uint_32)Res.U, (png_uint_32)Res.V, BitDepth, ColourType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

   png_set_sRGB(PngPtr, InfoPtr, PNG_sRGB_INTENT_ABSOLUTE);
   png_set_sRGB_gAMA_and_cHRM(PngPtr, InfoPtr, PNG_sRGB_INTENT_ABSOLUTE);

   png_color_16 BackGnd;
   BackGnd.red   = 0;
   BackGnd.green = 0;
   BackGnd.blue  = 0;
   png_set_bKGD(PngPtr, InfoPtr, &BackGnd);

   png_text PngText[2];
   memset(PngText, 0, sizeof(PngText));

   PngText[0].compression = PNG_TEXT_COMPRESSION_NONE;
   PngText[0].key = const_cast<png_charp>("Software");
   PngText[0].text = const_cast<png_charp>(AppName);
   PngText[0].text_length = strlen(PngText[0].text);

   PngText[1].compression = PNG_TEXT_COMPRESSION_NONE;
   PngText[1].key = const_cast<png_charp>("Author");
   PngText[1].text = const_cast<png_charp>(AppAuthor);
   PngText[1].text_length = strlen(PngText[1].text);

   png_set_text(PngPtr, InfoPtr, PngText, 2);

   png_write_info(PngPtr, InfoPtr);

   //Populate row pointer array
   Rows.Create((usize)Res.V);
   for (uiter I = 0; I < (usize)Res.V; I++)
      {
      Rows[I] = Image.Address(0, I);
      }

   //Encode
   png_write_image(PngPtr, Rows.Pointer());
   png_write_end(PngPtr, nullptr);

   //Clean up
   Destroy();
   }