Example #1
0
static BOOL 
WriteMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
	// XMP keyword
	char *g_png_xmp_keyword = "XML:com.adobe.xmp";

	FITAG *tag = NULL;
	FIMETADATA *mdhandle = NULL;
	BOOL bResult = TRUE;

	png_text text_metadata;
	int num_text = 0;

	// set the 'Comments' metadata as iTXt chuncks

	mdhandle = FreeImage_FindFirstMetadata(FIMD_COMMENTS, dib, &tag);

	if(mdhandle) {
		do {
			memset(&text_metadata, 0, sizeof(png_text));
			text_metadata.compression = 1;							// iTXt, none
			text_metadata.key = (char*)FreeImage_GetTagKey(tag);	// keyword, 1-79 character description of "text"
			text_metadata.text = (char*)FreeImage_GetTagValue(tag);	// comment, may be an empty string (ie "")
			text_metadata.text_length = FreeImage_GetTagLength(tag);// length of the text string
			text_metadata.itxt_length = FreeImage_GetTagLength(tag);// length of the itxt string
			text_metadata.lang = 0;		 // language code, 0-79 characters or a NULL pointer
			text_metadata.lang_key = 0;	 // keyword translated UTF-8 string, 0 or more chars or a NULL pointer

			// set the tag 
			png_set_text(png_ptr, info_ptr, &text_metadata, 1);

		} while(FreeImage_FindNextMetadata(mdhandle, &tag));

		FreeImage_FindCloseMetadata(mdhandle);
		bResult &= TRUE;
	}

	// set the 'XMP' metadata as iTXt chuncks
	tag = NULL;
	FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag);
	if(tag && FreeImage_GetTagLength(tag)) {
		memset(&text_metadata, 0, sizeof(png_text));
		text_metadata.compression = 1;							// iTXt, none
		text_metadata.key = g_png_xmp_keyword;					// keyword, 1-79 character description of "text"
		text_metadata.text = (char*)FreeImage_GetTagValue(tag);	// comment, may be an empty string (ie "")
		text_metadata.text_length = FreeImage_GetTagLength(tag);// length of the text string
		text_metadata.itxt_length = FreeImage_GetTagLength(tag);// length of the itxt string
		text_metadata.lang = 0;		 // language code, 0-79 characters or a NULL pointer
		text_metadata.lang_key = 0;	 // keyword translated UTF-8 string, 0 or more chars or a NULL pointer

		// set the tag 
		png_set_text(png_ptr, info_ptr, &text_metadata, 1);
		bResult &= TRUE;
	}

	return bResult;
}
Example #2
0
/*
	offsetを文字列化してPNGのテキストチャンクに埋め込む関数
	※この関数はrow_pointerに読み込む前に実行されないといけない
	@offset 埋め込むwoff_t
	@cspecs テキストチャンクにアクセスするために必要
*/
static void setOffsetToChunk(const woff_t *offset, struct png_control_specs *cspecs)
{
	png_text text;
	char buf[32];

	/* メモリの確保 */

	text.compression = PNG_TEXT_COMPRESSION_NONE;
	text.key = (char *)malloc(sizeof(char) * 16);
	text.text = (char *)malloc(sizeof(char) * 32);

	/* オフセットは書き込んであるビット数だけ */
	sprintf(buf, "%d", offset->total_bit);

	strcpy(text.key, "WaterMark offset");
	strcpy(text.text, buf);

	png_set_text(cspecs->png_ptr, cspecs->info_ptr, (png_textp)&text, 1);

#ifdef DEBUG
	puts("The offset wrote");
	printOffset(offset);
#endif

	png_write_info(cspecs->png_ptr, cspecs->info_ptr);

	/* メモリを解放する */
	free(text.key);
	free(text.text);
}
/** Wrapper for png_set_text.
 *
 * @param png_ptr PNG pointer.
 * @param info_ptr PNG info pointer.
 * @param ptext Text map.
 */
