Subversion Repositories Kolibri OS

Rev

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

  1. ;;================================================================================================;;
  2. ;;//// png.asm //// (c) diamond, 2009 ////////////////////////////////////////////////////////////;;
  3. ;;================================================================================================;;
  4. ;;                                                                                                ;;
  5. ;; This file is part of Common development libraries (Libs-Dev).                                  ;;
  6. ;;                                                                                                ;;
  7. ;; Libs-Dev is free software: you can redistribute it and/or modify it under the terms of the GNU ;;
  8. ;; Lesser General Public License as published by the Free Software Foundation, either version 2.1 ;;
  9. ;; of the License, or (at your option) any later version.                                         ;;
  10. ;;                                                                                                ;;
  11. ;; Libs-Dev is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without  ;;
  12. ;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  ;;
  13. ;; Lesser General Public License for more details.                                                ;;
  14. ;;                                                                                                ;;
  15. ;; You should have received a copy of the GNU Lesser General Public License along with Libs-Dev.  ;;
  16. ;; If not, see <http://www.gnu.org/licenses/>.                                                    ;;
  17. ;;                                                                                                ;;
  18. ;;================================================================================================;;
  19.  
  20. include 'libpng/png.asm'
  21.  
  22. ;;================================================================================================;;
  23. ;;proc img.is.png _data, _length ;////////////////////////////////////////////////////////////////;;
  24. img.is.png:
  25. ;;------------------------------------------------------------------------------------------------;;
  26. ;? Determine if raw data could be decoded (is in PNG format)                                      ;;
  27. ;;------------------------------------------------------------------------------------------------;;
  28. ;> _data = raw data as read from file/stream                                                      ;;
  29. ;> _length = data length                                                                          ;;
  30. ;;------------------------------------------------------------------------------------------------;;
  31. ;< eax = false / true                                                                             ;;
  32. ;;================================================================================================;;
  33. ; test 1 (length of data)
  34.         cmp     dword [esp+8], 8
  35.         jb      .nope
  36. ; test 2: signature
  37.         mov     eax, [esp+4]
  38.         cmp     dword [eax], 0x474E5089
  39.         jne     .nope
  40.         cmp     dword [eax+4], 0x0A1A0A0D
  41.         je      .yep
  42.  
  43.   .nope:
  44.         xor     eax, eax
  45.         ret     8
  46.  
  47.   .yep:
  48.         xor     eax, eax
  49.         inc     eax
  50.         ret     8
  51. ;endp
  52.  
  53. ;;================================================================================================;;
  54. ;;proc img.decode.png _data, _length, _options ;//////////////////////////////////////////////////;;
  55. img.decode.png:
  56.         xor     eax, eax        ; .image = 0
  57.         pushad
  58.         mov     ebp, esp
  59. .localsize = 29*4
  60. virtual at ebp - .localsize
  61. .width          dd      ?
  62. .height         dd      ?
  63. .bit_depth      dd      ?
  64. .color_type     dd      ?
  65. .bytes_per_pixel dd     ?
  66. .scanline_len   dd      ?
  67. .bits_per_pixel dd      ?
  68. .size_rest      dd      ?
  69. .cur_chunk_ptr  dd      ?
  70. .cur_chunk_size dd      ?
  71. .allocated      dd      ?
  72. .paeth_a        dd      ?
  73. .paeth_b        dd      ?
  74. .paeth_c        dd      ?
  75. .paeth_pa       dd      ?
  76. .paeth_pb       dd      ?
  77. .paeth_pc       dd      ?
  78. .i              dd      ?
  79. .j              dd      ?
  80. ; variables to handle interlace
  81. .row_distance   dd      ?       ; diff between two consecutives rows in destination
  82. .col_distance   dd      ?       ; summand for moving to next row in source
  83. .row_increment  dd      ?
  84. .col_increment  dd      ?
  85. .block_height   dd      ?
  86. .block_width    dd      ?
  87. .interlace      db      ?       ; 0 if not interlaced, 1 if interlaced
  88. .row_increment_shift db ?
  89. .col_increment_shift db ?
  90. .shift          db      ?       ; shift for current src byte
  91. .starting_row   dd      ?
  92. .starting_col   dd      ?
  93. .idat_read      dd      ?
  94.         rb      1Ch
  95. .image          dd      ?
  96.         rd      1
  97. .data           dd      ?
  98. .length         dd      ?
  99. .options        dd      ?
  100. end virtual
  101.         push    eax     ; .idat_read = 0
  102.         push    eax     ; .starting_col = 0
  103.         push    eax     ; .starting_row = 0
  104.         push    eax     ; .col_increment_shift, .row_increment_shift
  105.         inc     eax
  106.         push    eax     ; .block_width
  107.         push    eax     ; .block_height
  108.         push    eax     ; .col_increment
  109.         push    eax     ; .row_increment
  110.         sub     esp, .localsize-32
  111. ; load deflate unpacker, if not yet
  112. ; acquire mutex
  113. @@:
  114.         push    1
  115.         pop     eax
  116.         xchg    [deflate_loader_mutex], eax     ; 'xchg' has an implicit 'lock' prefix
  117.         test    eax, eax
  118.         jz      @f
  119.         mcall   5, 1
  120.         jmp     @b
  121. @@:
  122.         cmp     [deflate_unpack2], __deflate_unpack2_import_name__
  123.         jnz     .deflate_loaded
  124. ; do loading
  125.         invoke  dll.load, @IMPORT
  126.         test    eax, eax
  127.         jz      .deflate_loaded
  128.         add     esp, .localsize
  129.         popad
  130.         mov     [deflate_loader_mutex], eax
  131.         ret     12
  132. .deflate_loaded:
  133. ; release mutex
  134.         mov     [deflate_loader_mutex], 0
  135. ; ok, continue
  136.         mov     esi, [.data]            ; esi -> data
  137.         mov     ecx, [.length]          ; ecx = length
  138. ; the signature has been already checked in img.is.png
  139.         lodsd
  140.         lodsd
  141.         sub     ecx, 8
  142.         xor     ebx, ebx        ; no image allocated
  143. .chunks_loop:
  144.         sub     ecx, 12
  145.         jc      .eof
  146.         lodsd   ; chunk length
  147.         bswap   eax
  148.         sub     ecx, eax
  149.         jc      .eof
  150.         push    ecx     ; save length of data rest
  151.         xchg    eax, ecx        ; ecx = size of data in the chunk
  152.         lodsd   ; chunk type
  153.         cmp     eax, 'IHDR'
  154.         jz      .ihdr
  155.         cmp     eax, 'IDAT'
  156.         jz      .idat
  157.         cmp     eax, 'IEND'
  158.         jz      .iend
  159.         cmp     eax, 'PLTE'
  160.         jz      .palette
  161. ; unrecognized chunk, ignore
  162.         lea     esi, [esi+ecx+4]
  163.         pop     ecx
  164.         jmp     .chunks_loop
  165. ; IHDR chunk
  166. .ihdr:
  167.         cmp     ecx, 13
  168.         jnz     .invalid_chunk
  169.         cmp     [.image], 0
  170.         jnz     .invalid_chunk
  171. ; read image characteristics
  172.         lodsd
  173.         bswap   eax
  174.         mov     [.width], eax
  175.         lodsd
  176.         bswap   eax
  177.         mov     [.height], eax
  178.         xor     eax, eax
  179.         lea     ebx, [eax+1]
  180.         lodsb
  181.         cmp     al, 16
  182.         ja      .invalid_chunk
  183.         test    al, al
  184.         jz      .invalid_chunk
  185.         lea     edx, [eax-1]
  186.         test    al, dl
  187.         jnz     .invalid_chunk
  188.         mov     [.bit_depth], eax
  189.         lodsb
  190.         test    al, not 7
  191.         jnz     .invalid_chunk
  192.         mov     [.color_type], eax
  193.         lodsb
  194.         test    al, al
  195.         jnz     .invalid_chunk  ; only compression method 0 is defined
  196.         lodsb
  197.         test    al, al
  198.         jnz     .invalid_chunk  ; only filtering method 0 is defined
  199.         lodsb
  200.         cmp     al, 1
  201.         ja      .invalid_chunk  ; only interlacing methods 0 and 1 are defined
  202.         mov     [.interlace], al
  203. ; check for correctness and calculate bytes_per_pixel and scanline_len
  204.         mov     eax, [.bit_depth]
  205.         mov     edx, [.color_type]
  206.         dec     edx
  207.         js      .grayscale1
  208.         dec     edx
  209.         jz      .rgb1
  210.         dec     edx
  211.         jz      .palette1
  212.         dec     edx
  213.         jz      .grayscale_alpha1
  214.         dec     edx
  215.         dec     edx
  216.         jnz     .invalid_chunk
  217. .rgb_alpha1:
  218.         inc     ebx
  219. .rgb1:
  220.         inc     ebx
  221. .grayscale_alpha1:
  222.         inc     ebx
  223.         cmp     al, 8
  224.         jb      .invalid_chunk
  225.         jmp     @f
  226. .palette1:
  227.         cmp     al, 8
  228.         ja      .invalid_chunk
  229. .grayscale1:
  230. @@:
  231.         mul     ebx
  232.         mov     [.bits_per_pixel], eax
  233.         add     eax, 7
  234.         shr     eax, 3
  235.         mov     [.bytes_per_pixel], eax
  236. ; allocate image
  237.         push    Image.bpp24
  238.         pop     eax
  239.         cmp     [.color_type], 2
  240.         jz      @f
  241.         mov     al, Image.bpp32
  242.         cmp     [.color_type], 6
  243.         jz      @f
  244.         mov     al, Image.bpp8i
  245. @@:
  246.         stdcall img.create, [.width], [.height], eax
  247.         test    eax, eax
  248.         jz      .invalid_chunk
  249.         mov     [.image], eax
  250.         jmp     .next_chunk
  251. .invalid_chunk:
  252. .iend:
  253.         pop     ecx
  254. .eof:
  255.         add     esp, .localsize
  256.         popad
  257.         ret     12
  258. ; PLTE chunk
  259. .palette:
  260.         mov     eax, [.image]
  261.         test    eax, eax
  262.         jz      .invalid_chunk
  263.         cmp     [.color_type], 3
  264.         jz      .copy_palette
  265. .ignore_chunk:
  266.         add     esi, ecx
  267. .next_chunk:
  268.         lodsd
  269.         pop     ecx
  270.         jmp     .chunks_loop
  271. .copy_palette:
  272.         mov     edi, [eax + Image.Palette]
  273.         xor     eax, eax
  274.         cmp     ecx, 256*3
  275.         ja      .next_chunk
  276. @@:
  277.         sub     ecx, 3
  278.         jz      @f
  279.         js      .invalid_chunk
  280.         lodsd
  281.         dec     esi
  282.         bswap   eax
  283.         shr     eax, 8
  284.         stosd
  285.         jmp     @b
  286. @@:
  287.         lodsd
  288.         dec     esi
  289.         bswap   eax
  290.         shr     eax, 8
  291.         stosd
  292.         jmp     .next_chunk
  293. .idat:
  294.         jecxz   .next_chunk
  295.         cmp     [.idat_read], 0
  296.         jnz     @f
  297.         lodsb
  298.         inc     [.idat_read]
  299.         and     al, 0xF
  300.         cmp     al, 8
  301.         jnz     .invalid_chunk
  302.         dec     ecx
  303.         jz      .next_chunk
  304. @@:
  305.         cmp     [.idat_read], 1
  306.         jnz     @f
  307.         lodsb
  308.         inc     [.idat_read]
  309.         test    al, 20h
  310.         jnz     .invalid_chunk
  311.         dec     ecx
  312.         jz      .next_chunk
  313. @@:
  314.         mov     [.cur_chunk_ptr], esi
  315.         mov     [.cur_chunk_size], ecx
  316.         pop     [.length]
  317.         push    eax
  318.         push    esp
  319.         push    ebp
  320.         push    .deflate_callback
  321.         call    [deflate_unpack2]
  322.         pop     ecx
  323.         test    eax, eax
  324.         jz      .invalid_chunk
  325. ; convert PNG unpacked data to RAW data
  326.         mov     esi, eax
  327.         mov     [.allocated], eax
  328.         mov     [.size_rest], ecx
  329. ; unfilter and deinterlace
  330. ; .interlace_pass, .starting_row and .starting_col have been already set to 0
  331. ; .block_width, .block_height, .col_increment, .row_increment were set
  332. ; to values for non-interlaced images; correct if necessary
  333.         cmp     [.interlace], 0
  334.         jz      .deinterlace_loop
  335.         push    8
  336.         pop     eax
  337.         mov     [.row_increment], eax
  338.         mov     [.col_increment], eax
  339.         mov     [.block_height], eax
  340.         mov     [.block_width], eax
  341.         mov     [.row_increment_shift], 3
  342.         mov     [.col_increment_shift], 3
  343. .deinterlace_loop:
  344.         mov     edx, [.height]
  345.         cmp     edx, [.starting_row]
  346.         jbe     .deinterlace_next
  347.         mov     ebx, [.width]
  348.         sub     ebx, [.starting_col]
  349.         jbe     .deinterlace_next
  350.         mov     cl, [.col_increment_shift]
  351.         add     ebx, [.col_increment]
  352.         dec     ebx
  353.         shr     ebx, cl
  354.         mov     eax, [.bits_per_pixel]
  355.         imul    eax, ebx
  356.         add     eax, 7
  357.         shr     eax, 3
  358.         mov     [.scanline_len], eax
  359.         shl     ebx, cl
  360.         mov     [.col_distance], ebx
  361. ; Unfilter
  362.         mov     ecx, [.size_rest]
  363.         push    esi
  364. .unfilter_loop_e:
  365.         mov     ebx, [.scanline_len]
  366.         sub     ecx, 1
  367.         jc      .unfilter_abort
  368.         sub     ecx, ebx
  369.         jc      .unfilter_abort
  370.         movzx   eax, byte [esi]
  371.         add     esi, 1
  372.         cmp     eax, 4
  373.         ja      .next_scanline
  374.         jmp     dword [@f + eax*4]
  375. align 4
  376. @@:
  377.         dd      .unfilter_none
  378.         dd      .unfilter_sub
  379.         dd      .unfilter_up
  380.         dd      .unfilter_average
  381.         dd      .unfilter_paeth
  382. .unfilter_sub:
  383.         mov     edi, [.bytes_per_pixel]
  384.         add     esi, edi
  385.         sub     ebx, edi
  386.         jbe     .next_scanline
  387.         neg     edi
  388. @@:
  389.         mov     al, [esi+edi]
  390.         add     [esi], al
  391.         add     esi, 1
  392.         sub     ebx, 1
  393.         jnz     @b
  394.         jmp     .next_scanline
  395. .unfilter_up:
  396.         cmp     edx, [.height]
  397.         jz      .unfilter_none
  398.         lea     edi, [ebx+1]
  399.         neg     edi
  400. @@:
  401.         mov     al, [esi+edi]
  402.         add     [esi], al
  403.         add     esi, 1
  404.         sub     ebx, 1
  405.         jnz     @b
  406.         jmp     .next_scanline
  407. .unfilter_average:
  408.         mov     edi, [.bytes_per_pixel]
  409.         cmp     edx, [.height]
  410.         jz      .unfilter_average_firstline
  411.         push    edx
  412.         lea     edx, [ebx+1]
  413.         neg     edx
  414.         sub     ebx, edi
  415. @@:
  416.         mov     al, [esi+edx]
  417.         shr     al, 1
  418.         add     [esi], al
  419.         add     esi, 1
  420.         sub     edi, 1
  421.         jnz     @b
  422.         mov     edi, [.bytes_per_pixel]
  423.         neg     edi
  424.         test    ebx, ebx
  425.         jz      .unfilter_average_done
  426. @@:
  427.         mov     al, [esi+edx]
  428.         add     al, [esi+edi]
  429.         rcr     al, 1
  430.         add     [esi], al
  431.         add     esi, 1
  432.         sub     ebx, 1
  433.         jnz     @b
  434. .unfilter_average_done:
  435.         pop     edx
  436.         jmp     .next_scanline
  437. .unfilter_average_firstline:
  438.         mov     edi, [.bytes_per_pixel]
  439.         add     esi, edi
  440.         sub     ebx, edi
  441.         jbe     .next_scanline
  442.         neg     edi
  443. @@:
  444.         mov     al, [esi+edi]
  445.         shr     al, 1
  446.         add     [esi], al
  447.         add     esi, 1
  448.         sub     ebx, 1
  449.         jnz     @b
  450.         jmp     .unfilter_none
  451. .unfilter_paeth:
  452.         cmp     edx, [.height]
  453.         jz      .unfilter_sub
  454.         push    edx
  455.         lea     edx, [ebx+1]
  456.         mov     edi, [.bytes_per_pixel]
  457.         neg     edx
  458.         sub     ebx, edi
  459. @@:
  460.         mov     al, [esi+edx]
  461.         add     [esi], al
  462.         add     esi, 1
  463.         sub     edi, 1
  464.         jnz     @b
  465.         mov     edi, [.bytes_per_pixel]
  466.         neg     edi
  467.         test    ebx, ebx
  468.         jz      .unfilter_paeth_done
  469.         push    ecx
  470. @@:
  471.         push    ebx
  472. ; PaethPredictor(Raw(x-bpp) = a, Prior(x) = b, Prior(x-bpp) = c)
  473.         movzx   eax, byte [esi+edi]
  474.         mov     [.paeth_a], eax
  475.         movzx   ecx, byte [esi+edx]
  476.         add     edi, edx
  477.         mov     [.paeth_b], ecx
  478.         add     ecx, eax
  479.         movzx   eax, byte [esi+edi]
  480.         mov     [.paeth_c], eax
  481.         sub     ecx, eax        ; ecx = a + b - c = p
  482. ; calculate pa = abs(p-a), pb = abs(p-b), pc = abs(p-c)
  483.         mov     ebx, ecx
  484.         sub     ebx, eax        ; ebx = p - c
  485.         cmp     ebx, 80000000h
  486.         sbb     eax, eax        ; eax = (p < c) ? 0 : 0xFFFFFFF
  487.         not     eax             ; eax = (p < c) ? 0xFFFFFFFF : 0
  488.         and     eax, ebx        ; eax = (p < c) ? p - c : 0
  489.         sub     ebx, eax
  490.         sub     ebx, eax        ; ebx = abs(p-c)
  491.         mov     [.paeth_pc], ebx
  492.         mov     ebx, ecx
  493.         sub     ebx, [.paeth_a]
  494.         cmp     ebx, 80000000h
  495.         sbb     eax, eax
  496.         not     eax
  497.         and     eax, ebx
  498.         sub     ebx, eax
  499.         sub     ebx, eax
  500.         mov     [.paeth_pa], ebx
  501.         mov     ebx, ecx
  502.         sub     ebx, [.paeth_b]
  503.         cmp     ebx, 80000000h
  504.         sbb     eax, eax
  505.         not     eax
  506.         and     eax, ebx
  507.         sub     ebx, eax
  508.         sub     ebx, eax
  509.         ;mov    [.paeth_pb], ebx
  510. ; select closest value
  511.         push    edx
  512.         mov     edx, [.paeth_b]
  513.         sub     edx, [.paeth_a]
  514.         sub     ebx, [.paeth_pa]
  515.         sbb     ecx, ecx        ; ecx = (pa > pb) ? 0xFFFFFFFF : 0
  516.         sbb     eax, eax        ; eax = (pa > pb) ? 0xFFFFFFFF : 0
  517.         and     ecx, ebx        ; ecx = (pa > pb) ? pb - pa : 0
  518.         and     eax, edx        ; eax = (pa > pb) ? b - a : 0
  519.         add     ecx, [.paeth_pa]        ; ecx = (pa > pb) ? pb : pa = min(pa,pb)
  520.         add     eax, [.paeth_a]         ; eax = (pa > pb) ? b : a
  521.         mov     edx, [.paeth_c]
  522.         sub     edx, eax
  523.         sub     [.paeth_pc], ecx
  524.         sbb     ebx, ebx        ; ebx = (min(pa,pb) <= pc) ? 0 : 0xFFFFFFFF
  525.         and     ebx, edx        ; ebx = (min(pa,pb) <= pc) ? 0 : c - eax
  526.         add     eax, ebx
  527.         pop     edx
  528.         add     [esi], al
  529.         pop     ebx
  530.         sub     edi, edx
  531.         add     esi, 1
  532.         sub     ebx, 1
  533.         jnz     @b
  534.         pop     ecx
  535. .unfilter_paeth_done:
  536.         pop     edx
  537.         jmp     .next_scanline
  538. .unfilter_none:
  539.         add     esi, ebx
  540. .next_scanline:
  541.         sub     edx, [.row_increment]
  542.         jc      .unfilter_done
  543.         cmp     edx, [.starting_row]
  544.         jbe     .unfilter_done
  545.         jmp     .unfilter_loop_e
  546. .unfilter_abort:
  547.         xor     ecx, ecx
  548. .unfilter_done:
  549. ; unfiltering done, now convert to raw data
  550. ; with deinterlacing if needed
  551.         pop     esi
  552.         mov     ebx, [.image]
  553.         mov     eax, [.width]
  554.         call    img._.get_scanline_len
  555.         mov     [.row_distance], eax
  556.         mov     eax, [.row_increment]
  557.         mul     [.width]
  558.         sub     eax, [.col_distance]
  559.         call    img._.get_scanline_len
  560.         mov     [.col_distance], eax
  561.         mov     edi, [ebx + Image.Data]
  562.         mov     eax, [.starting_row]
  563.         mul     [.width]
  564.         add     eax, [.starting_col]
  565.         call    img._.get_scanline_len
  566.         add     edi, eax
  567.         mov     eax, ebx
  568.         mov     ebx, [.size_rest]
  569.         mov     [.size_rest], ecx
  570.         mov     edx, [.height]
  571.         sub     edx, [.starting_row]
  572.         mov     [.j], edx
  573.         cmp     [.color_type], 0
  574.         jz      .grayscale2
  575.         cmp     [.color_type], 2
  576.         jz      .rgb2
  577.         cmp     [.color_type], 3
  578.         jz      .palette2
  579.         cmp     [.color_type], 4
  580.         jz      .grayscale_alpha2
  581. .rgb_alpha2:
  582.         cmp     [.bit_depth], 16
  583.         jz      .rgb_alpha2_16bit
  584. .rgb_alpha2.next:
  585.         sub     ebx, 1
  586.         jc      .convert_done
  587.         add     esi, 1
  588.         sub     ebx, [.scanline_len]
  589.         jc      .convert_done
  590.         mov     ecx, [.width]
  591.         sub     ecx, [.starting_col]
  592.         mov     [.i], ecx
  593. .rgb_alpha2.extloop:
  594.  
  595. macro init_block
  596. {
  597.         push    ebx
  598.         mov     eax, [.col_increment]
  599.         mov     edx, [.j]
  600.         cmp     edx, [.block_height]
  601.         jb      @f
  602.         mov     edx, [.block_height]
  603. @@:
  604.         mov     ebx, [.i]
  605.         cmp     ebx, [.block_width]
  606.         jb      @f
  607.         mov     ebx, [.block_width]
  608. @@:
  609. }
  610.  
  611.         init_block
  612.         lea     eax, [edi+eax*4]
  613.         push    eax
  614. .rgb_alpha2.innloop1:
  615.         push    edi
  616.         mov     ecx, ebx
  617. .rgb_alpha2.innloop2:
  618.         mov     al, [esi+2]
  619.         mov     [edi], al
  620.         mov     al, [esi+1]
  621.         mov     [edi+1], al
  622.         mov     al, [esi]
  623.         mov     [edi+2], al
  624.         mov     al, [esi+3]
  625.         mov     [edi+3], al
  626.         add     edi, 4
  627.         dec     ecx
  628.         jnz     .rgb_alpha2.innloop2
  629.         pop     edi
  630.         add     edi, [.row_distance]
  631.         dec     edx
  632.         jnz     .rgb_alpha2.innloop1
  633.         pop     edi ebx
  634.         add     esi, 4
  635.         mov     eax, [.col_increment]
  636.         sub     [.i], eax
  637.         ja      .rgb_alpha2.extloop
  638.         add     edi, [.col_distance]
  639.         mov     eax, [.row_increment]
  640.         sub     [.j], eax
  641.         ja      .rgb_alpha2.next
  642.         jmp     .convert_done
  643. .rgb_alpha2_16bit:
  644.         sub     ebx, 1
  645.         jc      .convert_done
  646.         add     esi, 1
  647.         sub     ebx, [.scanline_len]
  648.         jc      .convert_done
  649.         mov     ecx, [.width]
  650.         sub     ecx, [.starting_col]
  651.         mov     [.i], ecx
  652. .rgb_alpha2_16bit.loop:
  653.         init_block
  654.         lea     eax, [edi+eax*4]
  655.         push    eax
  656.  
  657. ; convert 16 bit sample to 8 bit sample
  658. macro convert_16_to_8
  659. {
  660. local .l1,.l2
  661.         xor     ah, 0x80
  662.         js      .l1
  663.         cmp     al, ah
  664.         adc     al, 0
  665.         jmp     .l2
  666. .l1:
  667.         cmp     ah, al
  668.         sbb     al, 0
  669. .l2:
  670. }
  671.  
  672. .rgb_alpha2_16bit.innloop1:
  673.         push    edi
  674.         mov     ecx, ebx
  675. .rgb_alpha2_16bit.innloop2:
  676.         mov     ax, [esi+4]
  677.         convert_16_to_8
  678.         mov     [edi], al
  679.         mov     ax, [esi+2]
  680.         convert_16_to_8
  681.         mov     [edi+1], al
  682.         mov     ax, [esi]
  683.         convert_16_to_8
  684.         mov     [edi+2], al
  685.         ;mov    ax, [esi+6]
  686.         ;convert_16_to_8
  687.         ;mov    [edi+3], al
  688.         add     edi, 4
  689.         dec     ecx
  690.         jnz     .rgb_alpha2_16bit.innloop2
  691.         pop     edi
  692.         add     edi, [.row_distance]
  693.         dec     edx
  694.         jnz     .rgb_alpha2_16bit.innloop1
  695.         pop     edi ebx
  696.         add     esi, 8
  697.         mov     eax, [.col_increment]
  698.         sub     [.i], eax
  699.         ja      .rgb_alpha2_16bit.loop
  700.         add     edi, [.col_distance]
  701.         mov     eax, [.row_increment]
  702.         sub     [.j], eax
  703.         ja      .rgb_alpha2_16bit
  704.         jmp     .convert_done
  705. .grayscale2:
  706.         call    .create_grayscale_palette
  707.         cmp     [.bit_depth], 16
  708.         jz      .grayscale2_16bit
  709. .palette2:
  710.         cmp     [.bit_depth], 1
  711.         jz      .palette2_1bit
  712.         cmp     [.bit_depth], 2
  713.         jz      .palette2_2bit
  714.         cmp     [.bit_depth], 4
  715.         jz      .palette2_4bit
  716. .palette2_8bit:
  717.         sub     ebx, 1
  718.         jc      .convert_done
  719.         add     esi, 1
  720.         sub     ebx, [.scanline_len]
  721.         jc      .convert_done
  722.         mov     ecx, [.width]
  723.         sub     ecx, [.starting_col]
  724.         mov     [.i], ecx
  725. .palette2_8bit.extloop:
  726.         init_block
  727.         add     eax, edi
  728.         push    eax
  729.         mov     al, [esi]
  730.         inc     esi
  731. macro block_byte_innerloop extloop
  732. {
  733. local .l1
  734. .l1:
  735.         mov     ecx, ebx
  736.         rep     stosb
  737.         sub     edi, ebx
  738.         add     edi, [.row_distance]
  739.         dec     edx
  740.         jnz     .l1
  741.         pop     edi ebx
  742.         mov     eax, [.col_increment]
  743.         sub     [.i], eax
  744.         ja      extloop
  745.         add     edi, [.col_distance]
  746.         mov     eax, [.row_increment]
  747.         sub     [.j], eax
  748. }
  749.         block_byte_innerloop .palette2_8bit.extloop
  750.         ja      .palette2_8bit
  751.         jmp     .convert_done
  752. .palette2_4bit:
  753.         sub     ebx, 1
  754.         jc      .convert_done
  755.         add     esi, 1
  756.         sub     ebx, [.scanline_len]
  757.         jc      .convert_done
  758.         mov     ecx, [.width]
  759.         sub     ecx, [.starting_col]
  760.         mov     [.i], ecx
  761.         mov     [.shift], 0
  762. .palette2_4bit.extloop:
  763.         init_block
  764.         add     eax, edi
  765.         push    eax
  766.         xor     [.shift], 1
  767.         jz      .palette2_4bit.shifted
  768.         mov     al, [esi]
  769.         inc     esi
  770.         shr     al, 4
  771.         jmp     @f
  772. .palette2_4bit.shifted:
  773.         mov     al, [esi-1]
  774.         and     al, 0xF
  775. @@:
  776.         block_byte_innerloop .palette2_4bit.extloop
  777.         ja      .palette2_4bit
  778.         jmp     .convert_done
  779. .palette2_2bit:
  780.         sub     ebx, 1
  781.         jc      .convert_done
  782.         add     esi, 1
  783.         sub     ebx, [.scanline_len]
  784.         jc      .convert_done
  785.         mov     ecx, [.width]
  786.         sub     ecx, [.starting_col]
  787.         mov     [.i], ecx
  788.         mov     [.shift], 0
  789. .palette2_2bit.extloop:
  790.         init_block
  791.         add     eax, edi
  792.         push    eax
  793.         mov     cl, [.shift]
  794.         sub     cl, 2
  795.         jns     .palette2_2bit.shifted
  796.         mov     cl, 6
  797.         mov     al, [esi]
  798.         inc     esi
  799.         shr     al, cl
  800.         jmp     @f
  801. .palette2_2bit.shifted:
  802.         mov     al, [esi-1]
  803.         shr     al, cl
  804.         and     al, 3
  805. @@:
  806.         mov     [.shift], cl
  807.         block_byte_innerloop .palette2_2bit.extloop
  808.         ja      .palette2_2bit
  809.         jmp     .convert_done
  810. .palette2_1bit:
  811.         sub     ebx, 1
  812.         jc      .convert_done
  813.         add     esi, 1
  814.         sub     ebx, [.scanline_len]
  815.         jc      .convert_done
  816.         mov     ecx, [.width]
  817.         sub     ecx, [.starting_col]
  818.         mov     [.i], ecx
  819.         mov     [.shift], 0
  820. .palette2_1bit.extloop:
  821.         init_block
  822.         add     eax, edi
  823.         push    eax
  824.         mov     cl, [.shift]
  825.         dec     cl
  826.         jns     .palette2_1bit.shifted
  827.         mov     cl, 7
  828.         mov     al, [esi]
  829.         inc     esi
  830.         shr     al, cl
  831.         jmp     @f
  832. .palette2_1bit.shifted:
  833.         mov     al, [esi-1]
  834.         shr     al, cl
  835.         and     al, 1
  836. @@:
  837.         mov     [.shift], cl
  838.         block_byte_innerloop .palette2_1bit.extloop
  839.         ja      .palette2_1bit
  840.         jmp     .convert_done
  841. .grayscale2_16bit:
  842.         sub     ebx, 1
  843.         jc      .convert_done
  844.         add     esi, 1
  845.         sub     ebx, [.scanline_len]
  846.         jc      .convert_done
  847.         mov     ecx, [.width]
  848.         sub     ecx, [.starting_col]
  849.         mov     [.i], ecx
  850. .grayscale2_16bit.extloop:
  851.         init_block
  852.         add     eax, edi
  853.         push    eax
  854.         mov     ax, [esi]
  855.         add     esi, 2
  856.         convert_16_to_8
  857.         block_byte_innerloop .grayscale2_16bit.extloop
  858.         ja      .grayscale2_16bit
  859.         jmp     .convert_done
  860. .rgb2:
  861.         cmp     [.bit_depth], 16
  862.         jz      .rgb2_16bit
  863. .rgb2.next:
  864.         sub     ebx, 1
  865.         jc      .convert_done
  866.         add     esi, 1
  867.         sub     ebx, [.scanline_len]
  868.         jc      .convert_done
  869.         mov     ecx, [.width]
  870.         sub     ecx, [.starting_col]
  871.         mov     [.i], ecx
  872. .rgb2.extloop:
  873.         init_block
  874.         lea     eax, [eax*3]
  875.         add     eax, edi
  876.         push    eax
  877. .rgb2.innloop1:
  878.         push    edi
  879.         mov     ecx, ebx
  880. .rgb2.innloop2:
  881.         mov     al, [esi+2]
  882.         mov     [edi], al
  883.         mov     al, [esi+1]
  884.         mov     [edi+1], al
  885.         mov     al, [esi]
  886.         mov     [edi+2], al
  887.         add     edi, 3
  888.         dec     ecx
  889.         jnz     .rgb2.innloop2
  890.         pop     edi
  891.         add     edi, [.row_distance]
  892.         dec     edx
  893.         jnz     .rgb2.innloop1
  894.         pop     edi ebx
  895.         add     esi, 3
  896.         mov     eax, [.col_increment]
  897.         sub     [.i], eax
  898.         ja      .rgb2.extloop
  899.         add     edi, [.col_distance]
  900.         mov     eax, [.row_increment]
  901.         sub     [.j], eax
  902.         ja      .rgb2.next
  903.         jmp     .convert_done
  904. .rgb2_16bit:
  905.         sub     ebx, 1
  906.         jc      .convert_done
  907.         add     esi, 1
  908.         sub     ebx, [.scanline_len]
  909.         jc      .convert_done
  910.         mov     ecx, [.width]
  911.         sub     ecx, [.starting_col]
  912.         mov     [.i], ecx
  913. .rgb2_16bit.extloop:
  914.         init_block
  915.         lea     eax, [eax*3]
  916.         add     eax, edi
  917.         push    eax
  918. .rgb2_16bit.innloop1:
  919.         push    edi
  920.         mov     ecx, ebx
  921. .rgb2_16bit.innloop2:
  922.         mov     ax, [esi+4]
  923.         convert_16_to_8
  924.         mov     [edi], al
  925.         mov     ax, [esi+2]
  926.         convert_16_to_8
  927.         mov     [edi+1], al
  928.         mov     ax, [esi]
  929.         convert_16_to_8
  930.         mov     [edi+2], al
  931.         add     edi, 3
  932.         dec     ecx
  933.         jnz     .rgb2_16bit.innloop2
  934.         pop     edi
  935.         add     edi, [.row_distance]
  936.         dec     edx
  937.         jnz     .rgb2_16bit.innloop1
  938.         pop     edi ebx
  939.         add     esi, 6
  940.         mov     eax, [.col_increment]
  941.         sub     [.i], eax
  942.         ja      .rgb2_16bit.extloop
  943.         add     edi, [.col_distance]
  944.         mov     eax, [.row_increment]
  945.         sub     [.j], eax
  946.         ja      .rgb2_16bit
  947.         jmp     .convert_done
  948. .grayscale_alpha2:
  949.         call    .create_grayscale_palette
  950.         cmp     [.bit_depth], 16
  951.         jz      .grayscale_alpha2_16bit
  952. .grayscale_alpha2.next:
  953.         sub     ebx, 1
  954.         jc      .convert_done
  955.         add     esi, 1
  956.         sub     ebx, [.scanline_len]
  957.         jc      .convert_done
  958.         mov     ecx, [.width]
  959.         sub     ecx, [.starting_col]
  960.         mov     [.i], ecx
  961. .grayscale_alpha2.extloop:
  962.         init_block
  963.         add     eax, edi
  964.         push    eax
  965.         mov     al, [esi]
  966.         add     esi, 2
  967.         block_byte_innerloop .grayscale_alpha2.extloop
  968.         ja      .grayscale_alpha2.next
  969.         jmp     .convert_done
  970. .grayscale_alpha2_16bit:
  971.         sub     ebx, 1
  972.         jc      .convert_done
  973.         add     esi, 1
  974.         sub     ebx, [.scanline_len]
  975.         jc      .convert_done
  976.         mov     ecx, [.width]
  977.         sub     ecx, [.starting_col]
  978.         mov     [.i], ecx
  979. .grayscale_alpha2_16bit.extloop:
  980.         init_block
  981.         add     eax, edi
  982.         push    eax
  983.         mov     ax, [esi]
  984.         add     esi, 4
  985.         convert_16_to_8
  986.         block_byte_innerloop .grayscale_alpha2_16bit.extloop
  987.         ja      .grayscale_alpha2_16bit
  988. .convert_done:
  989. ; next interlace pass
  990. .deinterlace_next:
  991.         mov     eax, [.block_width]
  992.         cmp     eax, [.block_height]
  993.         jz      .deinterlace_dec_width
  994.         mov     [.block_height], eax
  995.         mov     [.col_increment], eax
  996.         dec     [.col_increment_shift]
  997.         mov     [.starting_row], eax
  998.         and     [.starting_col], 0
  999.         jmp     .deinterlace_loop
  1000. .deinterlace_dec_width:
  1001.         shr     eax, 1
  1002.         jz      .deinterlace_done
  1003.         mov     [.block_width], eax
  1004.         mov     [.starting_col], eax
  1005.         add     eax, eax
  1006.         and     [.starting_row], 0
  1007.         mov     [.row_increment], eax
  1008.         bsf     eax, eax
  1009.         mov     [.row_increment_shift], al
  1010.         jmp     .deinterlace_loop
  1011. .deinterlace_done:
  1012.         mcall   68, 13, [.allocated]
  1013.         mov     esi, [.cur_chunk_ptr]
  1014.         add     esi, [.cur_chunk_size]
  1015.         push    [.length]
  1016.         jmp     .next_chunk
  1017.  
  1018. .deflate_callback:
  1019.         mov     ebp, [esp+4]
  1020.         mov     ebx, [esp+8]
  1021.         xor     eax, eax
  1022.         mov     esi, [.cur_chunk_size]
  1023.         mov     [ebx], esi
  1024.         test    esi, esi
  1025.         jz      .deflate_callback.ret
  1026.         mov     eax, [.cur_chunk_ptr]
  1027.         mov     ecx, [.length]
  1028.         add     esi, eax
  1029.         mov     [.cur_chunk_ptr], esi
  1030.         and     [.cur_chunk_size], 0
  1031. @@:
  1032.         sub     ecx, 12
  1033.         jb      .deflate_callback.ret
  1034.         cmp     dword [esi+4+4], 'IDAT'
  1035.         jnz     .deflate_callback.ret
  1036.         mov     edx, [esi+4]
  1037.         bswap   edx
  1038.         sub     ecx, edx
  1039.         jb      .deflate_callback.ret
  1040.         add     esi, 4+8
  1041.         test    edx, edx
  1042.         jz      @b
  1043.         mov     [.cur_chunk_size], edx
  1044.         mov     [.cur_chunk_ptr], esi
  1045.         mov     [.length], ecx
  1046. .deflate_callback.ret:
  1047.         ret     8
  1048.  
  1049. .create_grayscale_palette:
  1050.         push    edi edx
  1051.         mov     edi, [eax + Image.Palette]
  1052.         mov     ecx, [.bit_depth]
  1053.         cmp     cl, 16
  1054.         jnz     @f
  1055.         mov     cl, 8
  1056. @@:
  1057.         push    1
  1058.         pop     eax
  1059.         shl     eax, cl
  1060.         xchg    eax, ecx
  1061.         mov     edx, 0x010101
  1062.         cmp     al, 8
  1063.         jz      .graypal_common
  1064.         mov     edx, 0x111111
  1065.         cmp     al, 4
  1066.         jz      .graypal_common
  1067.         mov     edx, 0x555555
  1068.         cmp     al, 2
  1069.         jz      .graypal_common
  1070.         mov     edx, 0xFFFFFF
  1071. .graypal_common:
  1072.         xor     eax, eax
  1073. @@:
  1074.         stosd
  1075.         add     eax, edx
  1076.         loop    @b
  1077.         pop     edx edi
  1078.         ret
  1079. ;endp
  1080.  
  1081.  
  1082.  
  1083. ;;================================================================================================;;
  1084. align 4
  1085. proc img.encode.png uses ebx edx, _img:dword, _common:dword, _specific:dword
  1086. ;;------------------------------------------------------------------------------------------------;;
  1087. ;? Encode image into raw data in png format                                                       ;;
  1088. ;;------------------------------------------------------------------------------------------------;;
  1089. ;> [_img]      = pointer to image                                                                 ;;
  1090. ;> [_common]   = format independent options                                                       ;;
  1091. ;> [_specific] = 0 / pointer to the structure of format specific options                          ;;
  1092. ;;------------------------------------------------------------------------------------------------;;
  1093. ;< eax = 0 / pointer to encoded data                                                              ;;
  1094. ;< ecx = error code / the size of encoded data                                                    ;;
  1095. ;;================================================================================================;;
  1096. locals
  1097.         encoded_file rd 1
  1098.         encoded_file_size rd 1
  1099.         simag png_image
  1100. endl
  1101.         mov ebx,[_img]
  1102.         mov     eax,[ebx+Image.Type]
  1103.         cmp     eax,Image.bpp24
  1104.         je @f
  1105.                 mov     ecx,LIBIMG_ERROR_BIT_DEPTH
  1106.                 jmp     .error
  1107.         @@:
  1108.  
  1109.         mov edx,ebp
  1110.         sub edx,sizeof.png_image
  1111.         mov dword[edx+png_image.version],PNG_IMAGE_VERSION
  1112.         mov ecx,[ebx+Image.Width]
  1113.         mov [edx+png_image.width],ecx ;Image width in pixels (columns)
  1114.         mov eax,[ebx+Image.Height]
  1115.         mov [edx+png_image.height],eax ;Image height in pixels (rows)
  1116.         mov dword[edx+png_image.format],PNG_COLOR_TYPE_RGB
  1117.         ;mov dword[edx+png_image.flags],PNG_IMAGE_FLAG_???
  1118.  
  1119.         imul ecx,3
  1120.         mov edi,ecx
  1121.         imul edi,[ebx+Image.Height]
  1122.         mov [encoded_file_size],edi
  1123.         stdcall [mem.alloc],edi
  1124.         test eax,eax
  1125.         jnz     @f
  1126.                 mov     ecx,LIBIMG_ERROR_OUT_OF_MEMORY
  1127.                 jmp     .error
  1128.     @@:
  1129.         mov [encoded_file],eax
  1130.         mov edi,edx
  1131.         sub edi,4
  1132.         stdcall png_image_write_to_memory, edx,eax,edi,0,[ebx+Image.Data],ecx,0
  1133.         mov     eax,[encoded_file]
  1134.         mov     ecx,[encoded_file_size]
  1135.         jmp     .quit
  1136.  
  1137. .error:
  1138.         xor     eax,eax
  1139. .quit:
  1140.         ret
  1141. endp