aboutsummaryrefslogtreecommitdiff
path: root/Src/png/PNGWriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/png/PNGWriter.cpp')
-rw-r--r--Src/png/PNGWriter.cpp193
1 files changed, 193 insertions, 0 deletions
diff --git a/Src/png/PNGWriter.cpp b/Src/png/PNGWriter.cpp
new file mode 100644
index 00000000..76b01ab3
--- /dev/null
+++ b/Src/png/PNGWriter.cpp
@@ -0,0 +1,193 @@
+#include "PNGWriter.h"
+#include "api__png.h"
+#include <png.h>
+#include <wchar.h>
+#include <bfc/platform/strcmp.h>
+
+
+// valid items include "quality" for jpeg files with value "0" to "100"
+// return value is 1 if the config item is supported, 0 if it is not.
+int PNGWriter::setConfig(const wchar_t * item, const wchar_t * value) {
+ return 0; // no config yet
+}
+
+// valid items include "quality" for jpeg files with value "0" to "100", "lossless" returns "1" if it is "0" otherwise
+// return value is 1 if the config item is supported, 0 if it is not.
+int PNGWriter::getConfig(const wchar_t * item, wchar_t * value, int valuelen) {
+ if(!_wcsicmp(item,L"lossless")) lstrcpynW(value,L"1",valuelen);
+ else return 0;
+ return 1;
+}
+
+typedef struct {
+ BYTE * data;
+ unsigned int len;
+ unsigned int alloc;
+} pngWrite;
+
+extern "C" static void PNGAPI png_write(png_structp png_ptr, png_bytep data, png_size_t len) {
+ pngWrite * p = (pngWrite *)png_get_io_ptr(png_ptr);
+ while (len + p->len > p->alloc) { // allocate more memory
+ int d = ((p->alloc / 4) & 0xffffff00) + 0x100;
+ if(d < 4096) d = 4096;
+ p->alloc+=d;
+ p->data = (BYTE*)WASABI_API_MEMMGR->sysRealloc(p->data,p->alloc);
+ }
+ memcpy(p->data+p->len,data,len);
+ p->len += int(len);
+}
+
+extern "C" static void PNGAPI png_flush(png_structp png_ptr) {}
+
+// returns 1 if the bit depth is supported (eg 32 for ARGB32, 24 for RGB24)
+// ARGB32 MUST be supported
+int PNGWriter::bitDepthSupported(int depth) {
+ if(depth == 32 || depth == 24) return 1;
+ return 0;
+}
+
+// returns the image in our format, free the returned buffer with api_memmgr::sysFree()
+void * PNGWriter::convert(const void *pixels0, int bitDepth, int w, int h, int *length) {
+ if(bitDepth != 32 && bitDepth != 24) return 0;
+ BYTE * pixels = (BYTE*)pixels0;
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also check that
+ * the library version is compatible with the one used at compile time,
+ * in case we are using dynamically linked libraries. REQUIRED.
+ */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ (png_voidp*)NULL, NULL, NULL);
+
+ if (png_ptr == NULL)
+ return 0;
+
+ /* 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 0;
+ }
+ pngWrite writer={0};
+
+ /* Set error handling. REQUIRED if you aren't supplying your own
+ * error handling functions in the png_create_write_struct() call.
+ */
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ /* If we get here, we had a problem reading the file */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ if(writer.data) WASABI_API_MEMMGR->sysFree(writer.data);
+ return 0;
+ }
+
+ writer.alloc = (int(double(w*h)*1.25) & 0xffffff00) + 0x100;
+ if (writer.alloc < 4096) writer.alloc = 4096;
+ writer.data = (BYTE*)WASABI_API_MEMMGR->sysMalloc(writer.alloc);
+
+ /* If you are using replacement read functions, instead of calling
+ * png_init_io() here you would call */
+ png_set_write_fn(png_ptr, (void *)&writer, png_write,
+ png_flush);
+
+ /* 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
+ */
+ int colortype = (bitDepth == 32) ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
+ png_set_IHDR(png_ptr, info_ptr, w, h, 8, colortype,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ /* optional significant bit chunk */
+ png_color_8 sig_bit;
+ /* if we are dealing with a grayscale image then */
+ sig_bit.gray = 8;
+ /* 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 = (bitDepth==32)?8:0;
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+ /* Write the file header information. REQUIRED */
+ png_write_info(png_ptr, info_ptr);
+
+ /* set up the transformations you want. Note that these are
+ * all optional. Only call them if you want them.
+ */
+
+ /* 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);
+
+ /* flip BGR pixels to RGB */
+ png_set_bgr(png_ptr);
+
+ /* swap bytes of 16-bit files to most significant byte first */
+ png_set_swap(png_ptr);
+
+ /* swap bits of 1, 2, 4 bit packed pixel formats */
+ png_set_packswap(png_ptr);
+
+ /*if (interlacing)
+ number_passes = png_set_interlace_handling(png_ptr);
+ else*/
+ png_uint_32 number_passes = 1;
+
+ /* 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.
+ */
+ int bytes_per_pixel = bitDepth / 8;
+
+ /* The number of passes is either 1 for non-interlaced images,
+ * or 7 for interlaced images.
+ */
+ for (png_uint_32 pass = 0; pass < number_passes; pass++)
+ {
+ BYTE * row = pixels; // + (h*w*bytes_per_pixel);
+ for (int y = 0; y < h; y++) {
+ //row -= w*bytes_per_pixel;
+ png_write_rows(png_ptr, &row, 1);
+ row += w*bytes_per_pixel;
+ }
+ }
+
+ /* 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);
+
+ /* that's it */
+ if(length) *length = writer.len;
+ return writer.data;
+}
+
+#define CBCLASS PNGWriter
+START_DISPATCH;
+ CB(GETIMAGETYPENAME, getImageTypeName);
+ CB(GETEXTENSIONS, getExtensions);
+ CB(SETCONFIG, setConfig);
+ CB(GETCONFIG, getConfig);
+ CB(BITDEPTHSUPPORTED, bitDepthSupported);
+ CB(CONVERT, convert);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file