static void png_set_text_map(png_structp png_ptr, png_infop info_ptr,
    const std::map<std::string, std::string> &ptext)
{
  png_textp text_array = new png_text[ptext.size()];
  png_textp iter = text_array;

  for(std::map<std::string, std::string>::const_iterator ii = ptext.begin(), ee = ptext.end();
      (ii != ee);
      ++ii)
  {
    const std::string &key = (*ii).first;
    const std::string &value = (*ii).second;

    memset(iter, 0, sizeof(png_text));

    iter->compression = PNG_TEXT_COMPRESSION_NONE;
    iter->key = const_cast<char*>(key.c_str());
    iter->text = const_cast<char*>(value.c_str());
    iter->text_length = value.length();

    ++iter;
  }

  png_set_text(png_ptr, info_ptr, text_array, static_cast<int>(ptext.size()));
  delete[] text_array;
}
Example #4
0
int writeImage(const char* filename, int width, int height, BGR *buffer, uint8_t *alpha, char *pimg)
{
	int code = 0;
	FILE *fp = nullptr;
	png_structp png_ptr;
	png_infop info_ptr;
	// Open file for writing (binary mode)
	fp = fopen(filename, "wb");

	// Initialize write structure
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	// Initialize info structure
	info_ptr = png_create_info_struct(png_ptr);

	png_init_io(png_ptr, fp);

	// Write header (8 bit colour depth)
	png_set_IHDR(png_ptr, info_ptr, width, height,
		8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	png_text text;
	text.compression = PNG_TEXT_COMPRESSION_NONE;
	char buff[16];
	strcpy(buff, "Comment");
	text.key = buff;
	text.text = pimg;
	text.text_length = strlen(text.text);

	png_set_text(png_ptr, info_ptr, (png_const_textp)&text, 1);

	png_write_info(png_ptr, info_ptr);

	RGBA *data = new RGBA[width*height];

	for (int i = 0; i < width*height; ++i) {
		data[i].a = alpha[i];
		data[i].r = buffer[i].b;
		data[i].g = buffer[i].g;
		data[i].b = buffer[i].r;
	}


	// Write image data

	for (int y=0 ; y<height ; y++) {
		png_write_row(png_ptr, (uint8_t *)data + y*width*4);
	}
	png_write_end(png_ptr, NULL);
	if (fp != NULL) fclose(fp);
	if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
	if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
	delete[] data;
	return 0;
}
void PngWriter::setText(const string& key, const string& value)
{
	png_text pngText;
		
	pngText.compression = -1;
	pngText.key = const_cast<char*>(key.c_str());
	pngText.text = const_cast<char*>(value.c_str());

	png_set_text(m_PngPtr, m_InfoPtr, &pngText, 1);	
}
Example #6
0
static void
vips__png_set_text( png_structp pPng, png_infop pInfo, 
	const char *key, const char *value )
{
	png_text text;

	text.compression = 0;
	text.key = (char *) key;
	text.text = (char *) value;
	text.text_length = strlen( value );

	/* Before 1.4, these fields were only there if explicitly enabled.
	 */
#if PNG_LIBPNG_VER > 10400
	text.itxt_length = 0;
	text.lang = NULL;
#endif

	png_set_text( pPng, pInfo, &text, 1 );
}
Example #7
0
/* write row_pointers data to png file */
int write_png(png_bytep *row_pointers, png_uint_32 width, png_uint_32 height, const char *filename) {
    png_structp png_ptr;
    png_infop info_ptr;
    FILE *fp;

    fp = fopen(filename, "wb");
    if (fp == NULL) {
        return 0;
    }
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
    info_ptr = png_create_info_struct(png_ptr);
    png_init_io(png_ptr, fp);
    png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
            PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
            PNG_FILTER_TYPE_DEFAULT);
    png_write_info(png_ptr, info_ptr);
    png_write_image(png_ptr, row_pointers);
    /* add some comments */
    if (config & CONFIG_COMMENT) {
        int num_text = 2;
        png_textp text_ptr = calloc(num_text, sizeof(png_text));

        text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
        text_ptr[0].key = "Software";
        text_ptr[0].text = VERSION_STRING;
        text_ptr[0].text_length = strlen(text_ptr[0].text);

        text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
        text_ptr[1].key = "Comment";
        text_ptr[1].text = "created with "VERSION_STRING;
        text_ptr[1].text_length = strlen(text_ptr[1].text);

        png_set_text(png_ptr, info_ptr, text_ptr, num_text);
        free(text_ptr);
    }
    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    fclose(fp);

    return 1;
}
Example #8
0
void write_png(char* filename, unsigned w, unsigned h,
               unsigned char** data, png_text* comments) {
  FILE* fp = fopen(filename, "wb");
  if (!fp) {
    fprintf(stderr, "ERROR: Could not open output file %s\n", filename);
    exit(-1);
  }
  
  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
   if (!png_ptr) {
     fprintf(stderr, "ERROR: Could not open output file %s\n", filename);
     fclose(fp);
     exit(-1);
   }

   png_infop info_ptr = png_create_info_struct(png_ptr);
   if (!info_ptr) {
     png_destroy_read_struct(&png_ptr, 0, 0);
     fprintf(stderr, "ERROR: Could not open output file %s\n", filename);
     fclose(fp);
     exit(-1);
   }
   
   if (setjmp(png_jmpbuf(png_ptr))) {
     png_destroy_write_struct(&png_ptr, &info_ptr);
     fprintf(stderr, "ERROR: Could not open output file %s\n", filename);
     fclose(fp);
     exit(-1);
   }
   
   png_init_io(png_ptr, fp);
   png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB_ALPHA,
                PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                PNG_FILTER_TYPE_DEFAULT);
  png_set_text(png_ptr, info_ptr, comments, 1);
  
   png_set_rows(png_ptr, info_ptr, data);
   png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
   
   fclose(fp);
}
Example #9
0
void
set_text(struct PNGImage *png)
{
	png_text *text;
	char buffer[3];

	text = malloc(sizeof(png_text));

	if (png->horizontal) {
		text[0].key = "h";
		text[0].text = "";
		text[0].compression = PNG_TEXT_COMPRESSION_NONE;
		png_set_text(png->png, png->info, text, 1);
	}
	if (png->trim) {
		text[0].key = "x";
		snprintf(buffer, 3, "%d", png->trim);
		text[0].text = buffer;
		text[0].compression = PNG_TEXT_COMPRESSION_NONE;
		png_set_text(png->png, png->info, text, 1);
	}
	if (*png->mapfile) {
		text[0].key = "t";
		text[0].text = "";
		text[0].compression = PNG_TEXT_COMPRESSION_NONE;
		png_set_text(png->png, png->info, text, 1);
	}
	if (png->mapout) {
		text[0].key = "T";
		text[0].text = "";
		text[0].compression = PNG_TEXT_COMPRESSION_NONE;
		png_set_text(png->png, png->info, text, 1);
	}
	if (*png->palfile) {
		text[0].key = "p";
		text[0].text = "";
		text[0].compression = PNG_TEXT_COMPRESSION_NONE;
		png_set_text(png->png, png->info, text, 1);
	}
	if (png->palout) {
		text[0].key = "P";
		text[0].text = "";
		text[0].compression = PNG_TEXT_COMPRESSION_NONE;
		png_set_text(png->png, png->info, text, 1);
	}

	free(text);
}
Example #10
0
void
get_text(struct PNGImage *png)
{
	png_text *text;
	int i, numtxts, numremoved;

	png_get_text(png->png, png->info, &text, &numtxts);
	for (i = 0; i < numtxts; i++) {
		if (strcmp(text[i].key, "h") == 0 && !*text[i].text) {
			png->horizontal = true;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "x") == 0) {
			png->trim = strtoul(text[i].text, NULL, 0);
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "t") == 0) {
			png->mapfile = text[i].text;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "T") == 0 && !*text[i].text) {
			png->mapout = true;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "p") == 0) {
			png->palfile = text[i].text;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "P") == 0 && !*text[i].text) {
			png->palout = true;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		}
	}

	/* TODO: Remove this and simply change the warning function not to warn instead. */
	for (i = 0, numremoved = 0; i < numtxts; i++) {
		if (text[i].key == NULL) {
			numremoved++;
		}
		text[i].key = text[i + numremoved].key;
		text[i].text = text[i + numremoved].text;
		text[i].compression = text[i + numremoved].compression;
	}
	png_set_text(png->png, png->info, text, numtxts - numremoved);
}
Example #11
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;
}
Example #12
0
BOOL OutputPNG::OutputPNGHeader(CCLexFile *File, LPBITMAPINFOHEADER pInfo,
                                BOOL InterlaceState, INT32 TransparentColour,
                                LPLOGPALETTE pPalette, LPRGBQUAD pQuadPalette)
{
    ERROR2IF(File==NULL,FALSE,"OutputPNG::OutputPNGHeader File pointer is null");
    if (pInfo == NULL)
        pInfo = &(DestBitmapInfo->bmiHeader);
    ERROR2IF(pInfo==NULL,FALSE,"OutputPNG::OutputPNGHeader BitmapInfo pointer is null");
    //ERROR2IF(pPalette==NULL && pQuadPalette==NULL,FALSE,"OutputPNG::OutputPNGHeader Bitmap palette pointer is null");

    TRACEUSER( "Jonathan", _T("PNG write: Interlace: %s\n"), InterlaceState ? _T("Yes") : _T("No"));

    // Note file in our class variable as used by all the low level routines
    OutputFile = File;

    // Note the specified transparency and interlace states in our class variables
    Interlace = InterlaceState;
    if (TransparentColour != -1)
        Transparent = TRUE;
    else
        Transparent = FALSE;

    // We are just about to start so set the PNG exception handling up with our CCFile pointer
    PNGUtil::SetCCFilePointer(File);

    // Must set the exception throwing flag to True and force reporting of errors to False.
    // This means that the caller must report an error if the function returns False.
    // Any calls to CCFile::GotError will now throw a file exception and should fall into
    // the catch handler at the end of the function.
    // Replaces the goto's that handled this before.
    BOOL OldThrowingState = File->SetThrowExceptions( TRUE );
    BOOL OldReportingState = File->SetReportErrors( FALSE );

    // PNG related items (NOTE: p at end means pointer and hence implied *)
    png_ptr		= NULL;
    info_ptr	= NULL;

    palette = NULL;

    try
    {
        // Work out the palette size
        INT32 PalSize = pInfo->biClrUsed;		// How many entries in palette
        TRACEUSER( "Jonathan", _T("PNG write: PalSize = %d\n"),PalSize);

        // Set up the class variables
        // First the width/height of the bitmap
        Width = pInfo->biWidth;
        Height = pInfo->biHeight;
        TRACEUSER( "Jonathan", _T("PNG write: Width = %d Height = %d\n"),Width,Height);

        BitsPerPixel = pInfo->biBitCount;

        // Start up the PNG writing code

        // allocate the necessary structures
        // Use the default handlers
        png_ptr = png_create_write_struct_2(
                      PNG_LIBPNG_VER_STRING,	// libpng version
                      0,						// Optional pointer to be sent with errors
                      camelot_png_error,		// Function called in case of error
                      camelot_png_warning,	// Function called for warnings
                      0,						// Optional pointer to be sent with mem ops
                      camelot_png_malloc,		// Function called to alloc memory
                      camelot_png_free		// Function called to free memory
                  );

        if (!png_ptr)
            File->GotError( _R(IDS_OUT_OF_MEMORY) );

        info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
        {
            png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
            File->GotError( _R(IDS_OUT_OF_MEMORY) );
        }

        // set up the input control to the fstream class
        // If not a disk file then panic for the present moment
        // Could use the memfile functions for reading and writing as they give us what
        // we want. Use the io_ptr and
        iostream* pFStream = File->GetIOFile();
        if (pFStream == NULL)
        {
            TRACEUSER( "Jonathan", _T("PNG write: OutputPNG::OutputPNGHeader No access to IOStream!"));
            File->GotError( _R(IDS_UNKNOWN_PNG_ERROR) );
        }

        // Should use our own function
        png_set_write_fn(png_ptr, pFStream, camelot_png_write_data, camelot_png_flush_data);
        // png_init_io(png_ptr, pFStream);

        // You now have the option of modifying how the compression library
        // will run.  The following functions are mainly for testing, but
        // may be useful in certain special cases, like if you need to
        // write png files extremely fast and are willing to give up some
        // compression, or if you want to get the maximum possible compression
        // at the expense of slower writing.  If you have no special needs
        // in this area, let the library do what it wants, as it has been
        // carefully tuned to deliver the best speed/compression ratio.
        // See the compression library for more details.

        // turn on or off filtering (1 or 0)
        //png_set_filtering(png_ptr, 1);

        // compression level (0 - none, 6 - default, 9 - maximum)
        //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
        //png_set_compression_mem_level(png_ptr, 8);
        //png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
        //png_set_compression_window_bits(png_ptr, 15);
        //png_set_compression_method(png_ptr, 8);

        // - this describes which optional chunks to write to the
        // file.  Note that if you are writing a
        // PNG_COLOR_TYPE_PALETTE file, the PLTE chunk is not
        // optional, but must still be marked for writing.  To
        // mark chunks for writing, OR valid with the
        // appropriate PNG_INFO_<chunk name> define.
        png_get_valid(png_ptr, info_ptr, 0);

        // resolution of image
        png_set_invalid(png_ptr, info_ptr, PNG_INFO_pHYs);
        png_set_pHYs(png_ptr, info_ptr,
                     pInfo->biXPelsPerMeter,
                     pInfo->biYPelsPerMeter,
                     1); //meter
        TRACEUSER( "Jonathan", _T("PNG write: x,y px per cm = %d %d\n"),
                   png_get_x_pixels_per_meter(png_ptr, info_ptr) / 1000,
                   png_get_y_pixels_per_meter(png_ptr, info_ptr) / 1000);

        BitsPerPixel				= pInfo->biBitCount;
        TRACEUSER( "Jonathan", _T("PNG write: Bitdepth = %d\n"), BitsPerPixel);
        palette		= NULL;
        num_palette	= 0;
        trans		= NULL;	// - array of transparent entries for paletted images
        num_trans	= 0;	// - number of transparent entries
        TRACEUSER( "Jonathan", _T("PNG write: TransColour = %d\n"), TransparentColour);
        if ( BitsPerPixel <= 8 )
        {
            png_set_IHDR(png_ptr, info_ptr,
                         Width,
                         Height,
                         BitsPerPixel,
                         PNG_COLOR_TYPE_PALETTE,
                         PNG_INTERLACE_NONE,
                         PNG_COMPRESSION_TYPE_BASE,
                         PNG_FILTER_TYPE_BASE);

            // set the palette if there is one
            png_set_invalid(png_ptr, info_ptr, PNG_INFO_PLTE);
            INT32 PaletteEntries = pInfo->biClrUsed;

            palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color));
            if (palette == NULL)
                File->GotError( _R(IDS_OUT_OF_MEMORY) );

            png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
            png_color_struct * pPNGPalette = palette;
            // ... set palette colors ...
            if (pQuadPalette && PaletteEntries > 0)
            {
                // Palette supplied in RGBQUAD form
                for (INT32 i = 0; i < PaletteEntries; i++)
                {
                    pPNGPalette->red 	= pQuadPalette->rgbRed;
                    pPNGPalette->green 	= pQuadPalette->rgbGreen;
                    pPNGPalette->blue 	= pQuadPalette->rgbBlue;
                    // skip to the next palette entry
                    pQuadPalette++;
                    pPNGPalette++;
                }
            }
            else if (pPalette && PaletteEntries > 0)
            {
                // Palette supplied in LOGPALETTE form
                for (INT32 i = 0; i < PaletteEntries; i++)
                {
                    pPNGPalette->red  	= pPalette->palPalEntry[i].peRed;
                    pPNGPalette->green 	= pPalette->palPalEntry[i].peGreen;
                    pPNGPalette->blue 	= pPalette->palPalEntry[i].peBlue;
                    pPNGPalette++;
                }
            }
            else
                File->GotError(_R(IDS_PNG_ERR_WRITE_PALETTE));

            // Now check to see if transparency is present or not
            if (TransparentColour >= 0 && TransparentColour <= PaletteEntries )
            {
                // Create the array of transparent entries for this palette
                // 0 is fully transparent, 255 is fully opaque, regardless of image bit depth
                // We will only create as many as we require, i.e. up to the transparent colour entry
                // rather a full palettes worth
                INT32 NumEntries = TransparentColour + 1;
                trans = (png_byte*)png_malloc(png_ptr, NumEntries * sizeof (png_byte));
                if (trans)
                {
                    // Set the number of transparent entries
                    num_trans			= NumEntries;
                    png_byte * pTransEntry		= trans;
                    png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
                    for (INT32 i = 0; i < TransparentColour; i++)
                    {
                        *pTransEntry = 255;	// set it fully opaque
                        pTransEntry++;
                    }
                    // We should now be at the transparent entry so set it fully transparent
                    *pTransEntry = 0;
                }
            }
        }
        else if (BitsPerPixel == 24)
        {
            png_set_IHDR(png_ptr, info_ptr,
                         Width,
                         Height,
                         8, /* bit_depth */
                         PNG_COLOR_TYPE_RGB,
                         PNG_INTERLACE_NONE,
                         PNG_COMPRESSION_TYPE_BASE,
                         PNG_FILTER_TYPE_BASE);
        }
        else if (BitsPerPixel == 32)
        {
            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);
        }
        else
            ERROR2(FALSE,"OutputPNG::OutputPNGHeader Unknown bit depth");

        TRACEUSER( "Jonathan", _T("PNG write: bit_depth = %d color_type = %d\n"),
                   png_get_bit_depth(png_ptr, info_ptr),
                   png_get_color_type(png_ptr, info_ptr));

        // Could use:-
        // if we are dealing with a grayscale image then
        //info_ptr->sig_bit.gray = true_bit_depth;

        png_set_hIST(png_ptr, info_ptr, NULL);
        png_set_text(png_ptr, info_ptr, NULL, 0);


        // write the file information
        png_write_info(png_ptr, info_ptr);

        TRACEUSER( "Jonathan", _T("PNG write: pixel_depth %d channels %d\n"),
                   png_get_bit_depth(png_ptr, info_ptr),
                   png_get_channels(png_ptr, info_ptr));
        TRACEUSER( "Jonathan", _T("PNG write: rowbytes %d color_type %d\n"),
                   png_get_rowbytes(png_ptr, info_ptr),
                   png_get_color_type(png_ptr, info_ptr));
        // Set up the transformations you want.
        // Note: that these are all optional.  Only call them if you want them

        // invert monocrome pixels
        //png_set_invert(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, &(info_ptr->sig_bit));

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

        png_set_bgr(png_ptr);

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

        // Must set the exception throwing and reporting flags back to their entry states
        File->SetThrowExceptions( OldThrowingState );
        File->SetReportErrors( OldReportingState );

        // er, we seem to have finished OK so say so
        return TRUE;
    }

    catch (...)
    {
        // catch our form of a file exception
        TRACE( _T("OutputPNG::OutputPNGHeader CC catch handler\n"));

        // Call up function to clean up the png structures
        CleanUpPngStructures();

        // Must set the exception throwing and reporting flags back to their entry states
        File->SetThrowExceptions( OldThrowingState );
        File->SetReportErrors( OldReportingState );

        // We have finished so reset the PNG exception handling
        PNGUtil::SetCCFilePointer(NULL);

        return FALSE;
    }

    ERROR2( FALSE, "Escaped exception clause somehow" );
}
Example #13
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;
}
Example #14
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()
                      );
    }
