; pngwrite.asm - general routines to write a PNG file ; Last changed in libpng 1.6.24 [August 4, 2016] ; Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson ; (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) ; (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) ; This code is released under the libpng license. ; For conditions of distribution and use, see the disclaimer ; and license in png.inc ; Write out all the unknown chunks for the current given location ;void (png_structrp png_ptr, png_const_inforp info_ptr, unsigned int where) align 4 proc write_unknown_chunks, png_ptr:dword, info_ptr:dword, where:dword pushad mov esi,[info_ptr] cmp dword[esi+png_info_def.unknown_chunks_num],0 je .end_f ;if(..!=0) mov edi,[png_ptr] ;ecx = up png_debug 5, 'writing extra chunks' mov ecx,[esi+png_info_def.unknown_chunks] mov edx,[esi+png_info_def.unknown_chunks_num] imul edx,sizeof.png_unknown_chunk add edx,ecx .cycle0: ;for (..;..<..;..) cmp ecx,edx jge .end_f movzx eax,byte[ecx+png_unknown_chunk.location] and eax,[where] jz .end0 ;if (..!=0) ; If per-chunk unknown chunk handling is enabled use it, otherwise ; just write the chunks the application has set. if PNG_SET_UNKNOWN_CHUNKS_SUPPORTED eq 1 mov eax,ecx add eax,png_unknown_chunk.name stdcall png_handle_as_unknown, edi, eax ; NOTE: this code is radically different from the read side in the ; matter of handling an ancillary unknown chunk. In the read side ; the default behavior is to discard it, in the code below the default ; behavior is to write it. Critical chunks are, however, only ; written if explicitly listed or if the default is set to write all ; unknown chunks. ; The default handling is also slightly weird - it is not possible to ; stop the writing of all unsafe-to-copy chunks! ; TODO: REVIEW: this would seem to be a bug. cmp eax,PNG_HANDLE_CHUNK_NEVER je .end0 mov bl,byte[ecx+png_unknown_chunk.name+3] and bl,0x20 cmp bl,0 jne .beg0 cmp eax,PNG_HANDLE_CHUNK_ALWAYS je .beg0 cmp eax,PNG_HANDLE_CHUNK_AS_DEFAULT jne .end0 cmp dword[edi+png_struct.unknown_default],PNG_HANDLE_CHUNK_ALWAYS jne .end0 end if .beg0: ;if (..!=.. && (.. safe-to-copy overrides everything || ..==.. || (..==.. && ..==..))) ; TODO: review, what is wrong with a zero length unknown chunk? cmp dword[ecx+png_unknown_chunk.size],0 jne @f ;if (..==0) png_warning [png_ptr], 'Writing zero-length unknown chunk' @@: mov eax,dword[ecx+png_unknown_chunk.name] stdcall png_write_chunk, edi, eax, [ecx+png_unknown_chunk.podata], [ecx+png_unknown_chunk.size] .end0: add ecx,sizeof.png_unknown_chunk jmp .cycle0 ;.cycle0end: .end_f: popad ret endp ; 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 (png_structrp png_ptr, png_const_inforp info_ptr) align 4 proc png_write_info_before_PLTE, png_ptr:dword, info_ptr:dword png_debug 1, 'in png_write_info_before_PLTE' pushad mov edi,[png_ptr] or edi,edi jz .end_f mov esi,[info_ptr] or esi,esi jz .end_f ;if(..==0 || ..==0) return mov eax,[edi+png_struct.mode] and eax,PNG_WROTE_INFO_BEFORE_PLTE jnz .end_f ;if (..==0) ; Write PNG signature stdcall png_write_sig, edi if PNG_MNG_FEATURES_SUPPORTED eq 1 mov eax,[edi+png_struct.mode] and eax,PNG_HAVE_PNG_SIGNATURE jz @f cmp dword[edi+png_struct.mng_features_permitted],0 je @f ;if(..!=0 && ..!=0) png_warning edi, 'MNG features are not allowed in a PNG datastream' mov dword[edi+png_struct.mng_features_permitted],0 @@: end if ; Write IHDR information. if PNG_WRITE_INTERLACING_SUPPORTED eq 1 movzx eax,byte[esi+png_info_def.interlace_type] push eax else push dword 0 end if movzx eax,byte[esi+png_info_def.filter_type] push eax movzx eax,byte[esi+png_info_def.compression_type] push eax movzx eax,byte[esi+png_info_def.color_type] push eax movzx eax,byte[esi+png_info_def.bit_depth] stdcall png_write_IHDR, edi,\ dword[esi+png_info_def.width], dword[esi+png_info_def.height], eax ; The rest of these check to see if the valid field has the appropriate ; flag set, and if it does, writes the chunk. ; 1.6.0: COLORSPACE support controls the writing of these chunks too, and ; the chunks will be written if the WRITE routine is there and ; information * is available in the COLORSPACE. (See ; png_colorspace_sync_info in png.c for where the valid flags get set.) ; Under certain circumstances the colorspace can be invalidated without ; syncing the info_struct 'valid' flags; this happens if libpng detects ; an error and calls png_error while the color space is being set, yet ; the application continues writing the PNG. So check the 'invalid' ; flag here too. if PNG_GAMMA_SUPPORTED eq 1 if PNG_WRITE_gAMA_SUPPORTED eq 1 movzx eax,word[esi+png_info_def.colorspace.flags] and eax,PNG_COLORSPACE_INVALID jnz @f movzx eax,word[esi+png_info_def.colorspace.flags] and eax,PNG_COLORSPACE_FROM_gAMA jz @f mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_gAMA jz @f ;if (..==0 && ..!=0 && ..!=0) stdcall png_write_gAMA_fixed, edi, [esi+png_info_def.colorspace.gamma] @@: end if end if if PNG_COLORSPACE_SUPPORTED eq 1 ; Write only one of sRGB or an ICC profile. If a profile was supplied ; and it matches one of the known sRGB ones issue a warning. if PNG_WRITE_iCCP_SUPPORTED eq 1 movzx eax,word[esi+png_info_def.colorspace.flags] and eax,PNG_COLORSPACE_INVALID jnz .end0 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_iCCP jz .end0 ;if (..==0 && ..!=0) if PNG_WRITE_sRGB_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_sRGB jz @f ;if (..!=0) png_app_warning edi, 'profile matches sRGB but writing iCCP instead' @@: end if stdcall png_write_iCCP, edi, [esi+png_info_def.iccp_name],\ [esi+png_info_def.iccp_profile] if PNG_WRITE_sRGB_SUPPORTED eq 1 jmp .end1 end if .end0: ;else end if if PNG_WRITE_sRGB_SUPPORTED eq 1 movzx eax,word[esi+png_info_def.colorspace.flags] and eax,PNG_COLORSPACE_INVALID jnz .end1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_sRGB jz .end1 ;if (..==0 && ..!=0) movzx eax,word[esi+png_info_def.colorspace.rendering_intent] stdcall png_write_sRGB, edi, eax .end1: end if ;sRGB end if ;COLORSPACE if PNG_WRITE_sBIT_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_sBIT jz @f ;if (..!=0) movzx eax,byte[esi+png_info_def.color_type] push eax mov eax,esi add eax,png_info_def.sig_bit stdcall png_write_sBIT, edi, eax ;, ...color_type @@: end if if PNG_COLORSPACE_SUPPORTED eq 1 if PNG_WRITE_cHRM_SUPPORTED eq 1 movzx eax,word[esi+png_info_def.colorspace.flags] and eax,PNG_COLORSPACE_INVALID jnz @f movzx eax,word[esi+png_info_def.colorspace.flags] and eax,PNG_COLORSPACE_FROM_cHRM jz @f mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_cHRM jz @f ;if (..==0 && ..!=0 && ..!=0) stdcall png_write_cHRM_fixed, edi, [esi+png_info_def.colorspace.end_points_xy] @@: end if end if if PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED eq 1 stdcall write_unknown_chunks, edi, esi, PNG_HAVE_IHDR end if or dword[edi+png_struct.mode],PNG_WROTE_INFO_BEFORE_PLTE .end_f: popad ret endp ;void (png_structrp png_ptr, png_const_inforp info_ptr) align 4 proc png_write_info, png_ptr:dword, info_ptr:dword if (PNG_WRITE_TEXT_SUPPORTED eq 1) | (PNG_WRITE_sPLT_SUPPORTED eq 1) ; int i; end if pushad png_debug 1, 'in png_write_info' mov edi,[png_ptr] or edi,edi jz .end_f mov esi,[info_ptr] or esi,esi jz .end_f ;if (..==0 || ..==0) return stdcall png_write_info_before_PLTE, edi, esi mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_PLTE jz @f ;if (..!=0) movzx eax,word[esi+png_info_def.num_palette] stdcall png_write_PLTE, edi, [esi+png_info_def.palette], eax jmp .end_0 @@: mov al,byte[esi+png_info_def.color_type] cmp al,PNG_COLOR_TYPE_PALETTE jne .end_0 ;else if (..==..) png_error edi, 'Valid palette required for paletted images' .end_0: if PNG_WRITE_tRNS_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_tRNS jz .end_1 ;if (..!=0) if PNG_WRITE_INVERT_ALPHA_SUPPORTED eq 1 ; Invert the alpha channel (in tRNS) ; if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 && ; info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ; { ; int j, jend; ; jend = info_ptr->num_trans; ; if (jend > PNG_MAX_PALETTE_LENGTH) ; jend = PNG_MAX_PALETTE_LENGTH; ; for (j = 0; jtrans_alpha[j] = ; (byte)(255 - info_ptr->trans_alpha[j]); ; } end if mov eax,esi add eax,png_info_def.trans_color movzx ebx,word[esi+png_info_def.num_trans] movzx ecx,byte[esi+png_info_def.color_type] stdcall png_write_tRNS, edi, dword[esi+png_info_def.trans_alpha], eax, ebx, ecx .end_1: end if if PNG_WRITE_bKGD_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_bKGD jz @f ;if (..!=0) mov eax,esi add eax,png_info_def.background movzx ebx,byte[esi+png_info_def.color_type] stdcall png_write_bKGD, edi, eax, ebx @@: end if if PNG_WRITE_hIST_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_hIST jz @f ;if (..!=0) movzx ebx,word[esi+png_info_def.num_palette] stdcall png_write_hIST, edi, [esi+png_info_def.hist], ebx @@: end if if PNG_WRITE_oFFs_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_oFFs jz @f ;if (..!=0) movzx ebx,byte[esi+png_info_def.offset_unit_type] stdcall png_write_oFFs, edi, [esi+png_info_def.x_offset], [esi+png_info_def.y_offset], ebx @@: end if if PNG_WRITE_pCAL_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_pCAL jz @f ;if (..!=0) movzx ebx,byte[esi+png_info_def.pcal_type] movzx ecx,byte[esi+png_info_def.pcal_nparams] stdcall png_write_pCAL, edi, [esi+png_info_def.pcal_purpose], [esi+png_info_def.pcal_X0], [esi+png_info_def.pcal_X1], ebx, ecx, [esi+png_info_def.pcal_units], [esi+png_info_def.pcal_params] @@: end if if PNG_WRITE_sCAL_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_sCAL jz @f ;if (..!=0) movzx ebx,byte[esi+png_info_def.scal_unit] stdcall png_write_sCAL_s, edi, ebx, [esi+png_info_def.scal_s_width], [esi+png_info_def.scal_s_height] @@: end if ;sCAL if PNG_WRITE_pHYs_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_pHYs jz @f ;if (..!=0) movzx ebx,byte[esi+png_info_def.phys_unit_type] stdcall png_write_pHYs, edi, [esi+png_info_def.x_pixels_per_unit], [esi+png_info_def.y_pixels_per_unit], ebx @@: end if ;pHYs if PNG_WRITE_tIME_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_tIME jz @f ;if (..!=0) mov eax,esi add eax,png_info_def.mod_time stdcall png_write_tIME, edi, eax or [edi+png_struct.mode],PNG_WROTE_tIME @@: end if ;tIME if PNG_WRITE_sPLT_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_sPLT jz @f ;if (..!=0) mov eax,[esi+png_info_def.splt_palettes] mov ecx,[esi+png_info_def.splt_palettes_num] cmp ecx,1 jl @f .cycle0: stdcall png_write_sPLT, edi, eax add eax,4 loop .cycle0 @@: end if ;sPLT if PNG_WRITE_TEXT_SUPPORTED eq 1 ; 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) ; { if PNG_WRITE_iTXt_SUPPORTED eq 1 ; 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 edi, 'Unable to write international text' end if ; } ; If we want a compressed text chunk ; else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) ; { if PNG_WRITE_zTXt_SUPPORTED eq 1 ; Write compressed chunk ; png_write_zTXt(png_ptr, info_ptr->text[i].key, ; info_ptr->text[i].text, info_ptr->text[i].compression); ; Mark this chunk as written ; info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; else png_warning edi, 'Unable to write compressed text' end if ; } ; else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) ; { if PNG_WRITE_tEXt_SUPPORTED eq 1 ; 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 edi, 'Unable to write uncompressed text' end if ; } ; } end if ;tEXt if PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED eq 1 stdcall write_unknown_chunks, edi, esi, PNG_HAVE_PLTE end if .end_f: popad ret endp ; 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 (png_structrp png_ptr, png_inforp info_ptr) align 4 proc png_write_end, png_ptr:dword, info_ptr:dword pushad png_debug 1, 'in png_write_end' mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return mov eax,[edi+png_struct.mode] and eax,PNG_HAVE_IDAT jnz @f ;if (..==0) png_error edi, 'No IDATs written into file' @@: if PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED eq 1 mov eax,[edi+png_struct.num_palette_max] cmp ax,[edi+png_struct.num_palette] jle @f ;if (..>..) png_benign_error edi, 'Wrote palette index exceeding num_palette' @@: end if ; See if user wants us to write information chunks mov esi,[info_ptr] cmp esi,0 je .end0 ;if (..!=0) if PNG_WRITE_TEXT_SUPPORTED eq 1 ; int i; /* local index variable */ end if if PNG_WRITE_tIME_SUPPORTED eq 1 ; Check to see if user has supplied a time chunk mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_tIME jz @f mov eax,[edi+png_struct.mode] and eax,PNG_WROTE_tIME jnz @f ;if (..!=0 && ..==0) mov eax,esi add eax,png_info_def.mod_time stdcall png_write_tIME, edi, eax @@: end if if PNG_WRITE_TEXT_SUPPORTED eq 1 ; Loop through comment chunks cmp dword[esi+png_info_def.num_text],0 jle .cycle0end xor ecx,ecx align 4 .cycle0: ;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? mov eax,ecx shl eax,2 add eax,[esi+png_info_def.text] ;eax = info_ptr.text[i] cmp dword[eax+png_text.compression],0 jle .end1 ;if (info_ptr.text[i].compression > 0) if PNG_WRITE_iTXt_SUPPORTED eq 1 ; Write international chunk stdcall png_write_iTXt, edi,\ [eax+png_text.compression],\ [eax+png_text.key],\ [eax+png_text.lang],\ [eax+png_text.lang_key],\ [eax+png_text.text] ; Mark this chunk as written mov ebx,PNG_TEXT_COMPRESSION_zTXt_WR cmp dword[eax+png_text.compression],PNG_TEXT_COMPRESSION_NONE jne @f mov ebx,PNG_TEXT_COMPRESSION_NONE_WR @@: mov dword[eax+png_text.compression],ebx else png_warning edi, 'Unable to write international text' end if jmp .end3 .end1: cmp dword[eax+png_text.compression],PNG_TEXT_COMPRESSION_zTXt jl .end2 ;else if (info_ptr.text[i].compression >= ..) if PNG_WRITE_zTXt_SUPPORTED eq 1 ; Write compressed chunk stdcall png_write_zTXt, edi, [eax+png_text.key],\ [eax+png_text.text], [eax+png_text.compression] ; Mark this chunk as written mov dword[eax+png_text.compression],PNG_TEXT_COMPRESSION_zTXt_WR else png_warning edi, 'Unable to write compressed text' end if jmp .end3 .end2: cmp dword[eax+png_text.compression],PNG_TEXT_COMPRESSION_NONE jl .end3 ;else if (info_ptr.text[i].compression == ..) if PNG_WRITE_tEXt_SUPPORTED eq 1 ; Write uncompressed chunk stdcall png_write_tEXt, edi, [eax+png_text.key],\ [eax+png_text.text], 0 ; Mark this chunk as written mov dword[eax+png_text.compression],PNG_TEXT_COMPRESSION_NONE_WR else png_warning edi, 'Unable to write uncompressed text' end if .end3: inc ecx cmp ecx,[esi+png_info_def.num_text] jl .cycle0 .cycle0end: end if if PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED eq 1 stdcall write_unknown_chunks, edi, esi, PNG_AFTER_IDAT end if .end0: or dword[edi+png_struct.mode], PNG_AFTER_IDAT ; Write end of PNG file stdcall png_write_IEND, edi ; 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 . if PNG_WRITE_FLUSH_SUPPORTED eq 1 if PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED eq 1 stdcall png_flush, edi end if end if .end_f: popad ret endp ;void (png_timep ptime, struct tm * ttime) align 4 proc png_convert_from_struct_tm, ptime:dword, ttime:dword png_debug 1, 'in png_convert_from_struct_tm' ; ptime->year = (uint_16)(1900 + ttime->tm_year); ; ptime->month = (byte)(ttime->tm_mon + 1); ; ptime->day = (byte)ttime->tm_mday; ; ptime->hour = (byte)ttime->tm_hour; ; ptime->minute = (byte)ttime->tm_min; ; ptime->second = (byte)ttime->tm_sec; ret endp ;void (png_timep ptime, time_t ttime) align 4 proc png_convert_from_time_t, ptime:dword, ttime:dword ; struct tm *tbuf; png_debug 1, 'in png_convert_from_time_t' ; tbuf = gmtime(&ttime); ; png_convert_from_struct_tm(ptime, tbuf); ret endp ; Initialize png_ptr structure, and allocate any memory needed ;png_structp (charp user_png_ver, voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn) align 4 proc png_create_write_struct, user_png_ver:dword, error_ptr:dword, error_fn:dword, warn_fn:dword if PNG_USER_MEM_SUPPORTED eq 1 stdcall png_create_png_struct, [user_png_ver], [error_ptr], [error_fn], [warn_fn], 0, 0, 0 ;eax = png_ptr end if ;USER_MEM test eax,eax jz .end0 ;if (..!=0) ; Set the zlib control values to defaults; they can be overridden by the ; application after the struct has been created. mov dword[eax+png_struct.zbuffer_size], PNG_ZBUF_SIZE ; The 'zlib_strategy' setting is irrelevant because png_default_claim in ; pngwutil.asm defaults it according to whether or not filters will be ; used, and ignores this setting. mov dword[eax+png_struct.zlib_strategy], PNG_Z_DEFAULT_STRATEGY mov dword[eax+png_struct.zlib_level], PNG_Z_DEFAULT_COMPRESSION mov dword[eax+png_struct.zlib_mem_level], 8 mov dword[eax+png_struct.zlib_window_bits], 15 mov dword[eax+png_struct.zlib_method], 8 if PNG_WRITE_COMPRESSED_TEXT_SUPPORTED eq 1 mov dword[eax+png_struct.zlib_text_strategy], PNG_TEXT_Z_DEFAULT_STRATEGY mov dword[eax+png_struct.zlib_text_level], PNG_TEXT_Z_DEFAULT_COMPRESSION mov dword[eax+png_struct.zlib_text_mem_level], 8 mov dword[eax+png_struct.zlib_text_window_bits], 15 mov dword[eax+png_struct.zlib_text_method], 8 end if ; This is a highly dubious configuration option; by default it is off, ; but it may be appropriate for private builds that are testing ; extensions not conformant to the current specification, or of ; applications that must not fail to write at all costs! if PNG_BENIGN_WRITE_ERRORS_SUPPORTED eq 1 ; In stable builds only warn if an application error can be completely ; handled. or dword[eax+png_struct.flags], PNG_FLAG_BENIGN_ERRORS_WARN end if ; App warnings are warnings in release (or release candidate) builds but ; are errors during development. if PNG_RELEASE_BUILD eq 1 or dword[eax+png_struct.flags], PNG_FLAG_APP_WARNINGS_WARN end if ; TODO: delay this, it can be done in png_init_io() (if the app doesn't ; do it itself) avoiding setting the default function if it is not ; required. stdcall png_set_write_fn, eax, 0, 0, 0 .end0: ret endp ; Write a few rows of image data. If the image is interlaced, ; either you will have to write the 7 sub images, or, if you ; have called png_set_interlace_handling(), you will have to ; "write" the image seven times. ;void (png_structrp png_ptr, bytepp row, uint_32 num_rows) align 4 proc png_write_rows uses ebx ecx edi, png_ptr:dword, row:dword, num_rows:dword ;locals ;i dd ? ;uint_32 ;row counter ;rp dd ? ;bytepp ;row pointer ;endl png_debug 1, 'in png_write_rows' mov edi,[png_ptr] cmp edi,0 je .end_f ;if(..==0) return ; Loop through the rows mov ecx,[num_rows] cmp ecx,1 jl .end_f mov ebx,[row] @@: ;for (i = 0, rp = row; i < num_rows; i++, rp++) stdcall png_write_row, edi, [ebx] add ebx,4 loop @b .end_f: ret endp ; Write the image. You only need to call this function once, even ; if you are writing an interlaced image. ;void (png_structrp png_ptr, bytepp image) align 4 proc png_write_image, png_ptr:dword, image:dword pushad ;ebx ;bytepp ;points to current row ;ecx ;uint_32 ;row index ;edx ;int ;pass ;esi ;int ;num_pass mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return png_debug 1, 'in png_write_image' if PNG_WRITE_INTERLACING_SUPPORTED eq 1 ; Initialize interlace handling. If image is not interlaced, ; this will set pass to 1 stdcall png_set_interlace_handling, edi mov esi,eax else xor esi,esi inc esi end if ; Loop through passes xor edx,edx .cycle0: ;for (edx = 0; edx < esi; edx++) cmp edx,esi jge .cycle0end ; Loop through image mov ebx,[image] xor ecx,ecx .cycle1: ;for (ecx = 0, ebx = image; ecx < png_ptr.height; ecx++, ebx++) stdcall png_write_row, edi,[ebx] inc ecx add ebx,4 cmp ecx,[edi+png_struct.height] jl .cycle1 ;.cycle1end: inc edx jmp .cycle0 .cycle0end: .end_f: popad ret endp ; Performs intrapixel differencing ;void (png_row_infop row_info, bytep row) align 4 proc png_do_write_intrapixel uses eax ebx ecx edx edi, row_info:dword, row:dword png_debug 1, 'in png_do_write_intrapixel' mov ebx,[row_info] movzx eax,byte[ebx+png_row_info.color_type] and eax,PNG_COLOR_MASK_COLOR jz .end_f ;if (..!=0) ;edx = bytes_per_pixel mov ecx,[ebx+png_row_info.width] ;ecx = row_width cmp byte[ebx+png_row_info.bit_depth],8 ;if (..==8) jne .end0 ; bytep rp; ; uint_32 i; cmp byte[ebx+png_row_info.color_type],PNG_COLOR_TYPE_RGB jne @f ;if (..==..) mov edx,3-1 ;(-1) for stosb jmp .end2 @@: cmp byte[ebx+png_row_info.color_type],PNG_COLOR_TYPE_RGB_ALPHA jne @f ;else if (..==..) mov edx,4-1 ;(-1) for stosb jmp .end2 @@: jmp .end_f ;else return .end2: mov edi,[row] align 4 .cycle0: ;for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) mov ax,word[edi] sub al,ah stosb ;*(rp) = (byte)(*rp - *(rp + 1)) mov ax,word[edi] sub ah,al mov byte[edi+1],ah ;*(rp + 2) = (byte)(*(rp + 2) - *(rp + 1)) add edi,edx loop .cycle0 .cycle0end: jmp .end_f .end0: if PNG_WRITE_16BIT_SUPPORTED eq 1 cmp byte[ebx+png_row_info.bit_depth],16 ;else if (..==16) jne .end1 ; bytep rp; ; uint_32 i; cmp byte[ebx+png_row_info.color_type],PNG_COLOR_TYPE_RGB jne @f ;if (..==..) mov edx,6 jmp .end3 @@: cmp byte[ebx+png_row_info.color_type],PNG_COLOR_TYPE_RGB_ALPHA jne @f ;else if (..==..) mov edx,8 jmp .end3 @@: jmp .end_f ;else return .end3: mov edi,[row] align 4 .cycle1: ;for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) ; uint_32 s0 = (*(rp ) << 8) | *(rp + 1); ; uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); ; uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); ; uint_32 red = (uint_32)((s0 - s1) & 0xffffL); ; uint_32 blue = (uint_32)((s2 - s1) & 0xffffL); ; *(rp ) = (byte)(red >> 8); ; *(rp + 1) = (byte)red; ; *(rp + 4) = (byte)(blue >> 8); ; *(rp + 5) = (byte)blue; add edi,edx loop .cycle1 .cycle1end: .end1: end if ;WRITE_16BIT .end_f: ret endp ; Called by user to write a row of image data ;void (png_structrp png_ptr, bytep row) align 4 proc png_write_row, png_ptr:dword, row:dword locals ; 1.5.6: moved from png_struct to be a local structure: row_info png_row_info endl pushad mov edi,[png_ptr] cmp edi,0 je .end_f ;if(..==0) return ; png_debug2(1, "in png_write_row (row %u, pass %d)", ; png_ptr->row_number, png_ptr->pass); png_debug1 1, 'in png_write_row (row %u)',[edi+png_struct.row_number] ; Initialize transformations and other stuff if first time cmp dword[edi+png_struct.row_number],0 jne .end0 cmp byte[edi+png_struct.pass],0 jne .end0 ;if(..==0 && ..==0) ; Make sure we wrote the header info mov eax,[edi+png_struct.mode] and eax,PNG_WROTE_INFO_BEFORE_PLTE jnz @f ;if(..==0) png_error edi, 'png_write_info was never called before png_write_row' @@: ; Check for transforms that have been set but were defined out if (PNG_WRITE_INVERT_SUPPORTED eq 0) & (PNG_READ_INVERT_SUPPORTED eq 1) mov eax,[edi+png_struct.transformations] and eax,PNG_INVERT_MONO jz @f ;if(..!=0) png_warning edi, 'PNG_WRITE_INVERT_SUPPORTED is not defined' @@: end if if (PNG_WRITE_FILLER_SUPPORTED eq 0) & (PNG_READ_FILLER_SUPPORTED eq 1) mov eax,[edi+png_struct.transformations] and eax,PNG_FILLER jz @f ;if(..!=0) png_warning edi, 'PNG_WRITE_FILLER_SUPPORTED is not defined' @@: end if if (PNG_WRITE_PACKSWAP_SUPPORTED eq 0) & (PNG_READ_PACKSWAP_SUPPORTED eq 1) mov eax,[edi+png_struct.transformations] and eax,PNG_PACKSWAP jz @f ;if(..!=0) png_warning edi, 'PNG_WRITE_PACKSWAP_SUPPORTED is not defined' @@: end if if (PNG_WRITE_PACK_SUPPORTED eq 0) & (PNG_READ_PACK_SUPPORTED eq 1) mov eax,[edi+png_struct.transformations] and eax,PNG_PACK jz @f ;if(..!=0) png_warning edi, 'PNG_WRITE_PACK_SUPPORTED is not defined' @@: end if if (PNG_WRITE_SHIFT_SUPPORTED eq 0) & (PNG_READ_SHIFT_SUPPORTED eq 1) mov eax,[edi+png_struct.transformations] and eax,PNG_SHIFT jz @f ;if(..!=0) png_warning edi, 'PNG_WRITE_SHIFT_SUPPORTED is not defined' @@: end if if (PNG_WRITE_BGR_SUPPORTED eq 0) & (PNG_READ_BGR_SUPPORTED eq 1) mov eax,[edi+png_struct.transformations] and eax,PNG_BGR jz @f ;if(..!=0) png_warning edi, 'PNG_WRITE_BGR_SUPPORTED is not defined' @@: end if if (PNG_WRITE_SWAP_SUPPORTED eq 0) & (PNG_READ_SWAP_SUPPORTED eq 1) mov eax,[edi+png_struct.transformations] and eax,PNG_SWAP_BYTES jz @f ;if(..!=0) png_warning edi, 'PNG_WRITE_SWAP_SUPPORTED is not defined' @@: end if stdcall png_write_start_row, edi .end0: if PNG_WRITE_INTERLACING_SUPPORTED eq 1 ; If interlaced and not interested in row, return cmp byte[edi+png_struct.interlaced],0 je .end1 mov eax,[edi+png_struct.transformations] and eax,PNG_INTERLACE jz .end1 ;if(..!=0 && ..!=0) cmp byte[edi+png_struct.pass],0 jne @f mov eax,[edi+png_struct.row_number] and eax,0x07 jz .end1 ;if (..!=0) stdcall png_write_finish_row, edi jmp .end_f @@: cmp byte[edi+png_struct.pass],1 jne @f mov eax,[edi+png_struct.row_number] and eax,0x07 jnz .end2 cmp dword[edi+png_struct.width],5 jge .end1 ;if (..!=0 || ..<..) .end2: stdcall png_write_finish_row, edi jmp .end_f @@: cmp byte[edi+png_struct.pass],2 jne @f mov eax,[edi+png_struct.row_number] and eax,0x07 cmp eax,4 je .end1 ;if (..!=..) stdcall png_write_finish_row, edi jmp .end_f @@: cmp byte[edi+png_struct.pass],3 jne @f mov eax,[edi+png_struct.row_number] and eax,0x03 jnz .end3 cmp dword[edi+png_struct.width],3 jge .end1 ;if (..!=0 || ..<..) .end3: stdcall png_write_finish_row, edi jmp .end_f @@: cmp byte[edi+png_struct.pass],4 jne @f mov eax,[edi+png_struct.row_number] and eax,0x03 cmp eax,2 je .end1 ;if (..!=..) stdcall png_write_finish_row, edi jmp .end_f @@: cmp byte[edi+png_struct.pass],5 jne @f mov eax,[edi+png_struct.row_number] and eax,0x01 jnz .end4 cmp dword[edi+png_struct.width],2 jge .end1 ;if (..!=0 || ..<..) .end4: stdcall png_write_finish_row, edi jmp .end_f @@: cmp byte[edi+png_struct.pass],6 jne .end1 mov eax,[edi+png_struct.row_number] and eax,0x01 jnz .end1 ;if (..==0) stdcall png_write_finish_row, edi jmp .end_f .end1: end if ; Set up row info for transformations mov ebx,ebp sub ebx,sizeof.png_row_info mov al,byte[edi+png_struct.color_type] mov byte[ebx+png_row_info.color_type],al mov eax,[edi+png_struct.usr_width] mov [ebx+png_row_info.width],eax movzx eax,byte[edi+png_struct.usr_channels] mov byte[ebx+png_row_info.channels],al movzx ecx,byte[edi+png_struct.usr_bit_depth] mov byte[ebx+png_row_info.bit_depth],cl imul eax,ecx ;.bit_depth * .channels mov byte[ebx+png_row_info.pixel_depth],al PNG_ROWBYTES eax, [ebx+png_row_info.width] mov [ebx+png_row_info.rowbytes], eax push eax movzx eax,byte[ebx+png_row_info.color_type] png_debug1 3, 'row_info->color_type = %d', eax png_debug1 3, 'row_info->width = %u', [ebx+png_row_info.width] movzx eax,byte[ebx+png_row_info.channels] png_debug1 3, 'row_info->channels = %d', eax movzx eax,byte[ebx+png_row_info.bit_depth] png_debug1 3, 'row_info->bit_depth = %d', eax movzx eax,byte[ebx+png_row_info.pixel_depth] png_debug1 3, 'row_info->pixel_depth = %d', eax png_debug1 3, 'row_info->rowbytes = %lu', [ebx+png_row_info.rowbytes] pop eax ; Copy user's row into buffer, leaving room for filter byte. push edi mov edi,[edi+png_struct.row_buf] inc edi mov esi,[row] mov ecx,eax rep movsb ;memcpy(... pop edi if PNG_WRITE_INTERLACING_SUPPORTED eq 1 ; Handle interlacing cmp byte[edi+png_struct.interlaced],0 je @f cmp byte[edi+png_struct.pass],6 jge @f mov eax,[edi+png_struct.transformations] and eax,PNG_INTERLACE jz @f ;if (.. && ..<.. && ..!=0) movzx eax,byte[edi+png_struct.pass] push eax mov eax,[edi+png_struct.row_buf] inc eax stdcall png_do_write_interlace, ebx, eax ;, ...pass ; This should always get caught above, but still ... cmp dword[ebx+png_row_info.width],0 jne @f ;if (..==0) stdcall png_write_finish_row, edi jmp .end_f @@: end if if PNG_WRITE_TRANSFORMS_SUPPORTED eq 1 ; Handle other transformations cmp dword[edi+png_struct.transformations],0 je @f ;if (..!=0) stdcall png_do_write_transformations, edi, ebx @@: end if ; At this point the row_info pixel depth must match the 'transformed' depth, ; which is also the output depth. mov al,[ebx+png_row_info.pixel_depth] cmp al,[edi+png_struct.pixel_depth] jne @f cmp al,[edi+png_struct.transformed_pixel_depth] je .end5 @@: ;if (..!=.. || ..!=..) png_error edi, 'internal write transform logic error' .end5: if PNG_MNG_FEATURES_SUPPORTED eq 1 ; Write filter_method 64 (intrapixel differencing) only if ; 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and ; 2. Libpng did not write a PNG signature (this filter_method is only ; used in PNG datastreams that are embedded in MNG datastreams) and ; 3. The application called png_permit_mng_features with a mask that ; included PNG_FLAG_MNG_FILTER_64 and ; 4. The filter_method is 64 and ; 5. The color_type is RGB or RGBA mov eax,[edi+png_struct.mng_features_permitted] and eax,PNG_FLAG_MNG_FILTER_64 jz @f cmp byte[edi+png_struct.filter_type],PNG_INTRAPIXEL_DIFFERENCING jne @f ;if (..!=0 && ..==..) ; Intrapixel differencing mov eax,[edi+png_struct.row_buf] inc eax stdcall png_do_write_intrapixel, ebx, eax @@: end if ; Added at libpng-1.5.10 if PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED eq 1 ; Check for out-of-range palette index cmp byte[ebx+png_row_info.color_type],PNG_COLOR_TYPE_PALETTE jne @f cmp dword[edi+png_struct.num_palette_max],0 jl @f ;if (..==.. && ..>=0) stdcall png_do_check_palette_indexes, edi, ebx @@: end if ; Find a filter if necessary, filter the row and write it out. mov ebx,ebp sub ebx,sizeof.png_row_info stdcall png_write_find_filter, edi, ebx cmp dword[edi+png_struct.write_row_fn],0 je .end_f ;if (..!=0) movzx eax,byte[edi+png_struct.pass] stdcall dword[edi+png_struct.write_row_fn], edi, [edi+png_struct.row_number], eax .end_f: popad ret endp ; Set the automatic flush interval or 0 to turn flushing off ;void (png_structrp png_ptr, int nrows) align 4 proc png_set_flush uses eax edi, png_ptr:dword, nrows:dword png_debug 1, 'in png_set_flush' mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return mov eax,[nrows] cmp eax,0 jge @f ;(nrows < 0 ? 0 : nrows) xor eax,eax @@: mov [edi+png_struct.flush_dist],eax .end_f: ret endp ; Flush the current output buffers now ;void (png_structrp png_ptr) align 4 proc png_write_flush uses eax edi, png_ptr:dword png_debug 1, 'in png_write_flush' mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return ; We have already written out all of the data mov eax,[edi+png_struct.num_rows] cmp [edi+png_struct.row_number],eax jge .end_f ;if (..>=..) return stdcall png_compress_IDAT, 0, 0, Z_SYNC_FLUSH mov dword[edi+png_struct.flush_rows],0 stdcall png_flush, edi .end_f: popad ret endp ; Free any memory used in png_ptr struct without freeing the struct itself. ;void (png_structrp png_ptr) align 4 proc png_write_destroy uses eax edi, png_ptr:dword png_debug 1, 'in png_write_destroy' ; Free any memory zlib uses mov edi,[png_ptr] mov eax,[edi+png_struct.flags] and eax,PNG_FLAG_ZSTREAM_INITIALIZED jz @f ;if (..!=0) mov eax,edi add eax,png_struct.zstream stdcall [deflateEnd], eax @@: ; Free our memory. png_free checks NULL for us. mov eax,edi add eax,png_struct.zbuffer_list stdcall png_free_buffer_list, edi, eax stdcall png_free, edi, [edi+png_struct.row_buf] mov dword[edi+png_struct.row_buf],0 if PNG_WRITE_FILTER_SUPPORTED eq 1 stdcall png_free, edi, [edi+png_struct.prev_row] stdcall png_free, edi, [edi+png_struct.try_row] stdcall png_free, edi, [edi+png_struct.tst_row] mov dword[edi+png_struct.prev_row],0 mov dword[edi+png_struct.try_row],0 mov dword[edi+png_struct.tst_row],0 end if if PNG_SET_UNKNOWN_CHUNKS_SUPPORTED eq 1 stdcall png_free, edi, [edi+png_struct.chunk_list] mov dword[edi+png_struct.chunk_list],0 end if ; The error handling and memory handling information is left intact at this ; point: the jmp_buf may still have to be freed. See png_destroy_png_struct ; for how this happens. ret endp ; Free all memory used by the write. ; In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for ; *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free ; the passed in info_structs but it would quietly fail to free any of the data ; inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it ; has no png_ptr.) ;void (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) align 4 proc png_destroy_write_struct uses edi esi, png_ptr_ptr:dword, info_ptr_ptr:dword png_debug 1, 'in png_destroy_write_struct' mov esi,[png_ptr_ptr] cmp esi,0 je @f ;if (..!=0) mov edi,[esi] cmp edi,0 je @f ;if (..!=0) ;added in libpng 1.6.0 stdcall png_destroy_info_struct, edi, [info_ptr_ptr] mov dword[esi],0 stdcall png_write_destroy, edi stdcall png_destroy_png_struct, edi @@: ret endp ; Allow the application to select one or more row filters to use. ;void (png_structrp png_ptr, int method, int filters) align 4 proc png_set_filter uses eax ebx ecx edi, png_ptr:dword, method:dword, filters:dword png_debug 1, 'in png_set_filter' pushad mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return if PNG_MNG_FEATURES_SUPPORTED eq 1 mov eax,[edi+png_struct.mng_features_permitted] and eax,PNG_FLAG_MNG_FILTER_64 je @f cmp dword[method], PNG_INTRAPIXEL_DIFFERENCING jne @f ;if (..!=0 && ..==..) mov dword[method], PNG_FILTER_TYPE_BASE @@: end if cmp dword[method], PNG_FILTER_TYPE_BASE jne .end0 ;if (..==..) mov ebx,[filters] and ebx,PNG_ALL_FILTERS or 0x07 ;switch (..) if PNG_WRITE_FILTER_SUPPORTED eq 1 cmp ebx,5 je .end2 cmp ebx,6 je .end2 cmp ebx,7 je .end2 jmp @f .end2: cStr ,'Unknown row filter for method 0' stdcall png_app_error, edi, eax ; FALL THROUGH @@: end if ;WRITE_FILTER cmp ebx,PNG_FILTER_VALUE_NONE jne @f mov byte[edi+png_struct.do_filter],PNG_FILTER_NONE jmp .end1 @@: if PNG_WRITE_FILTER_SUPPORTED eq 1 cmp ebx,PNG_FILTER_VALUE_SUB jne @f mov byte[edi+png_struct.do_filter],PNG_FILTER_SUB jmp .end1 @@: cmp ebx,PNG_FILTER_VALUE_UP jne @f mov byte[edi+png_struct.do_filter],PNG_FILTER_UP jmp .end1 @@: cmp ebx,PNG_FILTER_VALUE_AVG jne @f mov byte[edi+png_struct.do_filter],PNG_FILTER_AVG jmp .end1 @@: cmp ebx,PNG_FILTER_VALUE_PAETH jne @f mov byte[edi+png_struct.do_filter],PNG_FILTER_PAETH jmp .end1 @@: ;default: mov eax,[filters] mov byte[edi+png_struct.do_filter],al jmp .end1 else @@: ;default: cStr ,'Unknown row filter for method 0' stdcall png_app_error edi, eax end if ;WRITE_FILTER .end1: if PNG_WRITE_FILTER_SUPPORTED eq 1 ; If we have allocated the row_buf, this means we have already started ; with the image and we should have allocated all of the filter buffers ; that have been selected. If prev_row isn't already allocated, then ; it is too late to start using the filters that need it, since we ; will be missing the data in the previous row. If an application ; wants to start and stop using particular filters during compression, ; it should start out with all of the filters, and then remove them ; or add them back after the start of compression. ; NOTE: this is a nasty constraint on the code, because it means that the ; prev_row buffer must be maintained even if there are currently no ; 'prev_row' requiring filters active. cmp dword[edi+png_struct.row_buf],0 je .end3 ;if (..!=0) ;ebx = num_filters ;ecx = buf_size ; Repeat the checks in png_write_start_row; 1 pixel high or wide ; images cannot benefit from certain filters. If this isn't done here ; the check below will fire on 1 pixel high images. cmp dword[edi+png_struct.height],1 jne @f ;if (..==..) and dword[filters],not (PNG_FILTER_UP or PNG_FILTER_AVG or PNG_FILTER_PAETH) @@: cmp dword[edi+png_struct.width],1 jne @f ;if (..==..) and dword[filters],not (PNG_FILTER_SUB or PNG_FILTER_AVG or PNG_FILTER_PAETH) @@: mov eax,[filters] and eax,PNG_FILTER_UP or PNG_FILTER_AVG or PNG_FILTER_PAETH jz @f cmp dword[edi+png_struct.prev_row],0 je @f;if (..!=0 && ..==0) ; This is the error case, however it is benign - the previous row ; is not available so the filter can't be used. Just warn here. png_app_warning edi, 'png_set_filter: UP/AVG/PAETH cannot be added after start' and dword[filters],not (PNG_FILTER_UP or PNG_FILTER_AVG or PNG_FILTER_PAETH) @@: xor ebx,ebx mov eax,[filters] and eax,PNG_FILTER_SUB jz @f ;if (..) inc ebx @@: mov eax,[filters] and eax,PNG_FILTER_UP jz @f ;if (..) inc ebx @@: mov eax,[filters] and eax,PNG_FILTER_AVG jz @f ;if (..) inc ebx @@: mov eax,[filters] and eax,PNG_FILTER_PAETH jz @f ;if (..) inc ebx @@: ; Allocate needed row buffers if they have not already been ; allocated. movzx eax,byte[edi+png_struct.usr_channels] movzx ecx,byte[edi+png_struct.usr_bit_depth] imul eax,ecx ;.bit_depth * .channels mov ecx,[edi+png_struct.width] inc ecx PNG_ROWBYTES eax, ecx mov ecx, eax cmp dword[edi+png_struct.try_row],0 jne @f ;if (..==0) stdcall png_malloc, edi, ecx mov [edi+png_struct.try_row],eax @@: cmp ebx,1 jle .end3 ;if (..>..) cmp dword[edi+png_struct.tst_row],0 jne .end3 ;if (..==0) stdcall png_malloc, edi, ecx mov [edi+png_struct.tst_row],eax .end3: mov eax,[filters] mov byte[edi+png_struct.do_filter],al end if jmp .end_f .end0: ;else png_error edi, 'Unknown custom filter method' .end_f: popad ret endp ; Provide floating and fixed point APIs ;void (png_structrp png_ptr, int heuristic_method, ; int num_weights, png_const_doublep filter_weights, png_const_doublep filter_costs) align 4 proc png_set_filter_heuristics, png_ptr:dword, heuristic_method:dword, num_weights:dword, filter_weights:dword, filter_costs:dword ret endp ;void (png_structrp png_ptr, int heuristic_method, ; int num_weights, png_const_fixed_point_p filter_weights, ; png_const_fixed_point_p filter_costs) align 4 proc png_set_filter_heuristics_fixed, png_ptr:dword, heuristic_method:dword, num_weights:dword, filter_weights:dword, filter_costs:dword ret endp ;void (png_structrp png_ptr, int level) align 4 proc png_set_compression_level uses edi, png_ptr:dword, level:dword png_debug 1, 'in png_set_compression_level' mov edi,[png_ptr] cmp edi,0 je @f ;if (..==0) return m2m [edi+png_struct.zlib_level], [level] @@: ret endp ;void (png_structrp png_ptr, int mem_level) align 4 proc png_set_compression_mem_level uses edi, png_ptr:dword, mem_level:dword png_debug 1, 'in png_set_compression_mem_level' mov edi,[png_ptr] cmp edi,0 je @f ;if (..==0) return m2m [edi+png_struct.zlib_mem_level], [mem_level] @@: ret endp ;void (png_structrp png_ptr, int strategy) align 4 proc png_set_compression_strategy uses edi, png_ptr:dword, strategy:dword png_debug 1, 'in png_set_compression_strategy' mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return ; The flag setting here prevents the libpng dynamic selection of strategy. or dword[edi+png_struct.flags], PNG_FLAG_ZLIB_CUSTOM_STRATEGY m2m [edi+png_struct.zlib_strategy], [strategy] .end_f: ret endp ; If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a ; smaller value of window_bits if it can do so safely. ;void (png_structrp png_ptr, int window_bits) align 4 proc png_set_compression_window_bits uses eax edi, png_ptr:dword, window_bits:dword mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return ; Prior to 1.6.0 this would warn but then set the window_bits value. This ; meant that negative window bits values could be selected that would cause ; libpng to write a non-standard PNG file with raw deflate or gzip ; compressed IDAT or ancillary chunks. Such files can be read and there is ; no warning on read, so this seems like a very bad idea. mov eax,[window_bits] cmp eax,15 jle @f ;if (..>..) png_warning edi, 'Only compression windows <= 32k supported by PNG' mov eax,15 jmp .end0 @@: ;else if (..<..) cmp eax,8 jge @f png_warning edi, 'Only compression windows >= 256 supported by PNG' mov eax,8 .end0: mov [edi+png_struct.zlib_window_bits],eax .end_f: ret endp ;void (png_structrp png_ptr, int method) align 4 proc png_set_compression_method uses eax edi, png_ptr:dword, method:dword png_debug 1, 'in png_set_compression_method' mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return ; This would produce an invalid PNG file if it worked, but it doesn't and ; deflate will fault it, so it is harmless to just warn here. mov eax,[method] cmp eax,8 je @f ;if (..!=..) png_warning edi, 'Only compression method 8 is supported by PNG' @@: mov [edi+png_struct.zlib_method],eax .end_f: ret endp ; The following were added to libpng-1.5.4 if PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED eq 1 ;void (png_structrp png_ptr, int level) align 4 proc png_set_text_compression_level uses edi, png_ptr:dword, level:dword png_debug 1, 'in png_set_text_compression_level' mov edi,[png_ptr] cmp edi,0 je @f ;if (..==0) return m2m [edi+png_struct.zlib_text_level], [level] @@: ret endp ;void (png_structrp png_ptr, int mem_level) align 4 proc png_set_text_compression_mem_level uses edi, png_ptr:dword, mem_level:dword png_debug 1, 'in png_set_text_compression_mem_level' mov edi,[png_ptr] cmp edi,0 je @f ;if (..==0) return m2m [edi+png_struct.zlib_text_mem_level], [mem_level] @@: ret endp ;void (png_structrp png_ptr, int strategy) align 4 proc png_set_text_compression_strategy uses edi, png_ptr:dword, strategy:dword png_debug 1, 'in png_set_text_compression_strategy' mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return m2m [edi+png_struct.zlib_text_strategy], [strategy] .end_f: ret endp ; If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a ; smaller value of window_bits if it can do so safely. ;void (png_structrp png_ptr, int window_bits) align 4 proc png_set_text_compression_window_bits uses eax edi, png_ptr:dword, window_bits:dword mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return mov eax,[window_bits] cmp eax,15 jle @f ;if (..>..) png_warning edi, 'Only compression windows <= 32k supported by PNG' mov eax,15 jmp .end0 @@: ;else if (..<..) cmp eax,8 jge @f png_warning edi, 'Only compression windows >= 256 supported by PNG' mov eax,8 .end0: mov [edi+png_struct.zlib_text_window_bits],eax .end_f: ret endp ;void (png_structrp png_ptr, int method) align 4 proc png_set_text_compression_method uses edi, png_ptr:dword, method:dword png_debug 1, 'in png_set_text_compression_method' mov edi,[png_ptr] cmp edi,0 je .end_f ;if (..==0) return cmp dword[method],8 je @f ;if (..!=..) png_warning edi, 'Only compression method 8 is supported by PNG' @@: m2m [edi+png_struct.zlib_text_method], [method] .end_f: ret endp end if ;WRITE_CUSTOMIZE_ZTXT_COMPRESSION ; end of API added to libpng-1.5.4 ;void (png_structrp png_ptr, png_write_status_ptr write_row_fn) align 4 proc png_set_write_status_fn uses edi, png_ptr:dword, write_row_fn:dword mov edi,[png_ptr] cmp edi,0 je @f ;if (..==0) return m2m [edi+png_struct.write_row_fn], [write_row_fn] @@: ret endp ;void (png_structrp png_ptr, png_user_transform_ptr write_user_transform_fn) align 4 proc png_set_write_user_transform_fn uses edi, png_ptr:dword, write_user_transform_fn:dword png_debug 1, 'in png_set_write_user_transform_fn' mov edi,[png_ptr] cmp edi,0 je @f ;if (..==0) return or dword[edi+png_struct.transformations], PNG_USER_TRANSFORM m2m [edi+png_struct.write_user_transform_fn], [write_user_transform_fn] @@: ret endp ;void (png_structrp png_ptr, png_inforp info_ptr, int transforms, voidp params) align 4 proc png_write_png, png_ptr:dword, info_ptr:dword, transforms:dword, params:dword pushad mov edi,[png_ptr] cmp edi,0 je .end_f mov esi,[info_ptr] cmp esi,0 je .end_f ;if(..==0 || ..==0) return and dword[esi+png_info_def.valid],PNG_INFO_IDAT cmp esi,0 ;if(..==0) jne @f cStr ,'no rows for png_write_image to write' stdcall png_app_error edi, eax jmp .end_f ;return @@: ; Write the file header information. stdcall png_write_info, edi, esi ; ------ these transformations don't touch the info structure ------- ; Invert monochrome pixels mov eax,[transforms] and eax,PNG_TRANSFORM_INVERT_MONO jz @f ;if(..!=0) if PNG_WRITE_INVERT_SUPPORTED eq 1 stdcall png_set_invert_mono,edi else cStr ,'PNG_TRANSFORM_INVERT_MONO not supported' stdcall png_app_error edi, eax end if @@: ; Shift the pixels up to a legal bit depth and fill in ; as appropriate to correctly scale the image. mov eax,[transforms] and eax,PNG_TRANSFORM_SHIFT jz @f ;if(..!=0) if PNG_WRITE_SHIFT_SUPPORTED eq 1 mov eax,[esi+png_info_def.valid] and eax,PNG_INFO_sBIT jz @f ;if(..!=0) mov eax,esi add eax,png_info_def.sig_bit stdcall png_set_shift, edi, eax else cStr ,'PNG_TRANSFORM_SHIFT not supported' stdcall png_app_error edi, eax end if @@: ; Pack pixels into bytes mov eax,[transforms] and eax,PNG_TRANSFORM_PACKING jz @f ;if(..!=0) if PNG_WRITE_PACK_SUPPORTED eq 1 stdcall png_set_packing, edi else cStr ,'PNG_TRANSFORM_PACKING not supported' stdcall png_app_error edi, eax end if @@: ; Swap location of alpha bytes from ARGB to RGBA mov eax,[transforms] and eax,PNG_TRANSFORM_SWAP_ALPHA jz @f ;if(..!=0) if PNG_WRITE_SWAP_ALPHA_SUPPORTED eq 1 stdcall png_set_swap_alpha, edi else cStr ,'PNG_TRANSFORM_SWAP_ALPHA not supported' stdcall png_app_error edi, eax end if @@: ; Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into ; RGB, note that the code expects the input color type to be G or RGB; no ; alpha channel. mov eax,[transforms] and eax,PNG_TRANSFORM_STRIP_FILLER_AFTER or PNG_TRANSFORM_STRIP_FILLER_BEFORE jz .end_0 ;if(..!=0) if PNG_WRITE_FILLER_SUPPORTED eq 1 and eax,PNG_TRANSFORM_STRIP_FILLER_AFTER jz .end_1 ;if(..!=0) mov eax,[transforms] and eax,PNG_TRANSFORM_STRIP_FILLER_BEFORE jz @f ;if(..!=0) cStr ,'PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported' stdcall png_app_error edi, eax @@: ; Continue if ignored - this is the pre-1.6.10 behavior stdcall png_set_filler, edi, 0, PNG_FILLER_AFTER jmp .end_0 .end_1: ;else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) stdcall png_set_filler, edi, 0, PNG_FILLER_BEFORE else cStr ,'PNG_TRANSFORM_STRIP_FILLER not supported' stdcall png_app_error edi, eax end if .end_0: ; Flip BGR pixels to RGB mov eax,[transforms] and eax,PNG_TRANSFORM_BGR jz @f ;if(..!=0) if PNG_WRITE_BGR_SUPPORTED eq 1 stdcall png_set_bgr, edi else cStr ,'PNG_TRANSFORM_BGR not supported' stdcall png_app_error edi, eax end if @@: ; Swap bytes of 16-bit files to most significant byte first mov eax,[transforms] and eax,PNG_TRANSFORM_SWAP_ENDIAN jz @f ;if(..!=0) if PNG_WRITE_SWAP_SUPPORTED eq 1 stdcall png_set_swap, edi else cStr ,'PNG_TRANSFORM_SWAP_ENDIAN not supported' stdcall png_app_error edi, eax end if @@: ; Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats mov eax,[transforms] and eax,PNG_TRANSFORM_PACKSWAP jz @f ;if(..!=0) if PNG_WRITE_PACKSWAP_SUPPORTED eq 1 stdcall png_set_packswap, edi else cStr ,'PNG_TRANSFORM_PACKSWAP not supported' stdcall png_app_error edi, eax end if @@: ; Invert the alpha channel from opacity to transparency mov eax,[transforms] and eax,PNG_TRANSFORM_INVERT_ALPHA jz @f ;if(..!=0) if PNG_WRITE_INVERT_ALPHA_SUPPORTED eq 1 stdcall png_set_invert_alpha, edi else cStr ,'PNG_TRANSFORM_INVERT_ALPHA not supported' stdcall png_app_error edi, eax end if @@: ; ----------------------- end of transformations ------------------- ; Write the bits stdcall png_write_image, edi, dword[esi+png_info_def.row_pointers] ; It is REQUIRED to call this to finish writing the rest of the file stdcall png_write_end, edi, esi .end_f: popad ret endp if PNG_SIMPLIFIED_WRITE_SUPPORTED eq 1 ; Initialize the write structure - general purpose utility. ;int (png_imagep image) align 4 proc png_image_write_init uses ebx ecx edx edi esi, image:dword mov ebx,[image] stdcall png_create_write_struct, PNG_LIBPNG_VER_STRING, ebx, png_safe_error, png_safe_warning ;eax = png_ptr test eax,eax jz .end0 ;if (..!=0) mov edi,eax stdcall png_create_info_struct, edi ;eax = info_ptr test eax,eax jz .end1 ;if (..!=0) mov esi,eax stdcall png_malloc_warn, edi, sizeof.png_control ;control = eax test eax,eax jz .end2 ;if (..!=0) push eax mov edx,edi ; edx = png_ptr mov ecx,sizeof.png_control mov edi,eax xor eax,eax rep stosb ;memset(control, 0, (sizeof.control)) pop eax mov [eax+png_control.png_ptr], edx mov [eax+png_control.info_ptr], esi mov [eax+png_control.for_write], 1 mov [ebx+png_image.opaque], eax xor eax,eax inc eax jmp .end_f .end2: ; Error clean up push esi mov esi,esp stdcall png_destroy_info_struct, edi, esi add esp,4 .end1: push edi mov edi,esp stdcall png_destroy_write_struct, edi, 0 add esp,4 .end0: std_png_image_error ebx, 'png_image_write_: out of memory' .end_f: ret endp ; Arguments to png_image_write_main: struct png_image_write_control ; Arguments: image dd ? ;png_imagep buffer dd ? ;png_const_voidp row_stride dd ? ;int_32 colormap dd ? ;png_const_voidp convert_to_8bit dd ? ;int ; Local variables: first_row dd ? ;png_const_voidp row_bytes dd ? ;ptrdiff_t local_row dd ? ;voidp ; Byte count for memory writing memory dd ? ;bytep memory_bytes dd ? ;png_alloc_size_t ;not used for STDIO output_bytes dd ? ;png_alloc_size_t ;running total ends ; Write uint_16 input to a 16-bit PNG; the png_ptr has already been set to ; do any necessary byte swapping. The component order is defined by the ; png_image format value. ;int (voidp argument) align 4 proc png_write_image_16bit uses ebx ecx edx, argument:dword locals display dd ? ;png_image_write_control* ;= argument image dd ? ;png_imagep ;= display->image png_ptr dd ? ;png_structrp ;= image->opaque->png_ptr input_row dd ? ;const_uint_16p ;= display->first_row output_row dd ? ;uint_16p ;= display->local_row row_end dd ? ;uint_16p channels dd ? ;const int ;= (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; aindex dd 0 ;int ;= 0 y dd ? ;uint_32 ;= image->height endl mov ebx,[argument] mov [display],ebx mov edx,[ebx+png_image_write_control.image] mov [image],edx mov ecx,[edx+png_image.opaque] mov ecx,[ecx+png_control.png_ptr] mov [png_ptr],ecx mov ecx,[ebx+png_image_write_control.first_row] mov [input_row],ecx mov ecx,[ebx+png_image_write_control.local_row] mov [output_row],ecx mov ecx,1 mov eax,[edx+png_image.format] and eax,PNG_FORMAT_FLAG_COLOR jz @f mov ecx,3 @@: mov [channels],ecx mov eax,[edx+png_image.height] mov [y],eax mov eax,[edx+png_image.format] and eax,PNG_FORMAT_FLAG_ALPHA jz .end0 ;if (..!=0) if PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED eq 1 mov eax,[edx+png_image.format] and eax,PNG_FORMAT_FLAG_AFIRST jz @f ;if (..!=0) mov dword[aindex],-1 inc dword[input_row] ;To point to the first component inc dword[output_row] jmp .end1 @@: ;else end if mov eax,[channels] mov [aindex],eax jmp .end1 .end0: ;else png_error [png_ptr], 'png_write_image: internal call error' .end1: ; Work out the output row end and count over this, note that the increment ; above to 'row' means that row_end can actually be beyond the end of the ; row; this is correct. mov eax,[channels] inc eax imul eax,[edx+png_image.width] add eax,[output_row] mov [row_end],eax ; while (y-- > 0) ; { ; const_uint_16p in_ptr = input_row; ; uint_16p out_ptr = output_row; ; while (out_ptr < row_end) ; { ; const uint_16 alpha = in_ptr[aindex]; ; uint_32 reciprocal = 0; ; int c; ; out_ptr[aindex] = alpha; ; Calculate a reciprocal. The correct calculation is simply ; component/alpha*65535 << 15. (I.e. 15 bits of precision); this ; allows correct rounding by adding .5 before the shift. 'reciprocal' ; is only initialized when required. ; if (alpha > 0 && alpha < 65535) ; reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; ; c = channels; ; do /* always at least one channel */ ; { ; uint_16 component = *in_ptr++; ; The following gives 65535 for an alpha of 0, which is fine, ; otherwise if 0/0 is represented as some other value there is more ; likely to be a discontinuity which will probably damage ; compression when moving from a fully transparent area to a ; nearly transparent one. (The assumption here is that opaque ; areas tend not to be 0 intensity.) ; if (component >= alpha) ; component = 65535; ; component 0 && alpha < 65535) ; { ; uint_32 calc = component * reciprocal; ; calc += 16384; /* round to nearest */ ; component = (uint_16)(calc >> 15); ; } ; *out_ptr++ = component; ; } ; while (--c > 0); ; Skip to next component (skip the intervening alpha channel) ; ++in_ptr; ; ++out_ptr; ; } ; png_write_row(png_ptr, display->local_row); ; input_row += display->row_bytes/(sizeof (uint_16)); ; } xor eax,eax inc eax ;return 1 ret endp ; Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel ; is present it must be removed from the components, the components are then ; written in sRGB encoding. No components are added or removed. ; Calculate an alpha reciprocal to reverse pre-multiplication. As above the ; calculation can be done to 15 bits of accuracy; however, the output needs to ; be scaled in the range 0..255*65535, so include that scaling here. ;# define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) ;byte (uint_32 component, uint_32 alpha, uint_32 reciprocal/*from the above macro*/) align 4 proc png_unpremultiply, component:dword, alpha:dword, reciprocal:dword ; The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 ; is represented as some other value there is more likely to be a ; discontinuity which will probably damage compression when moving from a ; fully transparent area to a nearly transparent one. (The assumption here ; is that opaque areas tend not to be 0 intensity.) ; There is a rounding problem here; if alpha is less than 128 it will end up ; as 0 when scaled to 8 bits. To avoid introducing spurious colors into the ; output change for this too. mov eax,[alpha] cmp [component],eax jge @f cmp eax,128 jge .end0 @@: ;if (..>=.. || ..<..) mov eax,255 jmp .end_f ; component 0) cmp dword[component],0 jle .end1 ; The test is that alpha/257 (rounded) is less than 255, the first value ; that becomes 255 is 65407. ; NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, ; be exact!) [Could also test reciprocal != 0] ; if (alpha < 65407) ; { ; component *= reciprocal; ; component += 64; /* round to nearest */ ; component >>= 7; ; } ; else ; component *= 255; ; Convert the component to sRGB. PNG_sRGB_FROM_LINEAR [component] and eax,0xff jmp .end_f .end1: ;else xor eax,eax .end_f: ret endp ;int (voidp argument) align 4 proc png_write_image_8bit uses ebx ecx edx edi esi, argument:dword locals display dd ? ;png_image_write_control* ;= argument image dd ? ;png_imagep ;= display->image png_ptr dd ? ;png_structrp ;= image->opaque->png_ptr input_row dd ? ;const_uint_16p ;= display->first_row output_row dd ? ;uint_16p ;= display->local_row row_end dd ? ;uint_16p channels dd ? ;const int ;= (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; aindex dd 0 ;int ;= 0 y dd ? ;uint_32 ;= image->height component dd ? ;uint_32 endl mov ebx,[argument] mov [display],ebx mov edx,[ebx+png_image_write_control.image] mov [image],edx mov ecx,[edx+png_image.opaque] mov ecx,[ecx+png_control.png_ptr] mov [png_ptr],ecx mov ecx,[ebx+png_image_write_control.first_row] mov [input_row],ecx mov ecx,[ebx+png_image_write_control.local_row] mov [output_row],ecx mov ecx,1 mov eax,[edx+png_image.format] and eax,PNG_FORMAT_FLAG_COLOR jz @f mov ecx,3 @@: mov [channels],ecx mov eax,[edx+png_image.height] mov [y],eax mov eax,[edx+png_image.format] and eax,PNG_FORMAT_FLAG_ALPHA jz .end0 ;if (..!=0) if PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED eq 1 mov eax,[edx+png_image.format] and eax,PNG_FORMAT_FLAG_AFIRST jz .end2 ;if (..!=0) mov [aindex],-1 inc [input_row] ; To point to the first component inc [output_row] jmp @f .end2: ;else end if mov eax,[channels] mov [aindex],eax .@@: ; Use row_end in place of a loop counter: mov ecx,[channels] inc ecx imul ecx,[edx+png_image.width] add ecx,[output_row] ;ecx = row_end ; while (y-- > 0) ; { ; const_uint_16p in_ptr = input_row; ; bytep out_ptr = output_row; ; while (out_ptr < row_end) ; { ; uint_16 alpha = in_ptr[aindex]; ; byte alphabyte = (byte)PNG_DIV257(alpha); ; uint_32 reciprocal = 0; ; int c; ; Scale and write the alpha channel. ; out_ptr[aindex] = alphabyte; ; if (alphabyte > 0 && alphabyte < 255) ; reciprocal = UNP_RECIPROCAL(alpha); ; c = channels; ; do /* always at least one channel */ ; *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); ; while (--c > 0); ; Skip to next component (skip the intervening alpha channel) ; ++in_ptr; ; ++out_ptr; ; } /* while out_ptr < row_end */ ; png_write_row(png_ptr, display->local_row); ; input_row += display->row_bytes/(sizeof (uint_16)); ; } /* while y */ jmp .end1 .end0: ;else ; No alpha channel, so the row_end really is the end of the row and it ; is sufficient to loop over the components one by one. mov ecx,[edx+png_image.width] imul ecx,[channels] add ecx,[output_row] ;ecx = row_end .cycle2: ;while (y-- > 0) cmp dword[y],0 jle .cycle2end mov esi,[input_row] mov edi,[output_row] ;esi = in_ptr ;edi = out_ptr .cycle3: ;while (..<..) cmp edi,ecx jge .cycle3end xor eax,eax lodsw imul eax,255 mov [component],eax PNG_sRGB_FROM_LINEAR [component] stosb jmp .cycle3 align 4 .cycle3end: stdcall png_write_row, [png_ptr], [output_row] mov eax,[ebx+png_image_write_control.row_bytes] shr eax,1 ;sizeof.uint_16 add [input_row],eax dec dword[y] jmp .cycle2 align 4 .cycle2end: .end1: xor eax,eax inc eax ret endp ;void (png_image_write_control *display) align 4 proc png_image_set_PLTE, display:dword locals image dd ? ;png_imagep ;= display->image cmap dd ? ;void * ;= display->colormap entries dd ? ;int ; NOTE: the caller must check for cmap != NULL and entries != 0 format dd ? ;uint_32 ;= image->format channels dd ? ;int afirst dd 0 bgr dd 0 num_trans dd 0 palette rb 256*sizeof.png_color tRNS rb 256 ;byte[] endl pushad mov edx,[display] mov ebx,[edx+png_image_write_control.image] mov [image],ebx mov eax,[edx+png_image_write_control.colormap] mov [cmap],eax mov eax,[ebx+png_image.colormap_entries] cmp eax,256 jle @f mov eax,256 @@: mov [entries],eax mov ecx,[ebx+png_image.format] mov [format],ecx PNG_IMAGE_SAMPLE_CHANNELS ecx mov [channels],eax if (PNG_FORMAT_BGR_SUPPORTED eq 1) & (PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED eq 1) mov eax,ecx and eax,PNG_FORMAT_FLAG_AFIRST jz @f mov eax,ecx and eax,PNG_FORMAT_FLAG_ALPHA jz @f mov dword[afirst],-1 @@: end if if PNG_FORMAT_BGR_SUPPORTED eq 1 mov eax,ecx and eax,PNG_FORMAT_FLAG_BGR jz @f mov dword[bgr],2 @@: end if ; int i; xor eax,eax mov ecx,(256*sizeof.png_color)/4 mov edi,ebp sub edi,256+256*sizeof.png_color rep stosd ;memset(palette, 0, ... not eax mov ecx,256/4 ;;mov edi,ebp ;if 'tRNS' after 'palette' this code can be comment ;;sub edi,256 rep stosd ;memset(tRNS, 255, ... ; for (i=num_trans=0; i= 3) /* RGB */ ; { ; palette[i].blue = (byte)PNG_sRGB_FROM_LINEAR(255 * ; entry[(2 ^ bgr)]); ; palette[i].green = (byte)PNG_sRGB_FROM_LINEAR(255 * ; entry[1]); ; palette[i].red = (byte)PNG_sRGB_FROM_LINEAR(255 * ; entry[bgr]); ; } ; else /* Gray */ ; palette[i].blue = palette[i].red = palette[i].green = ; (byte)PNG_sRGB_FROM_LINEAR(255 * *entry); ; } ; else /* alpha */ ; { ; uint_16 alpha = entry[afirst ? 0 : channels-1]; ; byte alphabyte = (byte)PNG_DIV257(alpha); ; uint_32 reciprocal = 0; ; Calculate a reciprocal, as in the png_write_image_8bit code above ; this is designed to produce a value scaled to 255*65535 when ; divided by 128 (i.e. asr 7). ; if (alphabyte > 0 && alphabyte < 255) ; reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; ; tRNS[i] = alphabyte; ; if (alphabyte < 255) ; num_trans = i+1; ; if (channels >= 3) /* RGB */ ; { ; palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], ; alpha, reciprocal); ; palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, ; reciprocal); ; palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, ; reciprocal); ; } ; else /* gray */ ; palette[i].blue = palette[i].red = palette[i].green = ; png_unpremultiply(entry[afirst], alpha, reciprocal); ; } ; } ; else /* Color-map has sRGB values */ ; { ; bytep entry = cmap; ; entry += i * channels; ; switch (channels) ; { ; case 4: ; tRNS[i] = entry[afirst ? 0 : 3]; ; if (tRNS[i] < 255) ; num_trans = i+1; ; /* FALL THROUGH */ ; case 3: ; palette[i].blue = entry[afirst + (2 ^ bgr)]; ; palette[i].green = entry[afirst + 1]; ; palette[i].red = entry[afirst + bgr]; ; break; ; case 2: ; tRNS[i] = entry[1 ^ afirst]; ; if (tRNS[i] < 255) ; num_trans = i+1; ; /* FALL THROUGH */ ; case 1: ; palette[i].blue = palette[i].red = palette[i].green = ; entry[afirst]; ; break; ; default: ; break; ; } ; } ; } mov ecx,[ebx+png_image.opaque] mov eax,ebp sub eax,256+256*sizeof.png_color stdcall png_set_PLTE, [ecx+png_control.png_ptr], [ecx+png_control.info_ptr], eax, [entries] cmp dword[num_trans],0 jle @f ;if (..>0) mov eax,ebp sub eax,256 stdcall png_set_tRNS, [ecx+png_control.png_ptr], [ecx+png_control.info_ptr], eax, [num_trans], 0 @@: mov eax,[entries] mov [ebx+png_image.colormap_entries],eax popad ret endp ;int (voidp argument) align 4 proc png_image_write_main uses ebx ecx edx esi edi, argument:dword locals display dd ? ;= png_image_write_control * = argument image dd ? ;= display->image png_ptr dd ? ;= image->opaque->png_ptr info_ptr dd ? ;= image->opaque->info_ptr format dd ? ;= image->format colormap dd ? linear dd ? alpha dd ? write_16bit dd ? ;= linear && !colormap && (display->convert_to_8bit == 0) endl mov edx,[argument] mov [display],edx mov ebx,[edx+png_image_write_control.image] mov [image],ebx mov ecx,[ebx+png_image.format] mov [format],ecx mov eax,[ebx+png_image.opaque] mov edi,[eax+png_control.png_ptr] mov [png_ptr],edi mov esi,[eax+png_control.info_ptr] mov [info_ptr],esi ; The following four ints are actually booleans and ecx,PNG_FORMAT_FLAG_COLORMAP mov [colormap],ecx ;colormap = (format & PNG_FORMAT_FLAG_COLORMAP) not ecx mov eax,[format] and eax,PNG_FORMAT_FLAG_LINEAR and eax,ecx mov [linear],eax ;linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR) mov eax,[format] and eax,PNG_FORMAT_FLAG_ALPHA and eax,ecx mov [alpha],eax ;alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA) xor eax,eax ;false cmp dword[edx+png_image_write_control.convert_to_8bit],0 jne @f not eax ;true @@: and eax,[linear] and eax,ecx mov [write_16bit],eax if PNG_BENIGN_ERRORS_SUPPORTED eq 1 ; Make sure we error out on any bad situation stdcall png_set_benign_errors, edi, 0 ;error end if ; Default the 'row_stride' parameter if required, also check the row stride ; and total image size to ensure that they are within the system limits. PNG_IMAGE_PIXEL_CHANNELS [ebx+png_image.format] ;eax = channels push edx mov ecx,eax mov eax,0x7FFFFFFF xor edx,edx div ecx pop edx cmp [ebx+png_image.width],eax jg .end0 ;if (..<=..) ;no overflow imul ecx,[ebx+png_image.width] cmp dword[edx+png_image_write_control.row_stride],0 jne @f ;if (..==0) mov [edx+png_image_write_control.row_stride],ecx @@: mov eax,[edx+png_image_write_control.row_stride] cmp eax,0 jge .end2 ;if (..<0) neg eax inc eax .end2: cmp eax,ecx jl .end3 ;if (..>=..) ; Now check for overflow of the image buffer calculation; this ; limits the whole image size to 32 bits for API compatibility with ; the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. push edx mov eax,0xFFFFFFFF xor edx,edx div ecx pop edx cmp [ebx+png_image.height],eax jle @f ;if (..>..) mov eax,[ebx+png_image.opaque] mov eax,[eax+png_control.png_ptr] png_error eax, 'memory image too large' @@: jmp .end1 .end3: ;else mov eax,[ebx+png_image.opaque] mov eax,[eax+png_control.png_ptr] png_error eax, 'supplied row stride too small' jmp .end1 .end0: ;else mov eax,[ebx+png_image.opaque] mov eax,[eax+png_control.png_ptr] png_error eax, 'image row stride too large' .end1: ; Set the required transforms then write the rows in the correct order. mov eax,[format] and eax,PNG_FORMAT_FLAG_COLORMAP jz .end4 ;if (..!=0) cmp dword[edx+png_image_write_control.colormap],0 je .end6 mov eax,[ebx+png_image.colormap_entries] cmp eax,0 jle .end6 ;if (..!=0 && ..>0) ;eax = entries xor ecx,ecx inc ecx ;=1 cmp eax,2 jle @f shl ecx,1 ;=2 cmp eax,4 jle @f shl ecx,1 ;=4 cmp eax,16 jle @f shl ecx,1 ;=8 @@: stdcall png_set_IHDR, edi, esi, [ebx+png_image.width], [ebx+png_image.height],\ ecx, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE stdcall png_image_set_PLTE, edx jmp .end5 .end6: ;else mov eax,[ebx+png_image.opaque] mov eax,[eax+png_control.png_ptr] png_error eax, 'no color-map for color-mapped image' jmp .end5 .end4: ;else xor ecx,ecx mov eax,[format] and eax,PNG_FORMAT_FLAG_COLOR jz @f or ecx,PNG_COLOR_MASK_COLOR @@: mov eax,[format] and eax,PNG_FORMAT_FLAG_ALPHA jz @f or ecx,PNG_COLOR_MASK_ALPHA @@: mov eax,8 cmp dword[write_16bit],0 je @f mov eax,16 @@: stdcall png_set_IHDR, edi, esi, [ebx+png_image.width], [ebx+png_image.height],\ eax, ecx, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE .end5: ; Counter-intuitively the data transformations must be called *after* ; png_write_info, not before as in the read code, but the 'set' functions ; must still be called before. Just set the color space information, never ; write an interlaced image. cmp dword[write_16bit],0 je @f ;if (..!=0) ; The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. stdcall png_set_gAMA_fixed, edi, esi, PNG_GAMMA_LINEAR mov eax,[ebx+png_image.flags] and eax,PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB jnz @f ;if (..==0) stdcall png_set_cHRM_fixed, edi, esi,\ 31270, 32900,\ ;white 64000, 33000,\ ;red 30000, 60000,\ ;green 15000, 6000 ;blue jmp .end7 @@: mov eax,[ebx+png_image.flags] and eax,PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB jnz @f ;else if (..==0) stdcall png_set_sRGB, edi, esi, PNG_sRGB_INTENT_PERCEPTUAL jmp .end7 @@: ;else ; Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit ; space must still be gamma encoded. stdcall png_set_gAMA_fixed, edi, esi, PNG_GAMMA_sRGB_INVERSE .end7: ; Write the file header. stdcall png_write_info, edi, esi ; Now set up the data transformations (*after* the header is written), ; remove the handled transformations from the 'format' flags for checking. ; First check for a little endian system if writing 16-bit files. cmp dword[write_16bit],0 je @f ;if (..!=0) ; uint_16 le = 0x0001; ; if ((*(bytep) & le) != 0) stdcall png_set_swap, edi @@: if PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED eq 1 mov eax,[format] and eax,PNG_FORMAT_FLAG_BGR jz .end12 ;if (..!=0) cmp dword[colormap],0 jne @f mov eax,[format] and eax,PNG_FORMAT_FLAG_COLOR jz @f ;if (..==0 && ..!=0) stdcall png_set_bgr, edi @@: and dword[format], not PNG_FORMAT_FLAG_BGR .end12: end if if PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED eq 1 mov eax,[format] and eax,PNG_FORMAT_FLAG_AFIRST jz .end13 ;if (..!=0) cmp dword[colormap],0 jne @f mov eax,[format] and eax,PNG_FORMAT_FLAG_ALPHA jz @f ;if (..==0 && ..!=0) stdcall png_set_swap_alpha, edi @@: and dword[format], not PNG_FORMAT_FLAG_AFIRST .end13: end if ; If there are 16 or fewer color-map entries we wrote a lower bit depth ; above, but the application data is still byte packed. cmp dword[colormap],0 je @f cmp dword[ebx+png_image.colormap_entries],16 jg @f ;if (..!=0 && ..<=16) stdcall png_set_packing, edi @@: ; That should have handled all (both) the transforms. mov eax,[format] and eax, not (PNG_FORMAT_FLAG_COLOR or PNG_FORMAT_FLAG_LINEAR or PNG_FORMAT_FLAG_ALPHA or PNG_FORMAT_FLAG_COLORMAP) jz @f ;if (..!=0) png_error edi, 'png_write_image: unsupported transformation' @@: push esi ;ecx - row ;bytep ;esi - row_bytes mov ecx,[edx+png_image_write_control.buffer] mov esi,[edx+png_image_write_control.row_stride] cmp dword[linear],0 je @f ;if (..!=0) shl esi,1 ;*= sizeof.uint_16 @@: cmp esi,0 jge @f ;if (..<0) mov eax,[ebx+png_image.height] dec eax imul eax,esi sub ecx,eax @@: mov [edx+png_image_write_control.first_row],ecx mov [edx+png_image_write_control.row_bytes],esi pop esi ; Apply 'fast' options if the flag is set. mov eax,[ebx+png_image.flags] and eax,PNG_IMAGE_FLAG_FAST jz @f ;if (..!=0) stdcall png_set_filter, edi, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS ; NOTE: determined by experiment using pngstest, this reflects some ; balance between the time to write the image once and the time to read ; it about 50 times. The speed-up in pngstest was about 10-20% of the ; total (user) time on a heavily loaded system. if PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED eq 1 stdcall png_set_compression_level, edi, 3 end if @@: ; Check for the cases that currently require a pre-transform on the row ; before it is written. This only applies when the input is 16-bit and ; either there is an alpha channel or it is converted to 8-bit. cmp dword[linear],0 je @f cmp dword[alpha],0 je @f jmp .end10 @@: cmp dword[colormap],0 jne .end9 cmp dword[edx+png_image_write_control.convert_to_8bit],0 je .end9 .end10: ;if ((..!=0 && ..!=0 ) || (..==0 && ..!=0)) stdcall png_get_rowbytes, edi, esi stdcall png_malloc, edi, eax mov ecx,eax ;ecx = row mov [edx+png_image_write_control.local_row],ecx cmp dword[write_16bit],0 je @f ;if (..!=0) stdcall png_safe_execute, ebx, png_write_image_16bit, edx jmp .end11 @@: ;else stdcall png_safe_execute, ebx, png_write_image_8bit, edx .end11: mov dword[edx+png_image_write_control.local_row],0 stdcall png_free, edi, ecx ; Skip the 'write_end' on error: test eax,eax jz .end_f ;if (..==0) return 0 jmp .end8 ; Otherwise this is the case where the input is in a format currently ; supported by the rest of the libpng write code; call it directly. .end9: ;else if 1 ;;; IDAT compress all cmp dword[ebx+png_image.height],1 jl .end8 mov ecx,[edx+png_image_write_control.row_bytes] inc ecx imul ecx,[ebx+png_image.height] stdcall create_compress_IDAT, edi, [edx+png_image_write_control.first_row], ecx, [ebx+png_image.width], [ebx+png_image.height] else ;;; IDAT compress by lines mov ecx,[ebx+png_image.height] cmp ecx,1 jl .end8 mov eax,[edx+png_image_write_control.first_row] mov ebx,[edx+png_image_write_control.row_bytes] @@: stdcall png_write_row, edi, eax add eax, ebx loop @b end if .end8: stdcall png_write_end, edi, esi xor eax,eax inc eax .end_f: ret endp align 16 proc create_compress_IDAT, png_ptr:dword, buf:dword, len:dword, width:dword, height:dword locals m1 dd ? ;memory for compress IDAT buf_f dd ? ;memory for IDAT mins dd ? ;minimum sum endl pushad mov edi,[png_ptr] png_debug1 2, 'IDAT compress all len = %d', [len] ;create buffer with filters stdcall png_zalloc, edi, 1, [len] test eax,eax jz .end_f mov [buf_f],eax mov eax,ZLIB_IO_MAX cmp eax,[len] jge @f mov eax,[len] @@: stdcall png_zalloc, edi, 1, eax test eax,eax jz .end0 mov [m1],eax ;init buffer with filters mov ebx,[width] mov edx,[height] movzx eax,byte[edi+png_struct.color_type] mov edi,[buf_f] mov esi,[buf] cmp eax,PNG_COLOR_TYPE_RGB_ALPHA je .cycle5 .cycle0: ;24 bit image cmp edx,1 jl .cycle0end mov ecx,ebx xor al,al stosb ;insert filter (0 - none) align 4 .cycle1: lodsb ;1 inc edi ; movsb ;2 stosb ;3 lodsb ; mov [edi-3],al loop .cycle1 dec edx jmp .cycle0 .cycle0end: jmp .cycle5end .cycle5: ;32 bit image cmp edx,1 jl .cycle5end mov ecx,ebx xor al,al stosb ;insert filter (0 - none) align 4 .cycle6: lodsd bswap eax ror eax,8 stosd loop .cycle6 dec edx jmp .cycle5 .cycle5end: ;make filters mov edx,[height] mov edi,[png_ptr] mov esi,[edi+png_struct.rowbytes] inc esi cmp dword[edi+png_struct.try_row],0 jne @f ;if (..==0) stdcall png_malloc, edi, esi mov [edi+png_struct.try_row],eax @@: cmp dword[edi+png_struct.tst_row],0 jne @f ;if (..==0) stdcall png_malloc, edi, esi mov [edi+png_struct.tst_row],eax @@: dec esi mov edi,[buf_f] add edi,[len] .cycle3: dec edx cmp edx,1 jl .cycle3end sub edi,esi dec edi ;move in perv row ;init pointers for function png_setup_up_row mov ebx,[png_ptr] mov [ebx+png_struct.row_buf],edi mov [ebx+png_struct.prev_row],edi sub [ebx+png_struct.prev_row],esi dec dword[ebx+png_struct.prev_row] ;calculate start minimum sum push esi xor eax,eax xor ebx,ebx mov ecx,esi mov esi,edi inc esi .cycle2: lodsb png_setup_abs ebx loop .cycle2 pop esi mov [mins],ebx push edx mov edx,[png_ptr] mov eax,[edx+png_struct.tst_row] mov byte[eax],0 ;not filter ; Up filter stdcall png_setup_up_row, edx, esi, [mins] cmp eax,[mins] jge @f ;if (..<..) mov [mins],eax stdcall copy_row_mins, [edx+png_struct.tst_row], [edx+png_struct.try_row] @@: ; Find out how many bytes offset each pixel is movzx ebx,byte[edx+png_struct.pixel_depth] add ebx,7 shr ebx,3 ; Sub filter stdcall png_setup_sub_row, edx, ebx, esi, [mins] cmp eax,[mins] jge @f ;if (..<..) mov [mins],eax stdcall copy_row_mins, [edx+png_struct.tst_row], [edx+png_struct.try_row] @@: ; Avg filter stdcall png_setup_avg_row, edx, ebx, esi, [mins] cmp eax,[mins] jge @f ;if (..<..) mov [mins],eax stdcall copy_row_mins, [edx+png_struct.tst_row], [edx+png_struct.try_row] @@: ; Paeth filter stdcall png_setup_paeth_row, edx, ebx, esi, [mins] cmp eax,[mins] jge @f ;if (..<..) mov [mins],eax stdcall copy_row_mins, [edx+png_struct.tst_row], [edx+png_struct.try_row] @@: ; Copy best row mov eax,[edx+png_struct.tst_row] cmp byte[eax],0 je @f stdcall copy_row_mins, edi, [edx+png_struct.tst_row] @@: pop edx jmp .cycle3 .cycle3end: mov edi,[png_ptr] lea esi,[edi+png_struct.zstream] stdcall [deflateInit2], esi,\ -1, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY mov eax,[buf_f] mov [edi+png_struct.zstream.next_in],eax mov eax,[len] mov [edi+png_struct.zstream.avail_in],eax mov eax,[m1] mov [edi+png_struct.zstream.next_out],eax xor ecx,ecx align 4 .cycle4: mov dword[edi+png_struct.zstream.avail_out],16*1024 stdcall [deflate], esi, Z_FINISH ;Z_NO_FLUSH cmp eax,Z_STREAM_ERROR je .end1 add ecx,16*1024 sub ecx,[edi+png_struct.zstream.avail_out] cmp dword[edi+png_struct.zstream.avail_out],0 je .cycle4 ;while (strm.avail_out == 0) if 0 mov dword[edi+png_struct.zstream.avail_out],16*1024 stdcall [deflate], esi, Z_FINISH add ecx,16*1024 sub ecx,[edi+png_struct.zstream.avail_out] cmp eax,Z_STREAM_ERROR je .end1 end if stdcall [deflateEnd], esi if PNG_WRITE_OPTIMIZE_CMF_SUPPORTED eq 1 mov eax,[edi+png_struct.mode] and eax,PNG_HAVE_IDAT jnz @f cmp byte[edi+png_struct.compression_type],PNG_COMPRESSION_TYPE_BASE jne @f ;if (..==0 && ..==..) stdcall png_image_size, edi stdcall optimize_cmf, [m1], eax @@: end if stdcall png_write_complete_chunk, edi, png_IDAT, [m1], ecx or dword[edi+png_struct.mode],PNG_HAVE_IDAT jmp @f .end1: png_debug 1, 'Z_STREAM_ERROR' @@: ;free memory cmp dword[edi+png_struct.try_row],0 je @f ;if (..!=0) stdcall png_free, edi, [edi+png_struct.try_row] mov dword[edi+png_struct.try_row],0 @@: cmp dword[edi+png_struct.tst_row],0 je @f ;if (..!=0) stdcall png_free, edi, [edi+png_struct.tst_row] mov dword[edi+png_struct.tst_row],0 @@: stdcall png_free, edi, [m1] .end0: stdcall png_free, edi, [buf_f] .end_f: popad ret endp ;input: ; esi - rowbytes align 4 proc copy_row_mins uses edi esi, dest:dword, sour:dword mov ecx,esi inc ecx mov edi,[dest] mov esi,[sour] rep movsb ret endp ;void (png_structp png_ptr, bytep/*const*/ data, png_size_t size) align 4 proc image_memory_write uses eax ebx ecx edi esi, png_ptr:dword, p2data:dword, size:dword mov edi,[png_ptr] mov esi,[edi+png_struct.io_ptr] ;esi = png_image_write_control *display mov ebx,[esi+png_image_write_control.output_bytes] ;ebx = ob ; Check for overflow; this should never happen: mov eax,PNG_SIZE_MAX sub eax,ebx mov ecx,[size] cmp ecx,eax jg .end1 ;if (..<=..) ; I don't think libpng ever does this, but just in case: cmp ecx,0 jle .end0 ;if (..>0) mov eax,ebx add eax,ecx cmp [esi+png_image_write_control.memory_bytes],eax jl @f ;if (..>=..) ;writing push esi mov edi,[esi+png_image_write_control.memory] add edi,ebx mov esi,[p2data] rep movsb ;memcpy(... pop esi @@: ; Always update the size: add ebx,[size] mov [esi+png_image_write_control.output_bytes],ebx .end0: jmp .end2 .end1: ;else png_error edi, 'png_image_write_to_memory: PNG too big' .end2: ret endp ;void (png_structp png_ptr) align 4 proc image_memory_flush, png_ptr:dword ret endp ;int (voidp argument) align 4 proc png_image_write_memory uses ebx, argument:dword ; The rest of the memory-specific init and write_main in an error protected ; environment. This case needs to use callbacks for the write operations ; since libpng has no built in support for writing to memory. mov eax,[argument] mov ebx,[eax+png_image_write_control.image] mov ebx,[ebx+png_image.opaque] stdcall png_set_write_fn, [ebx+png_control.png_ptr], eax, image_memory_write, image_memory_flush stdcall png_image_write_main, [argument] ret endp ;int (png_imagep image, void *memory, ; png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit, ; const void *buffer, int_32 row_stride, const void *colormap) align 4 proc png_image_write_to_memory uses ebx ecx edx edi esi, image:dword, memory:dword,\ memory_bytes:dword, convert_to_8bit:dword, buffer:dword, row_stride:dword, colormap:dword locals display png_image_write_control ;local struct endl ;edi - display png_image_write_control ; Write the image to the given buffer, or count the bytes if it is NULL mov ebx,[image] or ebx,ebx jz .end0 cmp dword[ebx+png_image.version],PNG_IMAGE_VERSION jne .end0 ;if (..!=0 && ..==..) cmp dword[memory_bytes],0 je .end2 cmp dword[buffer],0 je .end2 ;if (..!=0 && ..!=0) ; This is to give the caller an easier error detection in the NULL ; case and guard against uninitialized variable problems: cmp dword[memory],0 jne @f ;if(..==0) mov eax,[memory_bytes] mov dword[eax],0 @@: stdcall png_image_write_init, ebx test eax,eax jz .end3 ;if (..!=0) mov ecx,sizeof.png_image_write_control mov edi,ebp sub edi,ecx xor eax,eax rep stosb ;memset(&display, 0, sizeof.display)) sub edi,sizeof.png_image_write_control mov [edi+png_image_write_control.image],ebx mov eax,[buffer] mov [edi+png_image_write_control.buffer],eax mov eax,[row_stride] mov [edi+png_image_write_control.row_stride],eax mov eax,[colormap] mov [edi+png_image_write_control.colormap],eax mov eax,[convert_to_8bit] mov [edi+png_image_write_control.convert_to_8bit],eax mov eax,[memory] mov [edi+png_image_write_control.memory],eax mov eax,[memory_bytes] mov eax,[eax] mov [edi+png_image_write_control.memory_bytes],eax mov dword[edi+png_image_write_control.output_bytes], 0 stdcall png_safe_execute, ebx, png_image_write_memory, edi mov ecx,eax ;ecx = result stdcall png_image_free, ebx ; write_memory returns true even if we ran out of buffer. or ecx,ecx ;if (..) jz .end4 ; On out-of-buffer this function returns '0' but still updates ; memory_bytes: mov edx,[edi+png_image_write_control.output_bytes] mov eax,[memory_bytes] cmp dword[memory],0 je @f ;if (..!=0 && ..>..) cmp edx,[eax] jle @f xor ecx,ecx @@: mov [eax],edx .end4: mov eax,ecx jmp .end_f .end3: ;else xor eax,eax jmp .end_f .end2: ;else std_png_image_error ebx, 'png_image_write_to_memory: invalid argument' jmp .end_f .end0: or ebx,ebx jz .end1 ;else if (..!=0) std_png_image_error ebx, 'png_image_write_to_memory: incorrect PNG_IMAGE_VERSION' jmp .end_f .end1: ;else xor eax,eax .end_f: ret endp ;int (png_imagep image, FILE *file, int convert_to_8bit, ; const void *buffer, int_32 row_stride, const void *colormap) align 4 proc png_image_write_to_stdio, image:dword, file:dword, convert_to_8bit:dword, buffer:dword, row_stride:dword, colormap:dword ; Write the image to the given (FILE*). ; if (image != NULL && image->version == PNG_IMAGE_VERSION) ; { ; if (file != NULL && buffer != NULL) ; { ; if (png_image_write_init(image) != 0) ; { ; png_image_write_control display; ; int result; ; This is slightly evil, but png_init_io doesn't do anything other ; than this and we haven't changed the standard IO functions so ; this saves a 'safe' function. ; image->opaque->png_ptr->io_ptr = file; ; memset(&display, 0, (sizeof display)); ; display.image = image; ; display.buffer = buffer; ; display.row_stride = row_stride; ; display.colormap = colormap; ; display.convert_to_8bit = convert_to_8bit; ; result = png_safe_execute(image, png_image_write_main, &display); ; png_image_free(image); ; return result; ; } ; else ; return 0; ; } ; else ; return png_image_error(image, ; "png_image_write_to_stdio: invalid argument"); ; } ; else if (image != NULL) ; return png_image_error(image, ; "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); ; else ; return 0; ret endp ;int (png_imagep image, const char *file_name, ; int convert_to_8bit, const void *buffer, int_32 row_stride, ; const void *colormap) align 4 proc png_image_write_to_file, image:dword, file_name:dword, convert_to_8bit:dword, buffer:dword, row_stride:dword, colormap:dword ; Write the image to the named file. ; if (image != NULL && image->version == PNG_IMAGE_VERSION) ; { ; if (file_name != NULL && buffer != NULL) ; { ; FILE *fp = fopen(file_name, "wb"); ; if (fp != NULL) ; { ; if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, ; row_stride, colormap) != 0) ; { ; int error; /* from fflush/fclose */ ; Make sure the file is flushed correctly. ; if (fflush(fp) == 0 && ferror(fp) == 0) ; { ; if (fclose(fp) == 0) ; return 1; ; error = errno; /* from fclose */ ; } ; else ; { ; error = errno; /* from fflush or ferror */ ; (void)fclose(fp); ; } ; (void)remove(file_name); ; The image has already been cleaned up; this is just used to ; set the error (because the original write succeeded). ; return png_image_error(image, strerror(error)); ; } ; else ; { ; Clean up: just the opened file. ; (void)fclose(fp); ; (void)remove(file_name); ; return 0; ; } ; } ; else ; return png_image_error(image, strerror(errno)); ; } ; else ; return png_image_error(image, ; "png_image_write_to_file: invalid argument"); ; } ; else if (image != NULL) ; return png_image_error(image, ; "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); ; else ; return 0; ret endp end if ;SIMPLIFIED_WRITE