Subversion Repositories Kolibri OS

Rev

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