Example #15
0
File: bitmap.c Project: dluco/ttf
int save_bitmap(TTF_Bitmap *bitmap, const char *filename, const char *title) {
	FILE *fp = NULL;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_byte *row = NULL;

	RETINIT(SUCCESS);

	CHECKFAIL(bitmap, warn("failed to save uninitialized bitmap"));

	// Open file for writing (binary mode)
	fp = fopen(filename, "wb");
	CHECKFAIL(fp, warnerr("failed to open file '%s' for saving bitmap", filename));

	// Initialize the write structure
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	CHECKFAIL(png_ptr, warn("failed to alloc png write struct"));

	// Initialize the info structure
	info_ptr = png_create_info_struct(png_ptr);
	CHECKFAIL(info_ptr, warn("failed to alloc png info struct"));

	// Setup libpng exception handling
	CHECKFAIL(setjmp(png_jmpbuf(png_ptr)) == 0, warn("error occurred during png creation"));

	png_init_io(png_ptr, fp);

	// Write header (8 bit colour depth)
	png_set_IHDR(png_ptr, info_ptr, bitmap->w, bitmap->h, 8,
			PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
			PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	// Set png title
	if (title) {
		png_text png_title;
		png_title.compression = PNG_TEXT_COMPRESSION_NONE;
		png_title.key = (png_charp) "Title";
		png_title.text = (png_charp) title;
		png_set_text(png_ptr, info_ptr, &png_title, 1);
	}

	png_write_info(png_ptr, info_ptr);

	// Allocate memory for one row (RBG = 3 bytes / pixel)
	row = (png_byte *) malloc((bitmap->w * 3) * sizeof(*row));
	CHECKFAIL(row, warnerr("failed to alloc png row"));

	// Write image data
	int x, y;
	for (y = 0; y < bitmap->h; y++) {
		for (x = 0; x < bitmap->w; x++) {
			set_rgb(&(row[x*3]), bitmap->data[y*bitmap->w + x]);
		}
		png_write_row(png_ptr, (png_bytep)row);
	}

	// End write
	png_write_end(png_ptr, NULL);

	RETRELEASE(
		/* RELEASE */
		if (row) free(row);
		if (info_ptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
		if (png_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
		if (fp) fclose(fp);
	);
Example #16
0
int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
{
	png_structp png_ptr;
	png_infop info_ptr;

	unsigned char *pixels = NULL;
	unsigned char *from, *to;
	unsigned short *pixels16 = NULL, *to16;
	float *from_float, from_straight[4];
	png_bytepp row_pointers = NULL;
	int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY;
	FILE *fp = NULL;

	int is_16bit = (ibuf->ftype & PNG_16BIT) && ibuf->rect_float;

	/* use the jpeg quality setting for compression */
	int compression;
	compression = (int)(((float)(ibuf->ftype & 0xff) / 11.1111f));
	compression = compression < 0 ? 0 : (compression > 9 ? 9 : compression);

	/* for prints */
	if (flags & IB_mem)
		name = "<memory>";

	bytesperpixel = (ibuf->planes + 7) >> 3;
	if ((bytesperpixel > 4) || (bytesperpixel == 2)) {
		printf("imb_savepng: Cunsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, name);
		return (0);
	}

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
	                                  NULL, NULL, NULL);
	if (png_ptr == NULL) {
		printf("imb_savepng: Cannot png_create_write_struct for file: '%s'\n", name);
		return 0;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		printf("imb_savepng: Cannot png_create_info_struct for file: '%s'\n", name);
		return 0;
	}

	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		printf("imb_savepng: Cannot setjmp for file: '%s'\n", name);
		return 0;
	}

	/* copy image data */

	if (is_16bit)
		pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned short), "png 16bit pixels");
	else
		pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "png 8bit pixels");

	if (pixels == NULL && pixels16 == NULL) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name);
		return 0;
	}

	from = (unsigned char *) ibuf->rect;
	to = pixels;
	from_float = ibuf->rect_float;
	to16 = pixels16;

	switch (bytesperpixel) {
		case 4:
			color_type = PNG_COLOR_TYPE_RGBA;
			if (is_16bit) {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					premul_to_straight_v4(from_straight, from_float);
					to16[0] = FTOUSHORT(from_straight[0]);
					to16[1] = FTOUSHORT(from_straight[1]);
					to16[2] = FTOUSHORT(from_straight[2]);
					to16[3] = FTOUSHORT(from_straight[3]);
					to16 += 4; from_float += 4;
				}
			}
			else {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					to[0] = from[0];
					to[1] = from[1];
					to[2] = from[2];
					to[3] = from[3];
					to += 4; from += 4;
				}
			}
			break;
		case 3:
			color_type = PNG_COLOR_TYPE_RGB;
			if (is_16bit) {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					premul_to_straight_v4(from_straight, from_float);
					to16[0] = FTOUSHORT(from_straight[0]);
					to16[1] = FTOUSHORT(from_straight[1]);
					to16[2] = FTOUSHORT(from_straight[2]);
					to16 += 3; from_float += 4;
				}
			}
			else {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					to[0] = from[0];
					to[1] = from[1];
					to[2] = from[2];
					to += 3; from += 4;
				}
			}
			break;
		case 1:
			color_type = PNG_COLOR_TYPE_GRAY;
			if (is_16bit) {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					premul_to_straight_v4(from_straight, from_float);
					to16[0] = FTOUSHORT(from_straight[0]);
					to16++; from_float += 4;
				}
			}
			else {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					to[0] = from[0];
					to++; from += 4;
				}
			}
			break;
	}

	if (flags & IB_mem) {
		/* create image in memory */
		imb_addencodedbufferImBuf(ibuf);
		ibuf->encodedsize = 0;

		png_set_write_fn(png_ptr,
		                 (png_voidp) ibuf,
		                 WriteData,
		                 Flush);
	}
	else {
		fp = BLI_fopen(name, "wb");
		if (!fp) {
			png_destroy_write_struct(&png_ptr, &info_ptr);
			if (pixels)
				MEM_freeN(pixels);
			if (pixels16)
				MEM_freeN(pixels16);
			printf("imb_savepng: Cannot open file for writing: '%s'\n", name);
			return 0;
		}
		png_init_io(png_ptr, fp);
	}

