Subversion Repositories Kolibri OS

Rev

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

  1.  
  2. ; pngwrite.asm - general routines 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. ; Write out all the unknown chunks for the current given location
  14. ;void (png_structrp png_ptr, png_const_inforp info_ptr, unsigned int where)
  15. align 4
  16. proc write_unknown_chunks, png_ptr:dword, info_ptr:dword, where:dword
  17. pushad
  18.         mov esi,[info_ptr]
  19.         cmp dword[esi+png_info_def.unknown_chunks_num],0
  20.         je .end_f ;if(..!=0)
  21.                 mov edi,[png_ptr]
  22.                 ;ecx = up
  23.  
  24.                 png_debug 5, 'writing extra chunks'
  25.  
  26.                 mov ecx,[esi+png_info_def.unknown_chunks]
  27.                 mov edx,[esi+png_info_def.unknown_chunks_num]
  28.                 imul edx,sizeof.png_unknown_chunk
  29.                 add edx,ecx
  30.                 .cycle0: ;for (..;..<..;..)
  31.                         cmp ecx,edx
  32.                         jge .end_f
  33.                         movzx eax,byte[ecx+png_unknown_chunk.location]
  34.                         and eax,[where]
  35.                         jz .end0 ;if (..!=0)
  36.                         ; If per-chunk unknown chunk handling is enabled use it, otherwise
  37.                         ; just write the chunks the application has set.
  38.  
  39. if PNG_SET_UNKNOWN_CHUNKS_SUPPORTED eq 1
  40.                         mov eax,ecx
  41.                         add eax,png_unknown_chunk.name
  42.                         stdcall png_handle_as_unknown, edi, eax
  43.  
  44.                         ; NOTE: this code is radically different from the read side in the
  45.                         ; matter of handling an ancillary unknown chunk.  In the read side
  46.                         ; the default behavior is to discard it, in the code below the default
  47.                         ; behavior is to write it.  Critical chunks are, however, only
  48.                         ; written if explicitly listed or if the default is set to write all
  49.                         ; unknown chunks.
  50.  
  51.                         ; The default handling is also slightly weird - it is not possible to
  52.                         ; stop the writing of all unsafe-to-copy chunks!
  53.  
  54.                         ; TODO: REVIEW: this would seem to be a bug.
  55.  
  56.                         cmp eax,PNG_HANDLE_CHUNK_NEVER
  57.                         je .end0
  58.                         mov bl,byte[ecx+png_unknown_chunk.name+3]
  59.                         and bl,0x20
  60.                         cmp bl,0
  61.                         jne .beg0
  62.                         cmp eax,PNG_HANDLE_CHUNK_ALWAYS
  63.                         je .beg0
  64.                         cmp eax,PNG_HANDLE_CHUNK_AS_DEFAULT
  65.                         jne .end0
  66.                         cmp dword[edi+png_struct.unknown_default],PNG_HANDLE_CHUNK_ALWAYS
  67.                         jne .end0
  68. end if
  69.                         .beg0: ;if (..!=.. && (.. safe-to-copy overrides everything || ..==.. || (..==.. && ..==..)))
  70.                                 ; TODO: review, what is wrong with a zero length unknown chunk?
  71.                                 cmp dword[ecx+png_unknown_chunk.size],0
  72.                                 jne @f ;if (..==0)
  73.                                         png_warning [png_ptr], 'Writing zero-length unknown chunk'
  74.                                 @@:
  75.                                 mov eax,dword[ecx+png_unknown_chunk.name]
  76.                                 stdcall png_write_chunk, edi, eax, [ecx+png_unknown_chunk.podata], [ecx+png_unknown_chunk.size]
  77.                         .end0:
  78.                         add ecx,sizeof.png_unknown_chunk
  79.                         jmp .cycle0
  80.                 ;.cycle0end:
  81. .end_f:
  82. popad
  83.         ret
  84. endp
  85.  
  86. ; Writes all the PNG information.  This is the suggested way to use the
  87. ; library.  If you have a new chunk to add, make a function to write it,
  88. ; and put it in the correct location here.  If you want the chunk written
  89. ; after the image data, put it in png_write_end().  I strongly encourage
  90. ; you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
  91. ; the chunk, as that will keep the code from breaking if you want to just
  92. ; write a plain PNG file.  If you have long comments, I suggest writing
  93. ; them in png_write_end(), and compressing them.
  94.  
  95. ;void (png_structrp png_ptr, png_const_inforp info_ptr)
  96. align 4
  97. proc png_write_info_before_PLTE, png_ptr:dword, info_ptr:dword
  98.         png_debug 1, 'in png_write_info_before_PLTE'
  99.  
  100. pushad
  101.         mov edi,[png_ptr]
  102.         cmp edi,0
  103.         je .end_f
  104.         mov esi,[info_ptr]
  105.         cmp esi,0
  106.         je .end_f ;if(..==0 || ..==0) return
  107.  
  108.         mov eax,[edi+png_struct.mode]
  109.         and eax,PNG_WROTE_INFO_BEFORE_PLTE
  110.         jnz .end_f ;if (..==0)
  111.  
  112.                 ; Write PNG signature
  113.                 stdcall png_write_sig, edi
  114.  
  115. if PNG_MNG_FEATURES_SUPPORTED eq 1
  116.                 mov eax,[edi+png_struct.mode]
  117.                 and eax,PNG_HAVE_PNG_SIGNATURE
  118.                 jz @f
  119.                 cmp dword[edi+png_struct.mng_features_permitted],0
  120.                 je @f ;if(..!=0 && ..!=0)
  121.                         png_warning edi, 'MNG features are not allowed in a PNG datastream'
  122.                         mov dword[edi+png_struct.mng_features_permitted],0
  123.                 @@:
  124. end if
  125.  
  126.         ; Write IHDR information.
  127. if PNG_WRITE_INTERLACING_SUPPORTED eq 1
  128.         movzx eax,byte[esi+png_info_def.interlace_type]
  129.         push eax
  130. else
  131.         push dword 0
  132. end if
  133.         movzx eax,byte[esi+png_info_def.filter_type]
  134.         push eax
  135.         movzx eax,byte[esi+png_info_def.compression_type]
  136.         push eax
  137.         movzx eax,byte[esi+png_info_def.color_type]
  138.         push eax
  139.         movzx eax,byte[esi+png_info_def.bit_depth]
  140.         stdcall png_write_IHDR, edi,\
  141.                 dword[esi+png_info_def.width], dword[esi+png_info_def.height], eax
  142.  
  143. ; The rest of these check to see if the valid field has the appropriate
  144. ; flag set, and if it does, writes the chunk.
  145.  
  146. ; 1.6.0: COLORSPACE support controls the writing of these chunks too, and
  147. ; the chunks will be written if the WRITE routine is there and
  148. ; information * is available in the COLORSPACE. (See
  149. ; png_colorspace_sync_info in png.c for where the valid flags get set.)
  150.  
  151. ; Under certain circumstances the colorspace can be invalidated without
  152. ; syncing the info_struct 'valid' flags; this happens if libpng detects
  153. ; an error and calls png_error while the color space is being set, yet
  154. ; the application continues writing the PNG.  So check the 'invalid'
  155. ; flag here too.
  156.  
  157. if PNG_GAMMA_SUPPORTED eq 1
  158. if PNG_WRITE_gAMA_SUPPORTED eq 1
  159.         movzx eax,word[esi+png_info_def.colorspace.flags]
  160.         and eax,PNG_COLORSPACE_INVALID
  161.         jnz @f
  162.         movzx eax,word[esi+png_info_def.colorspace.flags]
  163.         and eax,PNG_COLORSPACE_FROM_gAMA
  164.         jz @f
  165.         mov eax,[esi+png_info_def.valid]
  166.         and eax,PNG_INFO_gAMA
  167.         jz @f ;if (..==0 && ..!=0 && ..!=0)
  168.                 stdcall png_write_gAMA_fixed, edi, [esi+png_info_def.colorspace.gamma]
  169.         @@:
  170. end if
  171. end if
  172.  
  173. if PNG_COLORSPACE_SUPPORTED eq 1
  174.         ; Write only one of sRGB or an ICC profile.  If a profile was supplied
  175.         ; and it matches one of the known sRGB ones issue a warning.
  176.  
  177. if PNG_WRITE_iCCP_SUPPORTED eq 1
  178.         movzx eax,word[esi+png_info_def.colorspace.flags]
  179.         and eax,PNG_COLORSPACE_INVALID
  180.         jnz .end0
  181.         mov eax,[esi+png_info_def.valid]
  182.         and eax,PNG_INFO_iCCP
  183.         jz .end0 ;if (..==0 && ..!=0)
  184. if PNG_WRITE_sRGB_SUPPORTED eq 1
  185.                 mov eax,[esi+png_info_def.valid]
  186.                 and eax,PNG_INFO_sRGB
  187.                 jz @f ;if (..!=0)
  188.                         png_app_warning edi, 'profile matches sRGB but writing iCCP instead'
  189.                 @@:
  190. end if
  191.                 stdcall png_write_iCCP, edi, [esi+png_info_def.iccp_name],\
  192.                         [esi+png_info_def.iccp_profile]
  193. if PNG_WRITE_sRGB_SUPPORTED eq 1
  194.                 jmp .end1
  195. end if
  196.         .end0: ;else
  197. end if
  198.  
  199. if PNG_WRITE_sRGB_SUPPORTED eq 1
  200.         movzx eax,word[esi+png_info_def.colorspace.flags]
  201.         and eax,PNG_COLORSPACE_INVALID
  202.         jnz .end1
  203.         mov eax,[esi+png_info_def.valid]
  204.         and eax,PNG_INFO_sRGB
  205.         jz .end1 ;if (..==0 && ..!=0)
  206.                 movzx eax,word[esi+png_info_def.colorspace.rendering_intent]
  207.                 stdcall png_write_sRGB, edi, eax
  208.         .end1:
  209. end if ;sRGB
  210. end if ;COLORSPACE
  211.  
  212. if PNG_WRITE_sBIT_SUPPORTED eq 1
  213.         mov eax,[esi+png_info_def.valid]
  214.         and eax,PNG_INFO_sBIT
  215.         jz @f ;if (..!=0)
  216.                 movzx eax,byte[esi+png_info_def.color_type]
  217.                 push eax
  218.                 mov eax,esi
  219.                 add eax,png_info_def.sig_bit
  220.                 stdcall png_write_sBIT, edi, eax ;, ...color_type
  221.         @@:
  222. end if
  223.  
  224. if PNG_COLORSPACE_SUPPORTED eq 1
  225. if PNG_WRITE_cHRM_SUPPORTED eq 1
  226.         movzx eax,word[esi+png_info_def.colorspace.flags]
  227.         and eax,PNG_COLORSPACE_INVALID
  228.         jnz @f
  229.         movzx eax,word[esi+png_info_def.colorspace.flags]
  230.         and eax,PNG_COLORSPACE_FROM_cHRM
  231.         jz @f
  232.         mov eax,[esi+png_info_def.valid]
  233.         and eax,PNG_INFO_cHRM
  234.         jz @f ;if (..==0 && ..!=0 && ..!=0)
  235.                 stdcall png_write_cHRM_fixed, edi, [esi+png_info_def.colorspace.end_points_xy]
  236.         @@:
  237. end if
  238. end if
  239.  
  240. if PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED eq 1
  241.                 stdcall write_unknown_chunks, edi, esi, PNG_HAVE_IHDR
  242. end if
  243.                 or dword[edi+png_struct.mode],PNG_WROTE_INFO_BEFORE_PLTE
  244.         .end_f:
  245. popad
  246.         ret
  247. endp
  248.  
  249. ;void (png_structrp png_ptr, png_const_inforp info_ptr)
  250. align 4
  251. proc png_write_info, png_ptr:dword, info_ptr:dword
  252. if (PNG_WRITE_TEXT_SUPPORTED eq 1) | (PNG_WRITE_sPLT_SUPPORTED eq 1)
  253. ;   int i;
  254. end if
  255. pushad
  256.         png_debug 1, 'in png_write_info'
  257.  
  258.         mov edi,[png_ptr]
  259.         cmp edi,0
  260.         je .end_f
  261.         mov esi,[info_ptr]
  262.         cmp esi,0
  263.         je .end_f ;if (..==0 || ..==0) return
  264.  
  265.         stdcall png_write_info_before_PLTE, edi, esi
  266.  
  267.         mov eax,[esi+png_info_def.valid]
  268.         and eax,PNG_INFO_PLTE
  269.         jz @f ;if (..!=0)
  270.                 movzx eax,word[esi+png_info_def.num_palette]
  271.                 stdcall png_write_PLTE, edi, [esi+png_info_def.palette], eax
  272.                 jmp .end_0
  273.         @@:
  274.         mov al,byte[esi+png_info_def.color_type]
  275.         cmp al,PNG_COLOR_TYPE_PALETTE
  276.         jne .end_0 ;else if (..==..)
  277.                 png_error edi, 'Valid palette required for paletted images'
  278.         .end_0:
  279.  
  280. if PNG_WRITE_tRNS_SUPPORTED eq 1
  281.         mov eax,[esi+png_info_def.valid]
  282.         and eax,PNG_INFO_tRNS
  283.         jz .end_1 ;if (..!=0)
  284. if PNG_WRITE_INVERT_ALPHA_SUPPORTED eq 1
  285.         ; Invert the alpha channel (in tRNS)
  286. ;      if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 &&
  287. ;          info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
  288. ;      {
  289. ;         int j, jend;
  290.  
  291. ;         jend = info_ptr->num_trans;
  292. ;         if (jend > PNG_MAX_PALETTE_LENGTH)
  293. ;            jend = PNG_MAX_PALETTE_LENGTH;
  294.  
  295. ;         for (j = 0; j<jend; ++j)
  296. ;            info_ptr->trans_alpha[j] =
  297. ;               (byte)(255 - info_ptr->trans_alpha[j]);
  298. ;      }
  299. end if
  300.                 mov eax,esi
  301.                 add eax,png_info_def.trans_color
  302.                 movzx ebx,word[esi+png_info_def.num_trans]
  303.                 movzx ecx,byte[esi+png_info_def.color_type]
  304.                 stdcall png_write_tRNS, edi, dword[esi+png_info_def.trans_alpha], eax, ebx, ecx
  305.         .end_1:
  306. end if
  307. if PNG_WRITE_bKGD_SUPPORTED eq 1
  308.         mov eax,[esi+png_info_def.valid]
  309.         and eax,PNG_INFO_bKGD
  310.         jz @f ;if (..!=0)
  311.                 mov eax,esi
  312.                 add eax,png_info_def.background
  313.                 movzx ebx,byte[esi+png_info_def.color_type]
  314.                 stdcall png_write_bKGD, edi, eax, ebx
  315.         @@:
  316. end if
  317.  
  318. if PNG_WRITE_hIST_SUPPORTED eq 1
  319.         mov eax,[esi+png_info_def.valid]
  320.         and eax,PNG_INFO_hIST
  321.         jz @f ;if (..!=0)
  322.                 movzx ebx,word[esi+png_info_def.num_palette]
  323.                 stdcall png_write_hIST, edi, [esi+png_info_def.hist], ebx
  324.         @@:
  325. end if
  326.  
  327. if PNG_WRITE_oFFs_SUPPORTED eq 1
  328.         mov eax,[esi+png_info_def.valid]
  329.         and eax,PNG_INFO_oFFs
  330.         jz @f ;if (..!=0)
  331.                 movzx ebx,byte[esi+png_info_def.offset_unit_type]
  332.                 stdcall png_write_oFFs, edi, [esi+png_info_def.x_offset], [esi+png_info_def.y_offset], ebx
  333.         @@:
  334. end if
  335.  
  336. if PNG_WRITE_pCAL_SUPPORTED eq 1
  337.         mov eax,[esi+png_info_def.valid]
  338.         and eax,PNG_INFO_pCAL
  339.         jz @f ;if (..!=0)
  340.                 movzx ebx,byte[esi+png_info_def.pcal_type]
  341.                 movzx ecx,byte[esi+png_info_def.pcal_nparams]
  342.                 stdcall png_write_pCAL, edi, [esi+png_info_def.pcal_purpose], [esi+png_info_def.pcal_X0], [esi+png_info_def.pcal_X1], ebx, ecx, [esi+png_info_def.pcal_units], [esi+png_info_def.pcal_params]
  343.         @@:
  344. end if
  345.  
  346. if PNG_WRITE_sCAL_SUPPORTED eq 1
  347.         mov eax,[esi+png_info_def.valid]
  348.         and eax,PNG_INFO_sCAL
  349.         jz @f ;if (..!=0)
  350.                 movzx ebx,byte[esi+png_info_def.scal_unit]
  351.                 stdcall png_write_sCAL_s, edi, ebx, [esi+png_info_def.scal_s_width], [esi+png_info_def.scal_s_height]
  352.         @@:
  353. end if ;sCAL
  354.  
  355. if PNG_WRITE_pHYs_SUPPORTED eq 1
  356.         mov eax,[esi+png_info_def.valid]
  357.         and eax,PNG_INFO_pHYs
  358.         jz @f ;if (..!=0)
  359.                 movzx ebx,byte[esi+png_info_def.phys_unit_type]
  360.                 stdcall png_write_pHYs, edi, [esi+png_info_def.x_pixels_per_unit], [esi+png_info_def.y_pixels_per_unit], ebx
  361.         @@:
  362. end if ;pHYs
  363.  
  364. if PNG_WRITE_tIME_SUPPORTED eq 1
  365.         mov eax,[esi+png_info_def.valid]
  366.         and eax,PNG_INFO_tIME
  367.         jz @f ;if (..!=0)
  368.                 mov eax,esi
  369.                 add eax,png_info_def.mod_time
  370.                 stdcall png_write_tIME, edi, eax
  371.                 or [edi+png_struct.mode],PNG_WROTE_tIME
  372.         @@:
  373. end if ;tIME
  374.  
  375. if PNG_WRITE_sPLT_SUPPORTED eq 1
  376.         mov eax,[esi+png_info_def.valid]
  377.         and eax,PNG_INFO_sPLT
  378.         jz @f ;if (..!=0)
  379.                 mov eax,[esi+png_info_def.splt_palettes]
  380.                 mov ecx,[esi+png_info_def.splt_palettes_num]
  381.                 cmp ecx,1
  382.                 jl @f
  383.                 .cycle0:
  384.                         stdcall png_write_sPLT, edi, eax
  385.                         add eax,4
  386.                         loop .cycle0
  387.         @@:
  388. end if ;sPLT
  389.  
  390. if PNG_WRITE_TEXT_SUPPORTED eq 1
  391.         ; Check to see if we need to write text chunks
  392. ;   for (i = 0; i < info_ptr->num_text; i++)
  393. ;   {
  394. ;      png_debug2(2, "Writing header text chunk %d, type %d", i,
  395. ;          info_ptr->text[i].compression);
  396.         ; An internationalized chunk?
  397. ;      if (info_ptr->text[i].compression > 0)
  398. ;      {
  399. if PNG_WRITE_iTXt_SUPPORTED eq 1
  400.         ; Write international chunk
  401. ;         png_write_iTXt(png_ptr,
  402. ;             info_ptr->text[i].compression,
  403. ;             info_ptr->text[i].key,
  404. ;             info_ptr->text[i].lang,
  405. ;             info_ptr->text[i].lang_key,
  406. ;             info_ptr->text[i].text);
  407.         ; Mark this chunk as written
  408. ;         if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
  409. ;            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
  410. ;         else
  411. ;            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
  412. else
  413.         png_warning edi, 'Unable to write international text'
  414. end if
  415. ;      }
  416.  
  417.         ; If we want a compressed text chunk
  418. ;      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
  419. ;      {
  420. if PNG_WRITE_zTXt_SUPPORTED eq 1
  421.         ; Write compressed chunk
  422. ;         png_write_zTXt(png_ptr, info_ptr->text[i].key,
  423. ;             info_ptr->text[i].text, info_ptr->text[i].compression);
  424.         ; Mark this chunk as written
  425. ;         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
  426. else
  427.         png_warning edi, 'Unable to write compressed text'
  428. end if
  429. ;      }
  430.  
  431. ;      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
  432. ;      {
  433. if PNG_WRITE_tEXt_SUPPORTED eq 1
  434.         ; Write uncompressed chunk
  435. ;         png_write_tEXt(png_ptr, info_ptr->text[i].key,
  436. ;             info_ptr->text[i].text,
  437. ;             0);
  438.         ; Mark this chunk as written
  439. ;         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
  440. else
  441.         ; Can't get here
  442.         png_warning edi, 'Unable to write uncompressed text'
  443. end if
  444. ;      }
  445. ;   }
  446. end if ;tEXt
  447.  
  448. if PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED eq 1
  449.         stdcall write_unknown_chunks, edi, esi, PNG_HAVE_PLTE
  450. end if
  451.         .end_f:
  452. popad
  453.         ret
  454. endp
  455.  
  456. ; Writes the end of the PNG file.  If you don't want to write comments or
  457. ; time information, you can pass NULL for info.  If you already wrote these
  458. ; in png_write_info(), do not write them again here.  If you have long
  459. ; comments, I suggest writing them here, and compressing them.
  460.  
  461. ;void (png_structrp png_ptr, png_inforp info_ptr)
  462. align 4
  463. proc png_write_end, png_ptr:dword, info_ptr:dword
  464. pushad
  465.         png_debug 1, 'in png_write_end'
  466.  
  467.         mov edi,[png_ptr]
  468.         cmp edi,0
  469.         je .end_f ;if (..==0) return
  470.  
  471.         mov eax,[edi+png_struct.mode]
  472.         and eax,PNG_HAVE_IDAT
  473.         jnz @f ;if (..==0)
  474.                 png_error edi, 'No IDATs written into file'
  475.         @@:
  476.  
  477. if PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED eq 1
  478.         mov eax,[edi+png_struct.num_palette_max]
  479.         cmp ax,[edi+png_struct.num_palette]
  480.         jle @f ;if (..>..)
  481.                 png_benign_error edi, 'Wrote palette index exceeding num_palette'
  482.         @@:
  483. end if
  484.  
  485.         ; See if user wants us to write information chunks
  486.         mov esi,[info_ptr]
  487.         cmp esi,0
  488.         je .end0 ;if (..!=0)
  489. if PNG_WRITE_TEXT_SUPPORTED eq 1
  490. ;      int i; /* local index variable */
  491. end if
  492. if PNG_WRITE_tIME_SUPPORTED eq 1
  493.                 ; Check to see if user has supplied a time chunk
  494.                 mov eax,[esi+png_info_def.valid]
  495.                 and eax,PNG_INFO_tIME
  496.                 jz @f
  497.                 mov eax,[edi+png_struct.mode]
  498.                 and eax,PNG_WROTE_tIME
  499.                 jnz @f ;if (..!=0 && ..==0)
  500.                         mov eax,esi
  501.                         add eax,png_info_def.mod_time
  502.                         stdcall png_write_tIME, edi, eax
  503.                 @@:
  504.  
  505. end if
  506. if PNG_WRITE_TEXT_SUPPORTED eq 1
  507.                 ; Loop through comment chunks
  508.                 cmp dword[esi+png_info_def.num_text],0
  509.                 jle .cycle0end
  510.                 xor ecx,ecx
  511. align 4
  512.                 .cycle0: ;for (i = 0; i < info_ptr->num_text; i++)
  513.  
  514. ;         png_debug2(2, "Writing trailer text chunk %d, type %d", i,
  515. ;             info_ptr->text[i].compression);
  516.                         ; An internationalized chunk?
  517.                         mov eax,ecx
  518.                         shl eax,2
  519.                         add eax,[esi+png_info_def.text] ;eax = info_ptr.text[i]
  520.                         cmp dword[eax+png_text.compression],0
  521.                         jle .end1 ;if (info_ptr.text[i].compression > 0)
  522. if PNG_WRITE_iTXt_SUPPORTED eq 1
  523.                                 ; Write international chunk
  524.                                 stdcall png_write_iTXt, edi,\
  525.                                         [eax+png_text.compression],\
  526.                                         [eax+png_text.key],\
  527.                                         [eax+png_text.lang],\
  528.                                         [eax+png_text.lang_key],\
  529.                                         [eax+png_text.text]
  530.                                 ; Mark this chunk as written
  531.                                 mov ebx,PNG_TEXT_COMPRESSION_zTXt_WR
  532.                                 cmp dword[eax+png_text.compression],PNG_TEXT_COMPRESSION_NONE
  533.                                 jne @f
  534.                                         mov ebx,PNG_TEXT_COMPRESSION_NONE_WR
  535.                                 @@:
  536.                                 mov dword[eax+png_text.compression],ebx
  537. else
  538.                                 png_warning edi, 'Unable to write international text'
  539. end if
  540.                                 jmp .end3
  541.                         .end1:
  542.                         cmp dword[eax+png_text.compression],PNG_TEXT_COMPRESSION_zTXt
  543.                         jl .end2 ;else if (info_ptr.text[i].compression >= ..)
  544. if PNG_WRITE_zTXt_SUPPORTED eq 1
  545.                                 ; Write compressed chunk
  546.                                 stdcall png_write_zTXt, edi, [eax+png_text.key],\
  547.                                         [eax+png_text.text], [eax+png_text.compression]
  548.                                 ; Mark this chunk as written
  549.                                 mov dword[eax+png_text.compression],PNG_TEXT_COMPRESSION_zTXt_WR
  550. else
  551.                                 png_warning edi, 'Unable to write compressed text'
  552. end if
  553.                                 jmp .end3
  554.                         .end2:
  555.                         cmp dword[eax+png_text.compression],PNG_TEXT_COMPRESSION_NONE
  556.                         jl .end3 ;else if (info_ptr.text[i].compression == ..)
  557. if PNG_WRITE_tEXt_SUPPORTED eq 1
  558.                                 ; Write uncompressed chunk
  559.                                 stdcall png_write_tEXt, edi, [eax+png_text.key],\
  560.                                         [eax+png_text.text], 0
  561.                                 ; Mark this chunk as written
  562.                                 mov dword[eax+png_text.compression],PNG_TEXT_COMPRESSION_NONE_WR
  563. else
  564.                                 png_warning edi, 'Unable to write uncompressed text'
  565. end if
  566.                         .end3:
  567.  
  568.                         inc ecx
  569.                         cmp ecx,[esi+png_info_def.num_text]
  570.                         jl .cycle0
  571.                 .cycle0end:
  572. end if
  573. if PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED eq 1
  574.                 stdcall write_unknown_chunks, edi, esi, PNG_AFTER_IDAT
  575. end if
  576.         .end0:
  577.  
  578.         or dword[edi+png_struct.mode], PNG_AFTER_IDAT
  579.  
  580.         ; Write end of PNG file
  581.         stdcall png_write_IEND, edi
  582.  
  583. ; This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,
  584. ; and restored again in libpng-1.2.30, may cause some applications that
  585. ; do not set png_ptr->output_flush_fn to crash.  If your application
  586. ; experiences a problem, please try building libpng with
  587. ; PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to
  588. ; png-mng-implement at lists.sf.net .
  589.  
  590. if PNG_WRITE_FLUSH_SUPPORTED eq 1
  591. if PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED eq 1
  592.         stdcall png_flush, edi
  593. end if
  594. end if
  595. .end_f:
  596. popad
  597.         ret
  598. endp
  599.  
  600. ;void (png_timep ptime, struct tm * ttime)
  601. align 4
  602. proc png_convert_from_struct_tm, ptime:dword, ttime:dword
  603.         png_debug 1, 'in png_convert_from_struct_tm'
  604.  
  605. ;   ptime->year = (uint_16)(1900 + ttime->tm_year);
  606. ;   ptime->month = (byte)(ttime->tm_mon + 1);
  607. ;   ptime->day = (byte)ttime->tm_mday;
  608. ;   ptime->hour = (byte)ttime->tm_hour;
  609. ;   ptime->minute = (byte)ttime->tm_min;
  610. ;   ptime->second = (byte)ttime->tm_sec;
  611.         ret
  612. endp
  613.  
  614. ;void (png_timep ptime, time_t ttime)
  615. align 4
  616. proc png_convert_from_time_t, ptime:dword, ttime:dword
  617. ;   struct tm *tbuf;
  618.  
  619.         png_debug 1, 'in png_convert_from_time_t'
  620.  
  621. ;   tbuf = gmtime(&ttime);
  622. ;   png_convert_from_struct_tm(ptime, tbuf);
  623.         ret
  624. endp
  625.  
  626. ; Initialize png_ptr structure, and allocate any memory needed
  627. ;png_structp (charp user_png_ver, voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn)
  628. align 4
  629. proc png_create_write_struct, user_png_ver:dword, error_ptr:dword, error_fn:dword, warn_fn:dword
  630. if PNG_USER_MEM_SUPPORTED eq 1
  631.         stdcall png_create_png_struct, [user_png_ver], [error_ptr], [error_fn], [warn_fn], 0, 0, 0
  632.         ;eax = png_ptr
  633. end if ;USER_MEM
  634.         cmp eax,0
  635.         je .end0 ;if (..!=0)
  636.                 ; Set the zlib control values to defaults; they can be overridden by the
  637.                 ; application after the struct has been created.
  638.  
  639.                 mov dword[eax+png_struct.zbuffer_size], PNG_ZBUF_SIZE
  640.  
  641.                 ; The 'zlib_strategy' setting is irrelevant because png_default_claim in
  642.                 ; pngwutil.asm defaults it according to whether or not filters will be
  643.                 ; used, and ignores this setting.
  644.  
  645.                 mov dword[eax+png_struct.zlib_strategy], PNG_Z_DEFAULT_STRATEGY
  646.                 mov dword[eax+png_struct.zlib_level], PNG_Z_DEFAULT_COMPRESSION
  647.                 mov dword[eax+png_struct.zlib_mem_level], 8
  648.                 mov dword[eax+png_struct.zlib_window_bits], 15
  649.                 mov dword[eax+png_struct.zlib_method], 8
  650.  
  651. if PNG_WRITE_COMPRESSED_TEXT_SUPPORTED eq 1
  652.                 mov dword[eax+png_struct.zlib_text_strategy], PNG_TEXT_Z_DEFAULT_STRATEGY
  653.                 mov dword[eax+png_struct.zlib_text_level], PNG_TEXT_Z_DEFAULT_COMPRESSION
  654.                 mov dword[eax+png_struct.zlib_text_mem_level], 8
  655.                 mov dword[eax+png_struct.zlib_text_window_bits], 15
  656.                 mov dword[eax+png_struct.zlib_text_method], 8
  657. end if
  658.                 ; This is a highly dubious configuration option; by default it is off,
  659.                 ; but it may be appropriate for private builds that are testing
  660.                 ; extensions not conformant to the current specification, or of
  661.                 ; applications that must not fail to write at all costs!
  662.  
  663. if PNG_BENIGN_WRITE_ERRORS_SUPPORTED eq 1
  664.                 ; In stable builds only warn if an application error can be completely
  665.                 ; handled.
  666.  
  667.                 or dword[eax+png_struct.flags], PNG_FLAG_BENIGN_ERRORS_WARN
  668. end if
  669.                 ; App warnings are warnings in release (or release candidate) builds but
  670.                 ; are errors during development.
  671.  
  672. if PNG_RELEASE_BUILD eq 1
  673.                 or dword[eax+png_struct.flags], PNG_FLAG_APP_WARNINGS_WARN
  674. end if
  675.                 ; TODO: delay this, it can be done in png_init_io() (if the app doesn't
  676.                 ; do it itself) avoiding setting the default function if it is not
  677.                 ; required.
  678.  
  679.                 stdcall png_set_write_fn, eax, 0, 0, 0
  680.         .end0:
  681.         ret
  682. endp
  683.  
  684.  
  685. ; Write a few rows of image data.  If the image is interlaced,
  686. ; either you will have to write the 7 sub images, or, if you
  687. ; have called png_set_interlace_handling(), you will have to
  688. ; "write" the image seven times.
  689.  
  690. ;void (png_structrp png_ptr, bytepp row, uint_32 num_rows)
  691. align 4
  692. proc png_write_rows uses ebx ecx edi, png_ptr:dword, row:dword, num_rows:dword
  693. ;locals
  694.         ;i dd ? ;uint_32 ;row counter
  695.         ;rp dd ? ;bytepp ;row pointer
  696. ;endl
  697.         png_debug 1, 'in png_write_rows'
  698.  
  699.         mov edi,[png_ptr]
  700.         cmp edi,0
  701.         je .end_f ;if(..==0) return
  702.  
  703.         ; Loop through the rows
  704.         mov ecx,[num_rows]
  705.         cmp ecx,1
  706.         jl .end_f
  707.         mov ebx,[row]
  708.         @@: ;for (i = 0, rp = row; i < num_rows; i++, rp++)
  709.                 stdcall png_write_row, edi, [ebx]
  710.                 add ebx,4
  711.                 loop @b
  712. .end_f:
  713.         ret
  714. endp
  715.  
  716. ; Write the image.  You only need to call this function once, even
  717. ; if you are writing an interlaced image.
  718.  
  719. ;void (png_structrp png_ptr, bytepp image)
  720. align 4
  721. proc png_write_image, png_ptr:dword, image:dword
  722. pushad
  723. ;ebx ;bytepp ;points to current row
  724. ;ecx ;uint_32 ;row index
  725. ;edx ;int ;pass
  726. ;esi ;int ;num_pass
  727.         mov edi,[png_ptr]
  728.         cmp edi,0
  729.         je .end_f ;if (..==0) return
  730.  
  731.         png_debug 1, 'in png_write_image'
  732.  
  733. if PNG_WRITE_INTERLACING_SUPPORTED eq 1
  734.         ; Initialize interlace handling.  If image is not interlaced,
  735.         ; this will set pass to 1
  736.  
  737.         stdcall png_set_interlace_handling, edi
  738.         mov esi,eax
  739. else
  740.         xor esi,esi
  741.         inc esi
  742. end if
  743.         ; Loop through passes
  744.         xor edx,edx
  745.         .cycle0: ;for (edx = 0; edx < esi; edx++)
  746.                 cmp edx,esi
  747.                 jge .cycle0end
  748.                 ; Loop through image
  749.                 mov ebx,[image]
  750.                 xor ecx,ecx
  751.                 .cycle1: ;for (ecx = 0, ebx = image; ecx < png_ptr.height; ecx++, ebx++)
  752.                         stdcall png_write_row, edi,[ebx]
  753.                         inc ecx
  754.                         add ebx,4
  755.                         cmp ecx,[edi+png_struct.height]
  756.                         jl .cycle1
  757.                 ;.cycle1end:
  758.                 inc edx
  759.                 jmp .cycle0
  760.         .cycle0end:
  761. .end_f:
  762. popad
  763.         ret
  764. endp
  765.  
  766. ; Performs intrapixel differencing
  767. ;void (png_row_infop row_info, bytep row)
  768. align 4
  769. proc png_do_write_intrapixel uses eax ebx ecx edx edi, row_info:dword, row:dword
  770.         png_debug 1, 'in png_do_write_intrapixel'
  771.  
  772.         mov ebx,[row_info]
  773.         movzx eax,byte[ebx+png_row_info.color_type]
  774.         and eax,PNG_COLOR_MASK_COLOR
  775.         jz .end_f ;if (..!=0)
  776.                 ;edx = bytes_per_pixel
  777.                 mov ecx,[ebx+png_row_info.width] ;ecx = row_width
  778.                 cmp byte[ebx+png_row_info.bit_depth],8 ;if (..==8)
  779.                 jne .end0
  780. ;         bytep rp;
  781. ;         uint_32 i;
  782.  
  783.                         cmp byte[ebx+png_row_info.color_type],PNG_COLOR_TYPE_RGB
  784.                         jne @f ;if (..==..)
  785.                                 mov edx,3-1 ;(-1) for stosb
  786.                                 jmp .end2
  787.                         @@:
  788.                         cmp byte[ebx+png_row_info.color_type],PNG_COLOR_TYPE_RGB_ALPHA
  789.                         jne @f ;else if (..==..)
  790.                                 mov edx,4-1 ;(-1) for stosb
  791.                                 jmp .end2
  792.                         @@:
  793.                                 jmp .end_f ;else return
  794.                         .end2:
  795.  
  796.                         mov edi,[row]
  797. align 4
  798.                         .cycle0: ;for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
  799.                                 mov ax,word[edi]
  800.                                 sub al,ah
  801.                                 stosb ;*(rp) = (byte)(*rp - *(rp + 1))
  802.                                 mov ax,word[edi]
  803.                                 sub ah,al
  804.                                 mov byte[edi+1],ah ;*(rp + 2) = (byte)(*(rp + 2) - *(rp + 1))
  805.                                 add edi,edx
  806.                                 loop .cycle0
  807.                         .cycle0end:
  808.                         jmp .end_f
  809.                 .end0:
  810.  
  811. if PNG_WRITE_16BIT_SUPPORTED eq 1
  812.                 cmp byte[ebx+png_row_info.bit_depth],16 ;else if (..==16)
  813.                 jne .end1
  814. ;         bytep rp;
  815. ;         uint_32 i;
  816.  
  817.                         cmp byte[ebx+png_row_info.color_type],PNG_COLOR_TYPE_RGB
  818.                         jne @f ;if (..==..)
  819.                                 mov edx,6
  820.                                 jmp .end3
  821.                         @@:
  822.                         cmp byte[ebx+png_row_info.color_type],PNG_COLOR_TYPE_RGB_ALPHA
  823.                         jne @f ;else if (..==..)
  824.                                 mov edx,8
  825.                                 jmp .end3
  826.                         @@:
  827.                                 jmp .end_f ;else return
  828.                         .end3:
  829.  
  830.                         mov edi,[row]
  831. align 4
  832.                         .cycle1: ;for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
  833. ;            uint_32 s0   = (*(rp    ) << 8) | *(rp + 1);
  834. ;            uint_32 s1   = (*(rp + 2) << 8) | *(rp + 3);
  835. ;            uint_32 s2   = (*(rp + 4) << 8) | *(rp + 5);
  836. ;            uint_32 red  = (uint_32)((s0 - s1) & 0xffffL);
  837. ;            uint_32 blue = (uint_32)((s2 - s1) & 0xffffL);
  838. ;            *(rp    ) = (byte)(red >> 8);
  839. ;            *(rp + 1) = (byte)red;
  840. ;            *(rp + 4) = (byte)(blue >> 8);
  841. ;            *(rp + 5) = (byte)blue;
  842.                                 add edi,edx
  843.                                 loop .cycle1
  844.                         .cycle1end:
  845.                 .end1:
  846. end if ;WRITE_16BIT
  847. .end_f:
  848.         ret
  849. endp
  850.  
  851. ; Called by user to write a row of image data
  852. ;void (png_structrp png_ptr, bytep row)
  853. align 4
  854. proc png_write_row, png_ptr:dword, row:dword
  855. locals
  856.         ; 1.5.6: moved from png_struct to be a local structure:
  857.         row_info png_row_info
  858. endl
  859. pushad
  860.         mov edi,[png_ptr]
  861.         cmp edi,0
  862.         je .end_f ;if(..==0) return
  863.  
  864. ;   png_debug2(1, "in png_write_row (row %u, pass %d)",
  865. ;       png_ptr->row_number, png_ptr->pass);
  866. png_debug1 1, 'in png_write_row (row %u)',[edi+png_struct.row_number]
  867.  
  868.         ; Initialize transformations and other stuff if first time
  869.         cmp dword[edi+png_struct.row_number],0
  870.         jne .end0
  871.         cmp byte[edi+png_struct.pass],0
  872.         jne .end0 ;if(..==0 && ..==0)
  873.  
  874.         ; Make sure we wrote the header info
  875.         mov eax,[edi+png_struct.mode]
  876.         and eax,PNG_WROTE_INFO_BEFORE_PLTE
  877.         jnz @f ;if(..==0)
  878.                 png_error edi, 'png_write_info was never called before png_write_row'
  879.         @@:
  880.  
  881.         ; Check for transforms that have been set but were defined out
  882. if (PNG_WRITE_INVERT_SUPPORTED eq 0) & (PNG_READ_INVERT_SUPPORTED eq 1)
  883.         mov eax,[edi+png_struct.transformations]
  884.         and eax,PNG_INVERT_MONO
  885.         jz @f ;if(..!=0)
  886.                 png_warning edi, 'PNG_WRITE_INVERT_SUPPORTED is not defined'
  887.         @@:
  888. end if
  889.  
  890. if (PNG_WRITE_FILLER_SUPPORTED eq 0) & (PNG_READ_FILLER_SUPPORTED eq 1)
  891.         mov eax,[edi+png_struct.transformations]
  892.         and eax,PNG_FILLER
  893.         jz @f ;if(..!=0)
  894.                 png_warning edi, 'PNG_WRITE_FILLER_SUPPORTED is not defined'
  895.         @@:
  896. end if
  897.  
  898. if (PNG_WRITE_PACKSWAP_SUPPORTED eq 0) & (PNG_READ_PACKSWAP_SUPPORTED eq 1)
  899.         mov eax,[edi+png_struct.transformations]
  900.         and eax,PNG_PACKSWAP
  901.         jz @f ;if(..!=0)
  902.                 png_warning edi, 'PNG_WRITE_PACKSWAP_SUPPORTED is not defined'
  903.         @@:
  904. end if
  905.  
  906. if (PNG_WRITE_PACK_SUPPORTED eq 0) & (PNG_READ_PACK_SUPPORTED eq 1)
  907.         mov eax,[edi+png_struct.transformations]
  908.         and eax,PNG_PACK
  909.         jz @f ;if(..!=0)
  910.                 png_warning edi, 'PNG_WRITE_PACK_SUPPORTED is not defined'
  911.         @@:
  912. end if
  913.  
  914. if (PNG_WRITE_SHIFT_SUPPORTED eq 0) & (PNG_READ_SHIFT_SUPPORTED eq 1)
  915.         mov eax,[edi+png_struct.transformations]
  916.         and eax,PNG_SHIFT
  917.         jz @f ;if(..!=0)
  918.                 png_warning edi, 'PNG_WRITE_SHIFT_SUPPORTED is not defined'
  919.         @@:
  920. end if
  921.  
  922. if (PNG_WRITE_BGR_SUPPORTED eq 0) & (PNG_READ_BGR_SUPPORTED eq 1)
  923.         mov eax,[edi+png_struct.transformations]
  924.         and eax,PNG_BGR
  925.         jz @f ;if(..!=0)
  926.                 png_warning edi, 'PNG_WRITE_BGR_SUPPORTED is not defined'
  927.         @@:
  928. end if
  929.  
  930. if (PNG_WRITE_SWAP_SUPPORTED eq 0) & (PNG_READ_SWAP_SUPPORTED eq 1)
  931.         mov eax,[edi+png_struct.transformations]
  932.         and eax,PNG_SWAP_BYTES
  933.         jz @f ;if(..!=0)
  934.                 png_warning edi, 'PNG_WRITE_SWAP_SUPPORTED is not defined'
  935.         @@:
  936. end if
  937.  
  938.         stdcall png_write_start_row, edi
  939.         .end0:
  940.  
  941. if PNG_WRITE_INTERLACING_SUPPORTED eq 1
  942.         ; If interlaced and not interested in row, return
  943.         cmp byte[edi+png_struct.interlaced],0
  944.         je .end1
  945.         mov eax,[edi+png_struct.transformations]
  946.         and eax,PNG_INTERLACE
  947.         jz .end1 ;if(..!=0 && ..!=0)
  948.                 cmp byte[edi+png_struct.pass],0
  949.                 jne @f
  950.                         mov eax,[edi+png_struct.row_number]
  951.                         and eax,0x07
  952.                         jz .end1 ;if (..!=0)
  953.                                 stdcall png_write_finish_row, edi
  954.                                 jmp .end_f
  955.                 @@:
  956.                 cmp byte[edi+png_struct.pass],1
  957.                 jne @f
  958.                         mov eax,[edi+png_struct.row_number]
  959.                         and eax,0x07
  960.                         jnz .end2
  961.                         cmp dword[edi+png_struct.width],5
  962.                         jge .end1 ;if (..!=0 || ..<..)
  963.                         .end2:
  964.                                 stdcall png_write_finish_row, edi
  965.                                 jmp .end_f
  966.                 @@:
  967.                 cmp byte[edi+png_struct.pass],2
  968.                 jne @f
  969.                         mov eax,[edi+png_struct.row_number]
  970.                         and eax,0x07
  971.                         cmp eax,4
  972.                         je .end1 ;if (..!=..)
  973.                                 stdcall png_write_finish_row, edi
  974.                                 jmp .end_f
  975.                 @@:
  976.                 cmp byte[edi+png_struct.pass],3
  977.                 jne @f
  978.                         mov eax,[edi+png_struct.row_number]
  979.                         and eax,0x03
  980.                         jnz .end3
  981.                         cmp dword[edi+png_struct.width],3
  982.                         jge .end1 ;if (..!=0 || ..<..)
  983.                         .end3:
  984.                                 stdcall png_write_finish_row, edi
  985.                                 jmp .end_f
  986.                 @@:
  987.                 cmp byte[edi+png_struct.pass],4
  988.                 jne @f
  989.                         mov eax,[edi+png_struct.row_number]
  990.                         and eax,0x03
  991.                         cmp eax,2
  992.                         je .end1 ;if (..!=..)
  993.                                 stdcall png_write_finish_row, edi
  994.                                 jmp .end_f
  995.                 @@:
  996.                 cmp byte[edi+png_struct.pass],5
  997.                 jne @f
  998.                         mov eax,[edi+png_struct.row_number]
  999.                         and eax,0x01
  1000.                         jnz .end4
  1001.                         cmp dword[edi+png_struct.width],2
  1002.                         jge .end1 ;if (..!=0 || ..<..)
  1003.                         .end4:
  1004.                                 stdcall png_write_finish_row, edi
  1005.                                 jmp .end_f
  1006.                 @@:
  1007.                 cmp byte[edi+png_struct.pass],6
  1008.                 jne .end1
  1009.                         mov eax,[edi+png_struct.row_number]
  1010.                         and eax,0x01
  1011.                         jnz .end1 ;if (..==0)
  1012.                                 stdcall png_write_finish_row, edi
  1013.                                 jmp .end_f
  1014.         .end1:
  1015. end if
  1016.  
  1017.         ; Set up row info for transformations
  1018.         mov ebx,ebp
  1019.         sub ebx,sizeof.png_row_info
  1020.         mov al,byte[edi+png_struct.color_type]
  1021.         mov byte[ebx+png_row_info.color_type],al
  1022.         mov eax,[edi+png_struct.usr_width]
  1023.         mov [ebx+png_row_info.width],eax
  1024.         movzx eax,byte[edi+png_struct.usr_channels]
  1025.         mov byte[ebx+png_row_info.channels],al
  1026.         movzx ecx,byte[edi+png_struct.usr_bit_depth]
  1027.         mov byte[ebx+png_row_info.bit_depth],cl
  1028.         imul eax,ecx ;.bit_depth * .channels
  1029.         mov byte[ebx+png_row_info.pixel_depth],al
  1030.         PNG_ROWBYTES eax, [ebx+png_row_info.width]
  1031.         mov [ebx+png_row_info.rowbytes], eax
  1032.  
  1033.         push eax
  1034.         movzx eax,byte[ebx+png_row_info.color_type]
  1035.         png_debug1 3, 'row_info->color_type = %d', eax
  1036.         png_debug1 3, 'row_info->width = %u', [ebx+png_row_info.width]
  1037.         movzx eax,byte[ebx+png_row_info.channels]
  1038.         png_debug1 3, 'row_info->channels = %d', eax
  1039.         movzx eax,byte[ebx+png_row_info.bit_depth]
  1040.         png_debug1 3, 'row_info->bit_depth = %d', eax
  1041.         movzx eax,byte[ebx+png_row_info.pixel_depth]
  1042.         png_debug1 3, 'row_info->pixel_depth = %d', eax
  1043.         png_debug1 3, 'row_info->rowbytes = %lu', [ebx+png_row_info.rowbytes]
  1044.         pop eax
  1045.  
  1046.         ; Copy user's row into buffer, leaving room for filter byte.
  1047.         push edi
  1048.         mov edi,[edi+png_struct.row_buf]
  1049.         inc edi
  1050.         mov esi,[row]
  1051.         mov ecx,eax
  1052.         rep movsb ;memcpy(...
  1053.         pop edi
  1054.  
  1055. if PNG_WRITE_INTERLACING_SUPPORTED eq 1
  1056.         ; Handle interlacing
  1057.         cmp byte[edi+png_struct.interlaced],0
  1058.         je @f
  1059.         cmp byte[edi+png_struct.pass],6
  1060.         jge @f
  1061.         mov eax,[edi+png_struct.transformations]
  1062.         and eax,PNG_INTERLACE
  1063.         jz @f ;if (.. && ..<.. && ..!=0)
  1064.                 movzx eax,byte[edi+png_struct.pass]
  1065.                 push eax
  1066.                 mov eax,[edi+png_struct.row_buf]
  1067.                 inc eax
  1068.                 stdcall png_do_write_interlace, ebx, eax ;, ...pass
  1069.                 ; This should always get caught above, but still ...
  1070.                 cmp dword[ebx+png_row_info.width],0
  1071.                 jne @f ;if (..==0)
  1072.                         stdcall png_write_finish_row, edi
  1073.                         jmp .end_f
  1074.         @@:
  1075. end if
  1076.  
  1077. if PNG_WRITE_TRANSFORMS_SUPPORTED eq 1
  1078.         ; Handle other transformations
  1079.         cmp dword[edi+png_struct.transformations],0
  1080.         je @f ;if (..!=0)
  1081.                 stdcall png_do_write_transformations, edi, ebx
  1082.         @@:
  1083. end if
  1084.  
  1085.         ; At this point the row_info pixel depth must match the 'transformed' depth,
  1086.         ; which is also the output depth.
  1087.  
  1088.         mov al,[ebx+png_row_info.pixel_depth]
  1089.         cmp al,[edi+png_struct.pixel_depth]
  1090.         jne @f
  1091.         cmp al,[edi+png_struct.transformed_pixel_depth]
  1092.         je .end5
  1093.         @@: ;if (..!=.. || ..!=..)
  1094.                 png_error edi, 'internal write transform logic error'
  1095.         .end5:
  1096.  
  1097. if PNG_MNG_FEATURES_SUPPORTED eq 1
  1098.         ; Write filter_method 64 (intrapixel differencing) only if
  1099.         ; 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
  1100.         ; 2. Libpng did not write a PNG signature (this filter_method is only
  1101.         ;    used in PNG datastreams that are embedded in MNG datastreams) and
  1102.         ; 3. The application called png_permit_mng_features with a mask that
  1103.         ;    included PNG_FLAG_MNG_FILTER_64 and
  1104.         ; 4. The filter_method is 64 and
  1105.         ; 5. The color_type is RGB or RGBA
  1106.  
  1107.         mov eax,[edi+png_struct.mng_features_permitted]
  1108.         and eax,PNG_FLAG_MNG_FILTER_64
  1109.         jz @f
  1110.         cmp byte[edi+png_struct.filter_type],PNG_INTRAPIXEL_DIFFERENCING
  1111.         jne @f ;if (..!=0 && ..==..)
  1112.                 ; Intrapixel differencing
  1113.                 mov eax,[edi+png_struct.row_buf]
  1114.                 inc eax
  1115.                 stdcall png_do_write_intrapixel, ebx, eax
  1116.         @@:
  1117. end if
  1118.  
  1119. ; Added at libpng-1.5.10
  1120. if PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED eq 1
  1121.         ; Check for out-of-range palette index
  1122.         cmp byte[ebx+png_row_info.color_type],PNG_COLOR_TYPE_PALETTE
  1123.         jne @f
  1124.         cmp dword[edi+png_struct.num_palette_max],0
  1125.         jl @f ;if (..==.. && ..>=0)
  1126.                 stdcall png_do_check_palette_indexes, edi, ebx
  1127.         @@:
  1128. end if
  1129.  
  1130.         ; Find a filter if necessary, filter the row and write it out.
  1131.         mov ebx,ebp
  1132.         sub ebx,sizeof.png_row_info
  1133.         stdcall png_write_find_filter, edi, ebx
  1134.  
  1135.         cmp dword[edi+png_struct.write_row_fn],0
  1136.         je .end_f ;if (..!=0)
  1137.                 movzx eax,byte[edi+png_struct.pass]
  1138.                 stdcall dword[edi+png_struct.write_row_fn], edi, [edi+png_struct.row_number], eax
  1139. .end_f:
  1140. popad
  1141.         ret
  1142. endp
  1143.  
  1144. ; Set the automatic flush interval or 0 to turn flushing off
  1145. ;void (png_structrp png_ptr, int nrows)
  1146. align 4
  1147. proc png_set_flush uses eax edi, png_ptr:dword, nrows:dword
  1148.         png_debug 1, 'in png_set_flush'
  1149.  
  1150.         mov edi,[png_ptr]
  1151.         cmp edi,0
  1152.         je .end_f ;if (..==0) return
  1153.  
  1154.         mov eax,[nrows]
  1155.         cmp eax,0
  1156.         jge @f ;(nrows < 0 ? 0 : nrows)
  1157.                 xor eax,eax
  1158.         @@:
  1159.         mov [edi+png_struct.flush_dist],eax
  1160. .end_f:
  1161.         ret
  1162. endp
  1163.  
  1164. ; Flush the current output buffers now
  1165. ;void (png_structrp png_ptr)
  1166. align 4
  1167. proc png_write_flush uses eax edi, png_ptr:dword
  1168.         png_debug 1, 'in png_write_flush'
  1169.  
  1170.         mov edi,[png_ptr]
  1171.         cmp edi,0
  1172.         je .end_f ;if (..==0) return
  1173.  
  1174.         ; We have already written out all of the data
  1175.         mov eax,[edi+png_struct.num_rows]
  1176.         cmp [edi+png_struct.row_number],eax
  1177.         jge .end_f ;if (..>=..) return
  1178.  
  1179.         stdcall png_compress_IDAT, 0, 0, Z_SYNC_FLUSH
  1180.         mov dword[edi+png_struct.flush_rows],0
  1181.         stdcall png_flush, edi
  1182. .end_f:
  1183. popad
  1184.         ret
  1185. endp
  1186.  
  1187. ; Free any memory used in png_ptr struct without freeing the struct itself.
  1188. ;void (png_structrp png_ptr)
  1189. align 4
  1190. proc png_write_destroy uses eax edi, png_ptr:dword
  1191.         png_debug 1, 'in png_write_destroy'
  1192.  
  1193.         ; Free any memory zlib uses
  1194.         mov edi,[png_ptr]
  1195.         mov eax,[edi+png_struct.flags]
  1196.         and eax,PNG_FLAG_ZSTREAM_INITIALIZED
  1197.         jz @f ;if (..!=0)
  1198.                 mov eax,edi
  1199.                 add eax,png_struct.zstream
  1200.                 stdcall [deflateEnd], eax
  1201.         @@:
  1202.  
  1203.         ; Free our memory.  png_free checks NULL for us.
  1204.         mov eax,edi
  1205.         add eax,png_struct.zbuffer_list
  1206.         stdcall png_free_buffer_list, edi, eax
  1207.         stdcall png_free, edi, [edi+png_struct.row_buf]
  1208.         mov dword[edi+png_struct.row_buf],0
  1209. if PNG_WRITE_FILTER_SUPPORTED eq 1
  1210.         stdcall png_free, edi, [edi+png_struct.prev_row]
  1211.         stdcall png_free, edi, [edi+png_struct.try_row]
  1212.         stdcall png_free, edi, [edi+png_struct.tst_row]
  1213.         mov dword[edi+png_struct.prev_row],0
  1214.         mov dword[edi+png_struct.try_row],0
  1215.         mov dword[edi+png_struct.tst_row],0
  1216. end if
  1217.  
  1218. if PNG_SET_UNKNOWN_CHUNKS_SUPPORTED eq 1
  1219.         stdcall png_free, edi, [edi+png_struct.chunk_list]
  1220.         mov dword[edi+png_struct.chunk_list],0
  1221. end if
  1222.  
  1223.         ; The error handling and memory handling information is left intact at this
  1224.         ; point: the jmp_buf may still have to be freed.  See png_destroy_png_struct
  1225.         ; for how this happens.
  1226.         ret
  1227. endp
  1228.  
  1229. ; Free all memory used by the write.
  1230. ; In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for
  1231. ; *png_ptr_ptr.  Prior to 1.6.0 it would accept such a value and it would free
  1232. ; the passed in info_structs but it would quietly fail to free any of the data
  1233. ; inside them.  In 1.6.0 it quietly does nothing (it has to be quiet because it
  1234. ; has no png_ptr.)
  1235.  
  1236. ;void (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
  1237. align 4
  1238. proc png_destroy_write_struct uses edi esi, png_ptr_ptr:dword, info_ptr_ptr:dword
  1239.         png_debug 1, 'in png_destroy_write_struct'
  1240.  
  1241.         mov esi,[png_ptr_ptr]
  1242.         cmp esi,0
  1243.         je @f ;if (..!=0)
  1244.                 mov edi,[esi]
  1245.  
  1246.                 cmp edi,0
  1247.                 je @f ;if (..!=0) ;added in libpng 1.6.0
  1248.                         stdcall png_destroy_info_struct, edi, [info_ptr_ptr]
  1249.  
  1250.                         mov dword[esi],0
  1251.                         stdcall png_write_destroy, edi
  1252.                         stdcall png_destroy_png_struct, edi
  1253.         @@:
  1254.         ret
  1255. endp
  1256.  
  1257. ; Allow the application to select one or more row filters to use.
  1258. ;void (png_structrp png_ptr, int method, int filters)
  1259. align 4
  1260. proc png_set_filter uses eax ebx ecx edi, png_ptr:dword, method:dword, filters:dword
  1261.         png_debug 1, 'in png_set_filter'
  1262. pushad
  1263.         mov edi,[png_ptr]
  1264.         cmp edi,0
  1265.         je .end_f ;if (..==0) return
  1266.  
  1267. if PNG_MNG_FEATURES_SUPPORTED eq 1
  1268.         mov eax,[edi+png_struct.mng_features_permitted]
  1269.         and eax,PNG_FLAG_MNG_FILTER_64
  1270.         je @f
  1271.         cmp dword[method], PNG_INTRAPIXEL_DIFFERENCING
  1272.         jne @f ;if (..!=0 && ..==..)
  1273.                 mov dword[method], PNG_FILTER_TYPE_BASE
  1274.         @@:
  1275. end if
  1276.         cmp dword[method], PNG_FILTER_TYPE_BASE
  1277.         jne .end0 ;if (..==..)
  1278.         mov ebx,[filters]
  1279.         and ebx,PNG_ALL_FILTERS or 0x07 ;switch (..)
  1280.  
  1281. if PNG_WRITE_FILTER_SUPPORTED eq 1
  1282.         cmp ebx,5
  1283.         je .end2
  1284.         cmp ebx,6
  1285.         je .end2
  1286.         cmp ebx,7
  1287.         je .end2
  1288.                 jmp @f
  1289.         .end2:
  1290.                 cStr ,'Unknown row filter for method 0'
  1291.                 stdcall png_app_error, edi, eax
  1292.                 ; FALL THROUGH
  1293.         @@:
  1294. end if ;WRITE_FILTER
  1295.         cmp ebx,PNG_FILTER_VALUE_NONE
  1296.         jne @f
  1297.                 mov byte[edi+png_struct.do_filter],PNG_FILTER_NONE
  1298.                 jmp .end1
  1299.         @@:
  1300. if PNG_WRITE_FILTER_SUPPORTED eq 1
  1301.         cmp ebx,PNG_FILTER_VALUE_SUB
  1302.         jne @f
  1303.                 mov byte[edi+png_struct.do_filter],PNG_FILTER_SUB
  1304.                 jmp .end1
  1305.         @@:
  1306.         cmp ebx,PNG_FILTER_VALUE_UP
  1307.         jne @f
  1308.                 mov byte[edi+png_struct.do_filter],PNG_FILTER_UP
  1309.                 jmp .end1
  1310.         @@:
  1311.         cmp ebx,PNG_FILTER_VALUE_AVG
  1312.         jne @f
  1313.                 mov byte[edi+png_struct.do_filter],PNG_FILTER_AVG
  1314.                 jmp .end1
  1315.         @@:
  1316.         cmp ebx,PNG_FILTER_VALUE_PAETH
  1317.         jne @f
  1318.                 mov byte[edi+png_struct.do_filter],PNG_FILTER_PAETH
  1319.                 jmp .end1
  1320.         @@: ;default:
  1321.                 mov eax,[filters]
  1322.                 mov byte[edi+png_struct.do_filter],al
  1323.                 jmp .end1
  1324. else
  1325.         @@: ;default:
  1326.                 cStr ,'Unknown row filter for method 0'
  1327.                 stdcall png_app_error edi, eax
  1328. end if ;WRITE_FILTER
  1329.         .end1:
  1330.  
  1331. if PNG_WRITE_FILTER_SUPPORTED eq 1
  1332.         ; If we have allocated the row_buf, this means we have already started
  1333.         ; with the image and we should have allocated all of the filter buffers
  1334.         ; that have been selected.  If prev_row isn't already allocated, then
  1335.         ; it is too late to start using the filters that need it, since we
  1336.         ; will be missing the data in the previous row.  If an application
  1337.         ; wants to start and stop using particular filters during compression,
  1338.         ; it should start out with all of the filters, and then remove them
  1339.         ; or add them back after the start of compression.
  1340.  
  1341.                 ; NOTE: this is a nasty constraint on the code, because it means that the
  1342.                 ; prev_row buffer must be maintained even if there are currently no
  1343.                 ; 'prev_row' requiring filters active.
  1344.  
  1345.                 cmp dword[edi+png_struct.row_buf],0
  1346.                 je .end3 ;if (..!=0)
  1347.                         ;ebx = num_filters
  1348.                         ;ecx = buf_size
  1349.  
  1350.                         ; Repeat the checks in png_write_start_row; 1 pixel high or wide
  1351.                         ; images cannot benefit from certain filters.  If this isn't done here
  1352.                         ; the check below will fire on 1 pixel high images.
  1353.  
  1354.                         cmp dword[edi+png_struct.height],1
  1355.                         jne @f ;if (..==..)
  1356.                                 and dword[filters],not (PNG_FILTER_UP or PNG_FILTER_AVG or PNG_FILTER_PAETH)
  1357.                         @@:
  1358.                         cmp dword[edi+png_struct.width],1
  1359.                         jne @f ;if (..==..)
  1360.                                 and dword[filters],not (PNG_FILTER_SUB or PNG_FILTER_AVG or PNG_FILTER_PAETH)
  1361.                         @@:
  1362.                         mov eax,[filters]
  1363.                         and eax,PNG_FILTER_UP or PNG_FILTER_AVG or PNG_FILTER_PAETH
  1364.                         jz @f
  1365.                         cmp dword[edi+png_struct.prev_row],0
  1366.                         je @f;if (..!=0 && ..==0)
  1367.                                 ; This is the error case, however it is benign - the previous row
  1368.                                 ; is not available so the filter can't be used.  Just warn here.
  1369.  
  1370.                                 png_app_warning edi, 'png_set_filter: UP/AVG/PAETH cannot be added after start'
  1371.                                 and dword[filters],not (PNG_FILTER_UP or PNG_FILTER_AVG or PNG_FILTER_PAETH)
  1372.                         @@:
  1373.  
  1374.                         xor ebx,ebx
  1375.  
  1376.                         mov eax,[filters]
  1377.                         and eax,PNG_FILTER_SUB
  1378.                         jz @f ;if (..)
  1379.                                 inc ebx
  1380.                         @@:
  1381.                         mov eax,[filters]
  1382.                         and eax,PNG_FILTER_UP
  1383.                         jz @f ;if (..)
  1384.                                 inc ebx
  1385.                         @@:
  1386.                         mov eax,[filters]
  1387.                         and eax,PNG_FILTER_AVG
  1388.                         jz @f ;if (..)
  1389.                                 inc ebx
  1390.                         @@:
  1391.                         mov eax,[filters]
  1392.                         and eax,PNG_FILTER_PAETH
  1393.                         jz @f ;if (..)
  1394.                                 inc ebx
  1395.                         @@:
  1396.                         ; Allocate needed row buffers if they have not already been
  1397.                         ; allocated.
  1398.  
  1399.                         movzx eax,byte[edi+png_struct.usr_channels]
  1400.                         movzx ecx,byte[edi+png_struct.usr_bit_depth]
  1401.                         imul eax,ecx ;.bit_depth * .channels
  1402.                         mov ecx,[edi+png_struct.width]
  1403.                         inc ecx
  1404.                         PNG_ROWBYTES eax, ecx
  1405.                         mov ecx, eax
  1406.  
  1407.                         cmp dword[edi+png_struct.try_row],0
  1408.                         jne @f ;if (..==0)
  1409.                                 stdcall png_malloc, edi, ecx
  1410.                                 mov [edi+png_struct.try_row],eax
  1411.                         @@:
  1412.  
  1413.                         cmp ebx,1
  1414.                         jle .end3 ;if (..>..)
  1415.                         cmp dword[edi+png_struct.tst_row],0
  1416.                         jne .end3 ;if (..==0)
  1417.                                 stdcall png_malloc, edi, ecx
  1418.                                 mov [edi+png_struct.tst_row],eax
  1419.                 .end3:
  1420.                 mov eax,[filters]
  1421.                 mov byte[edi+png_struct.do_filter],al
  1422. end if
  1423.                 jmp .end_f
  1424.         .end0: ;else
  1425.                 png_error edi, 'Unknown custom filter method'
  1426. .end_f:
  1427. popad
  1428.         ret
  1429. endp
  1430.  
  1431. ; Provide floating and fixed point APIs
  1432. ;void (png_structrp png_ptr, int heuristic_method,
  1433. ;    int num_weights, png_const_doublep filter_weights, png_const_doublep filter_costs)
  1434. align 4
  1435. proc png_set_filter_heuristics, png_ptr:dword, heuristic_method:dword, num_weights:dword, filter_weights:dword, filter_costs:dword
  1436.         ret
  1437. endp
  1438.  
  1439. ;void (png_structrp png_ptr, int heuristic_method,
  1440. ;    int num_weights, png_const_fixed_point_p filter_weights,
  1441. ;    png_const_fixed_point_p filter_costs)
  1442. align 4
  1443. proc png_set_filter_heuristics_fixed, png_ptr:dword, heuristic_method:dword, num_weights:dword, filter_weights:dword, filter_costs:dword
  1444.         ret
  1445. endp
  1446.  
  1447. ;void (png_structrp png_ptr, int level)
  1448. align 4
  1449. proc png_set_compression_level uses edi, png_ptr:dword, level:dword
  1450.         png_debug 1, 'in png_set_compression_level'
  1451.  
  1452.         mov edi,[png_ptr]
  1453.         cmp edi,0
  1454.         je @f ;if (..==0) return
  1455.  
  1456.         m2m [edi+png_struct.zlib_level], [level]
  1457.         @@:
  1458.         ret
  1459. endp
  1460.  
  1461. ;void (png_structrp png_ptr, int mem_level)
  1462. align 4
  1463. proc png_set_compression_mem_level uses edi, png_ptr:dword, mem_level:dword
  1464.         png_debug 1, 'in png_set_compression_mem_level'
  1465.  
  1466.         mov edi,[png_ptr]
  1467.         cmp edi,0
  1468.         je @f ;if (..==0) return
  1469.  
  1470.         m2m [edi+png_struct.zlib_mem_level], [mem_level]
  1471.         @@:
  1472.         ret
  1473. endp
  1474.  
  1475. ;void (png_structrp png_ptr, int strategy)
  1476. align 4
  1477. proc png_set_compression_strategy uses edi, png_ptr:dword, strategy:dword
  1478.         png_debug 1, 'in png_set_compression_strategy'
  1479.  
  1480.         mov edi,[png_ptr]
  1481.         cmp edi,0
  1482.         je .end_f ;if (..==0) return
  1483.  
  1484.         ; The flag setting here prevents the libpng dynamic selection of strategy.
  1485.  
  1486.         or dword[edi+png_struct.flags], PNG_FLAG_ZLIB_CUSTOM_STRATEGY
  1487.         m2m [edi+png_struct.zlib_strategy], [strategy]
  1488. .end_f:
  1489.         ret
  1490. endp
  1491.  
  1492. ; If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
  1493. ; smaller value of window_bits if it can do so safely.
  1494.  
  1495. ;void (png_structrp png_ptr, int window_bits)
  1496. align 4
  1497. proc png_set_compression_window_bits uses eax edi, png_ptr:dword, window_bits:dword
  1498.         mov edi,[png_ptr]
  1499.         cmp edi,0
  1500.         je .end_f ;if (..==0) return
  1501.  
  1502.         ; Prior to 1.6.0 this would warn but then set the window_bits value. This
  1503.         ; meant that negative window bits values could be selected that would cause
  1504.         ; libpng to write a non-standard PNG file with raw deflate or gzip
  1505.         ; compressed IDAT or ancillary chunks.  Such files can be read and there is
  1506.         ; no warning on read, so this seems like a very bad idea.
  1507.  
  1508.         mov eax,[window_bits]
  1509.         cmp eax,15
  1510.         jle @f ;if (..>..)
  1511.                 png_warning edi, 'Only compression windows <= 32k supported by PNG'
  1512.                 mov eax,15
  1513.                 jmp .end0
  1514.         @@: ;else if (..<..)
  1515.         cmp eax,8
  1516.         jge @f
  1517.                 png_warning edi, 'Only compression windows >= 256 supported by PNG'
  1518.                 mov eax,8
  1519.         .end0:
  1520.  
  1521.         mov [edi+png_struct.zlib_window_bits],eax
  1522. .end_f:
  1523.         ret
  1524. endp
  1525.  
  1526. ;void (png_structrp png_ptr, int method)
  1527. align 4
  1528. proc png_set_compression_method uses eax edi, png_ptr:dword, method:dword
  1529.         png_debug 1, 'in png_set_compression_method'
  1530.  
  1531.         mov edi,[png_ptr]
  1532.         cmp edi,0
  1533.         je .end_f ;if (..==0) return
  1534.  
  1535.         ; This would produce an invalid PNG file if it worked, but it doesn't and
  1536.         ; deflate will fault it, so it is harmless to just warn here.
  1537.  
  1538.         mov eax,[method]
  1539.         cmp eax,8
  1540.         je @f ;if (..!=..)
  1541.                 png_warning edi, 'Only compression method 8 is supported by PNG'
  1542.         @@:
  1543.         mov [edi+png_struct.zlib_method],eax
  1544. .end_f:
  1545.         ret
  1546. endp
  1547.  
  1548. ; The following were added to libpng-1.5.4
  1549. if PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED eq 1
  1550. ;void (png_structrp png_ptr, int level)
  1551. align 4
  1552. proc png_set_text_compression_level uses edi, png_ptr:dword, level:dword
  1553.         png_debug 1, 'in png_set_text_compression_level'
  1554.  
  1555.         mov edi,[png_ptr]
  1556.         cmp edi,0
  1557.         je @f ;if (..==0) return
  1558.  
  1559.         m2m [edi+png_struct.zlib_text_level], [level]
  1560.         @@:
  1561.         ret
  1562. endp
  1563.  
  1564. ;void (png_structrp png_ptr, int mem_level)
  1565. align 4
  1566. proc png_set_text_compression_mem_level uses edi, png_ptr:dword, mem_level:dword
  1567.         png_debug 1, 'in png_set_text_compression_mem_level'
  1568.  
  1569.         mov edi,[png_ptr]
  1570.         cmp edi,0
  1571.         je @f ;if (..==0) return
  1572.  
  1573.         m2m [edi+png_struct.zlib_text_mem_level], [mem_level]
  1574.         @@:
  1575.         ret
  1576. endp
  1577.  
  1578. ;void (png_structrp png_ptr, int strategy)
  1579. align 4
  1580. proc png_set_text_compression_strategy uses edi, png_ptr:dword, strategy:dword
  1581.         png_debug 1, 'in png_set_text_compression_strategy'
  1582.  
  1583.         mov edi,[png_ptr]
  1584.         cmp edi,0
  1585.         je .end_f ;if (..==0) return
  1586.  
  1587.         m2m [edi+png_struct.zlib_text_strategy], [strategy]
  1588. .end_f:
  1589.         ret
  1590. endp
  1591.  
  1592. ; If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
  1593. ; smaller value of window_bits if it can do so safely.
  1594.  
  1595. ;void (png_structrp png_ptr, int window_bits)
  1596. align 4
  1597. proc png_set_text_compression_window_bits uses eax edi, png_ptr:dword, window_bits:dword
  1598.         mov edi,[png_ptr]
  1599.         cmp edi,0
  1600.         je .end_f ;if (..==0) return
  1601.  
  1602.         mov eax,[window_bits]
  1603.         cmp eax,15
  1604.         jle @f ;if (..>..)
  1605.                 png_warning edi, 'Only compression windows <= 32k supported by PNG'
  1606.                 mov eax,15
  1607.                 jmp .end0
  1608.         @@: ;else if (..<..)
  1609.         cmp eax,8
  1610.         jge @f
  1611.                 png_warning edi, 'Only compression windows >= 256 supported by PNG'
  1612.                 mov eax,8
  1613.         .end0:
  1614.  
  1615.         mov [edi+png_struct.zlib_text_window_bits],eax
  1616. .end_f:
  1617.         ret
  1618. endp
  1619.  
  1620. ;void (png_structrp png_ptr, int method)
  1621. align 4
  1622. proc png_set_text_compression_method uses edi, png_ptr:dword, method:dword
  1623.         png_debug 1, 'in png_set_text_compression_method'
  1624.  
  1625.         mov edi,[png_ptr]
  1626.         cmp edi,0
  1627.         je .end_f ;if (..==0) return
  1628.  
  1629.         cmp dword[method],8
  1630.         je @f ;if (..!=..)
  1631.                 png_warning edi, 'Only compression method 8 is supported by PNG'
  1632.         @@:
  1633.         m2m [edi+png_struct.zlib_text_method], [method]
  1634. .end_f:
  1635.         ret
  1636. endp
  1637. end if ;WRITE_CUSTOMIZE_ZTXT_COMPRESSION
  1638. ; end of API added to libpng-1.5.4
  1639.  
  1640. ;void (png_structrp png_ptr, png_write_status_ptr write_row_fn)
  1641. align 4
  1642. proc png_set_write_status_fn uses edi, png_ptr:dword, write_row_fn:dword
  1643.         mov edi,[png_ptr]
  1644.         cmp edi,0
  1645.         je @f ;if (..==0) return
  1646.                 m2m [edi+png_struct.write_row_fn], [write_row_fn]
  1647.         @@:
  1648.         ret
  1649. endp
  1650.  
  1651. ;void (png_structrp png_ptr, png_user_transform_ptr write_user_transform_fn)
  1652. align 4
  1653. proc png_set_write_user_transform_fn uses edi, png_ptr:dword, write_user_transform_fn:dword
  1654.         png_debug 1, 'in png_set_write_user_transform_fn'
  1655.  
  1656.         mov edi,[png_ptr]
  1657.         cmp edi,0
  1658.         je @f ;if (..==0) return
  1659.                 or dword[edi+png_struct.transformations], PNG_USER_TRANSFORM
  1660.                 m2m [edi+png_struct.write_user_transform_fn], [write_user_transform_fn]
  1661.         @@:
  1662.         ret
  1663. endp
  1664.  
  1665. ;void (png_structrp png_ptr, png_inforp info_ptr, int transforms, voidp params)
  1666. align 4
  1667. proc png_write_png, png_ptr:dword, info_ptr:dword, transforms:dword, params:dword
  1668. pushad
  1669.         mov edi,[png_ptr]
  1670.         cmp edi,0
  1671.         je .end_f
  1672.         mov esi,[info_ptr]
  1673.         cmp esi,0
  1674.         je .end_f ;if(..==0 || ..==0) return
  1675.  
  1676.         and dword[esi+png_info_def.valid],PNG_INFO_IDAT
  1677.         cmp esi,0 ;if(..==0)
  1678.         jne @f
  1679.                 cStr ,'no rows for png_write_image to write'
  1680.                 stdcall png_app_error edi, eax
  1681.                 jmp .end_f ;return
  1682.         @@:
  1683.  
  1684.         ; Write the file header information.
  1685.         stdcall png_write_info, edi, esi
  1686.  
  1687.         ; ------ these transformations don't touch the info structure -------
  1688.  
  1689.         ; Invert monochrome pixels
  1690.         mov eax,[transforms]
  1691.         and eax,PNG_TRANSFORM_INVERT_MONO
  1692.         jz @f ;if(..!=0)
  1693. if PNG_WRITE_INVERT_SUPPORTED eq 1
  1694.                 stdcall png_set_invert_mono,edi
  1695. else
  1696.                 cStr ,'PNG_TRANSFORM_INVERT_MONO not supported'
  1697.                 stdcall png_app_error edi, eax
  1698. end if
  1699.         @@:
  1700.  
  1701.         ; Shift the pixels up to a legal bit depth and fill in
  1702.         ; as appropriate to correctly scale the image.
  1703.  
  1704.         mov eax,[transforms]
  1705.         and eax,PNG_TRANSFORM_SHIFT
  1706.         jz @f ;if(..!=0)
  1707. if PNG_WRITE_SHIFT_SUPPORTED eq 1
  1708.         mov eax,[esi+png_info_def.valid]
  1709.         and eax,PNG_INFO_sBIT
  1710.         jz @f ;if(..!=0)
  1711.                 mov eax,esi
  1712.                 add eax,png_info_def.sig_bit
  1713.                 stdcall png_set_shift, edi, eax
  1714. else
  1715.                 cStr ,'PNG_TRANSFORM_SHIFT not supported'
  1716.                 stdcall png_app_error edi, eax
  1717. end if
  1718.         @@:
  1719.  
  1720.         ; Pack pixels into bytes
  1721.         mov eax,[transforms]
  1722.         and eax,PNG_TRANSFORM_PACKING
  1723.         jz @f ;if(..!=0)
  1724. if PNG_WRITE_PACK_SUPPORTED eq 1
  1725.                 stdcall png_set_packing, edi
  1726. else
  1727.                 cStr ,'PNG_TRANSFORM_PACKING not supported'
  1728.                 stdcall png_app_error edi, eax
  1729. end if
  1730.         @@:
  1731.  
  1732.         ; Swap location of alpha bytes from ARGB to RGBA
  1733.         mov eax,[transforms]
  1734.         and eax,PNG_TRANSFORM_SWAP_ALPHA
  1735.         jz @f ;if(..!=0)
  1736. if PNG_WRITE_SWAP_ALPHA_SUPPORTED eq 1
  1737.                 stdcall png_set_swap_alpha, edi
  1738. else
  1739.                 cStr ,'PNG_TRANSFORM_SWAP_ALPHA not supported'
  1740.                 stdcall png_app_error edi, eax
  1741. end if
  1742.         @@:
  1743.  
  1744.         ; Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into
  1745.         ; RGB, note that the code expects the input color type to be G or RGB; no
  1746.         ; alpha channel.
  1747.  
  1748.         mov eax,[transforms]
  1749.         and eax,PNG_TRANSFORM_STRIP_FILLER_AFTER or PNG_TRANSFORM_STRIP_FILLER_BEFORE
  1750.         jz .end_0 ;if(..!=0)
  1751. if PNG_WRITE_FILLER_SUPPORTED eq 1
  1752.         and eax,PNG_TRANSFORM_STRIP_FILLER_AFTER
  1753.         jz .end_1 ;if(..!=0)
  1754.                 mov eax,[transforms]
  1755.                 and eax,PNG_TRANSFORM_STRIP_FILLER_BEFORE
  1756.                 jz @f ;if(..!=0)
  1757.             cStr ,'PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported'
  1758.                         stdcall png_app_error edi, eax
  1759.                 @@:
  1760.  
  1761.                 ; Continue if ignored - this is the pre-1.6.10 behavior
  1762.                 stdcall png_set_filler, edi, 0, PNG_FILLER_AFTER
  1763.                 jmp .end_0
  1764.         .end_1: ;else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)
  1765.                 stdcall png_set_filler, edi, 0, PNG_FILLER_BEFORE
  1766. else
  1767.                 cStr ,'PNG_TRANSFORM_STRIP_FILLER not supported'
  1768.                 stdcall png_app_error edi, eax
  1769. end if
  1770.         .end_0:
  1771.  
  1772.         ; Flip BGR pixels to RGB
  1773.         mov eax,[transforms]
  1774.         and eax,PNG_TRANSFORM_BGR
  1775.         jz @f ;if(..!=0)
  1776. if PNG_WRITE_BGR_SUPPORTED eq 1
  1777.                 stdcall png_set_bgr, edi
  1778. else
  1779.                 cStr ,'PNG_TRANSFORM_BGR not supported'
  1780.                 stdcall png_app_error edi, eax
  1781. end if
  1782.         @@:
  1783.  
  1784.         ; Swap bytes of 16-bit files to most significant byte first
  1785.         mov eax,[transforms]
  1786.         and eax,PNG_TRANSFORM_SWAP_ENDIAN
  1787.         jz @f ;if(..!=0)
  1788. if PNG_WRITE_SWAP_SUPPORTED eq 1
  1789.                 stdcall png_set_swap, edi
  1790. else
  1791.                 cStr ,'PNG_TRANSFORM_SWAP_ENDIAN not supported'
  1792.                 stdcall png_app_error edi, eax
  1793. end if
  1794.         @@:
  1795.  
  1796.         ; Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats
  1797.         mov eax,[transforms]
  1798.         and eax,PNG_TRANSFORM_PACKSWAP
  1799.         jz @f ;if(..!=0)
  1800. if PNG_WRITE_PACKSWAP_SUPPORTED eq 1
  1801.                 stdcall png_set_packswap, edi
  1802. else
  1803.                 cStr ,'PNG_TRANSFORM_PACKSWAP not supported'
  1804.                 stdcall png_app_error edi, eax
  1805. end if
  1806.         @@:
  1807.  
  1808.         ; Invert the alpha channel from opacity to transparency
  1809.         mov eax,[transforms]
  1810.         and eax,PNG_TRANSFORM_INVERT_ALPHA
  1811.         jz @f ;if(..!=0)
  1812. if PNG_WRITE_INVERT_ALPHA_SUPPORTED eq 1
  1813.                 stdcall png_set_invert_alpha, edi
  1814. else
  1815.                 cStr ,'PNG_TRANSFORM_INVERT_ALPHA not supported'
  1816.                 stdcall png_app_error edi, eax
  1817. end if
  1818.         @@:
  1819.  
  1820.         ; ----------------------- end of transformations -------------------
  1821.  
  1822.         ; Write the bits
  1823.         stdcall png_write_image, edi, dword[esi+png_info_def.row_pointers]
  1824.  
  1825.         ; It is REQUIRED to call this to finish writing the rest of the file
  1826.         stdcall png_write_end, edi, esi
  1827.  
  1828. .end_f:
  1829. popad
  1830.         ret
  1831. endp
  1832.  
  1833. if PNG_SIMPLIFIED_WRITE_SUPPORTED eq 1
  1834. ; Initialize the write structure - general purpose utility.
  1835. ;int (png_imagep image)
  1836. align 4
  1837. proc png_image_write_init uses ebx ecx edx edi esi, image:dword
  1838.         mov ebx,[image]
  1839.         stdcall png_create_write_struct, PNG_LIBPNG_VER_STRING, ebx, png_safe_error, png_safe_warning
  1840.         ;eax = png_ptr
  1841.  
  1842.         cmp eax,0
  1843.         je .end0 ;if (..!=0)
  1844.                 mov edi,eax
  1845.                 stdcall png_create_info_struct, edi
  1846.                 ;eax = info_ptr
  1847.  
  1848.                 cmp eax,0
  1849.                 je .end1 ;if (..!=0)
  1850.                         mov esi,eax
  1851.                         stdcall png_malloc_warn, edi, sizeof.png_control
  1852.                         ;control = eax
  1853.  
  1854.                         cmp eax,0
  1855.                         je .end2 ;if (..!=0)
  1856.                                 push eax
  1857.                                 mov edx,edi ; edx = png_ptr
  1858.                                 mov ecx,sizeof.png_control
  1859.                                 mov edi,eax
  1860.                                 xor eax,eax
  1861.                                 rep stosb ;memset(control, 0, (sizeof.control))
  1862.                                 pop eax
  1863.  
  1864.                                 mov [eax+png_control.png_ptr], edx
  1865.                                 mov [eax+png_control.info_ptr], esi
  1866.                                 mov [eax+png_control.for_write], 1
  1867.  
  1868.                                 mov [ebx+png_image.opaque], eax
  1869.                                 xor eax,eax
  1870.                                 inc eax
  1871.                                 jmp .end_f
  1872.                         .end2:
  1873.  
  1874.                         ; Error clean up
  1875.                         push esi
  1876.                         mov esi,esp
  1877.                         stdcall png_destroy_info_struct, edi, esi
  1878.                         add esp,4
  1879.                 .end1:
  1880.  
  1881.                 push edi
  1882.                 mov edi,esp
  1883.                 stdcall png_destroy_write_struct, edi, 0
  1884.                 add esp,4
  1885.         .end0:
  1886.  
  1887.         std_png_image_error ebx, 'png_image_write_: out of memory'
  1888. .end_f:
  1889.         ret
  1890. endp
  1891.  
  1892. ; Arguments to png_image_write_main:
  1893. struct png_image_write_control
  1894.         ; Arguments:
  1895.         image  dd ? ;png_imagep
  1896.         buffer dd ? ;png_const_voidp
  1897.         row_stride dd ? ;int_32
  1898.         colormap   dd ? ;png_const_voidp
  1899.         convert_to_8bit dd ? ;int
  1900.         ; Local variables:
  1901.         first_row dd ? ;png_const_voidp
  1902.         row_bytes dd ? ;ptrdiff_t
  1903.         local_row dd ? ;voidp
  1904.         ; Byte count for memory writing
  1905.         memory    dd ? ;bytep
  1906.         memory_bytes dd ? ;png_alloc_size_t ;not used for STDIO
  1907.         output_bytes dd ? ;png_alloc_size_t ;running total
  1908. ends
  1909.  
  1910. ; Write uint_16 input to a 16-bit PNG; the png_ptr has already been set to
  1911. ; do any necessary byte swapping.  The component order is defined by the
  1912. ; png_image format value.
  1913.  
  1914. ;int (voidp argument)
  1915. align 4
  1916. proc png_write_image_16bit uses ebx ecx edx, argument:dword
  1917. locals
  1918.         display dd ? ;png_image_write_control* ;= argument
  1919.         image   dd ? ;png_imagep ;= display->image
  1920.         png_ptr dd ? ;png_structrp ;= image->opaque->png_ptr
  1921.         input_row  dd ? ;const_uint_16p ;= display->first_row
  1922.         output_row dd ? ;uint_16p ;= display->local_row
  1923.         row_end  dd ? ;uint_16p
  1924.         channels dd ? ;const int ;= (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1;
  1925.         aindex   dd 0 ;int  ;= 0
  1926.         y dd ? ;uint_32 ;= image->height
  1927. endl
  1928.         mov ebx,[argument]
  1929.         mov [display],ebx
  1930.         mov edx,[ebx+png_image_write_control.image]
  1931.         mov [image],edx
  1932.         mov ecx,[edx+png_image.opaque]
  1933.         mov ecx,[ecx+png_control.png_ptr]
  1934.         mov [png_ptr],ecx
  1935.         mov ecx,[ebx+png_image_write_control.first_row]
  1936.         mov [input_row],ecx
  1937.         mov ecx,[ebx+png_image_write_control.local_row]
  1938.         mov [output_row],ecx
  1939.  
  1940.         mov ecx,1
  1941.         mov eax,[edx+png_image.format]
  1942.         and eax,PNG_FORMAT_FLAG_COLOR
  1943.         jz @f
  1944.                 mov ecx,3
  1945.         @@:
  1946.         mov [channels],ecx
  1947.         mov eax,[edx+png_image.height]
  1948.         mov [y],eax
  1949.  
  1950.         mov eax,[edx+png_image.format]
  1951.         and eax,PNG_FORMAT_FLAG_ALPHA
  1952.         jz .end0 ;if (..!=0)
  1953. if PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED eq 1
  1954.         mov eax,[edx+png_image.format]
  1955.         and eax,PNG_FORMAT_FLAG_AFIRST
  1956.         jz @f ;if (..!=0)
  1957.                 mov dword[aindex],-1
  1958.                 inc dword[input_row] ;To point to the first component
  1959.                 inc dword[output_row]
  1960.                 jmp .end1
  1961.         @@: ;else
  1962. end if
  1963.                 mov eax,[channels]
  1964.                 mov [aindex],eax
  1965.                 jmp .end1
  1966.         .end0: ;else
  1967.                 png_error [png_ptr], 'png_write_image: internal call error'
  1968.         .end1:
  1969.  
  1970.         ; Work out the output row end and count over this, note that the increment
  1971.         ; above to 'row' means that row_end can actually be beyond the end of the
  1972.         ; row; this is correct.
  1973.  
  1974.         mov eax,[channels]
  1975.         inc eax
  1976.         imul eax,[edx+png_image.width]
  1977.         add eax,[output_row]
  1978.         mov [row_end],eax
  1979.  
  1980. ;   while (y-- > 0)
  1981. ;   {
  1982. ;      const_uint_16p in_ptr = input_row;
  1983. ;      uint_16p out_ptr = output_row;
  1984.  
  1985. ;      while (out_ptr < row_end)
  1986. ;      {
  1987. ;         const uint_16 alpha = in_ptr[aindex];
  1988. ;         uint_32 reciprocal = 0;
  1989. ;         int c;
  1990.  
  1991. ;         out_ptr[aindex] = alpha;
  1992.  
  1993.         ; Calculate a reciprocal.  The correct calculation is simply
  1994.         ; component/alpha*65535 << 15. (I.e. 15 bits of precision); this
  1995.         ; allows correct rounding by adding .5 before the shift.  'reciprocal'
  1996.         ; is only initialized when required.
  1997.  
  1998. ;         if (alpha > 0 && alpha < 65535)
  1999. ;            reciprocal = ((0xffff<<15)+(alpha>>1))/alpha;
  2000.  
  2001. ;         c = channels;
  2002. ;         do /* always at least one channel */
  2003. ;         {
  2004. ;            uint_16 component = *in_ptr++;
  2005.  
  2006.         ; The following gives 65535 for an alpha of 0, which is fine,
  2007.         ; otherwise if 0/0 is represented as some other value there is more
  2008.         ; likely to be a discontinuity which will probably damage
  2009.         ; compression when moving from a fully transparent area to a
  2010.         ; nearly transparent one.  (The assumption here is that opaque
  2011.         ; areas tend not to be 0 intensity.)
  2012.  
  2013. ;            if (component >= alpha)
  2014. ;               component = 65535;
  2015.  
  2016.         ; component<alpha, so component/alpha is less than one and
  2017.         ; component*reciprocal is less than 2^31.
  2018.  
  2019. ;            else if (component > 0 && alpha < 65535)
  2020. ;            {
  2021. ;               uint_32 calc = component * reciprocal;
  2022. ;               calc += 16384; /* round to nearest */
  2023. ;               component = (uint_16)(calc >> 15);
  2024. ;            }
  2025.  
  2026. ;            *out_ptr++ = component;
  2027. ;         }
  2028. ;         while (--c > 0);
  2029.  
  2030.         ; Skip to next component (skip the intervening alpha channel)
  2031. ;         ++in_ptr;
  2032. ;         ++out_ptr;
  2033. ;      }
  2034.  
  2035. ;      png_write_row(png_ptr, display->local_row);
  2036. ;      input_row += display->row_bytes/(sizeof (uint_16));
  2037. ;   }
  2038.  
  2039.         xor eax,eax
  2040.         inc eax ;return 1
  2041.         ret
  2042. endp
  2043.  
  2044. ; Given 16-bit input (1 to 4 channels) write 8-bit output.  If an alpha channel
  2045. ; is present it must be removed from the components, the components are then
  2046. ; written in sRGB encoding.  No components are added or removed.
  2047.  
  2048. ; Calculate an alpha reciprocal to reverse pre-multiplication.  As above the
  2049. ; calculation can be done to 15 bits of accuracy; however, the output needs to
  2050. ; be scaled in the range 0..255*65535, so include that scaling here.
  2051.  
  2052. ;#   define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha)
  2053.  
  2054. ;byte (uint_32 component, uint_32 alpha, uint_32 reciprocal/*from the above macro*/)
  2055. align 4
  2056. proc png_unpremultiply, component:dword, alpha:dword, reciprocal:dword
  2057.         ; The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0
  2058.         ; is represented as some other value there is more likely to be a
  2059.         ; discontinuity which will probably damage compression when moving from a
  2060.         ; fully transparent area to a nearly transparent one.  (The assumption here
  2061.         ; is that opaque areas tend not to be 0 intensity.)
  2062.  
  2063.         ; There is a rounding problem here; if alpha is less than 128 it will end up
  2064.         ; as 0 when scaled to 8 bits.  To avoid introducing spurious colors into the
  2065.         ; output change for this too.
  2066.  
  2067.         mov eax,[alpha]
  2068.         cmp [component],eax
  2069.         jge @f
  2070.         cmp eax,128
  2071.         jge .end0
  2072.         @@: ;if (..>=.. || ..<..)
  2073.                 mov eax,255
  2074.                 jmp .end_f
  2075.                 ; component<alpha, so component/alpha is less than one and
  2076.                 ; component*reciprocal is less than 2^31.
  2077.  
  2078.         .end0: ;else if (component > 0)
  2079.         cmp dword[component],0
  2080.         jle .end1
  2081.                 ; The test is that alpha/257 (rounded) is less than 255, the first value
  2082.                 ; that becomes 255 is 65407.
  2083.                 ; NOTE: this must agree with the PNG_DIV257 macro (which must, therefore,
  2084.                 ; be exact!)  [Could also test reciprocal != 0]
  2085.  
  2086. ;      if (alpha < 65407)
  2087. ;      {
  2088. ;         component *= reciprocal;
  2089. ;         component += 64; /* round to nearest */
  2090. ;         component >>= 7;
  2091. ;      }
  2092.  
  2093. ;      else
  2094. ;         component *= 255;
  2095.  
  2096.                 ; Convert the component to sRGB.
  2097.                 PNG_sRGB_FROM_LINEAR [component]
  2098.                 and eax,0xff
  2099.                 jmp .end_f
  2100.         .end1: ;else
  2101.                 xor eax,eax
  2102. .end_f:
  2103.         ret
  2104. endp
  2105.  
  2106. ;int (voidp argument)
  2107. align 4
  2108. proc png_write_image_8bit uses ebx ecx edx edi esi, argument:dword
  2109. locals
  2110.         display dd ? ;png_image_write_control* ;= argument
  2111.         image   dd ? ;png_imagep ;= display->image
  2112.         png_ptr dd ? ;png_structrp ;= image->opaque->png_ptr
  2113.         input_row  dd ? ;const_uint_16p ;= display->first_row
  2114.         output_row dd ? ;uint_16p ;= display->local_row
  2115.         row_end  dd ? ;uint_16p
  2116.         channels dd ? ;const int ;= (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1;
  2117.         aindex   dd 0 ;int  ;= 0
  2118.         y dd ? ;uint_32 ;= image->height
  2119.         component dd ? ;uint_32
  2120. endl
  2121.         mov ebx,[argument]
  2122.         mov [display],ebx
  2123.         mov edx,[ebx+png_image_write_control.image]
  2124.         mov [image],edx
  2125.         mov ecx,[edx+png_image.opaque]
  2126.         mov ecx,[ecx+png_control.png_ptr]
  2127.         mov [png_ptr],ecx
  2128.         mov ecx,[ebx+png_image_write_control.first_row]
  2129.         mov [input_row],ecx
  2130.         mov ecx,[ebx+png_image_write_control.local_row]
  2131.         mov [output_row],ecx
  2132.  
  2133.         mov ecx,1
  2134.         mov eax,[edx+png_image.format]
  2135.         and eax,PNG_FORMAT_FLAG_COLOR
  2136.         jz @f
  2137.                 mov ecx,3
  2138.         @@:
  2139.         mov [channels],ecx
  2140.         mov eax,[edx+png_image.height]
  2141.         mov [y],eax
  2142.  
  2143.         mov eax,[edx+png_image.format]
  2144.         and eax,PNG_FORMAT_FLAG_ALPHA
  2145.         jz .end0 ;if (..!=0)
  2146. ;      bytep row_end;
  2147. ;      int aindex;
  2148.  
  2149. if PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED eq 1
  2150. ;      if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
  2151. ;      {
  2152. ;         aindex = -1;
  2153. ;         ++input_row; /* To point to the first component */
  2154. ;         ++output_row;
  2155. ;      }
  2156.  
  2157. ;      else
  2158. end if
  2159. ;      aindex = channels;
  2160.  
  2161.         ; Use row_end in place of a loop counter:
  2162. ;      row_end = output_row + image->width * (channels+1);
  2163.  
  2164. ;      while (y-- > 0)
  2165. ;      {
  2166. ;         const_uint_16p in_ptr = input_row;
  2167. ;         bytep out_ptr = output_row;
  2168.  
  2169. ;         while (out_ptr < row_end)
  2170. ;         {
  2171. ;            uint_16 alpha = in_ptr[aindex];
  2172. ;            byte alphabyte = (byte)PNG_DIV257(alpha);
  2173. ;            uint_32 reciprocal = 0;
  2174. ;            int c;
  2175.  
  2176.         ; Scale and write the alpha channel.
  2177. ;            out_ptr[aindex] = alphabyte;
  2178.  
  2179. ;            if (alphabyte > 0 && alphabyte < 255)
  2180. ;               reciprocal = UNP_RECIPROCAL(alpha);
  2181.  
  2182. ;            c = channels;
  2183. ;            do /* always at least one channel */
  2184. ;               *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal);
  2185. ;            while (--c > 0);
  2186.  
  2187.         ; Skip to next component (skip the intervening alpha channel)
  2188. ;            ++in_ptr;
  2189. ;            ++out_ptr;
  2190. ;         } /* while out_ptr < row_end */
  2191.  
  2192. ;         png_write_row(png_ptr, display->local_row);
  2193. ;         input_row += display->row_bytes/(sizeof (uint_16));
  2194. ;      } /* while y */
  2195.                 jmp .end1
  2196.         .end0: ;else
  2197.                 ; No alpha channel, so the row_end really is the end of the row and it
  2198.                 ; is sufficient to loop over the components one by one.
  2199.  
  2200.                 mov ecx,[edx+png_image.width]
  2201.                 imul ecx,[channels]
  2202.                 add ecx,[output_row]
  2203.                 ;ecx = row_end
  2204.  
  2205.                 .cycle2: ;while (y-- > 0)
  2206.                         cmp dword[y],0
  2207.                         jle .cycle2end
  2208.                         mov esi,[input_row]
  2209.                         mov edi,[output_row]
  2210.                         ;esi = in_ptr
  2211.                         ;edi = out_ptr
  2212.  
  2213.                         .cycle3: ;while (..<..)
  2214.                                 cmp edi,ecx
  2215.                                 jge .cycle3end
  2216.                                 xor eax,eax
  2217.                                 lodsw
  2218.  
  2219.                                 imul eax,255
  2220.                                 mov [component],eax
  2221.                                 PNG_sRGB_FROM_LINEAR [component]
  2222.                                 stosb
  2223.                                 jmp .cycle3
  2224. align 4
  2225.                         .cycle3end:
  2226.  
  2227.                         stdcall png_write_row, [png_ptr], [output_row]
  2228.                         mov eax,[ebx+png_image_write_control.row_bytes]
  2229.                         shr eax,1 ;sizeof.uint_16
  2230.                         add [input_row],eax
  2231.                         dec dword[y]
  2232.                         jmp .cycle2
  2233. align 4
  2234.                 .cycle2end:
  2235.         .end1:
  2236.  
  2237.         xor eax,eax
  2238.         inc eax
  2239.         ret
  2240. endp
  2241.  
  2242. ;void (png_image_write_control *display)
  2243. align 4
  2244. proc png_image_set_PLTE, display:dword
  2245. locals
  2246.         image dd ? ;png_imagep ;= display->image
  2247.         cmap dd ? ;void * ;= display->colormap
  2248.         entries dd ? ;int
  2249.  
  2250.         ; NOTE: the caller must check for cmap != NULL and entries != 0
  2251.         format dd ? ;uint_32 ;= image->format
  2252.         channels dd ? ;int
  2253.         afirst dd 0
  2254.         bgr dd 0
  2255.         num_trans dd 0
  2256.         palette rb 256*sizeof.png_color
  2257.         tRNS rb 256 ;byte[]
  2258. endl
  2259. pushad
  2260.         mov edx,[display]
  2261.         mov ebx,[edx+png_image_write_control.image]
  2262.         mov [image],ebx
  2263.         mov eax,[edx+png_image_write_control.colormap]
  2264.         mov [cmap],eax
  2265.         mov eax,[ebx+png_image.colormap_entries]
  2266.         cmp eax,256
  2267.         jle @f
  2268.                 mov eax,256
  2269.         @@:
  2270.         mov [entries],eax
  2271.         mov ecx,[ebx+png_image.format]
  2272.         mov [format],ecx
  2273.         PNG_IMAGE_SAMPLE_CHANNELS ecx
  2274.         mov [channels],eax
  2275.  
  2276. if (PNG_FORMAT_BGR_SUPPORTED eq 1) & (PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED eq 1)
  2277.         mov eax,ecx
  2278.         and eax,PNG_FORMAT_FLAG_AFIRST
  2279.         jz @f
  2280.         mov eax,ecx
  2281.         and eax,PNG_FORMAT_FLAG_ALPHA
  2282.         jz @f
  2283.                 mov dword[afirst],-1
  2284.         @@:
  2285. end if
  2286.  
  2287. if PNG_FORMAT_BGR_SUPPORTED eq 1
  2288.         mov eax,ecx
  2289.         and eax,PNG_FORMAT_FLAG_BGR
  2290.         jz @f
  2291.                 mov dword[bgr],2
  2292.         @@:
  2293. end if
  2294.  
  2295. ;   int i;
  2296.  
  2297.         xor eax,eax
  2298.         mov ecx,(256*sizeof.png_color)/4
  2299.         mov edi,ebp
  2300.         sub edi,256+256*sizeof.png_color
  2301.         rep stosd ;memset(palette, 0, ...
  2302.         not eax
  2303.         mov ecx,256/4
  2304.         ;;mov edi,ebp ;if 'tRNS' after 'palette' this code can be comment
  2305.         ;;sub edi,256
  2306.         rep stosd ;memset(tRNS, 255, ...
  2307.  
  2308.  
  2309. ;   for (i=num_trans=0; i<entries; ++i)
  2310. ;   {
  2311.                 ; This gets automatically converted to sRGB with reversal of the
  2312.                 ; pre-multiplication if the color-map has an alpha channel.
  2313.  
  2314. ;      if ((format & PNG_FORMAT_FLAG_LINEAR) != 0)
  2315. ;      {
  2316. ;         png_const_uint_16p entry = cmap;
  2317.  
  2318. ;         entry += i * channels;
  2319.  
  2320. ;         if ((channels & 1) != 0) /* no alpha */
  2321. ;         {
  2322. ;            if (channels >= 3) /* RGB */
  2323. ;            {
  2324. ;               palette[i].blue = (byte)PNG_sRGB_FROM_LINEAR(255 *
  2325. ;                   entry[(2 ^ bgr)]);
  2326. ;               palette[i].green = (byte)PNG_sRGB_FROM_LINEAR(255 *
  2327. ;                   entry[1]);
  2328. ;               palette[i].red = (byte)PNG_sRGB_FROM_LINEAR(255 *
  2329. ;                   entry[bgr]);
  2330. ;            }
  2331.  
  2332. ;            else /* Gray */
  2333. ;               palette[i].blue = palette[i].red = palette[i].green =
  2334. ;                  (byte)PNG_sRGB_FROM_LINEAR(255 * *entry);
  2335. ;         }
  2336.  
  2337. ;         else /* alpha */
  2338. ;         {
  2339. ;            uint_16 alpha = entry[afirst ? 0 : channels-1];
  2340. ;            byte alphabyte = (byte)PNG_DIV257(alpha);
  2341. ;            uint_32 reciprocal = 0;
  2342.  
  2343.                 ; Calculate a reciprocal, as in the png_write_image_8bit code above
  2344.                 ; this is designed to produce a value scaled to 255*65535 when
  2345.                 ; divided by 128 (i.e. asr 7).
  2346.  
  2347. ;            if (alphabyte > 0 && alphabyte < 255)
  2348. ;               reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha;
  2349.  
  2350. ;            tRNS[i] = alphabyte;
  2351. ;            if (alphabyte < 255)
  2352. ;               num_trans = i+1;
  2353.  
  2354. ;            if (channels >= 3) /* RGB */
  2355. ;            {
  2356. ;               palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)],
  2357. ;                   alpha, reciprocal);
  2358. ;               palette[i].green = png_unpremultiply(entry[afirst + 1], alpha,
  2359. ;                   reciprocal);
  2360. ;               palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha,
  2361. ;                   reciprocal);
  2362. ;            }
  2363.  
  2364. ;            else /* gray */
  2365. ;               palette[i].blue = palette[i].red = palette[i].green =
  2366. ;                   png_unpremultiply(entry[afirst], alpha, reciprocal);
  2367. ;         }
  2368. ;      }
  2369.  
  2370. ;      else /* Color-map has sRGB values */
  2371. ;      {
  2372. ;         bytep entry = cmap;
  2373.  
  2374. ;         entry += i * channels;
  2375.  
  2376. ;         switch (channels)
  2377. ;         {
  2378. ;            case 4:
  2379. ;               tRNS[i] = entry[afirst ? 0 : 3];
  2380. ;               if (tRNS[i] < 255)
  2381. ;                  num_trans = i+1;
  2382. ;               /* FALL THROUGH */
  2383. ;            case 3:
  2384. ;               palette[i].blue = entry[afirst + (2 ^ bgr)];
  2385. ;               palette[i].green = entry[afirst + 1];
  2386. ;               palette[i].red = entry[afirst + bgr];
  2387. ;               break;
  2388.  
  2389. ;            case 2:
  2390. ;               tRNS[i] = entry[1 ^ afirst];
  2391. ;               if (tRNS[i] < 255)
  2392. ;                  num_trans = i+1;
  2393. ;               /* FALL THROUGH */
  2394. ;            case 1:
  2395. ;               palette[i].blue = palette[i].red = palette[i].green =
  2396. ;                  entry[afirst];
  2397. ;               break;
  2398.  
  2399. ;            default:
  2400. ;               break;
  2401. ;         }
  2402. ;      }
  2403. ;   }
  2404.  
  2405.         mov ecx,[ebx+png_image.opaque]
  2406.         mov eax,ebp
  2407.         sub eax,256+256*sizeof.png_color
  2408.         stdcall png_set_PLTE, [ecx+png_control.png_ptr], [ecx+png_control.info_ptr], eax, [entries]
  2409.  
  2410.         cmp dword[num_trans],0
  2411.         jle @f ;if (..>0)
  2412.                 mov eax,ebp
  2413.                 sub eax,256
  2414.                 stdcall png_set_tRNS, [ecx+png_control.png_ptr], [ecx+png_control.info_ptr], eax, [num_trans], 0
  2415.         @@:
  2416.  
  2417.         mov eax,[entries]
  2418.         mov [ebx+png_image.colormap_entries],eax
  2419. popad
  2420.         ret
  2421. endp
  2422.  
  2423. ;int (voidp argument)
  2424. align 4
  2425. proc png_image_write_main uses ebx ecx edx esi edi, argument:dword
  2426. locals
  2427.         display dd ? ;= png_image_write_control * = argument
  2428.         image dd ? ;= display->image
  2429.         png_ptr dd ? ;= image->opaque->png_ptr
  2430.         info_ptr dd ? ;= image->opaque->info_ptr
  2431.         format dd ? ;= image->format
  2432.  
  2433.         colormap dd ?
  2434.         linear dd ?
  2435.         alpha dd ?
  2436.         write_16bit dd ? ;= linear && !colormap && (display->convert_to_8bit == 0)
  2437. endl
  2438.         mov edx,[argument]
  2439.         mov [display],edx
  2440.         mov ebx,[edx+png_image_write_control.image]
  2441.         mov [image],ebx
  2442.         mov ecx,[ebx+png_image.format]
  2443.         mov [format],ecx
  2444.         mov eax,[ebx+png_image.opaque]
  2445.         mov edi,[eax+png_control.png_ptr]
  2446.         mov [png_ptr],edi
  2447.         mov esi,[eax+png_control.info_ptr]
  2448.         mov [info_ptr],esi
  2449.  
  2450.         ; The following four ints are actually booleans
  2451.         and ecx,PNG_FORMAT_FLAG_COLORMAP
  2452.         mov [colormap],ecx
  2453.         not ecx
  2454.         mov eax,[format]
  2455.         and eax,PNG_FORMAT_FLAG_LINEAR
  2456.         mov [linear],eax
  2457.         mov eax,[format]
  2458.         and eax,ecx
  2459.         and eax,PNG_FORMAT_FLAG_ALPHA
  2460.         and eax,ecx
  2461.         mov [alpha],eax
  2462.         xor eax,eax ;false
  2463.         cmp dword[edx+png_image_write_control.convert_to_8bit],0
  2464.         jne @f
  2465.                 not eax ;true
  2466.         @@:
  2467.         and eax,[linear]
  2468.         and eax,ecx
  2469.         mov [write_16bit],eax
  2470.  
  2471. if PNG_BENIGN_ERRORS_SUPPORTED eq 1
  2472.         ; Make sure we error out on any bad situation
  2473.         stdcall png_set_benign_errors, edi, 0 ;error
  2474. end if
  2475.  
  2476.         ; Default the 'row_stride' parameter if required, also check the row stride
  2477.         ; and total image size to ensure that they are within the system limits.
  2478.  
  2479.         PNG_IMAGE_PIXEL_CHANNELS [ebx+png_image.format]
  2480.         ;eax = channels
  2481.  
  2482.         push edx
  2483.         mov ecx,eax
  2484.         mov eax,0x7FFFFFFF
  2485.         xor edx,edx
  2486.         div ecx
  2487.         pop edx
  2488.         cmp [ebx+png_image.width],eax
  2489.         jg .end0 ;if (..<=..) ;no overflow
  2490.                 imul ecx,[ebx+png_image.width]
  2491.  
  2492.                 cmp dword[edx+png_image_write_control.row_stride],0
  2493.                 jne @f ;if (..==0)
  2494.                         mov [edx+png_image_write_control.row_stride],ecx
  2495.                 @@:
  2496.                 mov eax,[edx+png_image_write_control.row_stride]
  2497.                 cmp eax,0
  2498.                 jge .end2 ;if (..<0)
  2499.                         neg eax
  2500.                         inc eax
  2501.                 .end2:
  2502.  
  2503.                 cmp eax,ecx
  2504.                 jl .end3 ;if (..>=..)
  2505.                         ; Now check for overflow of the image buffer calculation; this
  2506.                         ; limits the whole image size to 32 bits for API compatibility with
  2507.                         ; the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro.
  2508.  
  2509.                         push edx
  2510.                         mov eax,0xFFFFFFFF
  2511.                         xor edx,edx
  2512.                         div ecx
  2513.                         pop edx
  2514.                         cmp [ebx+png_image.height],eax
  2515.                         jle @f ;if (..>..)
  2516.                                 mov eax,[ebx+png_image.opaque]
  2517.                                 mov eax,[eax+png_control.png_ptr]
  2518.                                 png_error eax, 'memory image too large'
  2519.                         @@:
  2520.                         jmp .end1
  2521.                 .end3: ;else
  2522.                         mov eax,[ebx+png_image.opaque]
  2523.                         mov eax,[eax+png_control.png_ptr]
  2524.                         png_error eax, 'supplied row stride too small'
  2525.                 jmp .end1
  2526.         .end0: ;else
  2527.                 mov eax,[ebx+png_image.opaque]
  2528.                 mov eax,[eax+png_control.png_ptr]
  2529.                 png_error eax, 'image row stride too large'
  2530.         .end1:
  2531.  
  2532.         ; Set the required transforms then write the rows in the correct order.
  2533.         mov eax,[format]
  2534.         and eax,PNG_FORMAT_FLAG_COLORMAP
  2535.         jz .end4 ;if (..!=0)
  2536.                 cmp dword[edx+png_image_write_control.colormap],0
  2537.                 je .end6
  2538.                 mov eax,[ebx+png_image.colormap_entries]
  2539.                 cmp eax,0
  2540.                 jle .end6 ;if (..!=0 && ..>0)
  2541.                         ;eax = entries
  2542.                         xor ecx,ecx
  2543.                         inc ecx ;=1
  2544.                         cmp eax,2
  2545.                         jle @f
  2546.                                 shl ecx,1 ;=2
  2547.                         cmp eax,4
  2548.                         jle @f
  2549.                                 shl ecx,1 ;=4
  2550.                         cmp eax,16
  2551.                         jle @f
  2552.                                 shl ecx,1 ;=8
  2553.                         @@:
  2554.                         stdcall png_set_IHDR, edi, esi, [ebx+png_image.width], [ebx+png_image.height],\
  2555.                                 ecx, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,\
  2556.                                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE
  2557.  
  2558.                         stdcall png_image_set_PLTE, edx
  2559.                         jmp .end5
  2560.                 .end6: ;else
  2561.                         mov eax,[ebx+png_image.opaque]
  2562.                         mov eax,[eax+png_control.png_ptr]
  2563.                         png_error eax, 'no color-map for color-mapped image'
  2564.                 jmp .end5
  2565.         .end4: ;else
  2566.                 xor ecx,ecx
  2567.                 mov eax,[format]
  2568.                 and eax,PNG_FORMAT_FLAG_COLOR
  2569.                 jz @f
  2570.                         or ecx,PNG_COLOR_MASK_COLOR
  2571.                 @@:
  2572.                 mov eax,[format]
  2573.                 and eax,PNG_FORMAT_FLAG_ALPHA
  2574.                 jz @f
  2575.                         or ecx,PNG_COLOR_MASK_ALPHA
  2576.                 @@:
  2577.                 mov eax,8
  2578.                 cmp dword[write_16bit],0
  2579.                 je @f
  2580.                         mov eax,16
  2581.                 @@:
  2582.                 stdcall png_set_IHDR, edi, esi, [ebx+png_image.width], [ebx+png_image.height],\
  2583.                         eax, ecx, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE
  2584.         .end5:
  2585.  
  2586.         ; Counter-intuitively the data transformations must be called *after*
  2587.         ; png_write_info, not before as in the read code, but the 'set' functions
  2588.         ; must still be called before.  Just set the color space information, never
  2589.         ; write an interlaced image.
  2590.  
  2591.         cmp dword[write_16bit],0
  2592.         je @f ;if (..!=0)
  2593.                 ; The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB.
  2594.                 stdcall png_set_gAMA_fixed, edi, esi, PNG_GAMMA_LINEAR
  2595.  
  2596.                 mov eax,[ebx+png_image.flags]
  2597.                 and eax,PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB
  2598.                 jnz @f ;if (..==0)
  2599.                         stdcall png_set_cHRM_fixed, edi, esi,\
  2600.                         31270, 32900,\ ;white
  2601.                         64000, 33000,\ ;red
  2602.                         30000, 60000,\ ;green
  2603.                         15000,  6000   ;blue
  2604.                 jmp .end7
  2605.         @@:
  2606.         mov eax,[ebx+png_image.flags]
  2607.         and eax,PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB
  2608.         jnz @f ;else if (..==0)
  2609.                 stdcall png_set_sRGB, edi, esi, PNG_sRGB_INTENT_PERCEPTUAL
  2610.                 jmp .end7
  2611.         @@: ;else
  2612.                 ; Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit
  2613.                 ; space must still be gamma encoded.
  2614.                 stdcall png_set_gAMA_fixed, edi, esi, PNG_GAMMA_sRGB_INVERSE
  2615.         .end7:
  2616.  
  2617.         ; Write the file header.
  2618.         stdcall png_write_info, edi, esi
  2619.  
  2620.         ; Now set up the data transformations (*after* the header is written),
  2621.         ; remove the handled transformations from the 'format' flags for checking.
  2622.  
  2623.         ; First check for a little endian system if writing 16-bit files.
  2624.  
  2625.         cmp dword[write_16bit],0
  2626.         je @f ;if (..!=0)
  2627. ;      uint_16 le = 0x0001;
  2628.  
  2629. ;      if ((*(bytep) & le) != 0)
  2630.                 stdcall png_set_swap, edi
  2631.         @@:
  2632.  
  2633. if PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED eq 1
  2634.         mov eax,[format]
  2635.         and eax,PNG_FORMAT_FLAG_BGR
  2636.         jz .end12 ;if (..!=0)
  2637.                 cmp dword[colormap],0
  2638.                 jne @f
  2639.                 mov eax,[format]
  2640.                 and eax,PNG_FORMAT_FLAG_COLOR
  2641.                 jz @f ;if (..==0 && ..!=0)
  2642.                         stdcall png_set_bgr, edi
  2643.                 @@:
  2644.                 and dword[format], not PNG_FORMAT_FLAG_BGR
  2645.         .end12:
  2646. end if
  2647.  
  2648. if PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED eq 1
  2649.         mov eax,[format]
  2650.         and eax,PNG_FORMAT_FLAG_AFIRST
  2651.         jz .end13 ;if (..!=0)
  2652.                 cmp dword[colormap],0
  2653.                 jne @f
  2654.                 mov eax,[format]
  2655.                 and eax,PNG_FORMAT_FLAG_ALPHA
  2656.                 jz @f ;if (..==0 && ..!=0)
  2657.                         stdcall png_set_swap_alpha, edi
  2658.                 @@:
  2659.                 and dword[format], not PNG_FORMAT_FLAG_AFIRST
  2660.         .end13:
  2661. end if
  2662.  
  2663.         ; If there are 16 or fewer color-map entries we wrote a lower bit depth
  2664.         ; above, but the application data is still byte packed.
  2665.  
  2666.         cmp dword[colormap],0
  2667.         je @f
  2668.         cmp dword[ebx+png_image.colormap_entries],16
  2669.         jg @f ;if (..!=0 && ..<=16)
  2670.                 stdcall png_set_packing, edi
  2671.         @@:
  2672.  
  2673.         ; That should have handled all (both) the transforms.
  2674.         mov eax,[format]
  2675.         and eax, not (PNG_FORMAT_FLAG_COLOR or PNG_FORMAT_FLAG_LINEAR or PNG_FORMAT_FLAG_ALPHA or PNG_FORMAT_FLAG_COLORMAP)
  2676.         jz @f ;if (..!=0)
  2677.                 png_error edi, 'png_write_image: unsupported transformation'
  2678.         @@:
  2679.  
  2680.         push esi
  2681.         ;ecx - row ;bytep
  2682.         ;esi - row_bytes
  2683.         mov ecx,[edx+png_image_write_control.buffer]
  2684.         mov esi,[edx+png_image_write_control.row_stride]
  2685.  
  2686.         cmp dword[linear],0
  2687.         je @f ;if (..!=0)
  2688.                 shl esi,1 ;*= sizeof.uint_16
  2689.         @@:
  2690.         cmp esi,0
  2691.         jge @f ;if (..<0)
  2692.                 mov eax,[ebx+png_image.height]
  2693.                 dec eax
  2694.                 imul eax,esi
  2695.                 sub ecx,eax
  2696.         @@:
  2697.         mov [edx+png_image_write_control.first_row],ecx
  2698.         mov [edx+png_image_write_control.row_bytes],esi
  2699.         pop esi
  2700.  
  2701.         ; Apply 'fast' options if the flag is set.
  2702.         mov eax,[ebx+png_image.flags]
  2703.         and eax,PNG_IMAGE_FLAG_FAST
  2704.         jz @f ;if (..!=0)
  2705.                 stdcall png_set_filter, edi, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS
  2706.                 ; NOTE: determined by experiment using pngstest, this reflects some
  2707.                 ; balance between the time to write the image once and the time to read
  2708.                 ; it about 50 times.  The speed-up in pngstest was about 10-20% of the
  2709.                 ; total (user) time on a heavily loaded system.
  2710.  
  2711. if PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED eq 1
  2712.                 stdcall png_set_compression_level, edi, 3
  2713. end if
  2714.         @@:
  2715.  
  2716.         ; Check for the cases that currently require a pre-transform on the row
  2717.         ; before it is written.  This only applies when the input is 16-bit and
  2718.         ; either there is an alpha channel or it is converted to 8-bit.
  2719.  
  2720.         cmp dword[linear],0
  2721.         je @f
  2722.         cmp dword[alpha],0
  2723.         je @f
  2724.                 jmp .end10
  2725.         @@:
  2726.         cmp dword[colormap],0
  2727.         jne .end9
  2728.         cmp dword[edx+png_image_write_control.convert_to_8bit],0
  2729.         je .end9
  2730.         .end10: ;if ((..!=0 && ..!=0 ) || (..==0 && ..!=0))
  2731.                 stdcall png_get_rowbytes, edi, esi
  2732.                 stdcall png_malloc, edi, eax
  2733.                 mov ecx,eax ;ecx = row
  2734.                
  2735.                 mov [edx+png_image_write_control.local_row],ecx
  2736.                 cmp dword[write_16bit],0
  2737.                 je @f ;if (..!=0)
  2738.                         stdcall png_safe_execute, ebx, png_write_image_16bit, edx
  2739.                         jmp .end11
  2740.                 @@: ;else
  2741.                         stdcall png_safe_execute, ebx, png_write_image_8bit, edx
  2742.                 .end11:
  2743.                 mov dword[edx+png_image_write_control.local_row],0
  2744.  
  2745.                 stdcall png_free, edi, ecx
  2746.  
  2747.                 ; Skip the 'write_end' on error:
  2748.                 cmp eax,0
  2749.                 je .end_f ;if (..==0) return 0
  2750.                 jmp .end8
  2751.  
  2752.         ; Otherwise this is the case where the input is in a format currently
  2753.         ; supported by the rest of the libpng write code; call it directly.
  2754.  
  2755.         .end9: ;else
  2756. if 1 ;;; IDAT compress all
  2757.                 mov ecx,[edx+png_image_write_control.row_bytes]
  2758.                 inc ecx
  2759.                 imul ecx,[ebx+png_image.height]
  2760.                 cmp ecx,1
  2761.                 jl .end8
  2762.                 stdcall create_compress_IDAT, edi, [edx+png_image_write_control.first_row], ecx, [ebx+png_image.width], [ebx+png_image.height]
  2763. else ;;; not work, IDAT compress by lines
  2764.                 mov ecx,[ebx+png_image.height]
  2765.                 cmp ecx,1
  2766.                 jl .end8
  2767.                 mov eax,[edx+png_image_write_control.first_row]
  2768.                 mov ebx,[edx+png_image_write_control.row_bytes]
  2769.                 @@:
  2770.                         stdcall png_write_row, edi, eax
  2771.                         add eax, ebx
  2772.                         loop @b
  2773. end if
  2774.         .end8:
  2775.  
  2776.         stdcall png_write_end, edi, esi
  2777.         xor eax,eax
  2778.         inc eax
  2779. .end_f:
  2780.         ret
  2781. endp
  2782.  
  2783. align 16
  2784. proc create_compress_IDAT, png_ptr:dword, buf:dword, len:dword, width:dword, height:dword
  2785. locals
  2786.         m1 dd ? ;memory for compress IDAT
  2787.         buf_f dd ? ;memory for IDAT
  2788.         mins dd ? ;minimum sum
  2789. endl
  2790. pushad
  2791.         mov edi,[png_ptr]
  2792. png_debug 1, 'IDAT compress all'
  2793.  
  2794.         ;create buffer with filters
  2795.         stdcall png_zalloc, edi, 1, [len]
  2796.         cmp eax,0
  2797.         je .end_f
  2798.         mov [buf_f],eax
  2799.  
  2800.         mov eax,ZLIB_IO_MAX
  2801.         cmp eax,[len]
  2802.         jge @f
  2803.                 mov eax,[len]
  2804.         @@:
  2805.         stdcall png_zalloc, edi, 1, eax
  2806.         cmp eax,0
  2807.         je .end0
  2808.         mov [m1],eax
  2809.  
  2810.         ;init buffer with filters
  2811.         mov ebx,[width]
  2812.         mov edx,[height]
  2813.         mov edi,[buf_f]
  2814.         mov esi,[buf]
  2815.         .cycle0:
  2816.         cmp edx,1
  2817.         jl .cycle0end
  2818.                 mov ecx,ebx
  2819.                 xor al,al
  2820.                 stosb ;insert filter (0 - none)
  2821. align 4
  2822.                 .cycle1:
  2823.                         lodsb   ;1
  2824.                         inc edi ;
  2825.                         movsb   ;2
  2826.                         stosb   ;3
  2827.                         lodsb   ;
  2828.                         mov [edi-3],al
  2829.                         loop .cycle1
  2830.                 dec edx
  2831.                 jmp .cycle0
  2832.         .cycle0end:
  2833.  
  2834.         ;make filters
  2835.         mov edx,[height]
  2836.         mov esi,[width]
  2837.         imul esi,3 ;esi - rowbytes
  2838.  
  2839.         inc esi
  2840.         mov edi,[png_ptr]
  2841.         cmp dword[edi+png_struct.try_row],0
  2842.         jne @f ;if (..==0)
  2843.                 stdcall png_malloc, edi, esi
  2844.                 mov [edi+png_struct.try_row],eax
  2845.         @@:
  2846.         cmp dword[edi+png_struct.tst_row],0
  2847.         jne @f ;if (..==0)
  2848.                 stdcall png_malloc, edi, esi
  2849.                 mov [edi+png_struct.tst_row],eax
  2850.         @@:
  2851.         dec esi
  2852.  
  2853.         mov edi,[buf_f]
  2854.         add edi,[len]
  2855.         .cycle3:
  2856.                 dec edx
  2857.                 cmp edx,1
  2858.                 jl .cycle3end
  2859.                 sub edi,esi
  2860.                 dec edi ;move in perv row
  2861.  
  2862.                 ;init pointers for function png_setup_up_row
  2863.                 mov ebx,[png_ptr]
  2864.                 mov [ebx+png_struct.row_buf],edi
  2865.                 mov [ebx+png_struct.prev_row],edi
  2866.                 sub [ebx+png_struct.prev_row],esi
  2867.                 dec dword[ebx+png_struct.prev_row]
  2868.  
  2869.                 ;calculate start minimum sum
  2870.                 push esi
  2871.                 xor eax,eax
  2872.                 xor ebx,ebx
  2873.                 mov ecx,esi
  2874.                 mov esi,edi
  2875.                 inc esi
  2876.                 .cycle2:
  2877.                         lodsb
  2878.                         png_setup_abs ebx
  2879.                         loop .cycle2
  2880.                 pop esi
  2881.                 mov [mins],ebx
  2882.  
  2883.                 push edx
  2884.                 mov edx,[png_ptr]
  2885.                 mov eax,[edx+png_struct.tst_row]
  2886.                 mov byte[eax],0 ;not filter
  2887.  
  2888.                 ; Up filter
  2889.                 stdcall png_setup_up_row, edx, esi, [mins]
  2890.                 cmp eax,[mins]
  2891.                 jge @f ;if (..<..)
  2892.                         mov [mins],eax
  2893.                         stdcall copy_row_mins, [edx+png_struct.tst_row], [edx+png_struct.try_row]
  2894.                 @@:
  2895.  
  2896.                 ; Find out how many bytes offset each pixel is
  2897.                 movzx ebx,byte[edx+png_struct.pixel_depth]
  2898.                 add ebx,7
  2899.                 shr ebx,3
  2900.  
  2901.                 ; Sub filter
  2902.                 stdcall png_setup_sub_row, edx, ebx, esi, [mins]
  2903.                 cmp eax,[mins]
  2904.                 jge @f ;if (..<..)
  2905.                         mov [mins],eax
  2906.                         stdcall copy_row_mins, [edx+png_struct.tst_row], [edx+png_struct.try_row]
  2907.                 @@:
  2908.  
  2909.                 ; Avg filter
  2910.                 stdcall png_setup_avg_row, edx, ebx, esi, [mins]
  2911.                 cmp eax,[mins]
  2912.                 jge @f ;if (..<..)
  2913.                         mov [mins],eax
  2914.                         stdcall copy_row_mins, [edx+png_struct.tst_row], [edx+png_struct.try_row]
  2915.                 @@:
  2916.  
  2917.                 ; Copy best row
  2918.                 mov eax,[edx+png_struct.tst_row]
  2919.                 cmp byte[eax],0
  2920.                 je @f
  2921.                         stdcall copy_row_mins, edi, [edx+png_struct.tst_row]
  2922.                 @@:
  2923.                 pop edx
  2924.                 jmp .cycle3
  2925.         .cycle3end:
  2926.        
  2927.         mov edi,[png_ptr]
  2928.         mov esi,edi
  2929.         add esi,png_struct.zstream
  2930.         stdcall [deflateInit2], esi,\
  2931.                 -1, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY
  2932.  
  2933.         mov eax,[buf_f]
  2934.         mov [edi+png_struct.zstream.next_in],eax
  2935.         mov eax,[len]
  2936.         mov [edi+png_struct.zstream.avail_in],eax
  2937.         mov eax,[m1]
  2938.         mov [edi+png_struct.zstream.next_out],eax
  2939.         xor ecx,ecx
  2940. align 4
  2941.         .cycle4:
  2942.                 mov word[edi+png_struct.zstream.avail_out],16*1024
  2943.  
  2944.                 stdcall [deflate], esi, Z_FINISH ;Z_NO_FLUSH
  2945.                 cmp eax,Z_STREAM_ERROR
  2946.                 je .end1
  2947.  
  2948.                 add ecx,16*1024
  2949.                 sub cx,[edi+png_struct.zstream.avail_out]
  2950.                 cmp word[edi+png_struct.zstream.avail_out],0
  2951.         je .cycle4 ;while (strm.avail_out == 0)
  2952. if 0
  2953.         mov word[edi+png_struct.zstream.avail_out],16*1024
  2954.         stdcall [deflate], esi, Z_FINISH
  2955.         cmp eax,Z_STREAM_ERROR
  2956.         je .end1
  2957. end if
  2958.         stdcall [deflateEnd], esi
  2959.  
  2960. if PNG_WRITE_OPTIMIZE_CMF_SUPPORTED eq 1
  2961.         mov eax,[edi+png_struct.mode]
  2962.         and eax,PNG_HAVE_IDAT
  2963.         jnz @f
  2964.         cmp byte[edi+png_struct.compression_type],PNG_COMPRESSION_TYPE_BASE
  2965.         jne @f ;if (..==0 && ..==..)
  2966.                 stdcall png_image_size, edi
  2967.                 stdcall optimize_cmf, [m1], eax
  2968.         @@:
  2969. end if
  2970.  
  2971.         stdcall png_write_complete_chunk, edi, png_IDAT, [m1], ecx
  2972.         or dword[edi+png_struct.mode],PNG_HAVE_IDAT
  2973.  
  2974.         jmp @f
  2975.         .end1:
  2976.                 png_debug 1, 'Z_STREAM_ERROR'
  2977.         @@:
  2978.  
  2979.         ;free memory
  2980.         cmp dword[edi+png_struct.try_row],0
  2981.         je @f ;if (..!=0)
  2982.                 stdcall png_free, edi, [edi+png_struct.try_row]
  2983.                 mov dword[edi+png_struct.try_row],0
  2984.         @@:
  2985.         cmp dword[edi+png_struct.tst_row],0
  2986.         je @f ;if (..!=0)
  2987.                 stdcall png_free, edi, [edi+png_struct.tst_row]
  2988.                 mov dword[edi+png_struct.tst_row],0
  2989.         @@:
  2990.         stdcall png_free, edi, [m1]
  2991. .end0:
  2992.         stdcall png_free, edi, [buf_f]
  2993. .end_f:
  2994. popad
  2995.         ret
  2996. endp
  2997.  
  2998. ;input:
  2999. ; esi - rowbytes
  3000. align 4
  3001. proc copy_row_mins uses edi esi, dest:dword, sour:dword
  3002.         mov ecx,esi
  3003.         inc ecx
  3004.         mov edi,[dest]
  3005.         mov esi,[sour]
  3006.         rep movsb
  3007.         ret
  3008. endp
  3009.  
  3010. ;void (png_structp png_ptr, bytep/*const*/ data, png_size_t size)
  3011. align 4
  3012. proc image_memory_write uses eax ebx ecx edi esi, png_ptr:dword, p2data:dword, size:dword
  3013.         mov edi,[png_ptr]
  3014.         mov esi,[edi+png_struct.io_ptr] ;esi = png_image_write_control *display
  3015.         mov ebx,[esi+png_image_write_control.output_bytes] ;ebx = ob
  3016.  
  3017.         ; Check for overflow; this should never happen:
  3018.         mov eax,PNG_SIZE_MAX
  3019.         sub eax,ebx
  3020.         mov ecx,[size]
  3021.         cmp ecx,eax
  3022.         jg .end1 ;if (..<=..)
  3023.                 ; I don't think libpng ever does this, but just in case:
  3024.                 cmp ecx,0
  3025.                 jle .end0 ;if (..>0)
  3026.                         mov eax,ebx
  3027.                         add eax,ecx
  3028.                         cmp [esi+png_image_write_control.memory_bytes],eax
  3029.                         jl @f ;if (..>=..) ;writing
  3030.                                 push esi
  3031.                                 mov edi,[esi+png_image_write_control.memory]
  3032.                                 add edi,ebx
  3033.                                 mov esi,[p2data]
  3034.                                 rep movsb ;memcpy(...
  3035.                                 pop esi
  3036.                         @@:
  3037.  
  3038.                         ; Always update the size:
  3039.                         add ebx,[size]
  3040.                         mov [esi+png_image_write_control.output_bytes],ebx
  3041.                 .end0:
  3042.                 jmp .end2
  3043.         .end1: ;else
  3044.                 png_error edi, 'png_image_write_to_memory: PNG too big'
  3045.         .end2:
  3046.         ret
  3047. endp
  3048.  
  3049. ;void (png_structp png_ptr)
  3050. align 4
  3051. proc image_memory_flush, png_ptr:dword
  3052.         ret
  3053. endp
  3054.  
  3055. ;int (voidp argument)
  3056. align 4
  3057. proc png_image_write_memory uses ebx, argument:dword
  3058.         ; The rest of the memory-specific init and write_main in an error protected
  3059.         ; environment.  This case needs to use callbacks for the write operations
  3060.         ; since libpng has no built in support for writing to memory.
  3061.  
  3062.         mov eax,[argument]
  3063.         mov ebx,[eax+png_image_write_control.image]
  3064.         mov ebx,[ebx+png_image.opaque]
  3065.         stdcall png_set_write_fn, [ebx+png_control.png_ptr], eax, image_memory_write, image_memory_flush
  3066.  
  3067.         stdcall png_image_write_main, [argument]
  3068.         ret
  3069. endp
  3070.  
  3071. ;int (png_imagep image, void *memory,
  3072. ;    png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit,
  3073. ;    const void *buffer, int_32 row_stride, const void *colormap)
  3074. align 4
  3075. proc png_image_write_to_memory uses ebx ecx edx edi esi, image:dword, memory:dword,\
  3076.         memory_bytes:dword, convert_to_8bit:dword, buffer:dword, row_stride:dword, colormap:dword
  3077. locals
  3078.         display png_image_write_control ;local struct
  3079. endl
  3080. ;edi - display png_image_write_control
  3081.  
  3082.         ; Write the image to the given buffer, or count the bytes if it is NULL
  3083.         mov ebx,[image]
  3084.         cmp ebx,0
  3085.         je .end0
  3086.         cmp dword[ebx+png_image.version],PNG_IMAGE_VERSION
  3087.         jne .end0 ;if (..!=0 && ..==..)
  3088.                 cmp dword[memory_bytes],0
  3089.                 je .end2
  3090.                 cmp dword[buffer],0
  3091.                 je .end2 ;if (..!=0 && ..!=0)
  3092.                         ; This is to give the caller an easier error detection in the NULL
  3093.                         ; case and guard against uninitialized variable problems:
  3094.  
  3095.                         cmp dword[memory],0
  3096.                         jne @f ;if(..==0)
  3097.                                 mov eax,[memory_bytes]
  3098.                                 mov dword[eax],0
  3099.                         @@:
  3100.  
  3101.                         stdcall png_image_write_init, ebx
  3102.                         cmp eax,0
  3103.                         je .end3 ;if (..!=0)
  3104.                                 mov ecx,sizeof.png_image_write_control
  3105.                                 mov edi,ebp
  3106.                                 sub edi,ecx
  3107.                                 xor eax,eax
  3108.                                 rep stosb ;memset(&display, 0, sizeof.display))
  3109.                                 sub edi,sizeof.png_image_write_control
  3110.                                 mov [edi+png_image_write_control.image],ebx
  3111.                                 mov eax,[buffer]
  3112.                                 mov [edi+png_image_write_control.buffer],eax
  3113.                                 mov eax,[row_stride]
  3114.                                 mov [edi+png_image_write_control.row_stride],eax
  3115.                                 mov eax,[colormap]
  3116.                                 mov [edi+png_image_write_control.colormap],eax
  3117.                                 mov eax,[convert_to_8bit]
  3118.                                 mov [edi+png_image_write_control.convert_to_8bit],eax
  3119.                                 mov eax,[memory]
  3120.                                 mov [edi+png_image_write_control.memory],eax
  3121.                                 mov eax,[memory_bytes]
  3122.                                 mov eax,[eax]
  3123.                                 mov [edi+png_image_write_control.memory_bytes],eax
  3124.                                 mov dword[edi+png_image_write_control.output_bytes], 0
  3125.  
  3126.                                 stdcall png_safe_execute, ebx, png_image_write_memory, edi
  3127.                                 mov ecx,eax ;ecx = result
  3128.                                 stdcall png_image_free, ebx
  3129.  
  3130.                                 ; write_memory returns true even if we ran out of buffer.
  3131.                                 cmp ecx,0 ;if (..)
  3132.                                 je .end4
  3133.                                         ; On out-of-buffer this function returns '0' but still updates
  3134.                                         ; memory_bytes:
  3135.  
  3136.                                         mov edx,[edi+png_image_write_control.output_bytes]
  3137.                                         mov eax,[memory_bytes]
  3138.                                         cmp dword[memory],0
  3139.                                         je @f ;if (..!=0 && ..>..)
  3140.                                         cmp edx,[eax]
  3141.                                         jle @f
  3142.                                                 xor ecx,ecx
  3143.                                         @@:
  3144.                                         mov [eax],edx
  3145.                                 .end4:
  3146.  
  3147.                                 mov eax,ecx
  3148.                                 jmp .end_f
  3149.                         .end3: ;else
  3150.                         xor eax,eax
  3151.                         jmp .end_f
  3152.                 .end2: ;else
  3153.                         std_png_image_error ebx, 'png_image_write_to_memory: invalid argument'
  3154.                         jmp .end_f
  3155.         .end0:
  3156.         cmp ebx,0
  3157.         je .end1 ;else if (..!=0)
  3158.                 std_png_image_error ebx, 'png_image_write_to_memory: incorrect PNG_IMAGE_VERSION'
  3159.                 jmp .end_f
  3160.         .end1: ;else
  3161.                 xor eax,eax
  3162. .end_f:
  3163.         ret
  3164. endp
  3165.  
  3166. ;int (png_imagep image, FILE *file, int convert_to_8bit,
  3167. ;    const void *buffer, int_32 row_stride, const void *colormap)
  3168. align 4
  3169. proc png_image_write_to_stdio, image:dword, file:dword, convert_to_8bit:dword, buffer:dword, row_stride:dword, colormap:dword
  3170.         ; Write the image to the given (FILE*).
  3171. ;   if (image != NULL && image->version == PNG_IMAGE_VERSION)
  3172. ;   {
  3173. ;      if (file != NULL && buffer != NULL)
  3174. ;      {
  3175. ;         if (png_image_write_init(image) != 0)
  3176. ;         {
  3177. ;            png_image_write_control display;
  3178. ;            int result;
  3179.  
  3180.         ; This is slightly evil, but png_init_io doesn't do anything other
  3181.         ; than this and we haven't changed the standard IO functions so
  3182.         ; this saves a 'safe' function.
  3183.  
  3184. ;            image->opaque->png_ptr->io_ptr = file;
  3185.  
  3186. ;            memset(&display, 0, (sizeof display));
  3187. ;            display.image = image;
  3188. ;            display.buffer = buffer;
  3189. ;            display.row_stride = row_stride;
  3190. ;            display.colormap = colormap;
  3191. ;            display.convert_to_8bit = convert_to_8bit;
  3192.  
  3193. ;            result = png_safe_execute(image, png_image_write_main, &display);
  3194. ;            png_image_free(image);
  3195. ;            return result;
  3196. ;         }
  3197.  
  3198. ;         else
  3199. ;            return 0;
  3200. ;      }
  3201.  
  3202. ;      else
  3203. ;         return png_image_error(image,
  3204. ;             "png_image_write_to_stdio: invalid argument");
  3205. ;   }
  3206.  
  3207. ;   else if (image != NULL)
  3208. ;      return png_image_error(image,
  3209. ;          "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION");
  3210.  
  3211. ;   else
  3212. ;      return 0;
  3213.         ret
  3214. endp
  3215.  
  3216. ;int (png_imagep image, const char *file_name,
  3217. ;    int convert_to_8bit, const void *buffer, int_32 row_stride,
  3218. ;    const void *colormap)
  3219. align 4
  3220. proc png_image_write_to_file, image:dword, file_name:dword, convert_to_8bit:dword, buffer:dword, row_stride:dword, colormap:dword
  3221.         ; Write the image to the named file.
  3222. ;   if (image != NULL && image->version == PNG_IMAGE_VERSION)
  3223. ;   {
  3224. ;      if (file_name != NULL && buffer != NULL)
  3225. ;      {
  3226. ;         FILE *fp = fopen(file_name, "wb");
  3227.  
  3228. ;         if (fp != NULL)
  3229. ;         {
  3230. ;            if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer,
  3231. ;                row_stride, colormap) != 0)
  3232. ;            {
  3233. ;               int error; /* from fflush/fclose */
  3234.  
  3235.         ; Make sure the file is flushed correctly.
  3236. ;               if (fflush(fp) == 0 && ferror(fp) == 0)
  3237. ;               {
  3238. ;                  if (fclose(fp) == 0)
  3239. ;                     return 1;
  3240.  
  3241. ;                  error = errno; /* from fclose */
  3242. ;               }
  3243.  
  3244. ;               else
  3245. ;               {
  3246. ;                  error = errno; /* from fflush or ferror */
  3247. ;                  (void)fclose(fp);
  3248. ;               }
  3249.  
  3250. ;               (void)remove(file_name);
  3251.         ; The image has already been cleaned up; this is just used to
  3252.         ; set the error (because the original write succeeded).
  3253.  
  3254. ;               return png_image_error(image, strerror(error));
  3255. ;            }
  3256.  
  3257. ;            else
  3258. ;            {
  3259.         ; Clean up: just the opened file.
  3260. ;               (void)fclose(fp);
  3261. ;               (void)remove(file_name);
  3262. ;               return 0;
  3263. ;            }
  3264. ;         }
  3265.  
  3266. ;         else
  3267. ;            return png_image_error(image, strerror(errno));
  3268. ;      }
  3269.  
  3270. ;      else
  3271. ;         return png_image_error(image,
  3272. ;             "png_image_write_to_file: invalid argument");
  3273. ;   }
  3274.  
  3275. ;   else if (image != NULL)
  3276. ;      return png_image_error(image,
  3277. ;          "png_image_write_to_file: incorrect PNG_IMAGE_VERSION");
  3278.  
  3279. ;   else
  3280. ;      return 0;
  3281.         ret
  3282. endp
  3283. end if ;SIMPLIFIED_WRITE
  3284.