Subversion Repositories Kolibri OS

Rev

Rev 6797 | Rev 6883 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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