#if 0
	png_set_filter(png_ptr, 0,
	               PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE  |
	               PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB   |
	               PNG_FILTER_UP    | PNG_FILTER_VALUE_UP    |
	               PNG_FILTER_AVG   | PNG_FILTER_VALUE_AVG   |
	               PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH |
	               PNG_ALL_FILTERS);
#endif

	png_set_compression_level(png_ptr, compression);

	/* png image settings */
	png_set_IHDR(png_ptr,
	             info_ptr,
	             ibuf->x,
	             ibuf->y,
	             is_16bit ? 16 : 8,
	             color_type,
	             PNG_INTERLACE_NONE,
	             PNG_COMPRESSION_TYPE_DEFAULT,
	             PNG_FILTER_TYPE_DEFAULT);

	/* image text info */
	if (ibuf->metadata) {
		png_text *metadata;
		ImMetaData *iptr;
		int num_text = 0;
		iptr = ibuf->metadata;
		while (iptr) {
			num_text++;
			iptr = iptr->next;
		}
		
		metadata = MEM_callocN(num_text * sizeof(png_text), "png_metadata");
		iptr = ibuf->metadata;
		num_text = 0;
		while (iptr) {
			
			metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
			metadata[num_text].key = iptr->key;
			metadata[num_text].text = iptr->value;
			num_text++;
			iptr = iptr->next;
		}
		
		png_set_text(png_ptr, info_ptr, metadata, num_text);
		MEM_freeN(metadata);

	}

	if (ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) {
		png_set_pHYs(png_ptr, info_ptr, (unsigned int)(ibuf->ppm[0] + 0.5), (unsigned int)(ibuf->ppm[1] + 0.5), PNG_RESOLUTION_METER);
	}

	/* write the file header information */
	png_write_info(png_ptr, info_ptr);

#ifdef __LITTLE_ENDIAN__
	png_set_swap(png_ptr);
#endif

	/* allocate memory for an array of row-pointers */
	row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
	if (row_pointers == NULL) {
		printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name);
		png_destroy_write_struct(&png_ptr, &info_ptr);
		if (pixels)
			MEM_freeN(pixels);
		if (pixels16)
			MEM_freeN(pixels16);
		if (fp) {
			fclose(fp);
		}
		return 0;
	}

	/* set the individual row-pointers to point at the correct offsets */
	if (is_16bit) {
		for (i = 0; i < ibuf->y; i++) {
			row_pointers[ibuf->y - 1 - i] = (png_bytep)
			                                ((unsigned short *)pixels16 + (i * ibuf->x) * bytesperpixel);
		}
	}
	else {
		for (i = 0; i < ibuf->y; i++) {
			row_pointers[ibuf->y - 1 - i] = (png_bytep)
			                                ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
		}
	}

	/* write out the entire image data in one call */
	png_write_image(png_ptr, row_pointers);

	/* write the additional chunks to the PNG file (not really needed) */
	png_write_end(png_ptr, info_ptr);

	/* clean up */
	if (pixels)
		MEM_freeN(pixels);
	if (pixels16)
		MEM_freeN(pixels16);
	MEM_freeN(row_pointers);
	png_destroy_write_struct(&png_ptr, &info_ptr);

	if (fp) {
		fflush(fp);
		fclose(fp);
	}

	return(1);
}
Example #17
0
/* returns 0 for success, 2 for libpng problem, 4 for out of memory, 11 for
 *  unexpected pnmtype; note that outfile might be stdout */
int writepng_init(mainprog_info *mainprog_ptr)
{
/*  This has been altered
    png_structp  png_ptr;*/       /* note:  temporary variables! */

    png_infop  info_ptr;
    int color_type, interlace_type;


    /* could also replace libpng warning-handler (final NULL), but no need: */
/*  This was altered
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr,
      writepng_error_handler, NULL); */
    if (!png_ptr)
        return 4;   /* out of memory */

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_write_struct(&png_ptr, NULL);
        return 4;   /* out of memory */
    }

    /* setjmp() must be called in every function that calls a PNG-writing
     * libpng function, unless an alternate error handler was installed--
     * but compatible error handlers must either use longjmp() themselves
     * (as in this program) or exit immediately, so here we go: */

    if (setjmp(mainprog_ptr->jmpbuf)) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return 2;
    }


    /* make sure outfile is (re)opened in BINARY mode */

/*  This was altered
    png_init_io(png_ptr, mainprog_ptr->outfile); */


    /* set the compression levels--in general, always want to leave filtering
     * turned on (except for palette images) and allow all of the filters,
     * which is the default; want 32K zlib window, unless entire image buffer
     * is 16K or smaller (unknown here)--also the default; usually want max
     * compression (NOT the default); and remaining compression flags should
     * be left alone */

    png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
/*
    >> this is default for no filtering; Z_FILTERED is default otherwise:
    png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
    >> these are all defaults:
    png_set_compression_mem_level(png_ptr, 8);
    png_set_compression_window_bits(png_ptr, 15);
    png_set_compression_method(png_ptr, 8);
 */


    /* set the image parameters appropriately */

    if (mainprog_ptr->pnmtype == 5)
        color_type = PNG_COLOR_TYPE_GRAY;
    else if (mainprog_ptr->pnmtype == 6)
        color_type = PNG_COLOR_TYPE_RGB;
    else if (mainprog_ptr->pnmtype == 8)
        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
    else {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return 11;
    }

    interlace_type = mainprog_ptr->interlaced? PNG_INTERLACE_ADAM7 :
                                               PNG_INTERLACE_NONE;

    png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height,
      mainprog_ptr->sample_depth, color_type, interlace_type,
      PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

    if (mainprog_ptr->gamma > 0.0)
        png_set_gAMA(png_ptr, info_ptr, mainprog_ptr->gamma);

    if (mainprog_ptr->have_bg) {   /* we know it's RGBA, not gray+alpha */
        png_color_16  background;

        background.red = mainprog_ptr->bg_red;
        background.green = mainprog_ptr->bg_green;
        background.blue = mainprog_ptr->bg_blue;
        png_set_bKGD(png_ptr, info_ptr, &background);
    }

    if (mainprog_ptr->have_time) {
        png_time  modtime;

        png_convert_from_time_t(&modtime, mainprog_ptr->modtime);
        png_set_tIME(png_ptr, info_ptr, &modtime);
    }

    if (mainprog_ptr->have_text) {
        png_text  text[6];
        int  num_text = 0;

        if (mainprog_ptr->have_text & TEXT_TITLE) {
            text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
            text[num_text].key = "Title";
            text[num_text].text = mainprog_ptr->title;
            ++num_text;
        }
        if (mainprog_ptr->have_text & TEXT_AUTHOR) {
            text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
            text[num_text].key = "Author";
            text[num_text].text = mainprog_ptr->author;
            ++num_text;
        }
        if (mainprog_ptr->have_text & TEXT_DESC) {
            text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
            text[num_text].key = "Description";
            text[num_text].text = mainprog_ptr->desc;
            ++num_text;
        }
        if (mainprog_ptr->have_text & TEXT_COPY) {
            text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
            text[num_text].key = "Copyright";
            text[num_text].text = mainprog_ptr->copyright;
            ++num_text;
        }
        if (mainprog_ptr->have_text & TEXT_EMAIL) {
            text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
            text[num_text].key = "E-mail";
            text[num_text].text = mainprog_ptr->email;
            ++num_text;
        }
        if (mainprog_ptr->have_text & TEXT_URL) {
            text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
            text[num_text].key = "URL";
            text[num_text].text = mainprog_ptr->url;
            ++num_text;
        }
        png_set_text(png_ptr, info_ptr, text, num_text);
    }


    /* write all chunks up to (but not including) first IDAT */

    png_write_info(png_ptr, info_ptr);


    /* if we wanted to write any more text info *after* the image data, we
     * would set up text struct(s) here and call png_set_text() again, with
     * just the new data; png_set_tIME() could also go here, but it would
     * have no effect since we already called it above (only one tIME chunk
     * allowed) */


    /* set up the transformations:  for now, just pack low-bit-depth pixels
     * into bytes (one, two or four pixels per byte) */

    png_set_packing(png_ptr);
