void writeFRAM( const QSize& size ) { struct { uchar mode; uchar n; uchar nu; uchar d; uchar t; uchar clip; uchar s; uchar deltatype; uint left; uint right; uint top; uint bottom; } chunk; chunk.mode=1; chunk.n='a'; chunk.nu=0; chunk.d=0; chunk.clip=1; chunk.t=0; chunk.s=0; chunk.deltatype=0; chunk.left=0; chunk.right=htonl(size.width()); chunk.top=0; chunk.bottom=htonl(size.height()); png_write_chunk(png_ptr, (png_byte*)"FRAM", (png_byte*)&chunk, sizeof(chunk)); }
bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data) { char realName[5]; strncpy(realName, name, 4); realName[0] = tolower(realName[0]); realName[1] = tolower(realName[1]); realName[4] = '\0'; if (setjmp(png_jmpbuf(png))) { return false; } png_write_chunk(png, (png_bytep) realName, data, size); return true; }
void writeMOVE( const QPoint& offset ) { struct { uchar filler[3]; uchar z[5]; int x,y; } chunk; memset(chunk.z,0,5); chunk.x=htonl(offset.x()); chunk.y=htonl(offset.y()); png_write_chunk(png_ptr, (png_byte*)"MOVE", ((png_byte*)&chunk)+3, sizeof(chunk)-3); }
void writeDEFI( const QPoint& offset, const QSize& size ) { struct { ushort o; uchar s; uchar concrete; int x,y; int lc,rc,tc,bc; } chunk; chunk.o=0; chunk.s=0; chunk.concrete=1; chunk.x=htonl(offset.x()); chunk.y=htonl(offset.y()); chunk.lc=0; chunk.rc=0; chunk.tc=htonl(INT_MAX); chunk.bc=htonl(INT_MAX); png_write_chunk(png_ptr, (png_byte*)"DEFI", (png_byte*)&chunk, sizeof(chunk)); }
void writeMHDR( const QSize& size, int framerate ) { dev->writeBlock("\212MNG\r\n\032\n", 8); struct { int width; int height; int framerate; int a,b,c; int profile; } chunk; chunk.width = htonl(size.width()); chunk.height = htonl(size.height()); chunk.framerate = htonl(framerate); chunk.a=0; chunk.b=0; chunk.c=0; chunk.profile= htonl(0x00000003); png_write_chunk(png_ptr, (png_byte*)"MHDR", (png_byte*)&chunk, sizeof(chunk)); }
void writeMEND() { png_write_chunk(png_ptr, (png_byte*)"MEND", 0, 0); }
/* Writes all the PNG information. This is the suggested way to use the * library. If you have a new chunk to add, make a function to write it, * and put it in the correct location here. If you want the chunk written * after the image data, put it in png_write_end(). I strongly encourage * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing * the chunk, as that will keep the code from breaking if you want to just * write a plain PNG file. If you have long comments, I suggest writing * them in png_write_end(), and compressing them. */ void PNGAPI png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) { png_debug(1, "in png_write_info_before_PLTE\n"); if (png_ptr == NULL || info_ptr == NULL) return; if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) { png_write_sig(png_ptr); /* write PNG signature */ #if defined(PNG_MNG_FEATURES_SUPPORTED) if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted)) { png_warning(png_ptr,"MNG features are not allowed in a PNG datastream"); png_ptr->mng_features_permitted=0; } #endif /* write IHDR information. */ png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, info_ptr->filter_type, #if defined(PNG_WRITE_INTERLACING_SUPPORTED) info_ptr->interlace_type); #else 0); #endif /* the rest of these check to see if the valid field has the appropriate flag set, and if it does, writes the chunk. */ #if defined(PNG_WRITE_gAMA_SUPPORTED) if (info_ptr->valid & PNG_INFO_gAMA) { # ifdef PNG_FLOATING_POINT_SUPPORTED png_write_gAMA(png_ptr, info_ptr->gamma); #else #ifdef PNG_FIXED_POINT_SUPPORTED png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma); # endif #endif } #endif #if defined(PNG_WRITE_sRGB_SUPPORTED) if (info_ptr->valid & PNG_INFO_sRGB) png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); #endif #if defined(PNG_WRITE_iCCP_SUPPORTED) if (info_ptr->valid & PNG_INFO_iCCP) png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); #endif #if defined(PNG_WRITE_sBIT_SUPPORTED) if (info_ptr->valid & PNG_INFO_sBIT) png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); #endif #if defined(PNG_WRITE_cHRM_SUPPORTED) if (info_ptr->valid & PNG_INFO_cHRM) { #ifdef PNG_FLOATING_POINT_SUPPORTED png_write_cHRM(png_ptr, info_ptr->x_white, info_ptr->y_white, info_ptr->x_red, info_ptr->y_red, info_ptr->x_green, info_ptr->y_green, info_ptr->x_blue, info_ptr->y_blue); #else # ifdef PNG_FIXED_POINT_SUPPORTED png_write_cHRM_fixed(png_ptr, info_ptr->int_x_white, info_ptr->int_y_white, info_ptr->int_x_red, info_ptr->int_y_red, info_ptr->int_x_green, info_ptr->int_y_green, info_ptr->int_x_blue, info_ptr->int_y_blue); # endif #endif } #endif #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) if (info_ptr->unknown_chunks_num) { png_unknown_chunk *up; png_debug(5, "writing extra chunks\n"); for (up = info_ptr->unknown_chunks; up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; up++) { int keep=png_handle_as_unknown(png_ptr, up->name); if (keep != PNG_HANDLE_CHUNK_NEVER && up->location && !(up->location & PNG_HAVE_PLTE) && !(up->location & PNG_HAVE_IDAT) && ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) { png_write_chunk(png_ptr, up->name, up->data, up->size); } } } #endif png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; }
/* * Copies a PNG file stream to another PNG file stream. */ int opng_copy_png(struct opng_codec_context *context, FILE *in_stream, const char *Infile, FILE *out_stream, const char *Outfile) { volatile png_bytep buf; /* volatile is required by cexcept */ const png_uint_32 buf_size_incr = 4096; png_uint_32 length; png_byte chunk_hdr[8]; const char * volatile err_msg; int volatile result = 0; context->libpng_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, opng_write_error, opng_write_warning); if (!context->libpng_ptr) { opng_error(0, "Out of memory"); exit(1); } struct opng_encoding_stats * stats = context->stats; opng_init_stats(stats); context->stream = out_stream; context->fname = Outfile; png_set_write_fn(context->libpng_ptr, context, opng_write_data, 0); Try { buf = 0; png_uint_32 buf_size = 0; /* Write the signature in the output file. */ png_write_sig(context->libpng_ptr); /* Copy all chunks until IEND. */ /* Error checking is done only at a very basic level. */ do { if (fread(chunk_hdr, 8, 1, in_stream) != 1) /* length + name */ { opng_error(Infile, "Read error"); result = -1; break; } length = png_get_uint_32(chunk_hdr); if (length > PNG_UINT_31_MAX) { if (!buf && length == 0x89504e47UL) /* "\x89PNG" */ continue; /* skip the signature */ opng_error(Infile, "Data error"); result = -1; break; } if (length + 4 > buf_size) { png_free(context->libpng_ptr, buf); buf_size = (((length + 4) + (buf_size_incr - 1)) / buf_size_incr) * buf_size_incr; buf = (png_bytep)png_malloc(context->libpng_ptr, buf_size); if (!buf) { exit(1); } /* Do not use realloc() here, it's unnecessarily slow. */ } if (fread(buf, length + 4, 1, in_stream) != 1) /* data + crc */ { opng_error(Infile, "Read error"); result = -1; break; } png_write_chunk(context->libpng_ptr, chunk_hdr + 4, buf, length); } while (memcmp(chunk_hdr + 4, opng_sig_IEND, 4) != 0); } Catch (err_msg) { opng_error(Outfile, err_msg); result = -1; } png_free(context->libpng_ptr, buf); png_destroy_write_struct(&context->libpng_ptr, 0); return result; }
cache Png_Create(int width, int height, int numpal, dPalette_t* pal, int bits, cache data, int lump, int* size) { int i = 0; int x = 0; int j = 0; cache image; cache out; cache* row_pointers; png_structp png_ptr; png_infop info_ptr; png_colorp palette; // setup png pointer png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if(png_ptr == NULL) { WGen_Complain("Png_Create: Failed getting png_ptr"); return NULL; } // setup info pointer info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); WGen_Complain("Png_Create: Failed getting info_ptr"); return NULL; } // what does this do again? if(setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); WGen_Complain("Png_Create: Failed on setjmp"); return NULL; } // setup custom data writing procedure png_set_write_fn(png_ptr, NULL, Png_WriteData, NULL); // setup image png_set_IHDR( png_ptr, info_ptr, width, height, bits, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT); // setup palette palette = (png_colorp)Mem_Alloc((16 * numpal) * png_sizeof(png_color)); // copy dPalette_t data over to png_colorp for(x = 0, j = 0; x < numpal; x++) { for(i = 0; i < 16; i++) { palette[j].red = pal[j].r; palette[j].green = pal[j].g; palette[j].blue = pal[j].b; j++; } } i = 0; // add palette to png png_set_PLTE(png_ptr, info_ptr, palette, (16 * numpal)); // set transparent index if(palette[0].red == 0 && palette[0].green == 0 && palette[0].blue == 0) { char tmp[9]; strncpy(tmp, romWadFile.lump[lump].name, 8); tmp[0] -= (char)0x80; tmp[8] = 0; // Exempt these lumps if(strcmp(tmp, "FIRE") && /*strcmp(tmp, "USLEGAL") && strcmp(tmp, "TITLE") &&*/ strcmp(tmp, "EVIL") && /*strcmp(tmp, "IDCRED1") && strcmp(tmp, "WMSCRED1") &&*/ strcmp(tmp, "SPACE") && strcmp(tmp, "CLOUD") && strcmp(tmp, "FINAL")) png_set_tRNS(png_ptr, info_ptr, (png_bytep)&i, 1, NULL); } // add png info to data png_write_info(png_ptr, info_ptr); // add offset chunk if png is a sprite if(INSPRITELIST(lump)) { for(i = 0; i < spriteExCount; i++) { if(exSpriteLump[i].lumpRef == lump) { int offs[2]; offs[0] = WGen_Swap32(exSpriteLump[i].sprite.offsetx); offs[1] = WGen_Swap32(exSpriteLump[i].sprite.offsety); png_write_chunk(png_ptr, "grAb", (byte*)offs, 8); break; } } } // setup packing if needed png_set_packing(png_ptr); png_set_packswap(png_ptr); // copy data over image = data; row_pointers = (cache*)Mem_Alloc(sizeof(byte*) * height); for(i = 0; i < height; i++) { row_pointers[i] = (cache)Mem_Alloc(width); if(bits == 4) { for(j = 0; j < width; j += 2) { row_pointers[i][j] = *image & 0xf; row_pointers[i][j+1] = *image >> 4; image++; } } else { for(j = 0; j < width; j++) { row_pointers[i][j] = *image; image++; } } png_write_rows(png_ptr, &row_pointers[i], 1); }
/* Writes the end of the PNG file. If you don't want to write comments or * time information, you can pass NULL for info. If you already wrote these * in png_write_info(), do not write them again here. If you have long * comments, I suggest writing them here, and compressing them. */ void PNGAPI png_write_end(png_structp png_ptr, png_infop info_ptr) { png_debug(1, "in png_write_end"); if (png_ptr == NULL) return; if (!(png_ptr->mode & PNG_HAVE_IDAT)) png_error(png_ptr, "No IDATs written into file"); #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED if (png_ptr->num_palette_max > png_ptr->num_palette) png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); #endif /* See if user wants us to write information chunks */ if (info_ptr != NULL) { #ifdef PNG_WRITE_TEXT_SUPPORTED int i; /* local index variable */ #endif #ifdef PNG_WRITE_tIME_SUPPORTED /* Check to see if user has supplied a time chunk */ if ((info_ptr->valid & PNG_INFO_tIME) && !(png_ptr->mode & PNG_WROTE_tIME)) png_write_tIME(png_ptr, &(info_ptr->mod_time)); #endif #ifdef PNG_WRITE_TEXT_SUPPORTED /* Loop through comment chunks */ for (i = 0; i < info_ptr->num_text; i++) { png_debug2(2, "Writing trailer text chunk %d, type %d", i, info_ptr->text[i].compression); /* An internationalized chunk? */ if (info_ptr->text[i].compression > 0) { #ifdef PNG_WRITE_iTXt_SUPPORTED /* Write international chunk */ png_write_iTXt(png_ptr, info_ptr->text[i].compression, info_ptr->text[i].key, info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else png_warning(png_ptr, "Unable to write international text"); #endif } else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) { #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0, info_ptr->text[i].compression); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #endif } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) { #ifdef PNG_WRITE_tEXt_SUPPORTED /* Write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else png_warning(png_ptr, "Unable to write uncompressed text"); #endif } } #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED if (info_ptr->unknown_chunks_num) { png_unknown_chunk *up; png_debug(5, "writing extra chunks"); for (up = info_ptr->unknown_chunks; up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; up++) { int keep = png_handle_as_unknown(png_ptr, up->name); if (keep != PNG_HANDLE_CHUNK_NEVER && up->location && (up->location & PNG_AFTER_IDAT) && ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) { png_write_chunk(png_ptr, up->name, up->data, up->size); } } } #endif } png_ptr->mode |= PNG_AFTER_IDAT; /* Write end of PNG file */ png_write_IEND(png_ptr); /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, * and restored again in libpng-1.2.30, may cause some applications that * do not set png_ptr->output_flush_fn to crash. If your application * experiences a problem, please try building libpng with * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to * png-mng-implement at lists.sf.net . */ #ifdef PNG_WRITE_FLUSH_SUPPORTED # ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED png_flush(png_ptr); # endif #endif }
void PNGAPI png_write_info(png_structp png_ptr, png_infop info_ptr) { #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) int i; #endif png_debug(1, "in png_write_info"); if (png_ptr == NULL || info_ptr == NULL) return; png_write_info_before_PLTE(png_ptr, info_ptr); if (info_ptr->valid & PNG_INFO_PLTE) png_write_PLTE(png_ptr, info_ptr->palette, (png_uint_32)info_ptr->num_palette); else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) png_error(png_ptr, "Valid palette required for paletted images"); #ifdef PNG_WRITE_tRNS_SUPPORTED if (info_ptr->valid & PNG_INFO_tRNS) { #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel (in tRNS) */ if ((png_ptr->transformations & PNG_INVERT_ALPHA) && info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { int j; for (j = 0; j<(int)info_ptr->num_trans; j++) info_ptr->trans_alpha[j] = (png_byte)(255 - info_ptr->trans_alpha[j]); } #endif png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color), info_ptr->num_trans, info_ptr->color_type); } #endif #ifdef PNG_WRITE_bKGD_SUPPORTED if (info_ptr->valid & PNG_INFO_bKGD) png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); #endif #ifdef PNG_WRITE_hIST_SUPPORTED if (info_ptr->valid & PNG_INFO_hIST) png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); #endif #ifdef PNG_WRITE_oFFs_SUPPORTED if (info_ptr->valid & PNG_INFO_oFFs) png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, info_ptr->offset_unit_type); #endif #ifdef PNG_WRITE_pCAL_SUPPORTED if (info_ptr->valid & PNG_INFO_pCAL) png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, info_ptr->pcal_units, info_ptr->pcal_params); #endif #ifdef PNG_WRITE_sCAL_SUPPORTED if (info_ptr->valid & PNG_INFO_sCAL) png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, info_ptr->scal_s_width, info_ptr->scal_s_height); #endif /* sCAL */ #ifdef PNG_WRITE_pHYs_SUPPORTED if (info_ptr->valid & PNG_INFO_pHYs) png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); #endif /* pHYs */ #ifdef PNG_WRITE_tIME_SUPPORTED if (info_ptr->valid & PNG_INFO_tIME) { png_write_tIME(png_ptr, &(info_ptr->mod_time)); png_ptr->mode |= PNG_WROTE_tIME; } #endif /* tIME */ #ifdef PNG_WRITE_sPLT_SUPPORTED if (info_ptr->valid & PNG_INFO_sPLT) for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); #endif /* sPLT */ #ifdef PNG_WRITE_TEXT_SUPPORTED /* Check to see if we need to write text chunks */ for (i = 0; i < info_ptr->num_text; i++) { png_debug2(2, "Writing header text chunk %d, type %d", i, info_ptr->text[i].compression); /* An internationalized chunk? */ if (info_ptr->text[i].compression > 0) { #ifdef PNG_WRITE_iTXt_SUPPORTED /* Write international chunk */ png_write_iTXt(png_ptr, info_ptr->text[i].compression, info_ptr->text[i].key, info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); /* Mark this chunk as written */ if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; else info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write international text"); #endif } /* If we want a compressed text chunk */ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) { #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0, info_ptr->text[i].compression); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #endif } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) { #ifdef PNG_WRITE_tEXt_SUPPORTED /* Write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else /* Can't get here */ png_warning(png_ptr, "Unable to write uncompressed text"); #endif } } #endif /* tEXt */ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED if (info_ptr->unknown_chunks_num) { png_unknown_chunk *up; png_debug(5, "writing extra chunks"); for (up = info_ptr->unknown_chunks; up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; up++) { int keep = png_handle_as_unknown(png_ptr, up->name); if (keep != PNG_HANDLE_CHUNK_NEVER && up->location && (up->location & PNG_HAVE_PLTE) && !(up->location & PNG_HAVE_IDAT) && !(up->location & PNG_AFTER_IDAT) && ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) { png_write_chunk(png_ptr, up->name, up->data, up->size); } } } #endif }
bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, const QString &description, int off_x_in, int off_y_in) { QPoint offset = image.offset(); int off_x = off_x_in + offset.x(); int off_y = off_y_in + offset.y(); png_structp png_ptr; png_infop info_ptr; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { return false; } png_set_error_fn(png_ptr, 0, 0, qt_png_warning); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, 0); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return false; } int quality = quality_in; if (quality >= 0) { if (quality > 9) { qWarning("PNG: Quality %d out of range", quality); quality = 9; } png_set_compression_level(png_ptr, quality); } png_set_write_fn(png_ptr, (void*)this, qpiw_write_fn, qpiw_flush_fn); int color_type = 0; if (image.colorCount()) { if (image.isGrayscale()) color_type = PNG_COLOR_TYPE_GRAY; else color_type = PNG_COLOR_TYPE_PALETTE; } else if (image.format() == QImage::Format_Grayscale8) color_type = PNG_COLOR_TYPE_GRAY; else if (image.hasAlphaChannel()) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else color_type = PNG_COLOR_TYPE_RGB; png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(), image.depth() == 1 ? 1 : 8, // per channel color_type, 0, 0, 0); // sets #channels if (gamma != 0.0) { png_set_gAMA(png_ptr, info_ptr, 1.0/gamma); } if (image.format() == QImage::Format_MonoLSB) png_set_packswap(png_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) { // Paletted int num_palette = qMin(256, image.colorCount()); png_color palette[256]; png_byte trans[256]; int num_trans = 0; for (int i=0; i<num_palette; i++) { QRgb rgba=image.color(i); palette[i].red = qRed(rgba); palette[i].green = qGreen(rgba); palette[i].blue = qBlue(rgba); trans[i] = qAlpha(rgba); if (trans[i] < 255) { num_trans = i+1; } } png_set_PLTE(png_ptr, info_ptr, palette, num_palette); if (num_trans) { png_set_tRNS(png_ptr, info_ptr, trans, num_trans, 0); } } // Swap ARGB to RGBA (normal PNG format) before saving on // BigEndian machines if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { png_set_swap_alpha(png_ptr); } // Qt==ARGB==Big(ARGB)==Little(BGRA). But RGB888 is RGB regardless if (QSysInfo::ByteOrder == QSysInfo::LittleEndian && image.format() != QImage::Format_RGB888) { png_set_bgr(png_ptr); } if (off_x || off_y) { png_set_oFFs(png_ptr, info_ptr, off_x, off_y, PNG_OFFSET_PIXEL); } if (frames_written > 0) png_set_sig_bytes(png_ptr, 8); if (image.dotsPerMeterX() > 0 || image.dotsPerMeterY() > 0) { png_set_pHYs(png_ptr, info_ptr, image.dotsPerMeterX(), image.dotsPerMeterY(), PNG_RESOLUTION_METER); } set_text(image, png_ptr, info_ptr, description); png_write_info(png_ptr, info_ptr); if (image.depth() != 1) png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_RGB && image.format() != QImage::Format_RGB888) png_set_filler(png_ptr, 0, QSysInfo::ByteOrder == QSysInfo::BigEndian ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); if (looping >= 0 && frames_written == 0) { uchar data[13] = "NETSCAPE2.0"; // 0123456789aBC data[0xB] = looping%0x100; data[0xC] = looping/0x100; png_write_chunk(png_ptr, const_cast<png_bytep>((const png_byte *)"gIFx"), data, 13); } if (ms_delay >= 0 || disposal!=Unspecified) { uchar data[4]; data[0] = disposal; data[1] = 0; data[2] = (ms_delay/10)/0x100; // hundredths data[3] = (ms_delay/10)%0x100; png_write_chunk(png_ptr, const_cast<png_bytep>((const png_byte *)"gIFg"), data, 4); } int height = image.height(); int width = image.width(); switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: case QImage::Format_Grayscale8: case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_RGB888: { png_bytep* row_pointers = new png_bytep[height]; for (int y=0; y<height; y++) row_pointers[y] = const_cast<png_bytep>(image.constScanLine(y)); png_write_image(png_ptr, row_pointers); delete [] row_pointers; } break; default: { QImage::Format fmt = image.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32; QImage row; png_bytep row_pointers[1]; for (int y=0; y<height; y++) { row = image.copy(0, y, width, 1).convertToFormat(fmt); row_pointers[0] = const_cast<png_bytep>(row.constScanLine(0)); png_write_rows(png_ptr, row_pointers, 1); } } break; } png_write_end(png_ptr, info_ptr); frames_written++; png_destroy_write_struct(&png_ptr, &info_ptr); return true; }
//--------------------------------------------------------------------------- void __fastcall TDeePNG::SaveToStream(Classes::TStream * Stream) { // SaveToStream method // warning: this method would change the pixelformat to pf24bit // if the pixelformat is pfDevice, pf15bit, pf16bit, or pfCustom. png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_bytep row_buffer = NULL; try { // create png_struct png_ptr = png_create_write_struct_2 (PNG_LIBPNG_VER_STRING, (png_voidp)this, DeePNG_error, DeePNG_warning, (png_voidp)this, DeePNG_malloc, DeePNG_free); // create png_info info_ptr = png_create_info_struct(png_ptr); // set write function png_set_write_fn(png_ptr, (png_voidp)Stream, DeePNG_write_data, DeePNG_flush); // set IHDR if(PixelFormat == pfDevice || PixelFormat == pf15bit || PixelFormat == pf16bit || PixelFormat == pfCustom) PixelFormat = pf24bit; bool grayscale = IsGrayscaleBitmap(this); int colordepth = GetBitmapColorDepth(this); int w = Width; int h = Height; int color_type; if(grayscale) color_type = PNG_COLOR_TYPE_GRAY; else if(colordepth <= 8) color_type = PNG_COLOR_TYPE_PALETTE; else if(colordepth == 32) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else color_type = PNG_COLOR_TYPE_RGB; png_set_IHDR(png_ptr, info_ptr, w, h, colordepth < 8 ? colordepth : 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // set oFFs if(ofs_set) png_set_oFFs(png_ptr, info_ptr, ofs_x, ofs_y, ofs_unit); // set palette if(color_type == PNG_COLOR_TYPE_PALETTE) { png_color *palette = (png_colorp)png_malloc(png_ptr, 256 * sizeof(png_color)); PALETTEENTRY palentry[256]; int num_palette = GetPaletteEntries(Palette, 0, (1<<colordepth), palentry); for(int i = 0; i < num_palette; i++) { palette[i].red = palentry[i].peRed; palette[i].green = palentry[i].peGreen; palette[i].blue = palentry[i].peBlue; } png_set_PLTE(png_ptr, info_ptr, palette, num_palette); } // write info png_write_info(png_ptr, info_ptr); // write vpAg private chunk if(vpag_set) { png_byte png_vpAg[5] = {118, 112, 65, 103, '\0'}; unsigned char vpag_chunk_data[9]; #define PNG_write_be32(p, a) (\ ((unsigned char *)(p))[0] = (unsigned char)(((a) >>24) & 0xff), \ ((unsigned char *)(p))[1] = (unsigned char)(((a) >>16) & 0xff), \ ((unsigned char *)(p))[2] = (unsigned char)(((a) >> 8) & 0xff), \ ((unsigned char *)(p))[3] = (unsigned char)(((a) ) & 0xff) ) PNG_write_be32(vpag_chunk_data, vpag_w); PNG_write_be32(vpag_chunk_data + 4, vpag_h); vpag_chunk_data[8] = (unsigned char)vpag_unit; png_write_chunk(png_ptr, png_vpAg, vpag_chunk_data, 9); } /* // change RGB order if(color_type = PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); // ???? why this does not work ? */ // write image if(color_type == PNG_COLOR_TYPE_RGB) { row_buffer = (png_bytep)png_malloc(png_ptr, 3 * w + 6); try { png_bytep row_pointer = row_buffer; for(int i = 0; i < h; i++) { png_bytep in = (png_bytep)ScanLine[i]; png_bytep out = row_buffer; for(int x = 0; x < w; x++) { out[2] = in[0]; out[1] = in[1]; out[0] = in[2]; out += 3; in += 3; } png_write_row(png_ptr, row_pointer); } } catch(...) { png_free(png_ptr, row_buffer); throw; } png_free(png_ptr, row_buffer); } else if(color_type == PNG_COLOR_TYPE_RGB_ALPHA) { row_buffer = (png_bytep)png_malloc(png_ptr, 4 * w + 6); try { png_bytep row_pointer = row_buffer; for(int i = 0; i < h; i++) { png_bytep in = (png_bytep)ScanLine[i]; png_bytep out = row_buffer; for(int x = 0; x < w; x++) { out[2] = in[0]; out[1] = in[1]; out[0] = in[2]; out[3] = in[3]; out += 4; in += 4; } png_write_row(png_ptr, row_pointer); } } catch(...) { png_free(png_ptr, row_buffer); throw; } png_free(png_ptr, row_buffer); } else { for(int i = 0; i < h; i++) { png_bytep row_pointer = (png_bytep)ScanLine[i]; png_write_row(png_ptr, row_pointer); } } // finish writing png_write_end(png_ptr, info_ptr); } catch(...) { png_destroy_write_struct(&png_ptr, &info_ptr); throw; } png_destroy_write_struct(&png_ptr, &info_ptr); }
static uint8_t png_write( png_structp writePtr, png_image * image, uint32_t flags ) { const uint32_t h = image->height; const uint32_t w = image->width; const uint8_t * p = image->data; const uint32_t bitDepth = 8; const uint32_t channels = 4; png_infop infoPtr = png_create_info_struct( writePtr ); if (!infoPtr) { pngio_error( "Couldn't initialize PNG info struct" ); png_destroy_write_struct( & writePtr, NULL ); return 0; } if (setjmp( png_jmpbuf( writePtr ) )) { png_destroy_write_struct( & writePtr, & infoPtr ); pngio_error( "An error occured while writing the PNG file." ); return 0; } png_set_filter( writePtr, 0, PNG_FILTER_NONE ); #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { png_write_sig( writePtr ); png_set_sig_bytes( writePtr, 8 ); png_set_compression_window_bits( writePtr, -15 ); png_set_write_user_transform_fn( writePtr, png_write_swap_and_premultiply_transform ); png_set_user_transform_info( writePtr, NULL, bitDepth, channels ); } #endif png_set_IHDR( writePtr, infoPtr, w, h, bitDepth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); png_set_gAMA( writePtr, infoPtr, 0.45455 ); png_set_cHRM( writePtr, infoPtr, 0.312700, 0.329, 0.64, 0.33, 0.3, 0.6, 0.15, 0.06 ); png_set_sRGB( writePtr, infoPtr, 0); #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { png_byte cname[] = { 'C', 'g', 'B', 'I', '\0' }; png_byte cdata[] = { 0x50, 0x00, 0x20, 0x02 }; png_write_chunk( writePtr, cname, cdata, 4 ); } #endif png_write_info( writePtr, infoPtr ); const size_t bytesPerRow = w * 4; if (flags & PNG_IMAGE_FLIP_VERTICAL) { for (size_t i = 0; i < h; i++) { png_write_row( writePtr, p + (bytesPerRow * (h - i - 1)) ); } } else { for (size_t i = 0; i < h; i++) { png_write_row( writePtr, p + (bytesPerRow * i) ); } } png_write_end( writePtr, infoPtr ); png_destroy_write_struct( & writePtr, & infoPtr ); return 1; }