Subversion Repositories Kolibri OS

Rev

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