/*  png_set_shift(png_ptr, &sig_bit);  to scale low-bit-depth values */


    /* make sure we save our pointers for use in writepng_encode_image() */

    mainprog_ptr->png_ptr = png_ptr;
    mainprog_ptr->info_ptr = info_ptr;


    /* OK, that's all we need to do for now; return happy */
    return 0;
}
Example #18
0
static BOOL 
WriteMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
	// XMP keyword
	const char *g_png_xmp_keyword = "XML:com.adobe.xmp";

	FITAG *tag = NULL;
	FIMETADATA *mdhandle = NULL;
	BOOL bResult = TRUE;

	png_text text_metadata;
	png_time mod_time;

	// set the 'Comments' metadata as iTXt chuncks

	mdhandle = FreeImage_FindFirstMetadata(FIMD_COMMENTS, dib, &tag);

	if(mdhandle) {
		do {
			memset(&text_metadata, 0, sizeof(png_text));
			text_metadata.compression = 1;							// iTXt, none
			text_metadata.key = (char*)FreeImage_GetTagKey(tag);	// keyword, 1-79 character description of "text"
			text_metadata.text = (char*)FreeImage_GetTagValue(tag);	// comment, may be an empty string (ie "")
			text_metadata.text_length = FreeImage_GetTagLength(tag);// length of the text string
			text_metadata.itxt_length = FreeImage_GetTagLength(tag);// length of the itxt string
			text_metadata.lang = 0;		 // language code, 0-79 characters or a NULL pointer
			text_metadata.lang_key = 0;	 // keyword translated UTF-8 string, 0 or more chars or a NULL pointer

			// set the tag 
			png_set_text(png_ptr, info_ptr, &text_metadata, 1);

		} while(FreeImage_FindNextMetadata(mdhandle, &tag));

		FreeImage_FindCloseMetadata(mdhandle);
		bResult &= TRUE;
	}

	// set the 'XMP' metadata as iTXt chuncks
	tag = NULL;
	FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag);
	if(tag && FreeImage_GetTagLength(tag)) {
		memset(&text_metadata, 0, sizeof(png_text));
		text_metadata.compression = 1;							// iTXt, none
		text_metadata.key = (char*)g_png_xmp_keyword;					// keyword, 1-79 character description of "text"
		text_metadata.text = (char*)FreeImage_GetTagValue(tag);	// comment, may be an empty string (ie "")
		text_metadata.text_length = FreeImage_GetTagLength(tag);// length of the text string
		text_metadata.itxt_length = FreeImage_GetTagLength(tag);// length of the itxt string
		text_metadata.lang = 0;		 // language code, 0-79 characters or a NULL pointer
		text_metadata.lang_key = 0;	 // keyword translated UTF-8 string, 0 or more chars or a NULL pointer

		// set the tag 
		png_set_text(png_ptr, info_ptr, &text_metadata, 1);
		bResult &= TRUE;
	}

	// set the Exif-TIFF 'DateTime' metadata as a tIME chunk
	tag = NULL;
	FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "DateTime", &tag);
	if(tag && FreeImage_GetTagLength(tag)) {
		int year, month, day, hour, minute, second;
		const char *value = (char*)FreeImage_GetTagValue(tag);
		if(sscanf(value, "%4d:%02d:%02d %2d:%02d:%02d", &year, &month, &day, &hour, &minute, &second) == 6) {
			mod_time.year = year;
			mod_time.month = month;
			mod_time.day = day;
			mod_time.hour = hour;
			mod_time.minute = minute;
			mod_time.second = second;
			png_set_tIME (png_ptr, info_ptr, &mod_time);
		}
	}

	return bResult;
}
Example #19
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;
}
Example #20
0
static int write_file(struct img_pixmap *img, struct img_io *io)
{
	png_struct *png;
	png_info *info;
	png_text txt;
	struct img_pixmap tmpimg;
	unsigned char **rows;
	unsigned char *pixptr;
	int i, coltype;

	img_init(&tmpimg);

	if(!(png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
		return -1;
	}
	if(!(info = png_create_info_struct(png))) {
		png_destroy_write_struct(&png, 0);
		return -1;
	}

	/* if the input image is floating-point, we need to convert it to integer */
	if(img_is_float(img)) {
		if(img_copy(&tmpimg, img) == -1) {
			return -1;
		}
		if(img_to_integer(&tmpimg) == -1) {
			img_destroy(&tmpimg);
			return -1;
		}
		img = &tmpimg;
	}

	txt.compression = PNG_TEXT_COMPRESSION_NONE;
	txt.key = "Software";
	txt.text = "libimago2";
	txt.text_length = 0;

	if(setjmp(png_jmpbuf(png))) {
		png_destroy_write_struct(&png, &info);
		img_destroy(&tmpimg);
		return -1;
	}
	png_set_write_fn(png, io, write_func, flush_func);

	coltype = fmt_to_png_type(img->fmt);
	png_set_IHDR(png, info, img->width, img->height, 8, coltype, PNG_INTERLACE_NONE,
			PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
	png_set_text(png, info, &txt, 1);

	if(!(rows = malloc(img->height * sizeof *rows))) {
		png_destroy_write_struct(&png, &info);
		img_destroy(&tmpimg);
		return -1;
	}

	pixptr = img->pixels;
	for(i=0; i<img->height; i++) {
		rows[i] = pixptr;
		pixptr += img->width * img->pixelsz;
	}
	png_set_rows(png, info, rows);

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

	free(rows);

	img_destroy(&tmpimg);
	return 0;
}
Example #21
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);
}
Example #22
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;
	}
