Subversion Repositories Kolibri OS

Rev

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

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