Subversion Repositories Kolibri OS

Rev

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