Example #23
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;
}
Example #24
0
/* write a png file */
int write_png(char *file_name, int width, int height,BYTE *prgb_data)
{
	int l=0;
	FILE *fp;
	png_structp png_ptr;
	png_infop info_ptr;
	png_text text_ptr[3];

	png_bytep row_pointers[height];
	/* open the file */
	fp = fopen(file_name, "wb");
	if (fp == NULL)
	return (1);

	/* 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.
	*/
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
		NULL, NULL, NULL);

	if (png_ptr == NULL)
	{
		fclose(fp);
		return (2);
	}
	
	/* Allocate/initialize the image information data. */
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL)
	{
		fclose(fp);
		png_destroy_write_struct(&png_ptr, NULL);
		return (3);
	}
  
	/* 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 */
		fclose(fp);
		png_destroy_write_struct(&png_ptr, &info_ptr);
		return (4);
	}

	/* set up the output control using standard C streams */
	png_init_io(png_ptr, fp);
	
	/* turn on or off filtering, and/or choose
	specific filters.  You can use either a single
	PNG_FILTER_VALUE_NAME or the bitwise OR of one
	or more PNG_FILTER_NAME masks. */
	/* png_set_filter(png_ptr, 0,
	PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE |
	PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB  |
	PNG_FILTER_UP    | PNG_FILTER_VALUE_UP   |
	PNG_FILTER_AVE   | PNG_FILTER_VALUE_AVE  |
	PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
	PNG_ALL_FILTERS);*/
	
	/* set the zlib compression level */
	//png_set_compression_level(png_ptr,
	//	Z_BEST_COMPRESSION);

	/* set other zlib parameters */
	//png_set_compression_mem_level(png_ptr, 8);
	//png_set_compression_strategy(png_ptr,
	//	Z_DEFAULT_STRATEGY);
	//png_set_compression_window_bits(png_ptr, 15);
	//png_set_compression_method(png_ptr, 8);
	//png_set_compression_buffer_size(png_ptr, 8192);
	
	png_set_IHDR(png_ptr, info_ptr, width, height,
		8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	/* 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 = file_name;
	text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
	text_ptr[1].key = "Software";
	text_ptr[1].text = "guvcview";
	text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
	text_ptr[2].key = "Description";
	text_ptr[2].text = "File generated by guvcview <http://guvcview.sourceforge.net>";
	text_ptr[2].compression = PNG_TEXT_COMPRESSION_NONE;
#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);

	/* Write the file header information.  REQUIRED */
	png_write_info(png_ptr, info_ptr);
	
	/* flip BGR pixels to RGB */
	//png_set_bgr(png_ptr); /*?no longuer required?*/
	
	/* Write the image data.*/
	for (l = 0; l < height; l++)
		row_pointers[l] = prgb_data + l*width*3;

	png_write_image(png_ptr, row_pointers);
	
	/* You can write optional chunks like tEXt, zTXt, and tIME at the end
	* as well.  Shouldn't be necessary in 1.1.0 and up as all the public
	* chunks are supported and you can use png_set_unknown_chunks() to
	* register unknown chunks into the info structure to be written out.
	*/

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

	/* If you png_malloced a palette, free it here (don't free info_ptr->palette,
	as recommended in versions 1.0.5m and earlier of this example; if
	libpng mallocs info_ptr->palette, libpng will free it).  If you
	allocated it with malloc() instead of png_malloc(), use free() instead
	of png_free(). */
	//png_free(png_ptr, palette);
	//palette=NULL;

	/* 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, trans);
	//trans=NULL;

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

	/* close the file */
	fflush(fp); //flush data stream to file system
	if(fsync(fileno(fp)) || fclose(fp))
	{
		perror("PNG ERROR - couldn't write to file");
		return(5);
	}
	
	for(l=0;l<height;l++) 
	{
		row_pointers[l]=NULL;
	}

	/* that's it */
	return (0);
}
Example #25
0
File: png.c Project: jinjoh/NOOR
short imb_savepng(struct ImBuf *ibuf, char *name, int flags)
{
    png_structp png_ptr;
    png_infop info_ptr;

    unsigned char *pixels = 0;
    unsigned char *from, *to;
    png_bytepp row_pointers = 0;
    int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY;
    FILE *fp = 0;

    bytesperpixel = (ibuf->depth + 7) >> 3;
    if ((bytesperpixel > 4) || (bytesperpixel == 2)) {
        printf("imb_savepng: unsupported bytes per pixel: %d\n", bytesperpixel);
        return (0);
    }

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                      NULL, NULL, NULL);
    if (png_ptr == NULL) {
        printf("Cannot png_create_write_struct\n");
        return 0;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        printf("Cannot png_create_info_struct\n");
        return 0;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        if (pixels) MEM_freeN(pixels);
        if (row_pointers) MEM_freeN(row_pointers);
        // printf("Aborting\n");
        if (fp) {
            fflush(fp);
            fclose(fp);
        }
        return 0;
    }

    // copy image data

    pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
    if (pixels == NULL) {
        printf("Cannot allocate pixels array\n");
        return 0;
    }

    from = (unsigned char *) ibuf->rect;
    to = pixels;

    switch (bytesperpixel) {
    case 4:
        color_type = PNG_COLOR_TYPE_RGBA;
        for (i = ibuf->x * ibuf->y; i > 0; i--) {
            to[0] = from[0];
            to[1] = from[1];
            to[2] = from[2];
            to[3] = from[3];
            to += 4;
            from += 4;
        }
        break;
    case 3:
        color_type = PNG_COLOR_TYPE_RGB;
        for (i = ibuf->x * ibuf->y; i > 0; i--) {
            to[0] = from[0];
            to[1] = from[1];
            to[2] = from[2];
            to += 3;
            from += 4;
        }
        break;
    case 1:
        color_type = PNG_COLOR_TYPE_GRAY;
        for (i = ibuf->x * ibuf->y; i > 0; i--) {
            to[0] = from[0];
            to++;
            from += 4;
        }
        break;
    }

    if (flags & IB_mem) {
        // create image in memory
        imb_addencodedbufferImBuf(ibuf);
        ibuf->encodedsize = 0;

        png_set_write_fn(png_ptr,
                         (png_voidp) ibuf,
                         WriteData,
                         Flush);
    } else {
        fp = fopen(name, "wb");
        if (!fp) {
            MEM_freeN(pixels);
            return 0;
        }
        png_init_io(png_ptr, fp);
    }

    /*
    png_set_filter(png_ptr, 0,
    	PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE |
    	PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB  |
    	PNG_FILTER_UP    | PNG_FILTER_VALUE_UP   |
    	PNG_FILTER_AVG   | PNG_FILTER_VALUE_AVG  |
    	PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
    	PNG_ALL_FILTERS);

    png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
    */

    // png image settings
    png_set_IHDR(png_ptr,
                 info_ptr,
                 ibuf->x,
                 ibuf->y,
                 8,
                 color_type,
                 PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);

    /* image text info */
    if (ibuf->img_info) {
        png_text*  imginfo;
        ImgInfo* iptr;
        int  num_text = 0;
        iptr = ibuf->img_info;
        while (iptr) {
            num_text++;
            iptr = iptr->next;
        }

        imginfo = MEM_callocN(num_text*sizeof(png_text), "png_imginfo");
        iptr = ibuf->img_info;
        num_text = 0;
        while (iptr) {

            imginfo[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
            imginfo[num_text].key = iptr->key;
            imginfo[num_text].text = iptr->value;
            num_text++;
            iptr = iptr->next;
        }

        png_set_text(png_ptr, info_ptr, imginfo, num_text);
        MEM_freeN(imginfo);

    }

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

    // allocate memory for an array of row-pointers
    row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
    if (row_pointers == NULL) {
        printf("Cannot allocate row-pointers array\n");
        MEM_freeN(pixels);
        return 0;
    }

    // set the individual row-pointers to point at the correct offsets
    for (i = 0; i < ibuf->y; i++) {
        row_pointers[ibuf->y-1-i] = (png_bytep)
                                    ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
    }

    // write out the entire image data in one call
    png_write_image(png_ptr, row_pointers);

    // write the additional chunks to the PNG file (not really needed)
    png_write_end(png_ptr, info_ptr);

    // clean up
    MEM_freeN(pixels);
    MEM_freeN(row_pointers);
    png_destroy_write_struct(&png_ptr, &info_ptr);

    if (fp) {
        fflush(fp);
        fclose(fp);
    }

    return(1);
}
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
}
Example #27
0
/*!
 *  pixWriteStreamPng()
 *
 *      Input:  stream
 *              pix
 *              gamma (use 0.0 if gamma is not defined)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) If called from pixWriteStream(), the stream is positioned
 *          at the beginning of the file.
 *      (2) To do sequential writes of png format images to a stream,
 *          use pixWriteStreamPng() directly.
 *      (3) gamma is an optional png chunk.  If no gamma value is to be
 *          placed into the file, use gamma = 0.0.  Otherwise, if
 *          gamma > 0.0, its value is written into the header.
 *      (4) The use of gamma in png is highly problematic.  For an illuminating
 *          discussion, see:  http://hsivonen.iki.fi/png-gamma/
 *      (5) What is the effect/meaning of gamma in the png file?  This
 *          gamma, which we can call the 'source' gamma, is the
 *          inverse of the gamma that was used in enhance.c to brighten
 *          or darken images.  The 'source' gamma is supposed to indicate
 *          the intensity mapping that was done at the time the
 *          image was captured.  Display programs typically apply a
 *          'display' gamma of 2.2 to the output, which is intended
 *          to linearize the intensity based on the response of
 *          thermionic tubes (CRTs).  Flat panel LCDs have typically
 *          been designed to give a similar response as CRTs (call it
 *          "backward compatibility").  The 'display' gamma is
 *          in some sense the inverse of the 'source' gamma.
 *          jpeg encoders attached to scanners and cameras will lighten
 *          the pixels, applying a gamma corresponding to approximately
 *          a square-root relation of output vs input:
 *                output = input^(gamma)
 *          where gamma is often set near 0.4545  (1/gamma is 2.2).
 *          This is stored in the image file.  Then if the display
 *          program reads the gamma, it will apply a display gamma,
 *          typically about 2.2; the product is 1.0, and the
 *          display program produces a linear output.  This works because
 *          the dark colors were appropriately boosted by the scanner,
 *          as described by the 'source' gamma, so they should not
 *          be further boosted by the display program.
 *      (6) As an example, with xv and display, if no gamma is stored,
 *          the program acts as if gamma were 0.4545, multiplies this by 2.2,
 *          and does a linear rendering.  Taking this as a baseline
 *          brightness, if the stored gamma is:
 *              > 0.4545, the image is rendered lighter than baseline
 *              < 0.4545, the image is rendered darker than baseline
 *          In contrast, gqview seems to ignore the gamma chunk in png.
 *      (7) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16
 *          and 32.  However, it is possible, and in some cases desirable,
 *          to write out a png file using an rgb pix that has 24 bpp.
 *          For example, the open source xpdf SplashBitmap class generates
 *          24 bpp rgb images.  Consequently, we anble writing 24 bpp pix.
 *          To generate such a pix, you can make a 24 bpp pix without data
 *          and assign the data array to the pix; e.g.,
 *              pix = pixCreateHeader(w, h, 24);
 *              pixSetData(pix, rgbdata);
 *          See pixConvert32To24() for an example, where we get rgbdata
 *          from the 32 bpp pix.  Caution: do not call pixSetPadBits(),
 *          because the alignment is wrong and you may erase part of the
 *          last pixel on each line.
 */
l_int32
pixWriteStreamPng(FILE      *fp,
                  PIX       *pix,
                  l_float32  gamma)
{
char         commentstring[] = "Comment";
l_int32      i, j, k;
l_int32      wpl, d, cmflag;
l_int32      ncolors;
l_int32     *rmap, *gmap, *bmap;
l_uint32    *data, *ppixel;
png_byte     bit_depth, color_type;
png_uint_32  w, h;
png_uint_32  xres, yres;
png_bytep   *row_pointers;
png_bytep    rowbuffer;
png_structp  png_ptr;
png_infop    info_ptr;
png_colorp   palette;
PIX         *pixt;
PIXCMAP     *cmap;
char        *text;

    PROCNAME("pixWriteStreamPng");

    if (!fp)
        return ERROR_INT("stream not open", procName, 1);
    if (!pix)
        return ERROR_INT("pix not defined", procName, 1);

        /* Allocate the 2 data structures */
    if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                   (png_voidp)NULL, NULL, NULL)) == NULL)
        return ERROR_INT("png_ptr not made", procName, 1);

    if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        return ERROR_INT("info_ptr not made", procName, 1);
    }

        /* Set up png setjmp error handling */
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return ERROR_INT("internal png error", procName, 1);
    }

    png_init_io(png_ptr, fp);

        /* With best zlib compression (9), get between 1 and 10% improvement
         * over default (5), but the compression is 3 to 10 times slower.
         * Our default compression is the zlib default (5). */
    png_set_compression_level(png_ptr, var_ZLIB_COMPRESSION);

    w = pixGetWidth(pix);
    h = pixGetHeight(pix);
    d = pixGetDepth(pix);
    if ((cmap = pixGetColormap(pix)))
        cmflag = 1;
    else
        cmflag = 0;

        /* Set the color type and bit depth. */
    if (d == 32 && var_PNG_WRITE_ALPHA == 1) {
        bit_depth = 8;
        color_type = PNG_COLOR_TYPE_RGBA;   /* 6 */
        cmflag = 0;  /* ignore if it exists */
    }
    else if (d == 24 || d == 32) {
        bit_depth = 8;
        color_type = PNG_COLOR_TYPE_RGB;   /* 2 */
        cmflag = 0;  /* ignore if it exists */
    }
    else {
        bit_depth = d;
        color_type = PNG_COLOR_TYPE_GRAY;  /* 0 */
    }
    if (cmflag)
        color_type = PNG_COLOR_TYPE_PALETTE;  /* 3 */

