Subversion Repositories Kolibri OS

Rev

Rev 8341 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1.  
  2. ; pngwutil.asm - utilities to write a PNG file
  3.  
  4. ; Last changed in libpng 1.6.24 [August 4, 2016]
  5. ; Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  6. ; (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  7. ; (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  8.  
  9. ; This code is released under the libpng license.
  10. ; For conditions of distribution and use, see the disclaimer
  11. ; and license in png.inc
  12.  
  13. ; Place a 32-bit number into a buffer in PNG byte order.  We work
  14. ; with unsigned numbers for convenience, although one supported
  15. ; ancillary chunk uses signed (two's complement) numbers.
  16.  
  17. ;void (bytep buf, uint_32 i)
  18. align 4
  19. proc png_save_uint_32 uses eax edi, buf:dword, i:dword
  20.         mov eax,[i]
  21.         bswap eax
  22.         mov edi,[buf]
  23.         stosd
  24.         ret
  25. endp
  26.  
  27. ; Place a 16-bit number into a buffer in PNG byte order.
  28. ; The parameter is declared unsigned int, not uint_16,
  29. ; just to avoid potential problems on pre-ANSI C compilers.
  30.  
  31. ;void (bytep buf, unsigned int i)
  32. align 4
  33. proc png_save_uint_16 uses eax edi, buf:dword, i:dword
  34.         mov eax,[i]
  35.         ror eax,16
  36.         bswap eax
  37.         mov edi,[buf]
  38.         stosw
  39.         ret
  40. endp
  41.  
  42. ; Simple function to write the signature.  If we have already written
  43. ; the magic bytes of the signature, or more likely, the PNG stream is
  44. ; being embedded into another stream and doesn't need its own signature,
  45. ; we should call png_set_sig_bytes() to tell libpng how many of the
  46. ; bytes have already been written.
  47.  
  48. align 4
  49. png_signature db 137, 80, 78, 71, 13, 10, 26, 10
  50.  
  51. ;void (png_structrp png_ptr)
  52. align 4
  53. proc png_write_sig uses eax ebx edi, png_ptr:dword
  54. if PNG_IO_STATE_SUPPORTED eq 1
  55.         ; Inform the I/O callback that the signature is being written
  56.         mov edi,[png_ptr]
  57.         mov dword[edi+png_struct.io_state], PNG_IO_WRITING or PNG_IO_SIGNATURE
  58. end if
  59.  
  60.         ; Write the rest of the 8 byte signature
  61.         movzx eax,byte[edi+png_struct.sig_bytes]
  62.         mov ebx,8
  63.         sub ebx,eax
  64.         add eax,png_signature
  65.         stdcall png_write_data, edi, eax, ebx
  66.  
  67.         cmp byte[edi+png_struct.sig_bytes], 3 ;if(..<3)
  68.         jge @f
  69.                 or dword[edi+png_struct.mode], PNG_HAVE_PNG_SIGNATURE
  70.         @@:
  71.         ret
  72. endp
  73.  
  74. ; Write the start of a PNG chunk.  The type is the chunk type.
  75. ; The total_length is the sum of the lengths of all the data you will be
  76. ; passing in png_write_chunk_data().
  77.  
  78. ;void (png_structrp png_ptr, uint_32 chunk_name, uint_32 length)
  79. align 4
  80. proc png_write_chunk_header uses ebx edi, png_ptr:dword, chunk_name:dword, length:dword
  81. locals
  82.         buf rb 8 ;ebp-8
  83. endl
  84.  
  85. if (PNG_DEBUG eq 1) & (PNG_DEBUG > 0)
  86. ;   PNG_CSTRING_FROM_CHUNK(buf, chunk_name);
  87. ;   png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length);
  88. end if
  89.  
  90.         mov edi,[png_ptr]
  91.         test edi,edi
  92.         jz .end_f ;if (..==0) return
  93.  
  94. if PNG_IO_STATE_SUPPORTED eq 1
  95.         ; Inform the I/O callback that the chunk header is being written.
  96.         ; PNG_IO_CHUNK_HDR requires a single I/O call.
  97.  
  98.         mov dword[edi+png_struct.io_state], PNG_IO_WRITING or PNG_IO_CHUNK_HDR
  99. end if
  100.  
  101.         ; Write the length and the chunk name
  102.         lea ebx,[ebp-8]
  103.         stdcall png_save_uint_32, ebx, [length]
  104.         m2m dword[ebx+4],dword[chunk_name]
  105.         stdcall png_write_data, edi, ebx, 8
  106.  
  107.         ; Put the chunk name into png_ptr->chunk_name
  108.         m2m dword[edi+png_struct.chunk_name],dword[chunk_name]
  109.  
  110.         ; Reset the crc and run it over the chunk name
  111.         stdcall png_reset_crc, edi
  112.         lea ebx,[ebp-4] ;buf + 4
  113.         stdcall png_calculate_crc, edi, ebx, 4
  114.  
  115. if PNG_IO_STATE_SUPPORTED eq 1
  116.         ; Inform the I/O callback that chunk data will (possibly) be written.
  117.         ; PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
  118.  
  119.         mov dword[edi+png_struct.io_state], PNG_IO_WRITING or PNG_IO_CHUNK_DATA
  120. end if
  121. .end_f:
  122.         ret
  123. endp
  124.  
  125. ;void (png_structrp png_ptr, bytep chunk_string, uint_32 length)
  126. align 4
  127. proc png_write_chunk_start uses eax, png_ptr:dword, chunk_string:dword, length:dword
  128.         mov eax,[chunk_string]
  129.         stdcall png_write_chunk_header, [png_ptr], [eax], [length]
  130.         ret
  131. endp
  132.  
  133. ; Write the data of a PNG chunk started with png_write_chunk_header().
  134. ; Note that multiple calls to this function are allowed, and that the
  135. ; sum of the lengths from these calls *must* add up to the total_length
  136. ; given to png_write_chunk_header().
  137.  
  138. ;void (png_structrp png_ptr, bytep data, png_size_t length)
  139. align 4
  140. proc png_write_chunk_data uses edi, png_ptr:dword, p2data:dword, length:dword
  141.         ; Write the data, and run the CRC over it
  142.         mov edi,[png_ptr]
  143.         cmp edi,0
  144.         je .end_f ;if (..==0) return
  145.  
  146.         cmp dword[p2data],0
  147.         je .end_f
  148.         cmp dword[length],0
  149.         jle .end_f ;if (..!=0 && ..>0)
  150.                 stdcall png_write_data, edi, [p2data], [length]
  151.                 ; Update the CRC after writing the data,
  152.                 ; in case the user I/O routine alters it.
  153.                 stdcall png_calculate_crc, edi, [p2data], [length]
  154. .end_f:
  155.         ret
  156. endp
  157.  
  158. ; Finish a chunk started with png_write_chunk_header().
  159. ;void (png_structrp png_ptr)
  160. align 4
  161. proc png_write_chunk_end uses ebx edi, png_ptr:dword
  162. locals
  163.         buf rb 4 ;ebp-4
  164. endl
  165.         mov edi,[png_ptr]
  166.         cmp edi,0
  167.         je .end_f ;if (..==0) return
  168.  
  169. if PNG_IO_STATE_SUPPORTED eq 1
  170.         ; Inform the I/O callback that the chunk CRC is being written.
  171.         ; PNG_IO_CHUNK_CRC requires a single I/O function call.
  172.  
  173.         mov dword[edi+png_struct.io_state], PNG_IO_WRITING or PNG_IO_CHUNK_CRC
  174. end if
  175.  
  176.         ; Write the crc in a single operation
  177.         lea ebx,[ebp-4]
  178.         stdcall png_save_uint_32, ebx, [edi+png_struct.crc]
  179.  
  180.         stdcall png_write_data, edi, ebx, 4
  181. .end_f:
  182.         ret
  183. endp
  184.  
  185. ; Write a PNG chunk all at once.  The type is an array of ASCII characters
  186. ; representing the chunk name.  The array must be at least 4 bytes in
  187. ; length, and does not need to be null terminated.  To be safe, pass the
  188. ; pre-defined chunk names here, and if you need a new one, define it
  189. ; where the others are defined.  The length is the length of the data.
  190. ; All the data must be present.  If that is not possible, use the
  191. ; png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
  192. ; functions instead.
  193.  
  194. ;void (png_structrp png_ptr, uint_32 chunk_name, bytep data, png_size_t length)
  195. align 4
  196. proc png_write_complete_chunk uses edi, png_ptr:dword, chunk_name:dword, p3data:dword, length:dword
  197.         mov edi,[png_ptr]
  198.         test edi,edi
  199.         jz .end_f ;if (..==0) return
  200.  
  201.         ; On 64-bit architectures 'length' may not fit in a uint_32.
  202.         cmp dword[length],PNG_UINT_31_MAX ;if(..>..)
  203.         jle @f
  204.                 png_error edi, 'length exceeds PNG maximum'
  205.         @@:
  206.         stdcall png_write_chunk_header, edi, [chunk_name], [length]
  207.         stdcall png_write_chunk_data, edi, [p3data], [length]
  208.         stdcall png_write_chunk_end, edi
  209. .end_f:
  210.         ret
  211. endp
  212.  
  213. ; This is the API that calls the internal function above.
  214. ;void (png_structrp png_ptr, bytep chunk_string, bytep data, png_size_t length)
  215. align 4
  216. proc png_write_chunk, png_ptr:dword, chunk_string:dword, p3data:dword, length:dword
  217.         stdcall png_write_complete_chunk, [png_ptr], [chunk_string], [p3data], [length]
  218.         ret
  219. endp
  220.  
  221. ; This is used below to find the size of an image to pass to png_deflate_claim,
  222. ; so it only needs to be accurate if the size is less than 16384 bytes (the
  223. ; point at which a lower LZ window size can be used.)
  224.  
  225. ;png_alloc_size_t (png_structrp png_ptr)
  226. align 4
  227. proc png_image_size uses ebx ecx edx edi esi, png_ptr:dword
  228. ; Only return sizes up to the maximum of a uint_32; do this by limiting
  229. ; the width and height used to 15 bits.
  230.  
  231.         mov edi,[png_ptr]
  232.         mov ebx,[edi+png_struct.height]
  233.  
  234.         cmp dword[edi+png_struct.rowbytes],32768
  235.         jge .end0
  236.         cmp ebx,32768
  237.         jge .end0 ;if (..<..  && ..<..)
  238.                 cmp byte[edi+png_struct.interlaced],0
  239.                 je .end1 ;if (..!=0)
  240.                         ; Interlacing makes the image larger because of the replication of
  241.                         ; both the filter byte and the padding to a byte boundary.
  242.  
  243.                         xor esi,esi
  244.                         xor ecx,ecx
  245.                         .cycle0:
  246.                                 PNG_PASS_COLS [edi+png_struct.width], ecx
  247.                                 ;eax = pw
  248.  
  249.                                 cmp eax,0
  250.                                 jle @f ;if (..>0)
  251.                                         mov edx,eax
  252.                                         movzx eax,byte[edi+png_struct.pixel_depth]
  253.                                         PNG_ROWBYTES eax, edx
  254.                                         inc eax
  255.                                         mov edx,eax
  256.                                         PNG_PASS_ROWS ebx, ecx
  257.                                         imul eax,edx
  258.                                         add esi,eax
  259.                                 @@:
  260.                                 inc ecx
  261.                                 cmp ecx,6
  262.                                 jle .cycle0
  263.  
  264.                         mov eax,esi
  265.                         jmp .end_f
  266.                 .end1: ;else
  267.                         mov eax,[edi+png_struct.rowbytes]
  268.                         inc eax
  269.                         imul eax,ebx
  270.                         jmp .end_f
  271.         .end0: ;else
  272.                 mov eax,0xffffffff
  273. .end_f:
  274.         ret
  275. endp
  276.  
  277. ; This is the code to hack the first two bytes of the deflate stream (the
  278. ; deflate header) to correct the windowBits value to match the actual data
  279. ; size.  Note that the second argument is the *uncompressed* size but the
  280. ; first argument is the *compressed* data (and it must be deflate
  281. ; compressed.)
  282.  
  283. ;void (bytep data, png_alloc_size_t data_size)
  284. align 4
  285. proc optimize_cmf, p1data:dword, data_size:dword
  286. ; Optimize the CMF field in the zlib stream.  The resultant zlib stream is
  287. ; still compliant to the stream specification.
  288.         png_debug 1, 'optimize_cmf'
  289. pushad
  290.         cmp dword[data_size],16384
  291.         jg .end_f ;if (..<=..) ;else windowBits must be 15
  292.                 mov esi,[p1data]
  293.                 movzx ebx,byte[esi]
  294.                 ;ebx = z_cmf ;zlib compression method and flags
  295.  
  296.                 mov eax,ebx
  297.                 and eax,0x0f
  298.                 cmp eax,8
  299.                 jne .end_f
  300.                 mov eax,ebx
  301.                 and eax,0xf0
  302.                 cmp eax,0x70
  303.                 jg .end_f ;if (..==.. && ..<=..)
  304.                         ;ecx = z_cinfo
  305.                         ;edi = half_z_window_size
  306.  
  307.                         mov ecx,ebx
  308.                         shr ecx,4
  309.                         xor edi,edi
  310.                         inc edi
  311.                         shl edi,7
  312.                         shl edi,cl
  313.  
  314.                         cmp [data_size],edi
  315.                         jg .end_f ;if (..<=..) ;else no change
  316.                                 .cycle0: ;do
  317.                                         shr edi,1
  318.                                         dec ecx
  319.                                         cmp ecx,0
  320.                                         jle @f
  321.                                         cmp [data_size],edi
  322.                                         jle .cycle0
  323.                                 @@: ;while (..>0 && ..<=..);
  324.  
  325.                                 and ebx,0x0f
  326.                                 mov eax,ecx
  327.                                 shl eax,4
  328.                                 or ebx,eax
  329.  
  330.                                 mov byte[esi],bl
  331.                                 movzx eax,byte[esi+1]
  332.                                 and eax,0xe0
  333.                                 shl ebx,8
  334.                                 add ebx,eax
  335.                                 add eax,0x1f
  336.                                 xchg eax,ebx
  337.                                 xor edx,edx
  338.                                 mov ecx,0x1f
  339.                                 div ecx
  340.                                 sub ebx,edx
  341.                                 mov byte[esi+1],bl
  342. .end_f:
  343. popad
  344.         ret
  345. endp
  346.  
  347. ; Initialize the compressor for the appropriate type of compression.
  348. ;int (png_structrp png_ptr, uint_32 owner, png_alloc_size_t data_size)
  349. ;input:
  350. ; edi - png_ptr
  351. align 4
  352. proc png_deflate_claim uses ebx ecx, owner:dword, data_size:dword
  353. locals
  354.         level dd ? ;int
  355.         method dd ? ;int
  356.         windowBits dd ? ;int
  357.         memLevel dd ? ;int
  358.         strategy dd ? ;int
  359.         msg rb 64 ;char[64]
  360. endl
  361.         png_debug 1, 'in png_deflate_claim'
  362.  
  363.         cmp dword[edi+png_struct.zowner],0
  364.         je .end0 ;if (..!=0)
  365.                 lea ebx,[ebp-64]
  366. if (PNG_WARNINGS_SUPPORTED eq 1) | (PNG_ERROR_TEXT_SUPPORTED eq 1)
  367.                 mov eax,[owner]
  368.                 mov [ebx],eax
  369.                 mov word[ebx+4],': '
  370.                 mov eax,[edi+png_struct.zowner]
  371.                 mov [ebx+6],eax
  372.                 ; So the message that results is "<chunk> using zstream"; this is an
  373.                 ; internal error, but is very useful for debugging.  i18n requirements
  374.                 ; are minimal.
  375.  
  376.                 cStr ,' using zstream'
  377.                 stdcall png_safecat, ebx, 64, 10, eax
  378. end if
  379. if PNG_RELEASE_BUILD eq 1
  380.                 png_warning edi, ebx
  381.  
  382.                 ; Attempt sane error recovery
  383.                 cmp dword[edi+png_struct.zowner],png_IDAT
  384.                 jne @f ;if (..==.) ;don't steal from IDAT
  385.                         cStr dword[edi+png_struct.zstream.msg],'in use by IDAT'
  386.                         mov eax,Z_STREAM_ERROR
  387.                         jmp .end_f
  388.                 @@:
  389.                 mov dword[edi+png_struct.zowner],0
  390. else
  391.                 png_error edi, ebx
  392. end if
  393.         .end0:
  394.  
  395.         mov eax,[edi+png_struct.zlib_level]
  396.         mov [level],eax
  397.         mov eax,[edi+png_struct.zlib_method]
  398.         mov [method],eax
  399.         mov eax,[edi+png_struct.zlib_window_bits]
  400.         mov [windowBits],eax
  401.         mov eax,[edi+png_struct.zlib_mem_level]
  402.         mov [memLevel],eax
  403.  
  404.         cmp dword[owner],png_IDAT
  405.         jne .end1 ;if (..==..)
  406.                 mov eax,[edi+png_struct.flags]
  407.                 and eax,PNG_FLAG_ZLIB_CUSTOM_STRATEGY
  408.                 jz @f ;if (..!=0)
  409.                         mov eax,[edi+png_struct.zlib_strategy]
  410.                         mov dword[strategy],eax
  411.                         jmp .end2
  412.                 @@:
  413.                 cmp byte[edi+png_struct.do_filter],PNG_FILTER_NONE
  414.                 je @f ;else if (..!=..)
  415.                         mov dword[strategy],PNG_Z_DEFAULT_STRATEGY
  416.                         jmp .end2
  417.                 @@: ;else
  418.                         mov dword[strategy],PNG_Z_DEFAULT_NOFILTER_STRATEGY
  419.                 jmp .end2
  420.         .end1: ;else
  421. if PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED eq 1
  422.                 mov eax,[edi+png_struct.zlib_text_level]
  423.                 mov [level],eax
  424.                 mov eax,[edi+png_struct.zlib_text_method]
  425.                 mov [method],eax
  426.                 mov eax,[edi+png_struct.zlib_text_window_bits]
  427.                 mov [windowBits],eax
  428.                 mov eax,[edi+png_struct.zlib_text_mem_level]
  429.                 mov [memLevel],eax
  430.                 mov eax,[edi+png_struct.zlib_text_strategy]
  431.                 mov [strategy],eax
  432. else
  433.                 ; If customization is not supported the values all come from the
  434.                 ; IDAT values except for the strategy, which is fixed to the
  435.                 ; default.  (This is the pre-1.6.0 behavior too, although it was
  436.                 ; implemented in a very different way.)
  437.  
  438.                 mov dword[strategy],Z_DEFAULT_STRATEGY
  439. end if
  440.         .end2:
  441.  
  442.         ; Adjust 'windowBits' down if larger than 'data_size'; to stop this
  443.         ; happening just pass 32768 as the data_size parameter.  Notice that zlib
  444.         ; requires an extra 262 bytes in the window in addition to the data to be
  445.         ; able to see the whole of the data, so if data_size+262 takes us to the
  446.         ; next windowBits size we need to fix up the value later.  (Because even
  447.         ; though deflate needs the extra window, inflate does not!)
  448.  
  449.         cmp dword[data_size],16384
  450.         jg .end3 ;if (..<=..)
  451.                 ; IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to
  452.                 ; work round a Microsoft Visual C misbehavior which, contrary to C-90,
  453.                 ; widens the result of the following shift to 64-bits if (and,
  454.                 ; apparently, only if) it is used in a test.
  455.  
  456.                 mov ecx,[windowBits]
  457.                 dec ecx
  458.                 xor eax,eax
  459.                 inc eax
  460.                 shl eax,cl ;eax = half_window_size
  461.                 mov ecx,[data_size]
  462.                 add ecx,262
  463.                 @@: ;while (..<=..)
  464.                         cmp ecx,eax
  465.                         jg .end3
  466.                         shr eax,1
  467.                         dec dword[windowBits]
  468.                         jmp @b
  469.         .end3:
  470.  
  471.         ; Check against the previous initialized values, if any.
  472.         mov eax,[edi+png_struct.flags]
  473.         and eax,PNG_FLAG_ZSTREAM_INITIALIZED
  474.         jz .end4
  475.         mov eax,[level]
  476.         cmp [edi+png_struct.zlib_set_level],eax
  477.         jne @f
  478.         mov eax,[method]
  479.         cmp [edi+png_struct.zlib_set_method],eax
  480.         jne @f
  481.         mov eax,[windowBits]
  482.         cmp [edi+png_struct.zlib_set_window_bits],eax
  483.         jne @f
  484.         mov eax,[memLevel]
  485.         cmp [edi+png_struct.zlib_set_mem_level],eax
  486.         jne @f
  487.         mov eax,[strategy]
  488.         cmp [edi+png_struct.zlib_set_strategy],eax
  489.         je .end4
  490.         @@: ;if (..!=0 && (..!=.. || ..!=.. || ..!=.. || ..!=.. || ..!=..))
  491.                 mov eax,edi
  492.                 add eax,png_struct.zstream
  493.                 stdcall [deflateEnd], eax
  494.                 cmp eax,Z_OK
  495.                 je @f ;if (..!=..)
  496.                         png_warning edi, 'deflateEnd failed (ignored)'
  497.                 @@:
  498.                 and dword[edi+png_struct.flags], not PNG_FLAG_ZSTREAM_INITIALIZED
  499.         .end4:
  500.  
  501.         ; For safety clear out the input and output pointers (currently zlib
  502.         ; doesn't use them on Init, but it might in the future).
  503.  
  504.         mov dword[edi+png_struct.zstream.next_in],0
  505.         mov dword[edi+png_struct.zstream.avail_in],0
  506.         mov dword[edi+png_struct.zstream.next_out],0
  507.         mov dword[edi+png_struct.zstream.avail_out],0
  508.  
  509.         ; Now initialize if required, setting the new parameters, otherwise just
  510.         ; to a simple reset to the previous parameters.
  511.  
  512.         mov ecx,edi
  513.         add ecx,png_struct.zstream
  514.         mov eax,[edi+png_struct.flags]
  515.         and eax,PNG_FLAG_ZSTREAM_INITIALIZED
  516.         jz @f ;if (..!=0)
  517.                 stdcall [deflateReset], ecx
  518.                 jmp .end5
  519.         @@: ;else
  520.                 stdcall [deflateInit2], ecx, [level], [method], [windowBits],\
  521.                         [memLevel], [strategy]
  522.  
  523.                 cmp eax,Z_OK
  524.                 je .end5 ;if (..==..)
  525.                         or dword[edi+png_struct.flags],PNG_FLAG_ZSTREAM_INITIALIZED
  526.         .end5:
  527.  
  528.         ; The return code is from either deflateReset or deflateInit2; they have
  529.         ; pretty much the same set of error codes.
  530.  
  531.         cmp eax,Z_OK
  532.         jne @f ;if (..==..)
  533.                 mov ecx,[owner]
  534.                 mov [edi+png_struct.zowner],ecx
  535.                 jmp .end_f
  536.         @@: ;else
  537.                 stdcall png_zstream_error, edi, eax
  538.  
  539. .end_f:
  540.         ret
  541. endp
  542.  
  543. ; Clean up (or trim) a linked list of compression buffers.
  544. ;void (png_structrp png_ptr, png_compression_bufferp *listp)
  545. align 4
  546. proc png_free_buffer_list uses eax ebx ecx edi, png_ptr:dword, listp:dword
  547.         mov eax,[listp]
  548.         mov ebx,[eax]
  549.         ;eax = png_compression_bufferp list
  550.  
  551.         cmp ebx,0
  552.         je @f ;if (..!=0)
  553.                 mov dword[eax],0
  554.                 .cycle0: ;do
  555.                         mov ecx,[ebx+png_compression_buffer.next]
  556.                         stdcall png_free, edi, ebx
  557.                         mov ebx,ecx
  558.                 cmp ebx,0
  559.                 jne .cycle0 ;while (..!=0)
  560.         @@:
  561.         ret
  562. endp
  563.  
  564. if PNG_WRITE_COMPRESSED_TEXT_SUPPORTED eq 1
  565. ; This pair of functions encapsulates the operation of (a) compressing a
  566. ; text string, and (b) issuing it later as a series of chunk data writes.
  567. ; The compression_state structure is shared context for these functions
  568. ; set up by the caller to allow access to the relevant local variables.
  569.  
  570. ; compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size
  571. ; temporary buffers.  From 1.6.0 it is retained in png_struct so that it will
  572. ; be correctly freed in the event of a write error (previous implementations
  573. ; just leaked memory.)
  574.  
  575. struct compression_state
  576.         input      dd ? ;bytep      ;The uncompressed input data
  577.         input_len  dd ? ;png_alloc_size_t ;Its length
  578.         output_len dd ? ;uint_32          ;Final compressed length
  579.         output     rb 1024 ;byte[1024]    ;First block of output
  580. ends
  581.  
  582. ;void (compression_state *comp, bytep input, png_alloc_size_t input_len)
  583. align 4
  584. proc png_text_compress_init uses eax ebx, comp:dword, input:dword, input_len:dword
  585.         mov ebx,[comp]
  586.         mov eax,[input]
  587.         mov [ebx+compression_state.input],eax
  588.         mov eax,[input_len]
  589.         mov [ebx+compression_state.input_len],eax
  590.         mov dword[ebx+compression_state.output_len],0
  591.         ret
  592. endp
  593.  
  594. ; Compress the data in the compression state input
  595. ;int (png_structrp png_ptr, uint_32 chunk_name, compression_state *comp, uint_32 prefix_len)
  596. align 4
  597. proc png_text_compress uses ebx ecx edx edi esi, png_ptr:dword, chunk_name:dword, comp:dword, prefix_len:dword
  598. locals
  599.         output_len dd ? ;uint_32
  600.         avail_in   dd ? ;uInt
  601.         next       dd ? ;png_compression_buffer*
  602. endl
  603.         ; To find the length of the output it is necessary to first compress the
  604.         ; input. The result is buffered rather than using the two-pass algorithm
  605.         ; that is used on the inflate side; deflate is assumed to be slower and a
  606.         ; PNG writer is assumed to have more memory available than a PNG reader.
  607.  
  608.         ; IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an
  609.         ; upper limit on the output size, but it is always bigger than the input
  610.         ; size so it is likely to be more efficient to use this linked-list
  611.         ; approach.
  612.  
  613.         mov ebx,[comp]
  614.         mov edi,[png_ptr]
  615.         stdcall png_deflate_claim, [chunk_name], [ebx+compression_state.input_len]
  616.  
  617.         cmp eax,Z_OK
  618.         jne .end_f ;if (..!=Z_OK) return ..
  619.  
  620.         ; Set up the compression buffers, we need a loop here to avoid overflowing a
  621.         ; uInt.  Use ZLIB_IO_MAX to limit the input.  The output is always limited
  622.         ; by the output buffer size, so there is no need to check that.  Since this
  623.         ; is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits
  624.         ; in size.
  625.  
  626.         mov edx,edi
  627.         add edx,png_struct.zbuffer_list
  628.         mov ecx,[ebx+compression_state.input_len] ;may be zero!
  629.         ;ecx = input_len
  630.         ;edx = end
  631.         ;esi = ret
  632.  
  633.         ; zlib updates these for us:
  634.         mov eax,[ebx+compression_state.input]
  635.         mov [edi+png_struct.zstream.next_in],eax
  636.         mov dword[edi+png_struct.zstream.avail_in],0 ;Set below
  637.         mov eax,ebx
  638.         add eax,compression_state.output
  639.         mov [edi+png_struct.zstream.next_out],eax
  640.         mov eax,sizeof.compression_state.output ;1024
  641.         mov [edi+png_struct.zstream.avail_out],eax
  642.  
  643.         mov [output_len],eax
  644.  
  645.         .cycle0: ;do
  646.                 mov dword[avail_in],ZLIB_IO_MAX
  647.  
  648.                 cmp [avail_in],ecx
  649.                 jle @f ;if (..>..)
  650.                         mov [avail_in],ecx
  651.                 @@:
  652.                 sub ecx,[avail_in]
  653.  
  654.                 mov eax,[avail_in]
  655.                 mov [edi+png_struct.zstream.avail_in],eax
  656.  
  657.                 cmp dword[edi+png_struct.zstream.avail_out],0
  658.                 jne .end0 ;if (..==0)
  659.                         ; Chunk data is limited to 2^31 bytes in length, so the prefix
  660.                         ; length must be counted here.
  661.  
  662.                         mov eax,[output_len]
  663.                         add eax,[prefix_len]
  664.                         cmp eax,PNG_UINT_31_MAX
  665.                         jle @f ;if (..>..)
  666.                                 mov esi,Z_MEM_ERROR
  667.                                 jmp .cycle0end
  668.                         @@:
  669.  
  670.                         ; Need a new (malloc'ed) buffer, but there may be one present
  671.                         ; already.
  672.  
  673.                         mov eax,[edx]
  674.                         mov [next],eax
  675.  
  676.                         test eax,eax
  677.                         jnz .end1 ;if (..==0)
  678.                                 PNG_COMPRESSION_BUFFER_SIZE edi
  679.                                 stdcall png_malloc, edi, eax
  680.                                 mov [next],eax
  681.  
  682.                                 test eax,eax
  683.                                 jnz @f ;if (..==0)
  684.                                         mov esi,Z_MEM_ERROR
  685.                                         jmp .cycle0end
  686.                                 @@:
  687.  
  688.                                 ; Link in this buffer (so that it will be freed later)
  689.                                 mov dword[eax+png_compression_buffer.next],0
  690.                                 mov [edx],eax
  691.                         .end1:
  692.  
  693.                         mov eax,[next]
  694.                         mov eax,[eax+png_compression_buffer.output]
  695.                         mov [edi+png_struct.zstream.next_out],eax
  696.                         mov eax,[edi+png_struct.zbuffer_size]
  697.                         mov [edi+png_struct.zstream.avail_out],eax
  698.                         add [output_len],eax
  699.  
  700.                         ; Move 'end' to the next buffer pointer.
  701.                         mov eax,[next]
  702.                         add eax,png_compression_buffer.next
  703.                         mov edx,eax
  704.                 .end0:
  705.  
  706.                 ; Compress the data
  707.                 mov eax,Z_FINISH
  708.                 cmp dword[input_len],0
  709.                 jle @f
  710.                         mov eax,Z_NO_FLUSH
  711.                 @@:
  712.                 push eax
  713.                 mov eax,edi
  714.                 add eax,png_struct.zstream
  715.                 stdcall [deflate], eax ;, ...
  716.                 mov esi,eax
  717.  
  718.                 ; Claw back input data that was not consumed (because avail_in is
  719.                 ; reset above every time round the loop).
  720.  
  721.                 mov eax,[edi+png_struct.zstream.avail_in]
  722.                 add [input_len],eax
  723.                 mov dword[edi+png_struct.zstream.avail_in],0 ;safety
  724.                 cmp esi,Z_OK
  725.                 je .cycle0 ;while (..==..)
  726.         .cycle0end:
  727.  
  728.         ; There may be some space left in the last output buffer. This needs to
  729.         ; be subtracted from output_len.
  730.  
  731.         mov eax,[edi+png_struct.zstream.avail_out]
  732.         sub [output_len],eax
  733.         mov dword[edi+png_struct.zstream.avail_out],0 ;safety
  734.         mov eax,[output_len]
  735.         mov [ebx+compression_state.output_len],eax
  736.  
  737.         ; Now double check the output length, put in a custom message if it is
  738.         ; too long.  Otherwise ensure the z_stream::msg pointer is set to
  739.         ; something.
  740.  
  741.         mov eax,[output_len]
  742.         add eax,[prefix_len]
  743.         cmp eax,PNG_UINT_31_MAX
  744.         jl @f ;if (..>=..)
  745.                 cStr dword[edi+png_struct.zstream.msg],'compressed data too long'
  746.                 mov esi,Z_MEM_ERROR
  747.                 jmp .end2
  748.         @@: ;else
  749.                 stdcall png_zstream_error, edi, esi
  750.         .end2:
  751.  
  752.         ; Reset zlib for another zTXt/iTXt or image data
  753.         mov dword[edi+png_struct.zowner],0
  754.  
  755.         ; The only success case is Z_STREAM_END, input_len must be 0; if not this
  756.         ; is an internal error.
  757.  
  758.         cmp esi,Z_STREAM_END
  759.         jne @f
  760.         cmp dword[input_len],0
  761.         jne @f ;if (..==.. && ..==0)
  762. if PNG_WRITE_OPTIMIZE_CMF_SUPPORTED eq 1
  763.                 ; Fix up the deflate header, if required
  764.                 mov eax,ebx
  765.                 add eax,compression_state.output
  766.                 stdcall optimize_cmf, eax, [ebx+compression_state.input_len]
  767. end if
  768.                 ; But Z_OK is returned, not Z_STREAM_END; this allows the claim
  769.                 ; function above to return Z_STREAM_END on an error (though it never
  770.                 ; does in the current versions of zlib.)
  771.  
  772.                 mov eax,Z_OK
  773.                 jmp .end_f
  774.         @@: ;else
  775.                 mov eax,esi
  776. .end_f:
  777.         ret
  778. endp
  779.  
  780. ; Ship the compressed text out via chunk writes
  781. ;void (png_structrp png_ptr, compression_state *comp)
  782. align 4
  783. proc png_write_compressed_data_out uses ebx edi, png_ptr:dword, comp:dword
  784. locals
  785.         output_len dd ? ;uint_32 ;= comp.output_len
  786.         output dd ? ;bytep ;= comp.output
  787.         avail  dd ? ;uint_32     ;= sizeof.comp.output
  788.         next   dd ? ;png_compression_buffer* ;= png_ptr.zbuffer_list
  789. endl
  790.         mov ebx,[comp]
  791.         mov eax,[ebx+compression_state.output_len]
  792.         mov [output_len],eax
  793.         mov eax,ebx
  794.         add eax,compression_state.output
  795.         mov [output],eax
  796.         mov [avail],sizeof.compression_state.output ;1024
  797.         mov edi,[png_ptr]
  798.         mov eax,[edi+png_struct.zbuffer_list]
  799.         mov [next],eax
  800.  
  801.         .cycle0: ;for (;;)
  802.                 mov eax,[output_len]
  803.                 cmp [avail],eax
  804.                 jle @f ;if (..>..)
  805.                         mov [avail],eax
  806.                 @@:
  807.  
  808.                 stdcall png_write_chunk_data, edi, [output], [avail]
  809.  
  810.                 mov [avail],eax
  811.                 sub [output_len],eax
  812.  
  813.                 cmp dword[output_len],0
  814.                 je .cycle0end
  815.                 cmp dword[next],0
  816.                 je .cycle0end ;if (..==0 || ..==0) break
  817.  
  818.                 mov eax,[edi+png_struct.zbuffer_size]
  819.                 mov [avail],eax
  820.                 mov eax,[next]
  821.                 add eax,png_compression_buffer.output
  822.                 mov [output],eax
  823.                 mov eax,[next]
  824.                 mov eax,[eax+png_compression_buffer.next]
  825.                 mov [next],eax
  826.                 jmp .cycle0
  827.         .cycle0end:
  828.  
  829.         ; This is an internal error; 'next' must have been NULL!
  830.         cmp dword[output_len],0
  831.         jle @f ;if (..>0)
  832.                 png_error edi, 'error writing ancillary chunked compressed data'
  833.         @@:
  834.         ret
  835. endp
  836. end if ;WRITE_COMPRESSED_TEXT
  837.  
  838. ; Write the IHDR chunk, and update the png_struct with the necessary
  839. ; information.  Note that the rest of this code depends upon this
  840. ; information being correct.
  841.  
  842. ;void (png_structrp png_ptr, uint_32 width, uint_32 height,
  843. ;    int bit_depth, int color_type, int compression_type, int filter_type, int interlace_type)
  844. align 4
  845. proc png_write_IHDR, png_ptr:dword, width:dword, height:dword, bit_depth:dword,\
  846.         color_type:dword, compression_type:dword, filter_type:dword, interlace_type:dword
  847. locals
  848.         buf rb 13 ;byte[13] ;Buffer to store the IHDR info
  849. endl
  850.         png_debug 1, 'in png_write_IHDR'
  851. pushad
  852.         ; Check that we have valid input data from the application info
  853.         mov edi,[png_ptr]
  854.         movzx ebx,byte[color_type]
  855.         cmp ebx,PNG_COLOR_TYPE_GRAY
  856.         jne .end_0
  857.                 cmp byte[bit_depth],1
  858.                 je @f
  859.                 cmp byte[bit_depth],2
  860.                 je @f
  861.                 cmp byte[bit_depth],4
  862.                 je @f
  863.                 cmp byte[bit_depth],8
  864.                 je @f
  865. if PNG_WRITE_16BIT_SUPPORTED eq 1
  866.                 cmp byte[bit_depth],16
  867.                 je @f
  868. end if
  869.                 jmp .def_0
  870.         @@:
  871.                 mov byte[edi+png_struct.channels], 1
  872.                 jmp .end_s0
  873.         .def_0: ;default
  874.                 png_error edi, 'Invalid bit depth for grayscale image'
  875.                 jmp .end_s0
  876.         .end_0:
  877.  
  878.         cmp ebx,PNG_COLOR_TYPE_RGB
  879.         jne .end_1
  880.                 cmp byte[bit_depth],8
  881.                 je @f ;if (..!=8)
  882. if PNG_WRITE_16BIT_SUPPORTED eq 1
  883.                 cmp byte[bit_depth],16
  884.                 je @f ;if (..!=16)
  885. end if
  886.             png_error edi, 'Invalid bit depth for RGB image'
  887.                 @@:
  888.                 mov byte[edi+png_struct.channels], 3
  889.                 jmp .end_s0
  890.         .end_1:
  891.  
  892.         cmp ebx,PNG_COLOR_TYPE_PALETTE
  893.         jne .end_2
  894.                 cmp byte[bit_depth],1
  895.                 je @f
  896.                 cmp byte[bit_depth],2
  897.                 je @f
  898.                 cmp byte[bit_depth],4
  899.                 je @f
  900.                 cmp byte[bit_depth],8
  901.                 je @f
  902.                 jmp .def_1
  903.                 @@:
  904.                         mov byte[edi+png_struct.channels], 1
  905.                         jmp .end_s0
  906.                 .def_1: ;default
  907.                         png_error edi, 'Invalid bit depth for paletted image'
  908.                 jmp .end_s0
  909.         .end_2:
  910.  
  911.         cmp ebx,PNG_COLOR_TYPE_GRAY_ALPHA
  912.         jne .end_3
  913.                 cmp byte[bit_depth],8
  914.                 je @f ;if (..!=8)
  915.                 cmp byte[bit_depth],16
  916.                 je @f ;if (..!=16)
  917.             png_error edi, 'Invalid bit depth for grayscale+alpha image'
  918.                 @@:
  919.                 mov byte[edi+png_struct.channels], 2
  920.                 jmp .end_s0
  921.         .end_3:
  922.  
  923.         cmp ebx,PNG_COLOR_TYPE_RGB_ALPHA
  924.         jne .end_4
  925.                 cmp byte[bit_depth],8
  926.                 je @f ;if (..!=8)
  927. if PNG_WRITE_16BIT_SUPPORTED eq 1
  928.                 cmp byte[bit_depth],16
  929.                 je @f ;if (..!=16)
  930. end if
  931.                         png_error edi, 'Invalid bit depth for RGBA image'
  932.                 @@:
  933.                 mov byte[edi+png_struct.channels], 4
  934.                 jmp .end_s0
  935.         .end_4:
  936.  
  937.         ;default:
  938.                 png_error edi, 'Invalid image color type specified'
  939.         .end_s0:
  940.  
  941.         cmp byte[compression_type], PNG_COMPRESSION_TYPE_BASE
  942.         je @f ;if (..!=..)
  943.                 png_warning edi, 'Invalid compression type specified'
  944.                 mov dword[compression_type], PNG_COMPRESSION_TYPE_BASE
  945.         @@:
  946.  
  947.         ; Write filter_method 64 (intrapixel differencing) only if
  948.         ; 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
  949.         ; 2. Libpng did not write a PNG signature (this filter_method is only
  950.         ;    used in PNG datastreams that are embedded in MNG datastreams) and
  951.         ; 3. The application called png_permit_mng_features with a mask that
  952.         ;    included PNG_FLAG_MNG_FILTER_64 and
  953.         ; 4. The filter_method is 64 and
  954.         ; 5. The color_type is RGB or RGBA
  955.  
  956. ;   if (
  957. if PNG_MNG_FEATURES_SUPPORTED eq 1
  958. ;       !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
  959. ;       ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
  960. ;       (color_type == PNG_COLOR_TYPE_RGB ||
  961. ;        color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
  962. ;       (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
  963. end if
  964.         cmp dword[filter_type],PNG_FILTER_TYPE_BASE
  965.         je @f ;if (..!=..)
  966.                 png_warning edi, 'Invalid filter type specified'
  967.                 mov dword[filter_type], PNG_FILTER_TYPE_BASE
  968.         @@:
  969.  
  970. if PNG_WRITE_INTERLACING_SUPPORTED eq 1
  971.         cmp dword[interlace_type],PNG_INTERLACE_NONE
  972.         je @f ;if (..!=..)
  973.         cmp dword[interlace_type],PNG_INTERLACE_ADAM7
  974.         je @f ;if (..!=..)
  975.                 png_warning edi, 'Invalid interlace type specified'
  976.                 mov dword[interlace_type], PNG_INTERLACE_ADAM7
  977.         @@:
  978. else
  979.         mov dword[interlace_type], PNG_INTERLACE_NONE
  980. end if
  981.  
  982.         ; Save the relevant information
  983.         mov al,byte[bit_depth]
  984.         mov byte[edi+png_struct.bit_depth],al
  985.         mov al,byte[color_type]
  986.         mov byte[edi+png_struct.color_type],al
  987.         mov al,byte[interlace_type]
  988.         mov byte[edi+png_struct.interlaced],al
  989. if PNG_MNG_FEATURES_SUPPORTED eq 1
  990.         mov al,byte[filter_type]
  991.         mov byte[edi+png_struct.filter_type],al
  992. end if
  993.         mov al,byte[compression_type]
  994.         mov byte[edi+png_struct.compression_type],al
  995.         mov eax,[width]
  996.         mov [edi+png_struct.width],eax
  997.         mov eax,[height]
  998.         mov [edi+png_struct.height],eax
  999.  
  1000.         movzx eax,byte[edi+png_struct.channels]
  1001.         imul ax,word[bit_depth]
  1002.         mov byte[edi+png_struct.pixel_depth],al
  1003.         PNG_ROWBYTES eax, [width]
  1004.         mov [edi+png_struct.rowbytes],eax
  1005.         ; Set the usr info, so any transformations can modify it
  1006.         mov eax,[edi+png_struct.width]
  1007.         mov [edi+png_struct.usr_width],eax
  1008.         mov al,[edi+png_struct.bit_depth]
  1009.         mov [edi+png_struct.usr_bit_depth],al
  1010.         mov al,[edi+png_struct.channels]
  1011.         mov [edi+png_struct.usr_channels],al
  1012.  
  1013.         ; Pack the header information into the buffer
  1014.         lea ebx,[ebp-13]
  1015.         stdcall png_save_uint_32, ebx, [width]
  1016.         add ebx,4
  1017.         stdcall png_save_uint_32, ebx, [height]
  1018.         add ebx,4
  1019.         mov al,byte[bit_depth]
  1020.         mov byte[ebx],al ;buf[8] = (byte)bit_depth
  1021.         inc ebx
  1022.         mov al,byte[color_type]
  1023.         mov byte[ebx],al ;buf[9] = (byte)color_type
  1024.         inc ebx
  1025.         mov al,byte[compression_type]
  1026.         mov byte[ebx],al ;buf[10] = (byte)compression_type
  1027.         inc ebx
  1028.         mov al,byte[filter_type]
  1029.         mov byte[ebx],al ;buf[11] = (byte)filter_type
  1030.         inc ebx
  1031.         mov al,byte[interlace_type]
  1032.         mov byte[ebx],al ;buf[12] = (byte)interlace_type
  1033.         sub ebx,12
  1034.  
  1035.         ; Write the chunk
  1036.         stdcall png_write_complete_chunk, edi, png_IHDR, ebx, dword 13
  1037.  
  1038.         cmp byte[edi+png_struct.do_filter],PNG_NO_FILTERS
  1039.         jne .end_5 ;if (..==..)
  1040.  
  1041.         cmp byte[edi+png_struct.color_type],PNG_COLOR_TYPE_PALETTE
  1042.         je @f
  1043.         cmp byte[edi+png_struct.bit_depth],8
  1044.         jge .els_5 ;if ((..==..)||(..<..))
  1045.         @@:
  1046.                 mov byte[edi+png_struct.do_filter], PNG_FILTER_NONE
  1047.                 jmp .end_5
  1048.         .els_5: ;else
  1049.                 mov byte[edi+png_struct.do_filter], PNG_ALL_FILTERS
  1050.         .end_5:
  1051.  
  1052.         mov dword[edi+png_struct.mode], PNG_HAVE_IHDR ;not READY_FOR_ZTXT
  1053. popad
  1054.         ret
  1055. endp
  1056.  
  1057. ; Write the palette.  We are careful not to trust png_color to be in the
  1058. ; correct order for PNG, so people can redefine it to any convenient
  1059. ; structure.
  1060.  
  1061. ;void (png_structrp png_ptr, png_const_colorp palette, uint_32 num_pal)
  1062. align 4
  1063. proc png_write_PLTE, png_ptr:dword, palette:dword, num_pal:dword
  1064. locals
  1065.         ;max_palette_length dd ? ;uint_32
  1066.         i dd ?
  1067.         pal_ptr dd ? ;png_const_colorp
  1068.         buf rb 3 ;byte[3]
  1069. endl
  1070.         png_debug 1, 'in png_write_PLTE'
  1071.  
  1072. pushad
  1073.         mov edi,[png_ptr]
  1074.         movzx eax,byte[edi+png_struct.color_type]
  1075.         cmp eax,PNG_COLOR_TYPE_PALETTE
  1076.         je @f ;if (..==..)
  1077.                 ;mov dword[max_palette_length],PNG_MAX_PALETTE_LENGTH
  1078.                 mov eax,PNG_MAX_PALETTE_LENGTH
  1079.                 jmp .end0
  1080.         @@:
  1081.                 mov cl,byte[edi+png_struct.bit_depth]
  1082.                 xor eax,eax
  1083.                 inc eax
  1084.                 shl eax,cl
  1085.                 ;mov [max_palette_length],eax
  1086.         .end0:
  1087.  
  1088. if PNG_MNG_FEATURES_SUPPORTED eq 1
  1089.         cmp [num_pal],eax
  1090.         jg @f
  1091.         mov eax,[edi+png_struct.mng_features_permitted]
  1092.         and eax,PNG_FLAG_MNG_EMPTY_PLTE
  1093.         jnz .end1
  1094.         cmp [num_pal],0
  1095.         jne .end1
  1096.         @@:
  1097. end if
  1098.  
  1099.         cmp byte[edi+png_struct.color_type],PNG_COLOR_TYPE_PALETTE ;if (..==..)
  1100.         jne @f
  1101.                 png_error edi, 'Invalid number of colors in palette'
  1102.                 jmp .end1
  1103.         @@: ;else
  1104.                 png_warning edi, 'Invalid number of colors in palette'
  1105.                 jmp .end_f
  1106.         .end1:
  1107.  
  1108.         movzx eax,byte[edi+png_struct.color_type]
  1109.         and eax,PNG_COLOR_MASK_COLOR
  1110.         jnz @f ;if (..==0)
  1111.                 png_warning edi, 'Ignoring request to write a PLTE chunk in grayscale PNG'
  1112.                 jmp .end_f
  1113.         @@:
  1114.  
  1115.         movzx eax,word[num_pal]
  1116.         mov word[edi+png_struct.num_palette],ax
  1117.         png_debug1 3, 'num_palette = %d', eax
  1118.  
  1119.         imul eax,3
  1120.         stdcall png_write_chunk_header, edi, png_PLTE, eax
  1121. if PNG_POINTER_INDEXING_SUPPORTED eq 1
  1122.  
  1123. ;   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
  1124. ;   {
  1125. ;      buf[0] = pal_ptr->red;
  1126. ;      buf[1] = pal_ptr->green;
  1127. ;      buf[2] = pal_ptr->blue;
  1128. ;      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
  1129. ;   }
  1130.  
  1131. else
  1132.         ; This is a little slower but some buggy compilers need to do this
  1133.         ; instead
  1134.  
  1135. ;   pal_ptr=palette;
  1136.  
  1137. ;   for (i = 0; i < num_pal; i++)
  1138. ;   {
  1139. ;      buf[0] = pal_ptr[i].red;
  1140. ;      buf[1] = pal_ptr[i].green;
  1141. ;      buf[2] = pal_ptr[i].blue;
  1142. ;      png_write_chunk_data(png_ptr, buf, (png_size_t)3);
  1143. ;   }
  1144.  
  1145. end if
  1146.         stdcall png_write_chunk_end, edi
  1147.         or dword[edi+png_struct.mode], PNG_HAVE_PLTE
  1148. .end_f:
  1149. popad
  1150.         ret
  1151. endp
  1152.  
  1153. ; This is similar to png_text_compress, above, except that it does not require
  1154. ; all of the data at once and, instead of buffering the compressed result,
  1155. ; writes it as IDAT chunks.  Unlike png_text_compress it *can* png_error out
  1156. ; because it calls the write interface.  As a result it does its own error
  1157. ; reporting and does not return an error code.  In the event of error it will
  1158. ; just call png_error.  The input data length may exceed 32-bits.  The 'flush'
  1159. ; parameter is exactly the same as that to deflate, with the following
  1160. ; meanings:
  1161.  
  1162. ; Z_NO_FLUSH: normal incremental output of compressed data
  1163. ; Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush
  1164. ; Z_FINISH: this is the end of the input, do a Z_FINISH and clean up
  1165.  
  1166. ; The routine manages the acquire and release of the png_ptr->zstream by
  1167. ; checking and (at the end) clearing png_ptr->zowner; it does some sanity
  1168. ; checks on the 'mode' flags while doing this.
  1169.  
  1170. ;void (png_structrp png_ptr, bytep input, png_alloc_size_t input_len, int flush)
  1171. ;input:
  1172. ; edi - png_ptr
  1173. align 4
  1174. proc png_compress_IDAT uses eax ebx ecx edx, input:dword, input_len:dword, flush:dword
  1175.         png_debug 1, 'in png_compress_IDAT'
  1176.  
  1177.         cmp dword[edi+png_struct.zowner],png_IDAT
  1178.         je .end0 ;if (..!=..)
  1179.                 ; First time.   Ensure we have a temporary buffer for compression and
  1180.                 ; trim the buffer list if it has more than one entry to free memory.
  1181.                 ; If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been
  1182.                 ; created at this point, but the check here is quick and safe.
  1183.  
  1184.                 cmp dword[edi+png_struct.zbuffer_list],0
  1185.                 jne @f ;if (..==0)
  1186.                         PNG_COMPRESSION_BUFFER_SIZE edi
  1187.                         stdcall png_malloc, edi, eax
  1188.                         mov [edi+png_struct.zbuffer_list],eax
  1189.                         mov dword[eax+png_compression_buffer.next],0
  1190.                         jmp .end1
  1191.                 @@: ;else
  1192.                         mov eax,[edi+png_struct.zbuffer_list]
  1193.                         add eax,png_compression_buffer.next
  1194.                         ;eax = &...next
  1195.                         stdcall png_free_buffer_list, edi, eax
  1196.                 .end1:
  1197.  
  1198.                 ;It is a terminal error if we can't claim the zstream.
  1199.                 stdcall png_image_size, edi
  1200.                 stdcall png_deflate_claim, png_IDAT, eax
  1201.                 cmp eax,Z_OK
  1202.                 je @f ;if (..!=..)
  1203.                         png_error edi, [edi+png_struct.zstream.msg]
  1204.                 @@:
  1205.  
  1206.                 ; The output state is maintained in png_ptr->zstream, so it must be
  1207.                 ; initialized here after the claim.
  1208.  
  1209.                 mov eax,[edi+png_struct.zbuffer_list]
  1210.                 add eax,png_compression_buffer.output
  1211.                 mov [edi+png_struct.zstream.next_out],eax
  1212.                 mov eax,[edi+png_struct.zbuffer_size]
  1213.                 mov [edi+png_struct.zstream.avail_out],eax
  1214.         .end0:
  1215.  
  1216.         ; Now loop reading and writing until all the input is consumed or an error
  1217.         ; terminates the operation.  The _out values are maintained across calls to
  1218.         ; this function, but the input must be reset each time.
  1219.  
  1220.         mov eax,[input]
  1221.         mov [edi+png_struct.zstream.next_in],eax
  1222.         mov dword[edi+png_struct.zstream.avail_in],0 ;set below
  1223. align 4
  1224.         .cycle0:
  1225.         ;INPUT: from the row data
  1226.                 mov eax,ZLIB_IO_MAX
  1227.  
  1228.                 cmp eax,[input_len]
  1229.                 jbe @f ;if (..>..)
  1230.                         mov eax,[input_len] ;safe because of the check
  1231.                 @@:
  1232.  
  1233.                 mov [edi+png_struct.zstream.avail_in],eax
  1234.                 sub [input_len],eax
  1235.  
  1236.                 mov eax,[flush]
  1237.                 cmp dword[input_len],0
  1238.                 jle @f
  1239.                         mov eax,Z_NO_FLUSH
  1240.                 @@:
  1241.                 mov ecx,edi
  1242.                 add ecx,png_struct.zstream
  1243.                 stdcall [deflate], ecx, eax
  1244.                 mov ebx,eax
  1245.  
  1246.                 ;Include as-yet unconsumed input
  1247.                 mov eax,[edi+png_struct.zstream.avail_in]
  1248.                 add [input_len],eax
  1249.                 mov dword[edi+png_struct.zstream.avail_in],0
  1250.  
  1251.                 ; OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note
  1252.                 ; that these two zstream fields are preserved across the calls, therefore
  1253.                 ; there is no need to set these up on entry to the loop.
  1254.  
  1255.                 cmp dword[edi+png_struct.zstream.avail_out],0
  1256.                 jne .end2 ;if (..==0)
  1257.                         mov edx,[edi+png_struct.zbuffer_list]
  1258.                         add edx,png_compression_buffer.output
  1259.                         mov ecx,[edi+png_struct.zbuffer_size]
  1260.                         ;edx = data
  1261.                         ;ecx = size
  1262.                         ; Write an IDAT containing the data then reset the buffer.  The
  1263.                         ; first IDAT may need deflate header optimization.
  1264.  
  1265. if PNG_WRITE_OPTIMIZE_CMF_SUPPORTED eq 1
  1266.                         mov eax,[edi+png_struct.mode]
  1267.                         and eax,PNG_HAVE_IDAT
  1268.                         jnz @f
  1269.                         cmp byte[edi+png_struct.compression_type],PNG_COMPRESSION_TYPE_BASE
  1270.                         jne @f ;if (..==0 && ..==..)
  1271.                                 stdcall png_image_size, edi
  1272.                                 stdcall optimize_cmf, edx, eax
  1273.                         @@:
  1274. end if
  1275.  
  1276.                         stdcall png_write_complete_chunk, edi, png_IDAT, edx, ecx
  1277.                         or dword[edi+png_struct.mode],PNG_HAVE_IDAT
  1278.  
  1279.                         mov [edi+png_struct.zstream.next_out],edx
  1280.                         mov [edi+png_struct.zstream.avail_out],ecx
  1281.  
  1282.                         ; For SYNC_FLUSH or FINISH it is essential to keep calling zlib with
  1283.                         ; the same flush parameter until it has finished output, for NO_FLUSH
  1284.                         ; it doesn't matter.
  1285.  
  1286.                         cmp ebx,Z_OK
  1287.                         jne .end2
  1288.                         cmp dword[flush],Z_NO_FLUSH
  1289.                         jne .cycle0 ;if (..==.. && ..!=..) continue
  1290.                 .end2:
  1291.  
  1292.                 ; The order of these checks doesn't matter much; it just affects which
  1293.                 ; possible error might be detected if multiple things go wrong at once.
  1294.  
  1295.                 cmp ebx,Z_OK
  1296.                 jne .end3 ;if (..==..) ;most likely return code!
  1297.                         ; If all the input has been consumed then just return.  If Z_FINISH
  1298.                         ; was used as the flush parameter something has gone wrong if we get
  1299.                         ; here.
  1300.  
  1301.                         cmp dword[input_len],0
  1302.                         jne .cycle0 ;if (..==0)
  1303.                                 cmp dword[flush],Z_FINISH
  1304.                                 jne .cycle0end ;if (..==..)
  1305.                                         png_error edi, 'Z_OK on Z_FINISH with output space'
  1306.                                 jmp .cycle0end
  1307.                 .end3:
  1308.                 cmp ebx,Z_STREAM_END
  1309.                 jne .end4
  1310.                 cmp dword[flush],Z_FINISH
  1311.                 jne .end4 ;else if (..==.. && ..==..)
  1312.                         ; This is the end of the IDAT data; any pending output must be
  1313.                         ; flushed.  For small PNG files we may still be at the beginning.
  1314.  
  1315.                         mov edx,[edi+png_struct.zbuffer_list]
  1316.                         add edx,png_compression_buffer.output
  1317.                         mov ecx,[edi+png_struct.zbuffer_size]
  1318.                         mov eax,[edi+png_struct.zstream.avail_out]
  1319.                         sub ecx,eax
  1320.                         ;edx = data
  1321.                         ;ecx = size
  1322.  
  1323. if PNG_WRITE_OPTIMIZE_CMF_SUPPORTED eq 1
  1324.                         mov eax,[edi+png_struct.mode]
  1325.                         and eax,PNG_HAVE_IDAT
  1326.                         jnz @f
  1327.                         cmp byte[edi+png_struct.compression_type],PNG_COMPRESSION_TYPE_BASE
  1328.                         jne @f ;if (..==0 && ..==..)
  1329.                                 stdcall png_image_size, edi
  1330.                                 stdcall optimize_cmf, edx, eax
  1331.                         @@:
  1332. end if
  1333.                         stdcall png_write_complete_chunk, edi, png_IDAT, edx, ecx
  1334.                         mov dword[edi+png_struct.zstream.avail_out],0
  1335.                         mov dword[edi+png_struct.zstream.next_out],0
  1336.                         or dword[edi+png_struct.mode], PNG_HAVE_IDAT or PNG_AFTER_IDAT
  1337.  
  1338.                         mov dword[edi+png_struct.zowner],0 ;Release the stream
  1339.                         jmp .cycle0end
  1340.                 .end4: ;else
  1341.                         ; This is an error condition.
  1342.                         stdcall png_zstream_error, edi, ebx
  1343.                         png_error edi, [edi+png_struct.zstream.msg]
  1344.                 jmp .cycle0
  1345.         .cycle0end:
  1346.         ret
  1347. endp
  1348.  
  1349. ; Write an IEND chunk
  1350. ;void (png_structrp png_ptr)
  1351. align 4
  1352. proc png_write_IEND uses edi, png_ptr:dword
  1353.         png_debug 1, 'in png_write_IEND'
  1354.  
  1355.         mov edi,[png_ptr]
  1356.         stdcall png_write_complete_chunk, edi, png_IEND, 0, 0
  1357.         or dword[edi+png_struct.mode], PNG_HAVE_IEND
  1358.         ret
  1359. endp
  1360.  
  1361. ; Write a gAMA chunk
  1362. ;void (png_structrp png_ptr, png_fixed_point file_gamma)
  1363. align 4
  1364. proc png_write_gAMA_fixed uses ebx, png_ptr:dword, file_gamma:dword
  1365. locals
  1366.         buf rb 4 ;byte[4]
  1367. endl
  1368.         png_debug 1, 'in png_write_gAMA'
  1369.  
  1370.         ; file_gamma is saved in 1/100,000ths
  1371.         lea ebx,[ebp-4]
  1372.         stdcall png_save_uint_32 ,ebx, [file_gamma]
  1373.         stdcall png_write_complete_chunk, [png_ptr], png_gAMA, ebx, 4
  1374.         ret
  1375. endp
  1376.  
  1377. ; Write a sRGB chunk
  1378. ;void (png_structrp png_ptr, int srgb_intent)
  1379. align 4
  1380. proc png_write_sRGB uses eax ebx, png_ptr:dword, srgb_intent:dword
  1381. locals
  1382.         buf db ? ;byte[1]
  1383. endl
  1384.         png_debug 1, 'in png_write_sRGB'
  1385.  
  1386.         cmp dword[srgb_intent], PNG_sRGB_INTENT_LAST ;if (..>=..)
  1387.         jl @f
  1388.                 png_warning [png_ptr], 'Invalid sRGB rendering intent specified'
  1389.         @@:
  1390.  
  1391.         mov al,byte[srgb_intent]
  1392.         mov ebx,ebp
  1393.         dec ebx
  1394.         mov byte[ebx],al ;buf[0]=(byte)srgb_intent
  1395.         stdcall png_write_complete_chunk, [png_ptr], png_sRGB, ebx, 1
  1396.         ret
  1397. endp
  1398.  
  1399. ; Write an iCCP chunk
  1400. ;void (png_structrp png_ptr, charp name, bytep profile)
  1401. align 4
  1402. proc png_write_iCCP uses eax ebx ecx edi, png_ptr:dword, name:dword, profile:dword
  1403. locals
  1404.         name_len dd ? ;uint_32
  1405.         profile_len dd ? ;uint_32
  1406.         temp dd ? ;uint_32
  1407.         new_name rb 81 ;byte[81] ;1 byte for the compression byte
  1408.         comp compression_state
  1409. endl
  1410.         png_debug 1, 'in png_write_iCCP'
  1411.  
  1412.         ; These are all internal problems: the profile should have been checked
  1413.         ; before when it was stored.
  1414.  
  1415.         mov edi,[png_ptr]
  1416.         cmp dword[profile],0
  1417.         jne @f ;if (..==0)
  1418.                 png_error edi, 'No profile for iCCP chunk' ;internal error
  1419.         @@:
  1420.  
  1421.         stdcall png_get_uint_32,[profile]
  1422.         mov [profile_len],eax
  1423.  
  1424.         cmp eax,132
  1425.         jge @f ;if (..<..)
  1426.                 png_error edi, 'ICC profile too short'
  1427.         @@:
  1428.  
  1429. ;   temp = (uint_32) (*(profile+8));
  1430. ;   if (temp > 3 && (profile_len & 0x03))
  1431. ;      png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)");
  1432.  
  1433. ;   {
  1434. ;      uint_32 embedded_profile_len = png_get_uint_32(profile);
  1435.  
  1436. ;      if (profile_len != embedded_profile_len)
  1437. ;         png_error(png_ptr, "Profile length does not match profile");
  1438. ;   }
  1439.  
  1440.         lea ebx,[ebp-sizeof.compression_state]
  1441.         mov ecx,ebx ;ecx = &comp
  1442.         sub ebx,81  ;ebx = &new_name
  1443.         stdcall png_check_keyword, edi, [name], ebx
  1444.         mov [name_len],eax
  1445.  
  1446.         test eax,eax
  1447.         jnz @f ;if (..==0)
  1448.                 png_error edi, 'iCCP: invalid keyword'
  1449.         @@:
  1450.  
  1451.         inc dword[name_len]
  1452.         mov eax,[name_len]
  1453.         add eax,ebx
  1454.         mov byte[eax], PNG_COMPRESSION_TYPE_BASE
  1455.  
  1456.         ; Make sure we include the NULL after the name and the compression type
  1457.         inc dword[name_len]
  1458.  
  1459.         stdcall png_text_compress_init, ecx, [profile], [profile_len]
  1460.  
  1461.         ; Allow for keyword terminator and compression byte
  1462. ;   if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK)
  1463. ;      png_error(png_ptr, png_ptr->zstream.msg);
  1464.  
  1465. ;   png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len);
  1466.  
  1467.         stdcall png_write_chunk_data, edi, ebx, [name_len]
  1468.  
  1469.         stdcall png_write_compressed_data_out, edi, ecx
  1470.  
  1471.         stdcall png_write_chunk_end, edi
  1472.         ret
  1473. endp
  1474.  
  1475. ; Write a sPLT chunk
  1476. ;void (png_structrp png_ptr, png_const_sPLT_tp spalette)
  1477. align 4
  1478. proc png_write_sPLT, png_ptr:dword, spalette:dword
  1479. ;   uint_32 name_len;
  1480. ;   byte new_name[80];
  1481. ;   byte entrybuf[10];
  1482. ;   png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);
  1483. ;   png_size_t palette_size = entry_size * spalette->nentries;
  1484. ;   png_sPLT_entryp ep;
  1485. if PNG_POINTER_INDEXING_SUPPORTED eq
  1486. ;   int i;
  1487. end if
  1488.  
  1489.         png_debug 1, 'in png_write_sPLT'
  1490.  
  1491. ;   name_len = png_check_keyword(png_ptr, spalette->name, new_name);
  1492.  
  1493. ;   if (name_len == 0)
  1494. ;      png_error(png_ptr, "sPLT: invalid keyword");
  1495.  
  1496.         ; Make sure we include the NULL after the name
  1497. ;   png_write_chunk_header(png_ptr, png_sPLT,
  1498. ;       (uint_32)(name_len + 2 + palette_size));
  1499.  
  1500. ;   png_write_chunk_data(png_ptr, (bytep)new_name,
  1501. ;       (png_size_t)(name_len + 1));
  1502.  
  1503. ;   png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1);
  1504.  
  1505.         ; Loop through each palette entry, writing appropriately
  1506. if PNG_POINTER_INDEXING_SUPPORTED eq 1
  1507. ;   for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++)
  1508. ;   {
  1509. ;      if (spalette->depth == 8)
  1510. ;      {
  1511. ;         entrybuf[0] = (byte)ep->red;
  1512. ;         entrybuf[1] = (byte)ep->green;
  1513. ;         entrybuf[2] = (byte)ep->blue;
  1514. ;         entrybuf[3] = (byte)ep->alpha;
  1515. ;         png_save_uint_16(entrybuf + 4, ep->frequency);
  1516. ;      }
  1517.  
  1518. ;      else
  1519. ;      {
  1520. ;         png_save_uint_16(entrybuf + 0, ep->red);
  1521. ;         png_save_uint_16(entrybuf + 2, ep->green);
  1522. ;         png_save_uint_16(entrybuf + 4, ep->blue);
  1523. ;         png_save_uint_16(entrybuf + 6, ep->alpha);
  1524. ;         png_save_uint_16(entrybuf + 8, ep->frequency);
  1525. ;      }
  1526.  
  1527. ;      png_write_chunk_data(png_ptr, entrybuf, entry_size);
  1528. ;   }
  1529. else
  1530. ;   ep=spalette->entries;
  1531. ;   for (i = 0; i>spalette->nentries; i++)
  1532. ;   {
  1533. ;      if (spalette->depth == 8)
  1534. ;      {
  1535. ;         entrybuf[0] = (byte)ep[i].red;
  1536. ;         entrybuf[1] = (byte)ep[i].green;
  1537. ;         entrybuf[2] = (byte)ep[i].blue;
  1538. ;         entrybuf[3] = (byte)ep[i].alpha;
  1539. ;         png_save_uint_16(entrybuf + 4, ep[i].frequency);
  1540. ;      }
  1541.  
  1542. ;      else
  1543. ;      {
  1544. ;         png_save_uint_16(entrybuf + 0, ep[i].red);
  1545. ;         png_save_uint_16(entrybuf + 2, ep[i].green);
  1546. ;         png_save_uint_16(entrybuf + 4, ep[i].blue);
  1547. ;         png_save_uint_16(entrybuf + 6, ep[i].alpha);
  1548. ;         png_save_uint_16(entrybuf + 8, ep[i].frequency);
  1549. ;      }
  1550.  
  1551. ;      png_write_chunk_data(png_ptr, entrybuf, entry_size);
  1552. ;   }
  1553. end if
  1554.  
  1555. ;   png_write_chunk_end(png_ptr);
  1556.         ret
  1557. endp
  1558.  
  1559. ; Write the sBIT chunk
  1560. ;void (png_structrp png_ptr, png_const_color_8p sbit, int color_type)
  1561. align 4
  1562. proc png_write_sBIT uses eax edi, png_ptr:dword, sbit:dword, color_type:dword
  1563. locals
  1564.         size dd ? ;png_size_t
  1565.         buf rb 4 ;byte[4]
  1566. endl
  1567.         png_debug 1, 'in png_write_sBIT'
  1568.  
  1569.         ; Make sure we don't depend upon the order of PNG_COLOR_8
  1570. ;   if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
  1571. ;   {
  1572. ;      byte maxbits;
  1573.  
  1574. ;      maxbits = (byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
  1575. ;          png_ptr->usr_bit_depth);
  1576.  
  1577. ;      if (sbit->red == 0 || sbit->red > maxbits ||
  1578. ;          sbit->green == 0 || sbit->green > maxbits ||
  1579. ;          sbit->blue == 0 || sbit->blue > maxbits)
  1580. ;      {
  1581. ;         png_warning(png_ptr, "Invalid sBIT depth specified");
  1582. ;         return;
  1583. ;      }
  1584.  
  1585. ;      buf[0] = sbit->red;
  1586. ;      buf[1] = sbit->green;
  1587. ;      buf[2] = sbit->blue;
  1588. ;      size = 3;
  1589. ;   }
  1590.  
  1591. ;   else
  1592. ;   {
  1593. ;      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
  1594. ;      {
  1595. ;         png_warning(png_ptr, "Invalid sBIT depth specified");
  1596. ;         return;
  1597. ;      }
  1598.  
  1599. ;      buf[0] = sbit->gray;
  1600. ;      size = 1;
  1601. ;   }
  1602.  
  1603. ;   if ((color_type & PNG_COLOR_MASK_ALPHA) != 0)
  1604. ;   {
  1605. ;      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
  1606. ;      {
  1607. ;         png_warning(png_ptr, "Invalid sBIT depth specified");
  1608. ;         return;
  1609. ;      }
  1610.  
  1611. ;      buf[size++] = sbit->alpha;
  1612. ;   }
  1613.  
  1614. ;   png_write_complete_chunk(png_ptr, png_sBIT, buf, size);
  1615. .end_f:
  1616.         ret
  1617. endp
  1618.  
  1619. ; Write the cHRM chunk
  1620. ;void (png_structrp png_ptr, const png_xy *xy)
  1621. align 4
  1622. proc png_write_cHRM_fixed uses eax ebx, png_ptr:dword, xy:dword
  1623. locals
  1624.         buf rb 32 ;byte[32]
  1625. endl
  1626.         png_debug 1, 'in png_write_cHRM'
  1627.  
  1628.         ; Each value is saved in 1/100,000ths
  1629.         mov eax,[xy]
  1630.         lea ebx,[ebp-32]
  1631. ;   png_save_int_32(buf,      xy->whitex);
  1632. ;   png_save_int_32(buf +  4, xy->whitey);
  1633.  
  1634. ;   png_save_int_32(buf +  8, xy->redx);
  1635. ;   png_save_int_32(buf + 12, xy->redy);
  1636.  
  1637. ;   png_save_int_32(buf + 16, xy->greenx);
  1638. ;   png_save_int_32(buf + 20, xy->greeny);
  1639.  
  1640. ;   png_save_int_32(buf + 24, xy->bluex);
  1641. ;   png_save_int_32(buf + 28, xy->bluey);
  1642.  
  1643.         stdcall png_write_complete_chunk, [png_ptr], png_cHRM, ebx, 32
  1644.         ret
  1645. endp
  1646.  
  1647. ; Write the tRNS chunk
  1648. ;void (png_structrp png_ptr, bytep trans_alpha, png_color_16p tran, int num_trans, int color_type)
  1649. align 4
  1650. proc png_write_tRNS uses eax ebx ecx edi, png_ptr:dword, trans_alpha:dword, tran:dword, num_trans:dword, color_type:dword
  1651. locals
  1652.         buf rb 6 ;byte[6]
  1653. endl
  1654.         png_debug 1, 'in png_write_tRNS'
  1655.  
  1656.         mov edi,[png_ptr]
  1657.         cmp byte[color_type],PNG_COLOR_TYPE_PALETTE
  1658.         jne .end0 ;if (..==..)
  1659.                 cmp dword[num_trans],0
  1660.                 jle @f
  1661.                 movzx eax,word[edi+png_struct.num_palette]
  1662.                 cmp [num_trans],eax
  1663.                 jle .end1
  1664.                 @@: ;if (..<=0 || ..>..)
  1665.                         png_app_warning edi, 'Invalid number of transparent colors specified'
  1666.                         jmp .end_f
  1667.                 .end1:
  1668.  
  1669.                 ; Write the chunk out as it is
  1670.                 stdcall png_write_complete_chunk, edi, png_tRNS, [trans_alpha], [num_trans]
  1671.                 jmp .end_f
  1672.         .end0:
  1673.  
  1674.         cmp dword[color_type],PNG_COLOR_TYPE_GRAY
  1675.         jne .end2 ;else if (..==..)
  1676.                 ; One 16-bit value
  1677.                 mov cl,[edi+png_struct.bit_depth]
  1678.                 xor eax,eax
  1679.                 inc eax
  1680.                 shl eax,cl
  1681.                 mov ecx,[tran]
  1682.                 cmp word[ecx+png_color_16.gray],ax
  1683.                 jl @f ;if (..>=..)
  1684.                         png_app_warning edi, 'Ignoring attempt to write tRNS chunk out-of-range for bit_depth'
  1685.                         jmp .end_f
  1686.                 @@:
  1687.                 movzx eax,word[ecx+png_color_16.gray]
  1688.                 lea ebx,[ebp-6]
  1689.                 stdcall png_save_uint_16, ebx, eax
  1690.                 stdcall png_write_complete_chunk, edi, png_tRNS, ebx, 2
  1691.                 jmp .end_f
  1692.         .end2:
  1693.  
  1694.         cmp dword[color_type],PNG_COLOR_TYPE_RGB
  1695.         jne .end3 ;else if (..== ..)
  1696.                 ; Three 16-bit values
  1697.                 lea ebx,[ebp-6]
  1698.                 mov ecx,[tran]
  1699.                 movzx eax,word[ecx+png_color_16.red]
  1700.                 stdcall png_save_uint_16, ebx, eax
  1701.                 add ebx,2
  1702.                 movzx eax,word[ecx+png_color_16.green]
  1703.                 stdcall png_save_uint_16, ebx, eax
  1704.                 add ebx,2
  1705.                 movzx eax,word[ecx+png_color_16.blue]
  1706.                 stdcall png_save_uint_16, ebx, eax
  1707.                 sub ebx,4
  1708. if PNG_WRITE_16BIT_SUPPORTED eq 1
  1709.                 cmp byte[edi+png_struct.bit_depth],8
  1710.                 jne @f ;if (..==.. && ...
  1711. end if
  1712.                 mov al,[ebx]
  1713.                 or al,[ebx+2]
  1714.                 or al,[ebx+4]
  1715.                 or al,al
  1716.                 jz @f ;if (..|..|..!=0)
  1717.                         png_app_warning edi, 'Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8'
  1718.                         jmp .end_f
  1719.                 @@:
  1720.                 stdcall png_write_complete_chunk, edi, png_tRNS, ebx, 6
  1721.                 jmp .end_f
  1722.         .end3: ;else
  1723.                 cStr ,<'Can',39,'t write tRNS with an alpha channel'>
  1724.                 png_app_warning edi, eax
  1725. .end_f:
  1726.         ret
  1727. endp
  1728.  
  1729. ; Write the background chunk
  1730. ;void (png_structrp png_ptr, png_const_color_16p back, int color_type)
  1731. align 4
  1732. proc png_write_bKGD, png_ptr:dword, back:dword, color_type:dword
  1733. locals
  1734.         buf rb 6 ;byte[6]
  1735. endl
  1736.         png_debug 1, 'in png_write_bKGD'
  1737.  
  1738. ;   if (color_type == PNG_COLOR_TYPE_PALETTE)
  1739. ;   {
  1740. ;      if (
  1741. if PNG_MNG_FEATURES_SUPPORTED eq 1
  1742. ;          (png_ptr->num_palette != 0 ||
  1743. ;          (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) &&
  1744. end if
  1745. ;         back->index >= png_ptr->num_palette)
  1746. ;      {
  1747. ;         png_warning(png_ptr, "Invalid background palette index");
  1748. ;         return;
  1749. ;      }
  1750.  
  1751. ;      buf[0] = back->index;
  1752. ;      png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1);
  1753. ;   }
  1754.  
  1755. ;   else if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
  1756. ;   {
  1757. ;      png_save_uint_16(buf, back->red);
  1758. ;      png_save_uint_16(buf + 2, back->green);
  1759. ;      png_save_uint_16(buf + 4, back->blue);
  1760. if PNG_WRITE_16BIT_SUPPORTED eq 1
  1761. ;      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0)
  1762. else
  1763. ;      if ((buf[0] | buf[2] | buf[4]) != 0)
  1764. end if
  1765. ;      {
  1766. ;         png_warning(png_ptr,
  1767. ;             "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
  1768.  
  1769. ;         return;
  1770. ;      }
  1771.  
  1772. ;      png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6);
  1773. ;   }
  1774.  
  1775. ;   else
  1776. ;   {
  1777. ;      if (back->gray >= (1 << png_ptr->bit_depth))
  1778. ;      {
  1779. ;         png_warning(png_ptr,
  1780. ;             "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
  1781.  
  1782. ;         return;
  1783. ;      }
  1784.  
  1785. ;      png_save_uint_16(buf, back->gray);
  1786. ;      png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2);
  1787. ;   }
  1788.         ret
  1789. endp
  1790.  
  1791. ; Write the histogram
  1792. ;void (png_structrp png_ptr, png_const_uint_16p hist, int num_hist)
  1793. align 4
  1794. proc png_write_hIST, png_ptr:dword, hist:dword, num_hist:dword
  1795. locals
  1796.         i dd ? ;int
  1797.         buf rb 3 ;byte[3]
  1798. endl
  1799.         png_debug 1, 'in png_write_hIST'
  1800. pushad
  1801.  
  1802.         mov edi,[png_ptr]
  1803.         movzx eax,word[edi+png_struct.num_palette]
  1804.         cmp [num_hist],eax
  1805.         jle @f ;if (..>..)
  1806. ;      png_debug2(3, "num_hist = %d, num_palette = %d", num_hist,
  1807. ;          png_ptr->num_palette);
  1808.  
  1809.                 png_warning edi, 'Invalid number of histogram entries specified'
  1810.                 jmp .end_f
  1811.         @@:
  1812.  
  1813.         mov eax,[num_hist]
  1814.         shl eax,1
  1815.         stdcall png_write_chunk_header, edi, png_hIST, eax
  1816.  
  1817. ;   for (i = 0; i < num_hist; i++)
  1818. ;   {
  1819. ;      png_save_uint_16(buf, hist[i]);
  1820. ;      png_write_chunk_data(png_ptr, buf, (png_size_t)2);
  1821. ;   }
  1822.  
  1823.         stdcall png_write_chunk_end, edi
  1824. .end_f:
  1825. popad
  1826.         ret
  1827. endp
  1828.  
  1829. ; Write a tEXt chunk
  1830. ;void (png_structrp png_ptr, charp key, charp text, png_size_t text_len)
  1831. align 4
  1832. proc png_write_tEXt uses eax edi, png_ptr:dword, key:dword, text:dword, text_len:dword
  1833. locals
  1834.         key_len dd ? ;uint_32
  1835.         new_key rb 80 ;byte[80]
  1836. endl
  1837.         png_debug 1, 'in png_write_tEXt'
  1838.  
  1839. ;   key_len = png_check_keyword(png_ptr, key, new_key);
  1840.  
  1841. ;   if (key_len == 0)
  1842. ;      png_error(png_ptr, "tEXt: invalid keyword");
  1843.  
  1844. ;   if (text == NULL || *text == '\0')
  1845. ;      text_len = 0;
  1846.  
  1847. ;   else
  1848. ;      text_len = strlen(text);
  1849.  
  1850. ;   if (text_len > PNG_UINT_31_MAX - (key_len+1))
  1851. ;      png_error(png_ptr, "tEXt: text too long");
  1852.  
  1853.         ; Make sure we include the 0 after the key
  1854. ;   png_write_chunk_header(png_ptr, png_tEXt,
  1855. ;       (uint_32)/*checked above*/(key_len + text_len + 1));
  1856.  
  1857.         ; We leave it to the application to meet PNG-1.0 requirements on the
  1858.         ; contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
  1859.         ; any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
  1860.         ; The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
  1861.  
  1862. ;   png_write_chunk_data(png_ptr, new_key, key_len + 1);
  1863.  
  1864. ;   if (text_len != 0)
  1865. ;      png_write_chunk_data(png_ptr, (bytep)text, text_len);
  1866.  
  1867. ;   png_write_chunk_end(png_ptr);
  1868.         ret
  1869. endp
  1870.  
  1871. if PNG_WRITE_zTXt_SUPPORTED eq 1
  1872. ; Write a compressed text chunk
  1873. ;void (png_structrp png_ptr, charp key, charp text, int compression)
  1874. align 4
  1875. proc png_write_zTXt uses eax edi, png_ptr:dword, key:dword, text:dword, compression:dword
  1876. locals
  1877.         key_len dd ? ;uint_32
  1878.         new_key rb 81 ;byte[81]
  1879.         comp compression_state
  1880. endl
  1881.         png_debug 1, 'in png_write_zTXt'
  1882.  
  1883.         mov edi,[png_ptr]
  1884.         cmp dword[compression],PNG_TEXT_COMPRESSION_NONE
  1885.         jne @f ;if (..==..)
  1886.                 stdcall png_write_tEXt, edi, [key], [text], 0
  1887.                 jmp .end_f
  1888.         @@:
  1889.  
  1890. ;   if (compression != PNG_TEXT_COMPRESSION_zTXt)
  1891. ;      png_error(png_ptr, "zTXt: invalid compression type");
  1892.  
  1893. ;   key_len = png_check_keyword(png_ptr, key, new_key);
  1894.  
  1895. ;   if (key_len == 0)
  1896. ;      png_error(png_ptr, "zTXt: invalid keyword");
  1897.  
  1898.         ; Add the compression method and 1 for the keyword separator.
  1899. ;   new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
  1900. ;   ++key_len;
  1901.  
  1902.         ; Compute the compressed data; do it now for the length
  1903. ;   png_text_compress_init(&comp, (bytep)text,
  1904. ;       text == NULL ? 0 : strlen(text));
  1905.  
  1906. ;   if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK)
  1907. ;      png_error(png_ptr, png_ptr->zstream.msg);
  1908.  
  1909.         ; Write start of chunk
  1910. ;   png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len);
  1911.  
  1912.         ; Write key
  1913. ;   png_write_chunk_data(png_ptr, new_key, key_len);
  1914.  
  1915.         ; Write the compressed data
  1916. ;   png_write_compressed_data_out(png_ptr, &comp);
  1917.  
  1918.         ; Close the chunk
  1919.         stdcall png_write_chunk_end, edi
  1920. .end_f:
  1921.         ret
  1922. endp
  1923. end if
  1924.  
  1925. if PNG_WRITE_iTXt_SUPPORTED eq 1
  1926. ; Write an iTXt chunk
  1927. ;void (png_structrp png_ptr, int compression, charp key,
  1928. ;    charp lang, charp lang_key, charp text)
  1929. align 4
  1930. proc png_write_iTXt, png_ptr:dword, compression:dword, key:dword, lang:dword, lang_key:dword, text:dword
  1931. locals
  1932.         key_len dd ? ;uint_32
  1933.         prefix_len dd ?
  1934.         ;png_size_t lang_len, lang_key_len;
  1935.         new_key rb 82 ;byte[82]
  1936.         comp compression_state
  1937. endl
  1938.  
  1939.         png_debug 1, 'in png_write_iTXt'
  1940. pushad
  1941.         mov edi,[png_ptr]
  1942.         lea ebx,[ebp-(82+sizeof.compression_state)]
  1943.         stdcall png_check_keyword, edi, [key], ebx
  1944.         mov [key_len],eax
  1945.  
  1946.         test eax,eax
  1947.         jnz @f ;if (..==0)
  1948.                 png_error edi, 'iTXt: invalid keyword'
  1949.         @@:
  1950.  
  1951.         ; Set the compression flag
  1952. ;   switch (compression)
  1953. ;   {
  1954. ;      case PNG_ITXT_COMPRESSION_NONE:
  1955. ;      case PNG_TEXT_COMPRESSION_NONE:
  1956. ;         compression = new_key[++key_len] = 0; /* no compression */
  1957. ;         break;
  1958.  
  1959. ;      case PNG_TEXT_COMPRESSION_zTXt:
  1960. ;      case PNG_ITXT_COMPRESSION_zTXt:
  1961. ;         compression = new_key[++key_len] = 1; /* compressed */
  1962. ;         break;
  1963.  
  1964. ;      default:
  1965. ;         png_error(png_ptr, "iTXt: invalid compression");
  1966. ;   }
  1967.  
  1968. ;   new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
  1969. ;   ++key_len; /* for the keywod separator */
  1970.  
  1971.         ; We leave it to the application to meet PNG-1.0 requirements on the
  1972.         ; contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
  1973.         ; any non-Latin-1 characters except for NEWLINE.  ISO PNG, however,
  1974.         ; specifies that the text is UTF-8 and this really doesn't require any
  1975.         ; checking.
  1976.  
  1977.         ; The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
  1978.  
  1979.         ; TODO: validate the language tag correctly (see the spec.)
  1980.  
  1981. ;   if (lang == NULL) lang = ""; /* empty language is valid */
  1982. ;   lang_len = strlen(lang)+1;
  1983. ;   if (lang_key == NULL) lang_key = ""; /* may be empty */
  1984. ;   lang_key_len = strlen(lang_key)+1;
  1985. ;   if (text == NULL) text = ""; /* may be empty */
  1986.  
  1987.         mov eax,[key_len]
  1988.         mov [prefix_len],eax
  1989. ;   if (lang_len > PNG_UINT_31_MAX-prefix_len)
  1990. ;      prefix_len = PNG_UINT_31_MAX;
  1991. ;   else
  1992. ;      prefix_len = (uint_32)(prefix_len + lang_len);
  1993.  
  1994. ;   if (lang_key_len > PNG_UINT_31_MAX-prefix_len)
  1995. ;      prefix_len = PNG_UINT_31_MAX;
  1996. ;   else
  1997. ;      prefix_len = (uint_32)(prefix_len + lang_key_len);
  1998.  
  1999. ;   png_text_compress_init(&comp, (bytep)text, strlen(text));
  2000.  
  2001. ;   if (compression != 0)
  2002. ;   {
  2003. ;      if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK)
  2004. ;         png_error(png_ptr, png_ptr->zstream.msg);
  2005. ;   }
  2006.  
  2007. ;   else
  2008. ;   {
  2009. ;      if (comp.input_len > PNG_UINT_31_MAX-prefix_len)
  2010. ;         png_error(png_ptr, "iTXt: uncompressed text too long");
  2011.  
  2012.         ; So the string will fit in a chunk:
  2013. ;      comp.output_len = (uint_32)/*SAFE*/comp.input_len;
  2014. ;   }
  2015.  
  2016. ;   png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len);
  2017.  
  2018. ;   png_write_chunk_data(png_ptr, new_key, key_len);
  2019.  
  2020. ;   png_write_chunk_data(png_ptr, (bytep)lang, lang_len);
  2021.  
  2022. ;   png_write_chunk_data(png_ptr, (bytep)lang_key, lang_key_len);
  2023.  
  2024. ;   if (compression != 0)
  2025. ;      png_write_compressed_data_out(png_ptr, &comp);
  2026.  
  2027. ;   else
  2028. ;      png_write_chunk_data(png_ptr, (bytep)text, comp.output_len);
  2029.  
  2030.         stdcall png_write_chunk_end, edi
  2031. popad
  2032.         ret
  2033. endp
  2034. end if
  2035.  
  2036. ; Write the oFFs chunk
  2037. ;void (png_structrp png_ptr, int_32 x_offset, int_32 y_offset, int unit_type)
  2038. align 4
  2039. proc png_write_oFFs uses eax ebx edi, png_ptr:dword, x_offset:dword, y_offset:dword, unit_type:dword
  2040. locals
  2041.         buf rb 9 ;byte[9]
  2042. endl
  2043.         png_debug 1, 'in png_write_oFFs'
  2044.  
  2045.         mov edi,[png_ptr]
  2046.         cmp dword[unit_type],PNG_OFFSET_LAST
  2047.         jl @f ;if (..>=..)
  2048.                 png_warning edi, 'Unrecognized unit type for oFFs chunk'
  2049.         @@:
  2050.  
  2051.         lea ebx,[ebp-9]
  2052.         stdcall png_save_int_32, ebx, [x_offset]
  2053.         add ebx,4
  2054.         stdcall png_save_int_32, ebx, [y_offset]
  2055.         add ebx,4
  2056.         mov eax,[unit_type]
  2057.         mov [ebx],al
  2058.         sub ebx,8
  2059.  
  2060.         stdcall png_write_complete_chunk, edi, png_oFFs, ebx, 9
  2061.         ret
  2062. endp
  2063.  
  2064. ; Write the pCAL chunk (described in the PNG extensions document)
  2065. ;void (png_structrp png_ptr, charp purpose, int_32 X0,
  2066. ;    int_32 X1, int type, int nparams, charp units, charpp params)
  2067. align 4
  2068. proc png_write_pCAL, png_ptr:dword, purpose:dword, X0:dword, X1:dword, type:dword,\
  2069.         nparams:dword, units:dword, params:dword
  2070. locals
  2071.         purpose_len dd ? ;uint_32
  2072.         units_len dd ?
  2073.         total_len dd ? ;png_size_t
  2074.         params_len dd ? ;png_size_tp
  2075.         buf rb 10 ;byte[10]
  2076.         new_purpose rb 80 ;byte[80]
  2077.         i dd ? ;int
  2078. endl
  2079. pushad
  2080.         png_debug1 1, 'in png_write_pCAL (%d parameters)', [nparams]
  2081.         mov edi,[png_ptr]
  2082.  
  2083.         cmp dword[type],PNG_EQUATION_LAST
  2084.         jl @f ;if (..>=..)
  2085.                 png_error edi, 'Unrecognized equation type for pCAL chunk'
  2086.         @@:
  2087.  
  2088.         lea ebx,[ebp-84] ;ebx = &new_purpose
  2089.         stdcall png_check_keyword, edi, [purpose], ebx
  2090.         mov [purpose_len],eax
  2091.  
  2092.         test eax,eax
  2093.         jnz @f ;if(..==0)
  2094.                 png_error edi, 'pCAL: invalid keyword'
  2095.         @@:
  2096.  
  2097.         inc dword[purpose_len] ; terminator
  2098.  
  2099.         png_debug1 3, 'pCAL purpose length = %d', [purpose_len]
  2100. ;   units_len = strlen(units) + (nparams == 0 ? 0 : 1);
  2101.         png_debug1 3, 'pCAL units length = %d', [units_len]
  2102. ;   total_len = purpose_len + units_len + 10;
  2103.  
  2104. ;   params_len = (png_size_tp)png_malloc(png_ptr,
  2105. ;       (png_alloc_size_t)(nparams * (sizeof (png_size_t))));
  2106.  
  2107.         ; Find the length of each parameter, making sure we don't count the
  2108.         ; null terminator for the last parameter.
  2109.  
  2110. ;   for (i = 0; i < nparams; i++)
  2111. ;   {
  2112. ;      params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
  2113. ;      png_debug2(3, "pCAL parameter %d length = %lu", i,
  2114. ;          (unsigned long)params_len[i]);
  2115. ;      total_len += params_len[i];
  2116. ;   }
  2117.  
  2118.         png_debug1 3, 'pCAL total length = %d', [total_len]
  2119.         stdcall png_write_chunk_header, edi, png_pCAL, [total_len]
  2120.         stdcall png_write_chunk_data, edi, ebx, [purpose_len]
  2121.         lea ebx,[ebp-94] ;ebx = &buf
  2122.         stdcall png_save_int_32, ebx, [X0]
  2123.         add ebx,4
  2124.         stdcall png_save_int_32, ebx, [X1]
  2125.         add ebx,4
  2126.         mov eax,[type]
  2127.         mov [ebx],al
  2128.         inc ebx
  2129.         mov eax,[nparams]
  2130.         mov [ebx],al
  2131.         sub ebx,9
  2132.         stdcall png_write_chunk_data, edi, ebx, 10
  2133.         stdcall png_write_chunk_data, edi, [units], [units_len]
  2134.  
  2135. ;   for (i = 0; i < nparams; i++)
  2136. ;   {
  2137. ;      png_write_chunk_data(png_ptr, (bytep)params[i], params_len[i]);
  2138. ;   }
  2139.  
  2140.         stdcall png_free, edi, [params_len]
  2141.         stdcall png_write_chunk_end, edi
  2142. popad
  2143.         ret
  2144. endp
  2145.  
  2146. ; Write the sCAL chunk
  2147. ;void (png_structrp png_ptr, int unit, charp width, charp height)
  2148. align 4
  2149. proc png_write_sCAL_s uses eax ebx ecx edi esi, png_ptr:dword, unit:dword, width:dword, height:dword
  2150. locals
  2151.         total_len dd 2
  2152.         wlen dd ?
  2153.         hlen dd ?
  2154.         buf rb 64 ;byte[64]
  2155. endl
  2156.         png_debug 1, 'in png_write_sCAL_s'
  2157.  
  2158.         stdcall strlen,[width]
  2159.         add [total_len],eax
  2160.         mov [wlen],eax
  2161.         stdcall strlen,[height]
  2162.         add [total_len],eax
  2163.         mov [hlen],eax
  2164.  
  2165.         cmp dword[total_len],64
  2166.         jle @f ;if (..>..)
  2167.                 cStr ,<'Can',39,'t write sCAL (buffer too small)'>
  2168.                 png_warning [png_ptr], eax
  2169.                 jmp .end_f
  2170.         @@:
  2171.  
  2172.         lea ebx,[ebp-64]
  2173.         mov eax,[unit]
  2174.         mov byte[ebx],al
  2175.         mov ecx,[wlen]
  2176.         inc ecx
  2177.         mov edi,ebx
  2178.         inc edi
  2179.         mov esi,[width]
  2180.         rep movsb ;Append the '\0' here
  2181.         mov ecx,[hlen]
  2182.         mov esi,[height]
  2183.         rep movsb ;Do NOT append the '\0' here
  2184.  
  2185.         png_debug1 3, 'sCAL total length = %u', [total_len]
  2186.         stdcall png_write_complete_chunk, [png_ptr], png_sCAL, ebx, [total_len]
  2187. .end_f:
  2188.         ret
  2189. endp
  2190.  
  2191. ; Write the pHYs chunk
  2192. ;void (png_structrp png_ptr, uint_32 x_pixels_per_unit,
  2193. ;    uint_32 y_pixels_per_unit, int unit_type)
  2194. align 4
  2195. proc png_write_pHYs uses eax ebx, png_ptr:dword, x_pixels_per_unit:dword, y_pixels_per_unit:dword, unit_type:dword
  2196. locals
  2197.         buf rb 9 ;byte[9]
  2198. endl
  2199.         png_debug 1, 'in png_write_pHYs'
  2200.  
  2201.         cmp dword[unit_type],PNG_RESOLUTION_LAST
  2202.         jl @f ;if (..>=..)
  2203.                 png_warning [png_ptr], 'Unrecognized unit type for pHYs chunk'
  2204.         @@:
  2205.  
  2206.         lea ebx,[ebp-9]
  2207.         stdcall png_save_uint_32, ebx, [x_pixels_per_unit]
  2208.         add ebx,4
  2209.         stdcall png_save_uint_32, ebx, [y_pixels_per_unit]
  2210.         add ebx,4
  2211.         mov al,byte[unit_type]
  2212.         mov byte[ebx],al
  2213.         sub ebx,8
  2214.  
  2215.         stdcall png_write_complete_chunk, [png_ptr], png_pHYs, ebx, 9
  2216.         ret
  2217. endp
  2218.  
  2219. ; Write the tIME chunk.  Use either png_convert_from_struct_tm()
  2220. ; or png_convert_from_time_t(), or fill in the structure yourself.
  2221.  
  2222. ;void (png_structrp png_ptr, png_const_timep mod_time)
  2223. align 4
  2224. proc png_write_tIME uses eax ebx ecx, png_ptr:dword, mod_time:dword
  2225. locals
  2226.         buf rb 7 ;byte[7]
  2227. endl
  2228.         png_debug 1, 'in png_write_tIME'
  2229.  
  2230.         mov eax,[mod_time]
  2231.         mov cl,[eax+png_time.month]
  2232.         cmp cl,12
  2233.         jg @f
  2234.         cmp cl,1
  2235.         jl @f
  2236.         mov ch,[eax+png_time.day]
  2237.         cmp ch,31
  2238.         jg @f
  2239.         cmp ch,1
  2240.         jl @f
  2241.         cmp byte[eax+png_time.hour],23
  2242.         jg @f
  2243.         cmp byte[eax+png_time.second],60
  2244.         jg @f
  2245.                 jmp .end0
  2246.         @@:
  2247.                 png_warning [png_ptr], 'Invalid time specified for tIME chunk'
  2248.                 jmp .end_f
  2249.         .end0:
  2250.  
  2251.         movzx ebx,word[eax+png_time.year]
  2252.         push ebx
  2253.         lea ebx,[ebp-7]
  2254.         stdcall png_save_uint_16, ebx ;, year
  2255.         add ebx,2
  2256.         mov byte[ebx],cl ;month
  2257.         inc ebx
  2258.         mov byte[ebx],ch ;day
  2259.         inc ebx
  2260.         mov cl,[eax+png_time.hour]
  2261.         mov byte[ebx],cl ;hour
  2262.         inc ebx
  2263.         mov cl,[eax+png_time.minute]
  2264.         mov byte[ebx],cl ;minute
  2265.         inc ebx
  2266.         mov cl,[eax+png_time.second]
  2267.         mov byte[ebx],cl ;second
  2268.         sub ebx,6
  2269.  
  2270.         stdcall png_write_complete_chunk, [png_ptr], png_tIME, ebx, 7
  2271. .end_f:
  2272.         ret
  2273. endp
  2274.  
  2275. if PNG_WRITE_INTERLACING_SUPPORTED eq 1
  2276.         ; Arrays to facilitate easy interlacing - use pass (0 - 6) as index
  2277.  
  2278.         ; Start of interlace block
  2279.         png_pass_start db 0, 4, 0, 2, 0, 1, 0
  2280.         ; Offset to next interlace block
  2281.         png_pass_inc db 8, 8, 4, 4, 2, 2, 1
  2282.         ; Start of interlace block in the y direction
  2283.         png_pass_ystart db 0, 0, 4, 0, 2, 0, 1
  2284.         ; Offset to next interlace block in the y direction
  2285.         png_pass_yinc db 8, 8, 8, 4, 4, 2, 2
  2286. end if
  2287.  
  2288. ; Initializes the row writing capability of libpng
  2289. ;void (png_structrp png_ptr)
  2290. align 4
  2291. proc png_write_start_row uses eax ebx ecx edx edi, png_ptr:dword
  2292. locals
  2293.         buf_size dd ? ;png_alloc_size_t
  2294.         usr_pixel_depth dd ? ;int
  2295. if PNG_WRITE_FILTER_SUPPORTED eq 1
  2296.         filters db ? ;byte
  2297. end if
  2298. endl
  2299.         png_debug 1, 'in png_write_start_row'
  2300.  
  2301.         mov edi,[png_ptr]
  2302.         movzx eax,byte[edi+png_struct.usr_channels]
  2303.         movzx ebx,byte[edi+png_struct.usr_bit_depth]
  2304.         imul eax,ebx
  2305.         mov [usr_pixel_depth],eax
  2306.         PNG_ROWBYTES eax,[edi+png_struct.width]
  2307.         inc eax
  2308.         mov [buf_size],eax
  2309.  
  2310.         ; 1.5.6: added to allow checking in the row write code.
  2311.         mov al,[edi+png_struct.pixel_depth]
  2312.         mov [edi+png_struct.transformed_pixel_depth],al
  2313.  
  2314.         mov eax,[usr_pixel_depth]
  2315.         mov [edi+png_struct.maximum_pixel_depth],al
  2316.  
  2317.         ; Set up row buffer
  2318.         stdcall png_malloc, edi, [buf_size]
  2319.         mov [edi+png_struct.row_buf],eax
  2320.  
  2321.         mov byte[eax],PNG_FILTER_VALUE_NONE
  2322.  
  2323. if PNG_WRITE_FILTER_SUPPORTED eq 1
  2324.         mov al,byte[edi+png_struct.do_filter]
  2325.  
  2326.         cmp dword[edi+png_struct.height],1
  2327.         jne @f ;if (..==1)
  2328.                 and al, 0xff and not(PNG_FILTER_UP or PNG_FILTER_AVG or PNG_FILTER_PAETH)
  2329.         @@:
  2330.         cmp dword[edi+png_struct.width],1
  2331.         jne @f ;if (..==1)
  2332.                 and al, 0xff and not(PNG_FILTER_SUB or PNG_FILTER_AVG or PNG_FILTER_PAETH)
  2333.         @@:
  2334.  
  2335.         cmp al,0
  2336.         jne @f ;if (..==0)
  2337.                 mov al,PNG_FILTER_NONE
  2338.         @@:
  2339.  
  2340.         mov [filters],al
  2341.         mov byte[edi+png_struct.do_filter],al
  2342.  
  2343.         ;mov al,[filters]
  2344.         and al,PNG_FILTER_SUB or PNG_FILTER_UP or PNG_FILTER_AVG or PNG_FILTER_PAETH
  2345.         cmp al,0
  2346.         je .end0
  2347.         cmp dword[edi+png_struct.try_row],0
  2348.         jne .end0 ;if (..!=0) && ..==0)
  2349.                 xor ebx,ebx
  2350.  
  2351.                 stdcall png_malloc, edi, [buf_size]
  2352.                 mov dword[edi+png_struct.try_row],eax
  2353.  
  2354.                 mov al,[filters]
  2355.                 and al,PNG_FILTER_SUB
  2356.                 cmp al,0
  2357.                 je @f
  2358.                         inc ebx
  2359.                 @@:
  2360.                 mov al,[filters]
  2361.                 and al,PNG_FILTER_UP
  2362.                 cmp al,0
  2363.                 je @f
  2364.                         inc ebx
  2365.                 @@:
  2366.                 mov al,[filters]
  2367.                 and al,PNG_FILTER_AVG
  2368.                 cmp al,0
  2369.                 je @f
  2370.                         inc ebx
  2371.                 @@:
  2372.                 mov al,[filters]
  2373.                 and al,PNG_FILTER_PAETH
  2374.                 cmp al,0
  2375.                 je @f
  2376.                         inc ebx
  2377.                 @@:
  2378.                 cmp ebx,1
  2379.                 jle .end0 ;if (..>1)
  2380.                         stdcall png_malloc, edi, [buf_size]
  2381.                         mov dword[edi+png_struct.tst_row],eax
  2382.         .end0:
  2383.  
  2384.         ; We only need to keep the previous row if we are using one of the following
  2385.         ; filters.
  2386.  
  2387.         mov al,[filters]
  2388.         and al,PNG_FILTER_AVG or PNG_FILTER_UP or PNG_FILTER_PAETH
  2389.         cmp al,0
  2390.         je @f ;if (..!=0)
  2391.                 stdcall png_calloc, edi, [buf_size]
  2392.                 mov dword[edi+png_struct.prev_row],eax
  2393.         @@:
  2394. end if ;WRITE_FILTER
  2395.  
  2396. if PNG_WRITE_INTERLACING_SUPPORTED eq 1
  2397.         ; If interlaced, we need to set up width and height of pass
  2398.         cmp byte[edi+png_struct.interlaced],0
  2399.         je @f
  2400.         mov eax,[edi+png_struct.transformations]
  2401.         and eax,PNG_INTERLACE
  2402.         jnz @f ;if(..!=0 && ..==0)
  2403.                 movzx ecx,byte[png_pass_yinc]
  2404.                 mov eax,[edi+png_struct.height]
  2405.                 add eax,ecx
  2406.                 dec eax
  2407.                 movzx edx,byte[png_pass_ystart]
  2408.                 sub eax,edx
  2409.                 xor edx,edx
  2410.                 div ecx
  2411.                 mov [edi+png_struct.num_rows],eax
  2412.  
  2413.                 movzx ecx,byte[png_pass_inc]
  2414.                 mov eax,[edi+png_struct.width]
  2415.                 add eax,ecx
  2416.                 dec eax
  2417.                 movzx edx,byte[png_pass_start]
  2418.                 sub eax,edx
  2419.                 xor edx,edx
  2420.                 div ecx
  2421.                 mov [edi+png_struct.usr_width],eax
  2422.                 jmp .end1
  2423.         @@: ;else
  2424. end if
  2425.                 mov eax,[edi+png_struct.height]
  2426.                 mov [edi+png_struct.num_rows],eax
  2427.                 mov eax,[edi+png_struct.width]
  2428.                 mov [edi+png_struct.usr_width],eax
  2429.         .end1:
  2430.         ret
  2431. endp
  2432.  
  2433. ; Internal use only.  Called when finished processing a row of data.
  2434. ;void (png_structrp png_ptr)
  2435. align 4
  2436. proc png_write_finish_row uses eax ecx edx edi, png_ptr:dword
  2437.         png_debug 1, 'in png_write_finish_row'
  2438.  
  2439.         mov edi,[png_ptr]
  2440.         ; Next row
  2441.         inc dword[edi+png_struct.row_number]
  2442.  
  2443.         ; See if we are done
  2444.         mov eax,[edi+png_struct.row_number]
  2445.         cmp eax,[edi+png_struct.num_rows]
  2446.         jl .end_f ;if (..<..) return
  2447.  
  2448. if PNG_WRITE_INTERLACING_SUPPORTED eq 1
  2449.         ; If interlaced, go to next pass
  2450.         cmp byte[edi+png_struct.interlaced],0
  2451.         je .end0 ;if (..!=0)
  2452.                 mov dword[edi+png_struct.row_number],0
  2453.                 mov eax,[edi+png_struct.transformations]
  2454.                 and eax,PNG_INTERLACE
  2455.                 jz @f ;if (..!=0)
  2456.                         inc byte[edi+png_struct.pass]
  2457.                         jmp .end1
  2458.                 @@: ;else
  2459.                         ; Loop until we find a non-zero width or height pass
  2460.                         .cycle0: ;do
  2461.                                 inc byte[edi+png_struct.pass]
  2462.                                 cmp byte[edi+png_struct.pass],7
  2463.                                 jge .cycle0end ;if (..>=..) break
  2464.  
  2465.                                 movzx ecx,byte[edi+png_struct.pass]
  2466.                                 add ecx,png_pass_inc
  2467.                                 movzx ecx,byte[ecx]
  2468.                                 mov eax,[edi+png_struct.width]
  2469.                                 add eax,ecx
  2470.                                 dec eax
  2471.                                 movzx edx,byte[edi+png_struct.pass]
  2472.                                 add edx,png_pass_start
  2473.                                 movzx edx,byte[edx]
  2474.                                 sub eax,edx
  2475.                                 xor edx,edx
  2476.                                 div ecx
  2477.                                 mov [edi+png_struct.usr_width],eax
  2478.  
  2479.                                 movzx ecx,byte[edi+png_struct.pass]
  2480.                                 add ecx,png_pass_yinc
  2481.                                 movzx ecx,byte[ecx]
  2482.                                 mov eax,[edi+png_struct.height]
  2483.                                 add eax,ecx
  2484.                                 dec eax
  2485.                                 movzx edx,byte[edi+png_struct.pass]
  2486.                                 add edx,png_pass_ystart
  2487.                                 movzx edx,byte[edx]
  2488.                                 sub eax,edx
  2489.                                 xor edx,edx
  2490.                                 div ecx
  2491.                                 mov [edi+png_struct.num_rows],eax
  2492.  
  2493.                                 mov eax,[edi+png_struct.transformations]
  2494.                                 and eax,PNG_INTERLACE
  2495.                                 jnz .cycle0end ;if(..!=0) break
  2496.  
  2497.                                 cmp dword[edi+png_struct.usr_width],0
  2498.                                 je .cycle0
  2499.                                 cmp dword[edi+png_struct.num_rows],0
  2500.                                 je .cycle0
  2501.                         .cycle0end: ;while (..==0 || ..==0)
  2502.                 .end1:
  2503.  
  2504.                 ; Reset the row above the image for the next pass
  2505.                 cmp byte[edi+png_struct.pass],7
  2506.                 jge .end0 ;if (..<..)
  2507.                         cmp dword[edi+png_struct.prev_row],0
  2508.                         je .end_f ;if (..!=0)
  2509.                                 movzx eax,byte[edi+png_struct.usr_channels]
  2510.                                 movzx edx,byte[edi+png_struct.usr_bit_depth]
  2511.                                 imul eax,edx
  2512.                                 PNG_ROWBYTES eax, [edi+png_struct.width]
  2513.                                 inc eax
  2514.                                 push edi
  2515.                                 mov ecx,eax
  2516.                                 xor eax,eax
  2517.                                 mov edi,[edi+png_struct.prev_row]
  2518.                                 rep stosb ;memset(...
  2519.                                 pop edi
  2520.                         jmp .end_f
  2521.         .end0:
  2522. end if
  2523.  
  2524.         ; If we get here, we've just written the last row, so we need
  2525.         ; to flush the compressor
  2526.         stdcall png_compress_IDAT, 0, 0, Z_FINISH
  2527. .end_f:
  2528.         ret
  2529. endp
  2530.  
  2531. ; Pick out the correct pixels for the interlace pass.
  2532. ; The basic idea here is to go through the row with a source
  2533. ; pointer and a destination pointer (sp and dp), and copy the
  2534. ; correct pixels for the pass.  As the row gets compacted,
  2535. ; sp will always be >= dp, so we should never overwrite anything.
  2536. ; See the default: case for the easiest code to understand.
  2537.  
  2538. ;void (png_row_infop row_info, bytep row, int pass)
  2539. align 4
  2540. proc png_do_write_interlace, row_info:dword, row:dword, pass:dword
  2541.         png_debug 1, 'in png_do_write_interlace'
  2542.  
  2543.         ; We don't have to do anything on the last pass (6)
  2544.         cmp dword[pass],6
  2545.         jge .end_f ;if (..<..)
  2546.         ; Each pixel depth is handled separately
  2547. ;      switch (row_info->pixel_depth)
  2548. ;      {
  2549. ;         case 1:
  2550. ;         {
  2551. ;            bytep sp;
  2552. ;            bytep dp;
  2553. ;            unsigned int shift;
  2554. ;            int d;
  2555. ;            int value;
  2556. ;            uint_32 i;
  2557. ;            uint_32 row_width = row_info->width;
  2558.  
  2559. ;            dp = row;
  2560. ;            d = 0;
  2561. ;            shift = 7;
  2562.  
  2563. ;            for (i = png_pass_start[pass]; i < row_width;
  2564. ;               i += png_pass_inc[pass])
  2565. ;            {
  2566. ;               sp = row + (png_size_t)(i >> 3);
  2567. ;               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
  2568. ;               d |= (value << shift);
  2569.  
  2570. ;               if (shift == 0)
  2571. ;               {
  2572. ;                  shift = 7;
  2573. ;                  *dp++ = (byte)d;
  2574. ;                  d = 0;
  2575. ;               }
  2576.  
  2577. ;               else
  2578. ;                  shift--;
  2579.  
  2580. ;            }
  2581. ;            if (shift != 7)
  2582. ;               *dp = (byte)d;
  2583.  
  2584. ;            break;
  2585. ;         }
  2586.  
  2587. ;         case 2:
  2588. ;         {
  2589. ;            bytep sp;
  2590. ;            bytep dp;
  2591. ;            unsigned int shift;
  2592. ;            int d;
  2593. ;            int value;
  2594. ;            uint_32 i;
  2595. ;            uint_32 row_width = row_info->width;
  2596.  
  2597. ;            dp = row;
  2598. ;            shift = 6;
  2599. ;            d = 0;
  2600.  
  2601. ;            for (i = png_pass_start[pass]; i < row_width;
  2602. ;               i += png_pass_inc[pass])
  2603. ;            {
  2604. ;               sp = row + (png_size_t)(i >> 2);
  2605. ;               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
  2606. ;               d |= (value << shift);
  2607.  
  2608. ;               if (shift == 0)
  2609. ;               {
  2610. ;                  shift = 6;
  2611. ;                  *dp++ = (byte)d;
  2612. ;                  d = 0;
  2613. ;               }
  2614.  
  2615. ;               else
  2616. ;                  shift -= 2;
  2617. ;            }
  2618. ;            if (shift != 6)
  2619. ;               *dp = (byte)d;
  2620.  
  2621. ;            break;
  2622. ;         }
  2623.  
  2624. ;         case 4:
  2625. ;         {
  2626. ;            bytep sp;
  2627. ;            bytep dp;
  2628. ;            unsigned int shift;
  2629. ;            int d;
  2630. ;            int value;
  2631. ;            uint_32 i;
  2632. ;            uint_32 row_width = row_info->width;
  2633.  
  2634. ;            dp = row;
  2635. ;            shift = 4;
  2636. ;            d = 0;
  2637. ;            for (i = png_pass_start[pass]; i < row_width;
  2638. ;                i += png_pass_inc[pass])
  2639. ;            {
  2640. ;               sp = row + (png_size_t)(i >> 1);
  2641. ;               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
  2642. ;               d |= (value << shift);
  2643.  
  2644. ;               if (shift == 0)
  2645. ;               {
  2646. ;                  shift = 4;
  2647. ;                  *dp++ = (byte)d;
  2648. ;                  d = 0;
  2649. ;               }
  2650.  
  2651. ;               else
  2652. ;                  shift -= 4;
  2653. ;            }
  2654. ;            if (shift != 4)
  2655. ;               *dp = (byte)d;
  2656.  
  2657. ;            break;
  2658. ;         }
  2659.  
  2660. ;         default:
  2661. ;         {
  2662. ;            bytep sp;
  2663. ;            bytep dp;
  2664. ;            uint_32 i;
  2665. ;            uint_32 row_width = row_info->width;
  2666. ;            png_size_t pixel_bytes;
  2667.  
  2668.         ; Start at the beginning
  2669. ;            dp = row;
  2670.  
  2671.         ; Find out how many bytes each pixel takes up
  2672. ;            pixel_bytes = (row_info->pixel_depth >> 3);
  2673.  
  2674.         ; Loop through the row, only looking at the pixels that matter
  2675. ;            for (i = png_pass_start[pass]; i < row_width;
  2676. ;               i += png_pass_inc[pass])
  2677. ;            {
  2678.         ; Find out where the original pixel is
  2679. ;               sp = row + (png_size_t)i * pixel_bytes;
  2680.  
  2681.         ; Move the pixel
  2682. ;               if (dp != sp)
  2683. ;                  memcpy(dp, sp, pixel_bytes);
  2684.  
  2685.         ; Next pixel
  2686. ;               dp += pixel_bytes;
  2687. ;            }
  2688. ;            break;
  2689. ;         }
  2690. ;      }
  2691.         ; Set new row width
  2692. ;      row_info->width = (row_info->width +
  2693. ;          png_pass_inc[pass] - 1 -
  2694. ;          png_pass_start[pass]) /
  2695. ;          png_pass_inc[pass];
  2696.  
  2697. ;      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
  2698. ;          row_info->width);
  2699. .end_f:
  2700.         ret
  2701. endp
  2702.  
  2703. ; This filters the row, chooses which filter to use, if it has not already
  2704. ; been specified by the application, and then writes the row out with the
  2705. ; chosen filter.
  2706.  
  2707. ;void png_write_filtered_row(png_structrp png_ptr, bytep filtered_row,
  2708. ;    png_size_t row_bytes);
  2709.  
  2710. ;png_size_t (png_structrp png_ptr, const uint_32 bpp, const png_size_t row_bytes, const png_size_t lmins)
  2711. align 4
  2712. proc png_setup_sub_row uses ebx ecx edx edi esi, png_ptr:dword, bpp:dword, row_bytes:dword, lmins:dword
  2713.         mov ebx,[png_ptr]
  2714.         mov edi,[ebx+png_struct.try_row]
  2715.         mov byte[edi],PNG_FILTER_VALUE_SUB
  2716.  
  2717.         mov ecx,[bpp]
  2718.         inc edi
  2719.         mov esi,[ebx+png_struct.row_buf]
  2720.         inc esi
  2721.         xor eax,eax
  2722.         xor edx,edx
  2723.         .cycle0:
  2724.                 lodsb
  2725.                 stosb
  2726.                 png_setup_abs edx
  2727.                 loop .cycle0
  2728.  
  2729.         mov ecx,[row_bytes]
  2730.         sub ecx,[bpp]
  2731.         mov ebx,[ebx+png_struct.row_buf]
  2732.         inc ebx
  2733.         .cycle1:
  2734.                 lodsb
  2735.                 sub al,byte[ebx]
  2736.                 stosb
  2737.                 png_setup_abs edx
  2738.                 cmp edx,[lmins]
  2739.                 jg .cycle1end ;if (..>..) ;We are already worse, don't continue.
  2740.                 inc ebx
  2741.                 loop .cycle1
  2742.         .cycle1end:
  2743.         mov eax,edx
  2744.         ret
  2745. endp
  2746.  
  2747. ;void (png_structrp png_ptr, const uint_32 bpp, const png_size_t row_bytes)
  2748. align 4
  2749. proc png_setup_sub_row_only, png_ptr:dword, bpp:dword, row_bytes:dword
  2750. pushad
  2751.         mov ebx,[png_ptr]
  2752.         mov edi,[ebx+png_struct.try_row]
  2753.         mov byte[edi],PNG_FILTER_VALUE_SUB
  2754.  
  2755.         mov ecx,[bpp]
  2756.         inc edi
  2757.         mov esi,[ebx+png_struct.row_buf]
  2758.         inc esi
  2759.         rep movsb
  2760.  
  2761.         mov ecx,[row_bytes]
  2762.         sub ecx,[bpp]
  2763.         mov edx,[ebx+png_struct.row_buf]
  2764.         inc edx
  2765. align 4
  2766.         .cycle0:
  2767.                 lodsb
  2768.                 sub al,byte[edx]
  2769.                 stosb
  2770.                 inc edx
  2771.                 loop .cycle0
  2772. popad
  2773.         ret
  2774. endp
  2775.  
  2776. ;png_size_t (png_structrp png_ptr, const png_size_t row_bytes, const png_size_t lmins)
  2777. align 4
  2778. proc png_setup_up_row uses ebx ecx edx edi esi, png_ptr:dword, row_bytes:dword, lmins:dword
  2779.         mov ebx,[png_ptr]
  2780.         mov edi,[ebx+png_struct.try_row]
  2781.         mov byte[edi],PNG_FILTER_VALUE_UP
  2782.  
  2783.         mov ecx,[row_bytes]
  2784.         inc edi
  2785.         mov esi,[ebx+png_struct.row_buf]
  2786.         inc esi
  2787.         mov ebx,[ebx+png_struct.prev_row]
  2788.         inc ebx
  2789.         xor edx,edx
  2790.         .cycle0:
  2791.                 lodsb
  2792.                 sub al,byte[ebx]
  2793.                 stosb
  2794.                 png_setup_abs edx
  2795.                 cmp edx,[lmins]
  2796.                 jg .cycle0end ;if (..>..) ;We are already worse, don't continue.
  2797.                 inc ebx
  2798.                 loop .cycle0
  2799.         .cycle0end:
  2800.         mov eax,edx
  2801.         ret
  2802. endp
  2803.  
  2804. ;void (png_structrp png_ptr, const png_size_t row_bytes)
  2805. align 4
  2806. proc png_setup_up_row_only, png_ptr:dword, row_bytes:dword
  2807. pushad
  2808.         mov ebx,[png_ptr]
  2809.         mov edi,[ebx+png_struct.try_row]
  2810.         mov byte[edi],PNG_FILTER_VALUE_UP
  2811.  
  2812.         mov ecx,[row_bytes]
  2813.         inc edi
  2814.         mov esi,[ebx+png_struct.row_buf]
  2815.         inc esi
  2816.         mov ebx,[ebx+png_struct.prev_row]
  2817.         inc ebx
  2818.         .cycle0:
  2819.                 lodsb
  2820.                 sub al,byte[ebx]
  2821.                 stosb
  2822.                 inc ebx
  2823.                 loop .cycle0
  2824. popad
  2825.         ret
  2826. endp
  2827.  
  2828. ;png_size_t (png_structrp png_ptr, const uint_32 bpp, const png_size_t row_bytes, const png_size_t lmins)
  2829. align 4
  2830. proc png_setup_avg_row uses ebx ecx edx edi esi, png_ptr:dword, bpp:dword, row_bytes:dword, lmins:dword
  2831. locals
  2832.         sum dd 0 ;png_size_t
  2833. endl
  2834.         mov ebx,[png_ptr]
  2835.         mov edi,[ebx+png_struct.try_row]
  2836.         mov byte[edi],PNG_FILTER_VALUE_AVG
  2837.  
  2838.         mov ecx,[bpp]
  2839.         inc edi
  2840.         mov esi,[ebx+png_struct.row_buf]
  2841.         inc esi
  2842.         mov ebx,[ebx+png_struct.prev_row]
  2843.         inc ebx
  2844.         .cycle0:
  2845.                 lodsb
  2846.                 mov ah,byte[ebx]
  2847.                 shr ah,1
  2848.                 sub al,ah
  2849.                 stosb
  2850.                 png_setup_abs dword[sum]
  2851.                 inc ebx
  2852.                 loop .cycle0
  2853.  
  2854.         mov ecx,[row_bytes]
  2855.         sub ecx,[bpp]
  2856.         mov eax,[png_ptr]
  2857.         mov edx,[eax+png_struct.row_buf]
  2858.         inc edx
  2859.         .cycle1:
  2860.                 lodsb
  2861.                 shl eax,24
  2862.                 movzx ax,byte[ebx]
  2863.                 add al,byte[edx]
  2864.                 jnc @f
  2865.                         mov ah,1
  2866.                 @@:
  2867.                 shr ax,1
  2868.                 rol eax,8
  2869.                 sub al,ah
  2870.                 stosb
  2871.                 png_setup_abs dword[sum]
  2872.                 mov eax,[sum]
  2873.                 cmp eax,[lmins]
  2874.                 jg .cycle1end ;if (..>..) ;We are already worse, don't continue.
  2875.                 inc ebx
  2876.                 inc edx
  2877.                 loop .cycle1
  2878.         .cycle1end:
  2879.         mov eax,[sum]
  2880.         ret
  2881. endp
  2882.  
  2883. ;void (png_structrp png_ptr, const uint_32 bpp, const png_size_t row_bytes)
  2884. align 4
  2885. proc png_setup_avg_row_only, png_ptr:dword, bpp:dword, row_bytes:dword
  2886. pushad
  2887.         mov ebx,[png_ptr]
  2888.         mov edi,[ebx+png_struct.try_row]
  2889.         mov byte[edi],PNG_FILTER_VALUE_AVG
  2890.  
  2891.         mov ecx,[bpp]
  2892.         inc edi
  2893.         mov esi,[ebx+png_struct.row_buf]
  2894.         inc esi
  2895.         mov ebx,[ebx+png_struct.prev_row]
  2896.         inc ebx
  2897.         .cycle0:
  2898.                 lodsb
  2899.                 mov ah,byte[ebx]
  2900.                 shr ah,1
  2901.                 sub al,ah
  2902.                 stosb
  2903.                 inc ebx
  2904.                 loop .cycle0
  2905.  
  2906.         mov ecx,[row_bytes]
  2907.         sub ecx,[bpp]
  2908.         mov eax,[png_ptr]
  2909.         mov edx,[eax+png_struct.row_buf]
  2910.         inc edx
  2911.         .cycle1:
  2912.                 lodsb
  2913.                 mov ah,byte[ebx]
  2914.                 shr ah,1
  2915.                 sub al,ah
  2916.                 mov ah,byte[edx]
  2917.                 shr ah,1
  2918.                 sub al,ah
  2919.                 stosb
  2920.                 inc ebx
  2921.                 inc edx
  2922.                 loop .cycle1
  2923. popad
  2924.         ret
  2925. endp
  2926.  
  2927. ;png_size_t (png_structrp png_ptr, const uint_32 bpp,
  2928. ;    const png_size_t row_bytes, const png_size_t lmins)
  2929. align 4
  2930. proc png_setup_paeth_row uses ebx ecx edx edi esi, png_ptr:dword, bpp:dword, row_bytes:dword, lmins:dword
  2931. locals
  2932.         pp dd ?
  2933.         sum dd ?
  2934.         v dd ?
  2935.         lp dd ?
  2936.         cp dd ?
  2937.         a dd ?
  2938.         b dd ?
  2939.         c dd ?
  2940.         p dd ?
  2941.         pa dd ?
  2942.         pb dd ?
  2943.         pc dd ?
  2944. endl
  2945.         ;ecx - i
  2946.         ;edi - dp
  2947.         ;esi - rp
  2948.         mov dword[sum],0
  2949.         mov ebx,[png_ptr]
  2950.         mov eax,[ebx+png_struct.try_row]
  2951.         mov byte[eax],PNG_FILTER_VALUE_PAETH
  2952.         xor ecx,ecx
  2953.         mov esi,[ebx+png_struct.row_buf]
  2954.         inc esi
  2955.         mov edi,[ebx+png_struct.try_row]
  2956.         inc edi
  2957.         mov eax,[ebx+png_struct.prev_row]
  2958.         inc eax
  2959.         mov [pp],eax
  2960.         jmp @f
  2961.  
  2962. align 4
  2963. .cycle0:
  2964.         inc ecx
  2965.         @@:
  2966.         cmp ecx,[bpp]
  2967.         jae .cycle0end
  2968.         lodsb
  2969.         mov edx,[pp]
  2970.         movzx edx,byte[edx]
  2971.         sub al,dl
  2972.         stosb
  2973.         and eax,0xff
  2974.         mov [v],eax
  2975.         inc dword[pp]
  2976.         cmp eax,0x80
  2977.         jge @f
  2978.                 add [sum],eax
  2979.                 jmp .cycle0
  2980.         @@:
  2981.         mov eax,0x100
  2982.         sub eax,[v]
  2983.         add [sum],eax
  2984.         jmp .cycle0
  2985. .cycle0end:
  2986.  
  2987.         mov eax,[ebx+png_struct.row_buf]
  2988.         inc eax
  2989.         mov [lp],eax
  2990.         mov eax,[ebx+png_struct.prev_row]
  2991.         inc eax
  2992.         mov [cp],eax
  2993.         jmp @f
  2994.  
  2995. align 4
  2996. .cycle1:
  2997.         inc ecx
  2998.         @@:
  2999.         cmp ecx,[row_bytes]
  3000.         jae .cycle1end
  3001.         mov eax,[pp]
  3002.         movzx ebx,byte[eax]
  3003.         mov [b],ebx
  3004.         inc dword[pp]
  3005.         mov eax,[cp]
  3006.         movzx ebx,byte[eax]
  3007.         mov [c],ebx
  3008.         inc dword[cp]
  3009.         mov eax,[lp]
  3010.         movzx ebx,byte[eax]
  3011.         mov [a],ebx
  3012.         inc dword[lp]
  3013.         mov eax,[b]
  3014.         sub eax,[c]
  3015.         mov [p],eax
  3016.         mov ebx,[a]
  3017.         sub ebx,[c]
  3018.         mov [pc],ebx
  3019.         mov eax,[p]
  3020.         cmp eax,0
  3021.         jge @f
  3022.                 neg eax
  3023.         @@:
  3024.         mov [pa],eax
  3025.         mov eax,[pc]
  3026.         cmp eax,0
  3027.         jge @f
  3028.                 neg eax
  3029.         @@:
  3030.         mov [pb],eax
  3031.         mov eax,[p]
  3032.         add eax,[pc]
  3033.         jns @f
  3034.                 neg eax
  3035.         @@:
  3036.         mov [pc],eax
  3037.         mov eax,[pa]
  3038.         cmp eax,[pb]
  3039.         jg .end0
  3040.         cmp eax,[pc]
  3041.         jg .end0
  3042.                 mov eax,[a]
  3043.                 jmp .end1
  3044.         .end0:
  3045.                 mov eax,[pb]
  3046.                 cmp eax,[pc]
  3047.                 jg .end2
  3048.                         mov eax,[b]
  3049.                         jmp .end1
  3050.                 .end2:
  3051.                         mov eax,[c]
  3052.         .end1:
  3053.         mov [p],eax
  3054.         movzx eax,byte[esi]
  3055.         sub eax,[p]
  3056.         and eax,0xff
  3057.         stosb
  3058.         mov [v],eax
  3059.         inc esi
  3060.         cmp dword[v],0x80
  3061.         jge .end3
  3062.                 mov eax,[v]
  3063.                 add [sum],eax
  3064.                 jmp .end4
  3065.         .end3:
  3066.                 mov eax,0x100
  3067.                 sub eax,[v]
  3068.                 add [sum],eax
  3069.         .end4:
  3070.         mov eax,[sum]
  3071.         cmp eax,[lmins] ;We are already worse, don't continue.
  3072.         jbe .cycle1
  3073. .cycle1end:
  3074.         mov eax,[sum]
  3075.         ret
  3076. endp
  3077.  
  3078. ;void (png_structrp png_ptr, const uint_32 bpp, const png_size_t row_bytes)
  3079. align 4
  3080. proc png_setup_paeth_row_only, png_ptr:dword, bpp:dword, row_bytes:dword
  3081. locals
  3082.         pp dd ?
  3083.         lp dd ?
  3084.         cp dd ?
  3085.         a dd ?
  3086.         b dd ?
  3087.         c dd ?
  3088.         p dd ?
  3089.         pa dd ?
  3090.         pb dd ?
  3091.         pc dd ?
  3092. endl
  3093. pushad
  3094.         ;ecx - i
  3095.         ;edi - dp
  3096.         ;esi - rp
  3097.         mov eax,[png_ptr]
  3098.         mov ebx,[eax+png_struct.try_row]
  3099.         mov byte[ebx],4
  3100.         xor ecx,ecx
  3101.         mov edx,[png_ptr]
  3102.         mov eax,[edx+png_struct.row_buf]
  3103.         inc eax
  3104.         mov esi,eax
  3105.         mov ebx,[png_ptr]
  3106.         mov edx,[ebx+png_struct.try_row]
  3107.         inc edx
  3108.         mov edi,edx
  3109.         mov eax,[png_ptr]
  3110.         mov ebx,[eax+png_struct.prev_row]
  3111.         inc ebx
  3112.         mov [pp],ebx
  3113.         jmp @f
  3114.  
  3115. align 4
  3116. .cycle0:
  3117.         inc ecx
  3118.         @@:
  3119.         cmp ecx,[bpp]
  3120.         jae .cycle0end
  3121.         lodsb
  3122.         mov ebx,[pp]
  3123.         movzx ebx,byte[ebx]
  3124.         sub al,bl
  3125.         stosb
  3126.         inc dword[pp]
  3127.         jmp .cycle0
  3128. .cycle0end:
  3129.  
  3130.         mov eax,[png_ptr]
  3131.         mov ebx,[eax+png_struct.row_buf]
  3132.         inc ebx
  3133.         mov [lp],ebx
  3134.         mov edx,[png_ptr]
  3135.         mov eax,[edx+png_struct.prev_row]
  3136.         inc eax
  3137.         mov [cp],eax
  3138.         jmp @f
  3139.  
  3140. align 4
  3141. .cycle1:
  3142.         inc ecx
  3143.         @@:
  3144.         cmp ecx,[row_bytes]
  3145.         jae .cycle1end
  3146.         mov eax,[pp]
  3147.         movzx ebx,byte[eax]
  3148.         mov [b],ebx
  3149.         inc dword[pp]
  3150.         mov eax,[cp]
  3151.         movzx ebx,byte[eax]
  3152.         mov [c],ebx
  3153.         inc dword[cp]
  3154.         mov eax,[lp]
  3155.         movzx ebx,byte[eax]
  3156.         mov [a],ebx
  3157.         inc dword[lp]
  3158.         mov eax,[b]
  3159.         sub eax,[c]
  3160.         mov [p],eax
  3161.         mov ebx,[a]
  3162.         sub ebx,[c]
  3163.         mov [pc],ebx
  3164.         mov eax,[p]
  3165.         cmp eax,0
  3166.         jge @f
  3167.                 neg eax
  3168.         @@:
  3169.         mov [pa],eax
  3170.         mov eax,[pc]
  3171.         cmp eax,0
  3172.         jge @f
  3173.                 neg eax
  3174.         @@:
  3175.         mov [pb],eax
  3176.         mov eax,[p]
  3177.         add eax,[pc]
  3178.         jns @f
  3179.                 neg eax
  3180.         @@:
  3181.         mov [pc],eax
  3182.         mov eax,[pa]
  3183.         cmp eax,[pb]
  3184.         jg .end0
  3185.         cmp eax,[pc]
  3186.         jg .end0
  3187.                 mov eax,[a]
  3188.                 jmp .end1
  3189.         .end0:
  3190.                 mov eax,[pb]
  3191.                 cmp eax,[pc]
  3192.                 jg .end2
  3193.                         mov eax,[b]
  3194.                         jmp .end1
  3195.                 .end2:
  3196.                         mov eax,[c]
  3197.         .end1:
  3198.         mov [p],eax
  3199.         movzx eax,byte[esi]
  3200.         sub eax,[p]
  3201.         and eax,0xff
  3202.         stosb
  3203.         inc esi
  3204.         jmp .cycle1
  3205. .cycle1end:
  3206. popad
  3207.         ret
  3208. endp
  3209.  
  3210. ;void (png_structrp png_ptr, png_row_infop row_info)
  3211. align 4
  3212. proc png_write_find_filter, png_ptr:dword, row_info:dword
  3213. locals
  3214.         filter_to_do dd ? ;unsigned int ;= png_ptr->do_filter
  3215.         row_buf  dd ? ;bytep
  3216.         best_row dd ? ;bytep
  3217.         bpp      dd ? ;uint_32
  3218.         mins     dd ? ;png_size_t
  3219.         row_bytes dd ? ;png_size_t ;= row_info->rowbytes
  3220. endl
  3221. pushad
  3222.         mov edi,[png_ptr]
  3223. if PNG_WRITE_FILTER_SUPPORTED eq 0
  3224.         mov eax,[edi+png_struct.rowbytes]
  3225.         inc eax
  3226.         stdcall png_write_filtered_row, edi, [edi+png_struct.row_buf], eax
  3227. else
  3228.         mov esi,[row_info]
  3229.         movzx eax,byte[edi+png_struct.do_filter]
  3230.         mov [filter_to_do],eax
  3231.         mov eax,[esi+png_row_info.rowbytes]
  3232.         mov [row_bytes],eax
  3233.  
  3234.         png_debug 1, 'in png_write_find_filter'
  3235.  
  3236.         ; Find out how many bytes offset each pixel is
  3237.         movzx eax,byte[edi+png_struct.pixel_depth]
  3238.         add eax,7
  3239.         shr eax,3
  3240.         mov [bpp],eax
  3241.  
  3242.         mov eax,[edi+png_struct.row_buf]
  3243.         mov [row_buf],eax
  3244.         mov dword[mins], PNG_SIZE_MAX - 256 ;so we can detect potential overflow of the
  3245.                 ;running sum
  3246.  
  3247. ; The prediction method we use is to find which method provides the
  3248. ; smallest value when summing the absolute values of the distances
  3249. ; from zero, using anything >= 128 as negative numbers.  This is known
  3250. ; as the "minimum sum of absolute differences" heuristic.  Other
  3251. ; heuristics are the "weighted minimum sum of absolute differences"
  3252. ; (experimental and can in theory improve compression), and the "zlib
  3253. ; predictive" method (not implemented yet), which does test compressions
  3254. ; of lines using different filter methods, and then chooses the
  3255. ; (series of) filter(s) that give minimum compressed data size (VERY
  3256. ; computationally expensive).
  3257.  
  3258. ; GRR 980525:  consider also
  3259.  
  3260. ;   (1) minimum sum of absolute differences from running average (i.e.,
  3261. ;       keep running sum of non-absolute differences & count of bytes)
  3262. ;       [track dispersion, too?  restart average if dispersion too large?]
  3263.  
  3264. ;  (1b) minimum sum of absolute differences from sliding average, probably
  3265. ;       with window size <= deflate window (usually 32K)
  3266.  
  3267. ;   (2) minimum sum of squared differences from zero or running average
  3268. ;       (i.e., ~ root-mean-square approach)
  3269.  
  3270.  
  3271.  
  3272. ; We don't need to test the 'no filter' case if this is the only filter
  3273. ; that has been chosen, as it doesn't actually do anything to the data.
  3274.  
  3275.         mov eax,[edi+png_struct.row_buf]
  3276.         mov [best_row],eax
  3277.  
  3278.         cmp dword[row_bytes],PNG_SIZE_MAX/128
  3279.         jl @f ;if (..>=..)
  3280.                 ; Overflow can occur in the calculation, just select the lowest set
  3281.                 ; filter.
  3282.  
  3283.                 xor eax,eax
  3284.                 sub eax,[filter_to_do]
  3285.                 and [filter_to_do],eax
  3286.                 jmp .end0
  3287.         @@:
  3288.         mov eax,[filter_to_do]
  3289.         and eax,PNG_FILTER_NONE
  3290.         jz .end0
  3291.         cmp dword[filter_to_do],PNG_FILTER_NONE
  3292.         je .end0 ;else if (..!=0 && ..!=..)
  3293.                 ; Overflow not possible and multiple filters in the list, including the
  3294.                 ; 'none' filter.
  3295.  
  3296.                 push esi
  3297.                 xor eax,eax
  3298.                 xor ebx,ebx
  3299.                 mov ecx,[row_bytes]
  3300.                 mov esi,[row_buf]
  3301.                 .cycle0:
  3302.                         lodsb
  3303.                         png_setup_abs ebx
  3304.                         loop .cycle0
  3305.                 pop esi
  3306.                 mov [mins],ebx
  3307.         .end0:
  3308.  
  3309.         ; Sub filter
  3310.         mov eax,[filter_to_do]
  3311.         cmp eax,PNG_FILTER_SUB
  3312.         jne @f ;if (..==..)
  3313.                 ; It's the only filter so no testing is needed
  3314.                 stdcall png_setup_sub_row_only, edi, [bpp], [row_bytes]
  3315.                 mov eax,[edi+png_struct.try_row]
  3316.                 mov [best_row],eax
  3317.                 jmp .end1
  3318.         @@:
  3319.         and eax,PNG_FILTER_SUB
  3320.         jz .end1 ;else if (..!=0)
  3321.                 stdcall png_setup_sub_row, edi, [bpp], [row_bytes], [mins]
  3322.                 cmp eax,[mins]
  3323.                 jge .end1 ;if (..<..)
  3324.                         mov [mins],eax
  3325.                         mov eax,[edi+png_struct.try_row]
  3326.                         mov [best_row],eax
  3327.                         test eax,eax
  3328.                         jz .end1 ;if (..!=0)
  3329.                                 mov eax,[edi+png_struct.tst_row]
  3330.                                 mov [edi+png_struct.try_row],eax
  3331.                                 mov eax,[best_row]
  3332.                                 mov [edi+png_struct.tst_row],eax
  3333.         .end1:
  3334.  
  3335.         ; Up filter
  3336.         mov eax,[filter_to_do]
  3337.         cmp eax,PNG_FILTER_UP
  3338.         jne @f ;if (..==..)
  3339.                 ; It's the only filter so no testing is needed
  3340.                 stdcall png_setup_up_row_only, edi, [row_bytes]
  3341.                 mov eax,[edi+png_struct.try_row]
  3342.                 mov [best_row],eax
  3343.                 jmp .end2
  3344.         @@:
  3345.         and eax,PNG_FILTER_UP
  3346.         jz .end2 ;else if (..!=0)
  3347.                 stdcall png_setup_up_row, edi, [row_bytes], [mins]
  3348.                 cmp eax,[mins]
  3349.                 jge .end2 ;if (..<..)
  3350.                         mov [mins],eax
  3351.                         mov eax,[edi+png_struct.try_row]
  3352.                         mov [best_row],eax
  3353.                         test eax,eax
  3354.                         jz .end2 ;if (..!=0)
  3355.                                 mov eax,[edi+png_struct.tst_row]
  3356.                                 mov [edi+png_struct.try_row],eax
  3357.                                 mov eax,[best_row]
  3358.                                 mov [edi+png_struct.tst_row],eax
  3359.         .end2:
  3360.  
  3361.         ; Avg filter
  3362.         mov eax,[filter_to_do]
  3363.         cmp eax,PNG_FILTER_AVG
  3364.         jne @f ;if (..==..)
  3365.                 ; It's the only filter so no testing is needed
  3366.                 stdcall png_setup_avg_row_only, edi, [bpp], [row_bytes]
  3367.                 mov eax,[edi+png_struct.try_row]
  3368.                 mov [best_row],eax
  3369.                 jmp .end3
  3370.         @@:
  3371.         and eax,PNG_FILTER_AVG
  3372.         jz .end3 ;else if (..!=0)
  3373.                 stdcall png_setup_avg_row, edi, [bpp], [row_bytes], [mins]
  3374.                 cmp eax,[mins]
  3375.                 jge .end3 ;if (..<..)
  3376.                         mov [mins],eax
  3377.                         mov eax,[edi+png_struct.try_row]
  3378.                         mov [best_row],eax
  3379.                         test eax,eax
  3380.                         jz .end3 ;if (..!=0)
  3381.                                 mov eax,[edi+png_struct.tst_row]
  3382.                                 mov [edi+png_struct.try_row],eax
  3383.                                 mov eax,[best_row]
  3384.                                 mov [edi+png_struct.tst_row],eax
  3385.         .end3:
  3386.  
  3387.         ; Paeth filter
  3388.         mov eax,[filter_to_do]
  3389.         cmp eax,PNG_FILTER_PAETH
  3390.         jne @f ;if (..==..)
  3391.                 ; It's the only filter so no testing is needed
  3392.                 stdcall png_setup_paeth_row_only, edi, [bpp], [row_bytes]
  3393.                 mov eax,[edi+png_struct.try_row]
  3394.                 mov [best_row],eax
  3395.                 jmp .end4
  3396.         @@:
  3397.         and eax,PNG_FILTER_PAETH
  3398.         jz .end4 ;else if (..!=0)
  3399.                 stdcall png_setup_paeth_row, edi, [bpp], [row_bytes], [mins]
  3400.                 cmp eax,[mins]
  3401.                 jge .end4 ;if (..<..)
  3402.                         mov [mins],eax
  3403.                         mov eax,[edi+png_struct.try_row]
  3404.                         mov [best_row],eax
  3405.                         test eax,eax
  3406.                         jz .end4 ;if (..!=0)
  3407.                                 mov eax,[edi+png_struct.tst_row]
  3408.                                 mov [edi+png_struct.try_row],eax
  3409.                                 mov eax,[best_row]
  3410.                                 mov [edi+png_struct.tst_row],eax
  3411.         .end4:
  3412.  
  3413.         ; Do the actual writing of the filtered row data from the chosen filter.
  3414.         mov eax,[esi+png_row_info.rowbytes]
  3415.         inc eax
  3416.         stdcall png_write_filtered_row, edi, [best_row], eax
  3417. end if ;WRITE_FILTER
  3418. popad
  3419.         ret
  3420. endp
  3421.  
  3422.  
  3423. ; Do the actual writing of a previously filtered row.
  3424. ;void (png_structrp png_ptr, bytep filtered_row,
  3425. ;    png_size_t full_row_length/*includes filter byte*/)
  3426. align 4
  3427. proc png_write_filtered_row uses eax ebx edi, png_ptr:dword, filtered_row:dword, full_row_length:dword
  3428.         png_debug 1, 'in png_write_filtered_row'
  3429.  
  3430.         mov eax,[filtered_row]
  3431.         movzx eax,byte[eax]
  3432.         png_debug1 2, 'filter = %d', eax
  3433.  
  3434.         mov edi,[png_ptr]
  3435.         stdcall png_compress_IDAT, [filtered_row], [full_row_length], Z_NO_FLUSH
  3436.  
  3437. if PNG_WRITE_FILTER_SUPPORTED eq 1
  3438.         ; Swap the current and previous rows
  3439.         mov eax,[edi+png_struct.prev_row]
  3440.         test eax,eax
  3441.         jz @f ;if (..!=0)
  3442.                 ;eax = tptr
  3443.                 mov ebx,[edi+png_struct.row_buf]
  3444.                 mov [edi+png_struct.prev_row],ebx
  3445.                 mov [edi+png_struct.row_buf],eax
  3446.         @@:
  3447. end if ;WRITE_FILTER
  3448.  
  3449.         ; Finish row - updates counters and flushes zlib if last row
  3450.         stdcall png_write_finish_row, edi
  3451.  
  3452. if PNG_WRITE_FLUSH_SUPPORTED eq 1
  3453.         inc dword[edi+png_struct.flush_rows]
  3454.  
  3455.         mov eax,[edi+png_struct.flush_dist]
  3456.         cmp eax,0
  3457.         jle @f
  3458.         cmp [edi+png_struct.flush_rows],eax
  3459.         jl @f ;if (..>0 && ..>=..)
  3460.                 stdcall png_write_flush, edi
  3461.         @@:
  3462. end if ;WRITE_FLUSH
  3463.         ret
  3464. endp
  3465.