#if  DEBUG
    fprintf(stderr, "cmflag = %d, bit_depth = %d, color_type = %d\n",
            cmflag, bit_depth, color_type);
#endif  /* DEBUG */

    png_set_IHDR(png_ptr, info_ptr, w, h, bit_depth, color_type,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                 PNG_FILTER_TYPE_BASE);

        /* Store resolution in ppm, if known */
    xres = (png_uint_32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5);
    yres = (png_uint_32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5);
    if ((xres == 0) || (yres == 0))
        png_set_pHYs(png_ptr, info_ptr, 0, 0, PNG_RESOLUTION_UNKNOWN);
    else
        png_set_pHYs(png_ptr, info_ptr, xres, yres, PNG_RESOLUTION_METER);

    if (cmflag) {
        pixcmapToArrays(cmap, &rmap, &gmap, &bmap);
        ncolors = pixcmapGetCount(cmap);

            /* Make and save the palette */
        if ((palette = (png_colorp)(CALLOC(ncolors, sizeof(png_color))))
                == NULL)
            return ERROR_INT("palette not made", procName, 1);

        for (i = 0; i < ncolors; i++) {
            palette[i].red = (png_byte)rmap[i];
            palette[i].green = (png_byte)gmap[i];
            palette[i].blue = (png_byte)bmap[i];
        }

        png_set_PLTE(png_ptr, info_ptr, palette, (int)ncolors);
        FREE(rmap);
        FREE(gmap);
        FREE(bmap);
    }

        /* 0.4545 is treated as the default by some image
         * display programs (not gqview).  A value > 0.4545 will
         * lighten an image as displayed by xv, display, etc. */
    if (gamma > 0.0)
        png_set_gAMA(png_ptr, info_ptr, (l_float64)gamma);

    if ((text = pixGetText(pix))) {
        png_text text_chunk;
        text_chunk.compression = PNG_TEXT_COMPRESSION_NONE;
        text_chunk.key = commentstring;
        text_chunk.text = text;
        text_chunk.text_length = strlen(text);
#ifdef PNG_ITXT_SUPPORTED
        text_chunk.itxt_length = 0;
        text_chunk.lang = NULL;
        text_chunk.lang_key = NULL;
#endif
        png_set_text(png_ptr, info_ptr, &text_chunk, 1);
    }

        /* Write header and palette info */
    png_write_info(png_ptr, info_ptr);

    if ((d != 32) && (d != 24)) {  /* not rgb color */
            /* Generate a temporary pix with bytes swapped.
             * For a binary image, there are two conditions in
             * which you must first invert the data for writing png:
             *    (a) no colormap
             *    (b) colormap with BLACK set to 0
             * png writes binary with BLACK = 0, unless contradicted
             * by a colormap.  If the colormap has BLACK = "1"
             * (typ. about 255), do not invert the data.  If there
             * is no colormap, you must invert the data to store
             * in default BLACK = 0 state.  */
        if (d == 1 &&
            (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) {
            pixt = pixInvert(NULL, pix);
            pixEndianByteSwap(pixt);
        }
        else
            pixt = pixEndianByteSwapNew(pix);
        if (!pixt) {
            png_destroy_write_struct(&png_ptr, &info_ptr);
            return ERROR_INT("pixt not made", procName, 1);
        }

            /* Make and assign array of image row pointers */
        if ((row_pointers = (png_bytep *)CALLOC(h, sizeof(png_bytep))) == NULL)
            return ERROR_INT("row-pointers not made", procName, 1);
        wpl = pixGetWpl(pixt);
        data = pixGetData(pixt);
        for (i = 0; i < h; i++)
            row_pointers[i] = (png_bytep)(data + i * wpl);
        png_set_rows(png_ptr, info_ptr, row_pointers);

            /* Transfer the data */
        png_write_image(png_ptr, row_pointers);
        png_write_end(png_ptr, info_ptr);

        if (cmflag)
            FREE(palette);
        FREE(row_pointers);
        pixDestroy(&pixt);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return 0;
    }

        /* For rgb, compose and write a row at a time */
    data = pixGetData(pix);
    wpl = pixGetWpl(pix);
    if (d == 24) {  /* See note 7 above: special case of 24 bpp rgb */
        for (i = 0; i < h; i++) {
            ppixel = data + i * wpl;
            png_write_rows(png_ptr, (png_bytepp)&ppixel, 1);
        }
    }
    else {  /* 32 bpp rgb and rgba */
        if ((rowbuffer = (png_bytep)CALLOC(w, 4)) == NULL)
            return ERROR_INT("rowbuffer not made", procName, 1);
        for (i = 0; i < h; i++) {
            ppixel = data + i * wpl;
            for (j = k = 0; j < w; j++) {
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
                if (var_PNG_WRITE_ALPHA == 1)
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL);
                ppixel++;
            }

            png_write_rows(png_ptr, &rowbuffer, 1);
        }
        FREE(rowbuffer);
    }

    png_write_end(png_ptr, info_ptr);

    if (cmflag)
        FREE(palette);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    return 0;

}
Example #28
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;
}
Example #29
0
int begin(char* base_file_name, unsigned char *png_buf, long long png_length) {

  MY_PNG_READ_OFFSET = 0;
  PNG_LENGTH = png_length; 
  ENTIRE_PNG_BUF = png_buf;

  if (png_sig_cmp(ENTIRE_PNG_BUF, 0, 8) != 0) {
    error(-1, "png_sig_cmp", E_INVALID);
    return -1;
  }

  DEBUG_PRINT(("Initial png size is %lld bytes\n", PNG_LENGTH));

  my_png_meta *pm = calloc(1, sizeof(my_png_meta));
  my_init_libpng(pm);

  //If libpng errors, we end up here
  if (setjmp(png_jmpbuf(pm->read_ptr))) {
    DEBUG_PRINT(("libpng called setjmp!\n"));
    my_deinit_libpng(pm);
    free(ENTIRE_PNG_BUF);
    error(-1, "libpng", "libpng encountered an error\n");
    return -1;
  }

  //Normally a file, but instead make it our buffer
  void *read_io_ptr = png_get_io_ptr(pm->read_ptr);
  png_set_read_fn(pm->read_ptr, read_io_ptr, my_png_read_fn);

  //Transform all PNG image types to RGB
  int transforms = 
    PNG_TRANSFORM_GRAY_TO_RGB |
    PNG_TRANSFORM_STRIP_ALPHA | 
    PNG_TRANSFORM_EXPAND;

  png_read_png(pm->read_ptr, pm->info_ptr, transforms, NULL);

  //Now that it was read and transformed, its size will differ
  PNG_LENGTH = 0; 

  //Lets collect our metadata
  struct ihdr_infos_s ihdr_infos;
  ihdr_infos.bit_depth        = png_get_bit_depth(pm->read_ptr, pm->info_ptr);
  ihdr_infos.color_type       = png_get_color_type(pm->read_ptr, pm->info_ptr);
  ihdr_infos.filter_method    = png_get_filter_type(pm->read_ptr, pm->info_ptr);
  ihdr_infos.compression_type = png_get_compression_type(pm->read_ptr, pm->info_ptr);
  ihdr_infos.interlace_type   = png_get_interlace_type(pm->read_ptr, pm->info_ptr);
  ihdr_infos.height           = png_get_image_height(pm->read_ptr, pm->info_ptr);
  ihdr_infos.width            = png_get_image_width(pm->read_ptr, pm->info_ptr);

  if (ihdr_infos.color_type != 2) {
    DEBUG_PRINT((E_INVALID));
    free(ENTIRE_PNG_BUF);
    my_deinit_libpng(pm);
    DEBUG_PRINT(("Looks like libpng could not correctly convert to RGB\n"));
    return -1;
  }

  //Just in case we want to enable alpha, etc
  switch(ihdr_infos.color_type) {
    case 0:  //greyscale
    case 3:  //indexed
      ihdr_infos.bytes_per_pixel = 1;
      break;
    case 4: ihdr_infos.bytes_per_pixel = 2; break; //greyscale w/ alpha 
    case 2: ihdr_infos.bytes_per_pixel = 3; break; //Truecolour (RGB)
    case 6: ihdr_infos.bytes_per_pixel = 4; break; //Truecolour w/ alpha
    default: error_fatal(1, "ihdr_infos", "Unknown image type"); //should never happen
  }

  ihdr_infos.scanline_len = (ihdr_infos.bytes_per_pixel * ihdr_infos.width) + 1;

  DEBUG_PRINT(("HEIGHT: %u\n", ihdr_infos.height));
  DEBUG_PRINT(("WIDTH: %u\n", ihdr_infos.width));
  DEBUG_PRINT(("BIT_DEPTH: %u\n", ihdr_infos.bit_depth));

  // Don't compress, since we are merely copying it to memory,
  // we will be decompressing it again anyway
  png_set_compression_level(pm->write_ptr, Z_NO_COMPRESSION);

  void *write_io_ptr = png_get_io_ptr(pm->write_ptr);
  png_set_write_fn(pm->write_ptr, write_io_ptr, my_png_write_fn, my_png_dummy_flush);

  //Make sure we use all filters
  png_set_filter(pm->write_ptr, 0,
      PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE |
      PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB  |
      PNG_FILTER_UP    | PNG_FILTER_VALUE_UP   |
      PNG_FILTER_AVG   | PNG_FILTER_VALUE_AVG  |
      PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH);

  //Set our comment
  struct png_text_struct comment_struct;

  comment_struct.compression = -1;
  comment_struct.key = " Glitched by pnglitch.xyz ";
  comment_struct.text = NULL;
  comment_struct.text_length = 0;
  
  png_set_text(pm->write_ptr, pm->info_ptr, &comment_struct, 1);

  //Buffer is Written using callback my_png_write_fn to buffer
  //ENTIRE_PNG_BUF. PNG_LENGTH will be updated automatically by it
  png_write_png(pm->write_ptr, pm->info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

  my_deinit_libpng(pm);

  DEBUG_PRINT(("libpng output buf is %lld bytes\n", PNG_LENGTH));

  //Now that libpng has converted the image
  //and we have it in a buffer, we process it by hand with zlib
  struct z_stream_s inflate_stream;
  my_init_zlib(&inflate_stream);
  inflateInit(&inflate_stream);

  //Pointer to keep track of where we are
  unsigned char *pngp = ENTIRE_PNG_BUF;

  //Skip PNG Signature
  pngp += 8; 

  //Get Header
  unsigned char ihdr_bytes_buf[4+4+13+4]; // size + label + content + crc
  buf_read(ihdr_bytes_buf, &pngp, 4+4+13+4);

  //When we run into non-idat chunks, we will want to preserve them.
  //The spec says there's no chunk that needs to go after IDAT,
  //so we can simply concatenate all of these chunks into a buffer
  //then write them all at once after the IHDR
  
  //ancillary chunks, eg comments
  unsigned char *ancil_chunks_buf = calloc(1,1);
  long long ancil_chunks_len = 0;

  unsigned char *unzip_idats_buf = calloc(1, 1);
  long unzip_buf_len = 1;
  long unzip_buf_offset = 0;

  long long zipped_idats_len = 0; //Length of all idats as we read them

  unsigned long accum_png_len = 8 + (4+4+13+4);

  int chunk_count = 0;

  printf("Uncompressing image data...\n");
  while (1) {
    unsigned char chunk_label[4];
    unsigned char chunk_len_buf[4];

    buf_read(chunk_len_buf, &pngp, 4);

    //first 4 bytes are the length of data section
    long chunk_len = four_bytes_to_int(chunk_len_buf);

    accum_png_len += chunk_len + 4 + 4 + 4; // plus len, crc, label
    DEBUG_PRINT(("at %lu --> %lld\n", accum_png_len, PNG_LENGTH));

    //leave at end of buffer
    if (accum_png_len >= PNG_LENGTH)
      break;

    //read the chunk label (name of this header)
    buf_read(chunk_label, &pngp, 4);

    DEBUG_PRINT(("Reading chunk %d with label '%c%c%c%c', size %ld\n",
          chunk_count, chunk_label[0], chunk_label[1], chunk_label[2],
          chunk_label[3], chunk_len));

    chunk_count += 1;

    if (memcmp(chunk_label, "IDAT", 4) == 0) {

      zipped_idats_len += chunk_len;

      //read the chunk's data section
      unsigned char *raw_chunk_buf = calloc(chunk_len, 1);
      buf_read(raw_chunk_buf, &pngp, chunk_len);

      //Tell inflate to uncompress it
      inflate_stream.next_in = raw_chunk_buf; 
      inflate_stream.avail_in = chunk_len; 

      //Now uncompress it (resizes buffer automatically)
      unsigned char *check_uncompress = uncompress_buffer(&inflate_stream, 
          unzip_idats_buf, &unzip_buf_len, &unzip_buf_offset);

      //Stop if error
      if (check_uncompress == NULL) {
        DEBUG_PRINT((E_GLITCH));
        free(ancil_chunks_buf);
        free(raw_chunk_buf);
        free(unzip_idats_buf);
        free(ENTIRE_PNG_BUF);
        return -1;
      }

      //Moving on
      unzip_idats_buf = check_uncompress;
      free(raw_chunk_buf);
      pngp += 4; // skip CRC

    } else { //This is not an idat

      ancil_chunks_buf = realloc(ancil_chunks_buf, 
          ancil_chunks_len + 4 + 4 + chunk_len + 4); //make room for new data

      //append length and label bytes
      append_bytes(ancil_chunks_buf, chunk_len_buf, &ancil_chunks_len, 4);
      append_bytes(ancil_chunks_buf, chunk_label, &ancil_chunks_len, 4);

      //append chunk data
      unsigned char *raw_chunk_buf = calloc(chunk_len, 1);
      buf_read(raw_chunk_buf, &pngp, chunk_len);
      append_bytes(ancil_chunks_buf, raw_chunk_buf, &ancil_chunks_len, chunk_len );

      //append chunk crc
      unsigned char chunk_crc_buf[4];
      buf_read(chunk_crc_buf, &pngp, 4);
      append_bytes(ancil_chunks_buf, chunk_crc_buf, &ancil_chunks_len, 4);

      free(raw_chunk_buf);

      DEBUG_PRINT(("ancillary chunks length: %lld\n", ancil_chunks_len));

    }
  }

  //buf contains all idats uncompressed, concatenated
  unsigned long unzipped_idats_len = inflate_stream.total_out; 
  unzip_idats_buf = realloc(unzip_idats_buf, unzipped_idats_len);

  //we already have ancillary chunks and idats, don't need the original
  free(ENTIRE_PNG_BUF);
  inflateEnd(&inflate_stream);

  printf("Uncompressed %lld bytes to %ld bytes\n", zipped_idats_len, unzipped_idats_len);

  printf("Glitching image data...\n");

  for (int g=0;g<NUM_OUTPUT_FILES;g++) {

    //do glitches
    switch(g) {
      case 5:
        glitch_random(unzip_idats_buf, unzipped_idats_len,
            ihdr_infos.scanline_len, 0.0005);
        break;
      case 6:
        glitch_random_filter(unzip_idats_buf, unzipped_idats_len,
            ihdr_infos.scanline_len);
        break;
      default:
        glitch_filter(unzip_idats_buf, unzipped_idats_len,
            ihdr_infos.scanline_len, g);
    }

    //recompress so we can write them to file
    long long glitched_idats_len = 0;
    unsigned char *glitched_idats = zip_idats(unzip_idats_buf,
        unzipped_idats_len, &glitched_idats_len);

    if (glitched_idats == NULL) {
      DEBUG_PRINT((E_GLITCH));
      free (unzip_idats_buf);
      free (ancil_chunks_buf);
      return -1;
    }

    char path[MAX_PATH_LENGTH];
    bzero(path, MAX_PATH_LENGTH);

    snprintf(path, MAX_PATH_LENGTH, "%s%s%s-%d.png", OUTPUT_DIRECTORY, DIR_SEP,
        base_file_name, g);

    DEBUG_PRINT(("Output file name is %s\n", path));

    FILE *outfp = fopen(path, "wb");

    write_glitched_image(glitched_idats, glitched_idats_len, ihdr_bytes_buf,
        ancil_chunks_buf, ancil_chunks_len, outfp);

    printf("%s\n", path);
    fflush(stdout);

    fclose(outfp);
    free(glitched_idats);
  }

  free(ancil_chunks_buf);
  free(unzip_idats_buf);
  return 0;
}
Example #30
0
/*
TextureToPng

Inputs:
data      : This is an array of RGBA with 8 bits per channel. 4 bytes for each pixel.
row_stride: Determines the amount of bytes per row of pixels.
*/
bool TextureToPng(u8* data, int row_stride, const std::string& filename, int width, int height, bool saveAlpha)
{
	bool success = false;

	if (!data)
		return false;

	char title[] = "Dolphin Screenshot";
	char title_key[] = "Title";
	png_structp png_ptr = nullptr;
	png_infop info_ptr = nullptr;

	// Open file for writing (binary mode)
	File::IOFile fp(filename, "wb");
	if (!fp.IsOpen())
	{
		PanicAlertT("Screenshot failed: Could not open file \"%s\" (error %d)", filename.c_str(), errno);
		goto finalise;
	}

	// Initialize write structure
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
	if (png_ptr == nullptr)
	{
		PanicAlert("Screenshot failed: Could not allocate write struct");
		goto finalise;
	}

	// Initialize info structure
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == nullptr)
	{
		PanicAlert("Screenshot failed: Could not allocate info struct");
		goto finalise;
	}

	// Setup Exception handling
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		PanicAlert("Screenshot failed: Error during PNG creation");
		goto finalise;
	}

	png_init_io(png_ptr, fp.GetHandle());

	// Write header (8 bit color depth)
	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);

	png_text title_text;
	title_text.compression = PNG_TEXT_COMPRESSION_NONE;
	title_text.key = title_key;
	title_text.text = title;
	png_set_text(png_ptr, info_ptr, &title_text, 1);

	png_write_info(png_ptr, info_ptr);

	// Write image data
	for (auto y = 0; y < height; ++y)
	{
		u8* row_ptr = (u8*)data + y * row_stride;
		u8* ptr = row_ptr;
		for (auto x = 0; x < row_stride / 4; ++x)
		{
			if (!saveAlpha)
				ptr[3] = 0xff;
			ptr += 4;
		}
		png_write_row(png_ptr, row_ptr);
	}

	// End write
	png_write_end(png_ptr, nullptr);

	success = true;

finalise:
	if (info_ptr != nullptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
	if (png_ptr != nullptr) png_destroy_write_struct(&png_ptr, (png_infopp)nullptr);

	return success;
}