Subversion Repositories Kolibri OS

Rev

Rev 8341 | Rev 8449 | 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.         mov     al, 0xff
  284.         ror     eax, 8
  285.         stosd
  286.         jmp     @b
  287. @@:
  288.         lodsd
  289.         dec     esi
  290.         bswap   eax
  291.         shr     eax, 8
  292.         stosd
  293.         jmp     .next_chunk
  294. .idat:
  295.         jecxz   .next_chunk
  296.         cmp     [.idat_read], 0
  297.         jnz     @f
  298.         lodsb
  299.         inc     [.idat_read]
  300.         and     al, 0xF
  301.         cmp     al, 8
  302.         jnz     .invalid_chunk
  303.         dec     ecx
  304.         jz      .next_chunk
  305. @@:
  306.         cmp     [.idat_read], 1
  307.         jnz     @f
  308.         lodsb
  309.         inc     [.idat_read]
  310.         test    al, 20h
  311.         jnz     .invalid_chunk
  312.         dec     ecx
  313.         jz      .next_chunk
  314. @@:
  315.         mov     [.cur_chunk_ptr], esi
  316.         mov     [.cur_chunk_size], ecx
  317.         pop     [.length]
  318.         push    eax
  319.         push    esp
  320.         push    ebp
  321.         push    .deflate_callback
  322.         call    [deflate_unpack2]
  323.         pop     ecx
  324.         test    eax, eax
  325.         jz      .invalid_chunk
  326. ; convert PNG unpacked data to RAW data
  327.         mov     esi, eax
  328.         mov     [.allocated], eax
  329.         mov     [.size_rest], ecx
  330. ; unfilter and deinterlace
  331. ; .interlace_pass, .starting_row and .starting_col have been already set to 0
  332. ; .block_width, .block_height, .col_increment, .row_increment were set
  333. ; to values for non-interlaced images; correct if necessary
  334.         cmp     [.interlace], 0
  335.         jz      .deinterlace_loop
  336.         push    8
  337.         pop     eax
  338.         mov     [.row_increment], eax
  339.         mov     [.col_increment], eax
  340.         mov     [.block_height], eax
  341.         mov     [.block_width], eax
  342.         mov     [.row_increment_shift], 3
  343.         mov     [.col_increment_shift], 3
  344. .deinterlace_loop:
  345.         mov     edx, [.height]
  346.         cmp     edx, [.starting_row]
  347.         jbe     .deinterlace_next
  348.         mov     ebx, [.width]
  349.         sub     ebx, [.starting_col]
  350.         jbe     .deinterlace_next
  351.         mov     cl, [.col_increment_shift]
  352.         add     ebx, [.col_increment]
  353.         dec     ebx
  354.         shr     ebx, cl
  355.         mov     eax, [.bits_per_pixel]
  356.         imul    eax, ebx
  357.         add     eax, 7
  358.         shr     eax, 3
  359.         mov     [.scanline_len], eax
  360.         shl     ebx, cl
  361.         mov     [.col_distance], ebx
  362. ; Unfilter
  363.         mov     ecx, [.size_rest]
  364.         push    esi
  365. .unfilter_loop_e:
  366.         mov     ebx, [.scanline_len]
  367.         sub     ecx, 1
  368.         jc      .unfilter_abort
  369.         sub     ecx, ebx
  370.         jc      .unfilter_abort
  371.         movzx   eax, byte [esi]
  372.         add     esi, 1
  373.         cmp     eax, 4
  374.         ja      .next_scanline
  375.         jmp     dword [@f + eax*4]
  376. align 4
  377. @@:
  378.         dd      .unfilter_none
  379.         dd      .unfilter_sub
  380.         dd      .unfilter_up
  381.         dd      .unfilter_average
  382.         dd      .unfilter_paeth
  383. .unfilter_sub:
  384.         mov     edi, [.bytes_per_pixel]
  385.         add     esi, edi
  386.         sub     ebx, edi
  387.         jbe     .next_scanline
  388.         neg     edi
  389. @@:
  390.         mov     al, [esi+edi]
  391.         add     [esi], al
  392.         add     esi, 1
  393.         sub     ebx, 1
  394.         jnz     @b
  395.         jmp     .next_scanline
  396. .unfilter_up:
  397.         cmp     edx, [.height]
  398.         jz      .unfilter_none
  399.         lea     edi, [ebx+1]
  400.         neg     edi
  401. @@:
  402.         mov     al, [esi+edi]
  403.         add     [esi], al
  404.         add     esi, 1
  405.         sub     ebx, 1
  406.         jnz     @b
  407.         jmp     .next_scanline
  408. .unfilter_average:
  409.         mov     edi, [.bytes_per_pixel]
  410.         cmp     edx, [.height]
  411.         jz      .unfilter_average_firstline
  412.         push    edx
  413.         lea     edx, [ebx+1]
  414.         neg     edx
  415.         sub     ebx, edi
  416. @@:
  417.         mov     al, [esi+edx]
  418.         shr     al, 1
  419.         add     [esi], al
  420.         add     esi, 1
  421.         sub     edi, 1
  422.         jnz     @b
  423.         mov     edi, [.bytes_per_pixel]
  424.         neg     edi
  425.         test    ebx, ebx
  426.         jz      .unfilter_average_done
  427. @@:
  428.         mov     al, [esi+edx]
  429.         add     al, [esi+edi]
  430.         rcr     al, 1
  431.         add     [esi], al
  432.         add     esi, 1
  433.         sub     ebx, 1
  434.         jnz     @b
  435. .unfilter_average_done:
  436.         pop     edx
  437.         jmp     .next_scanline
  438. .unfilter_average_firstline:
  439.         mov     edi, [.bytes_per_pixel]
  440.         add     esi, edi
  441.         sub     ebx, edi
  442.         jbe     .next_scanline
  443.         neg     edi
  444. @@:
  445.         mov     al, [esi+edi]
  446.         shr     al, 1
  447.         add     [esi], al
  448.         add     esi, 1
  449.         sub     ebx, 1
  450.         jnz     @b
  451.         jmp     .unfilter_none
  452. .unfilter_paeth:
  453.         cmp     edx, [.height]
  454.         jz      .unfilter_sub
  455.         push    edx
  456.         lea     edx, [ebx+1]
  457.         mov     edi, [.bytes_per_pixel]
  458.         neg     edx
  459.         sub     ebx, edi
  460. @@:
  461.         mov     al, [esi+edx]
  462.         add     [esi], al
  463.         add     esi, 1
  464.         sub     edi, 1
  465.         jnz     @b
  466.         mov     edi, [.bytes_per_pixel]
  467.         neg     edi
  468.         test    ebx, ebx
  469.         jz      .unfilter_paeth_done
  470.         push    ecx
  471. @@:
  472.         push    ebx
  473. ; PaethPredictor(Raw(x-bpp) = a, Prior(x) = b, Prior(x-bpp) = c)
  474.         movzx   eax, byte [esi+edi]
  475.         mov     [.paeth_a], eax
  476.         movzx   ecx, byte [esi+edx]
  477.         add     edi, edx
  478.         mov     [.paeth_b], ecx
  479.         add     ecx, eax
  480.         movzx   eax, byte [esi+edi]
  481.         mov     [.paeth_c], eax
  482.         sub     ecx, eax        ; ecx = a + b - c = p
  483. ; calculate pa = abs(p-a), pb = abs(p-b), pc = abs(p-c)
  484.         mov     ebx, ecx
  485.         sub     ebx, eax        ; ebx = p - c
  486.         cmp     ebx, 80000000h
  487.         sbb     eax, eax        ; eax = (p < c) ? 0 : 0xFFFFFFF
  488.         not     eax             ; eax = (p < c) ? 0xFFFFFFFF : 0
  489.         and     eax, ebx        ; eax = (p < c) ? p - c : 0
  490.         sub     ebx, eax
  491.         sub     ebx, eax        ; ebx = abs(p-c)
  492.         mov     [.paeth_pc], ebx
  493.         mov     ebx, ecx
  494.         sub     ebx, [.paeth_a]
  495.         cmp     ebx, 80000000h
  496.         sbb     eax, eax
  497.         not     eax
  498.         and     eax, ebx
  499.         sub     ebx, eax
  500.         sub     ebx, eax
  501.         mov     [.paeth_pa], ebx
  502.         mov     ebx, ecx
  503.         sub     ebx, [.paeth_b]
  504.         cmp     ebx, 80000000h
  505.         sbb     eax, eax
  506.         not     eax
  507.         and     eax, ebx
  508.         sub     ebx, eax
  509.         sub     ebx, eax
  510.         ;mov    [.paeth_pb], ebx
  511. ; select closest value
  512.         push    edx
  513.         mov     edx, [.paeth_b]
  514.         sub     edx, [.paeth_a]
  515.         sub     ebx, [.paeth_pa]
  516.         sbb     ecx, ecx        ; ecx = (pa > pb) ? 0xFFFFFFFF : 0
  517.         sbb     eax, eax        ; eax = (pa > pb) ? 0xFFFFFFFF : 0
  518.         and     ecx, ebx        ; ecx = (pa > pb) ? pb - pa : 0
  519.         and     eax, edx        ; eax = (pa > pb) ? b - a : 0
  520.         add     ecx, [.paeth_pa]        ; ecx = (pa > pb) ? pb : pa = min(pa,pb)
  521.         add     eax, [.paeth_a]         ; eax = (pa > pb) ? b : a
  522.         mov     edx, [.paeth_c]
  523.         sub     edx, eax
  524.         sub     [.paeth_pc], ecx
  525.         sbb     ebx, ebx        ; ebx = (min(pa,pb) <= pc) ? 0 : 0xFFFFFFFF
  526.         and     ebx, edx        ; ebx = (min(pa,pb) <= pc) ? 0 : c - eax
  527.         add     eax, ebx
  528.         pop     edx
  529.         add     [esi], al
  530.         pop     ebx
  531.         sub     edi, edx
  532.         add     esi, 1
  533.         sub     ebx, 1
  534.         jnz     @b
  535.         pop     ecx
  536. .unfilter_paeth_done:
  537.         pop     edx
  538.         jmp     .next_scanline
  539. .unfilter_none:
  540.         add     esi, ebx
  541. .next_scanline:
  542.         sub     edx, [.row_increment]
  543.         jc      .unfilter_done
  544.         cmp     edx, [.starting_row]
  545.         jbe     .unfilter_done
  546.         jmp     .unfilter_loop_e
  547. .unfilter_abort:
  548.         xor     ecx, ecx
  549. .unfilter_done:
  550. ; unfiltering done, now convert to raw data
  551. ; with deinterlacing if needed
  552.         pop     esi
  553.         mov     ebx, [.image]
  554.         mov     eax, [.width]
  555.         call    img._.get_scanline_len
  556.         mov     [.row_distance], eax
  557.         mov     eax, [.row_increment]
  558.         mul     [.width]
  559.         sub     eax, [.col_distance]
  560.         call    img._.get_scanline_len
  561.         mov     [.col_distance], eax
  562.         mov     edi, [ebx + Image.Data]
  563.         mov     eax, [.starting_row]
  564.         mul     [.width]
  565.         add     eax, [.starting_col]
  566.         call    img._.get_scanline_len
  567.         add     edi, eax
  568.         mov     eax, ebx
  569.         mov     ebx, [.size_rest]
  570.         mov     [.size_rest], ecx
  571.         mov     edx, [.height]
  572.         sub     edx, [.starting_row]
  573.         mov     [.j], edx
  574.         cmp     [.color_type], 0
  575.         jz      .grayscale2
  576.         cmp     [.color_type], 2
  577.         jz      .rgb2
  578.         cmp     [.color_type], 3
  579.         jz      .palette2
  580.         cmp     [.color_type], 4
  581.         jz      .grayscale_alpha2
  582. .rgb_alpha2:
  583.         cmp     [.bit_depth], 16
  584.         jz      .rgb_alpha2_16bit
  585. .rgb_alpha2.next:
  586.         sub     ebx, 1
  587.         jc      .convert_done
  588.         add     esi, 1
  589.         sub     ebx, [.scanline_len]
  590.         jc      .convert_done
  591.         mov     ecx, [.width]
  592.         sub     ecx, [.starting_col]
  593.         mov     [.i], ecx
  594. .rgb_alpha2.extloop:
  595.  
  596. macro init_block
  597. {
  598.         push    ebx
  599.         mov     eax, [.col_increment]
  600.         mov     edx, [.j]
  601.         cmp     edx, [.block_height]
  602.         jb      @f
  603.         mov     edx, [.block_height]
  604. @@:
  605.         mov     ebx, [.i]
  606.         cmp     ebx, [.block_width]
  607.         jb      @f
  608.         mov     ebx, [.block_width]
  609. @@:
  610. }
  611.  
  612.         init_block
  613.         lea     eax, [edi+eax*4]
  614.         push    eax
  615. .rgb_alpha2.innloop1:
  616.         push    edi
  617.         mov     ecx, ebx
  618. .rgb_alpha2.innloop2:
  619.         mov     al, [esi+2]
  620.         mov     [edi], al
  621.         mov     al, [esi+1]
  622.         mov     [edi+1], al
  623.         mov     al, [esi]
  624.         mov     [edi+2], al
  625.         mov     al, [esi+3]
  626.         mov     [edi+3], al
  627.         add     edi, 4
  628.         dec     ecx
  629.         jnz     .rgb_alpha2.innloop2
  630.         pop     edi
  631.         add     edi, [.row_distance]
  632.         dec     edx
  633.         jnz     .rgb_alpha2.innloop1
  634.         pop     edi ebx
  635.         add     esi, 4
  636.         mov     eax, [.col_increment]
  637.         sub     [.i], eax
  638.         ja      .rgb_alpha2.extloop
  639.         add     edi, [.col_distance]
  640.         mov     eax, [.row_increment]
  641.         sub     [.j], eax
  642.         ja      .rgb_alpha2.next
  643.         jmp     .convert_done
  644. .rgb_alpha2_16bit:
  645.         sub     ebx, 1
  646.         jc      .convert_done
  647.         add     esi, 1
  648.         sub     ebx, [.scanline_len]
  649.         jc      .convert_done
  650.         mov     ecx, [.width]
  651.         sub     ecx, [.starting_col]
  652.         mov     [.i], ecx
  653. .rgb_alpha2_16bit.loop:
  654.         init_block
  655.         lea     eax, [edi+eax*4]
  656.         push    eax
  657.  
  658. ; convert 16 bit sample to 8 bit sample
  659. macro convert_16_to_8
  660. {
  661. local .l1,.l2
  662.         xor     ah, 0x80
  663.         js      .l1
  664.         cmp     al, ah
  665.         adc     al, 0
  666.         jmp     .l2
  667. .l1:
  668.         cmp     ah, al
  669.         sbb     al, 0
  670. .l2:
  671. }
  672.  
  673. .rgb_alpha2_16bit.innloop1:
  674.         push    edi
  675.         mov     ecx, ebx
  676. .rgb_alpha2_16bit.innloop2:
  677.         mov     ax, [esi+4]
  678.         convert_16_to_8
  679.         mov     [edi], al
  680.         mov     ax, [esi+2]
  681.         convert_16_to_8
  682.         mov     [edi+1], al
  683.         mov     ax, [esi]
  684.         convert_16_to_8
  685.         mov     [edi+2], al
  686.         ;mov    ax, [esi+6]
  687.         ;convert_16_to_8
  688.         ;mov    [edi+3], al
  689.         add     edi, 4
  690.         dec     ecx
  691.         jnz     .rgb_alpha2_16bit.innloop2
  692.         pop     edi
  693.         add     edi, [.row_distance]
  694.         dec     edx
  695.         jnz     .rgb_alpha2_16bit.innloop1
  696.         pop     edi ebx
  697.         add     esi, 8
  698.         mov     eax, [.col_increment]
  699.         sub     [.i], eax
  700.         ja      .rgb_alpha2_16bit.loop
  701.         add     edi, [.col_distance]
  702.         mov     eax, [.row_increment]
  703.         sub     [.j], eax
  704.         ja      .rgb_alpha2_16bit
  705.         jmp     .convert_done
  706. .grayscale2:
  707.         call    .create_grayscale_palette
  708.         cmp     [.bit_depth], 16
  709.         jz      .grayscale2_16bit
  710. .palette2:
  711.         cmp     [.bit_depth], 1
  712.         jz      .palette2_1bit
  713.         cmp     [.bit_depth], 2
  714.         jz      .palette2_2bit
  715.         cmp     [.bit_depth], 4
  716.         jz      .palette2_4bit
  717. .palette2_8bit:
  718.         sub     ebx, 1
  719.         jc      .convert_done
  720.         add     esi, 1
  721.         sub     ebx, [.scanline_len]
  722.         jc      .convert_done
  723.         mov     ecx, [.width]
  724.         sub     ecx, [.starting_col]
  725.         mov     [.i], ecx
  726. .palette2_8bit.extloop:
  727.         init_block
  728.         add     eax, edi
  729.         push    eax
  730.         mov     al, [esi]
  731.         inc     esi
  732. macro block_byte_innerloop extloop
  733. {
  734. local .l1
  735. .l1:
  736.         mov     ecx, ebx
  737.         rep     stosb
  738.         sub     edi, ebx
  739.         add     edi, [.row_distance]
  740.         dec     edx
  741.         jnz     .l1
  742.         pop     edi ebx
  743.         mov     eax, [.col_increment]
  744.         sub     [.i], eax
  745.         ja      extloop
  746.         add     edi, [.col_distance]
  747.         mov     eax, [.row_increment]
  748.         sub     [.j], eax
  749. }
  750.         block_byte_innerloop .palette2_8bit.extloop
  751.         ja      .palette2_8bit
  752.         jmp     .convert_done
  753. .palette2_4bit:
  754.         sub     ebx, 1
  755.         jc      .convert_done
  756.         add     esi, 1
  757.         sub     ebx, [.scanline_len]
  758.         jc      .convert_done
  759.         mov     ecx, [.width]
  760.         sub     ecx, [.starting_col]
  761.         mov     [.i], ecx
  762.         mov     [.shift], 0
  763. .palette2_4bit.extloop:
  764.         init_block
  765.         add     eax, edi
  766.         push    eax
  767.         xor     [.shift], 1
  768.         jz      .palette2_4bit.shifted
  769.         mov     al, [esi]
  770.         inc     esi
  771.         shr     al, 4
  772.         jmp     @f
  773. .palette2_4bit.shifted:
  774.         mov     al, [esi-1]
  775.         and     al, 0xF
  776. @@:
  777.         block_byte_innerloop .palette2_4bit.extloop
  778.         ja      .palette2_4bit
  779.         jmp     .convert_done
  780. .palette2_2bit:
  781.         sub     ebx, 1
  782.         jc      .convert_done
  783.         add     esi, 1
  784.         sub     ebx, [.scanline_len]
  785.         jc      .convert_done
  786.         mov     ecx, [.width]
  787.         sub     ecx, [.starting_col]
  788.         mov     [.i], ecx
  789.         mov     [.shift], 0
  790. .palette2_2bit.extloop:
  791.         init_block
  792.         add     eax, edi
  793.         push    eax
  794.         mov     cl, [.shift]
  795.         sub     cl, 2
  796.         jns     .palette2_2bit.shifted
  797.         mov     cl, 6
  798.         mov     al, [esi]
  799.         inc     esi
  800.         shr     al, cl
  801.         jmp     @f
  802. .palette2_2bit.shifted:
  803.         mov     al, [esi-1]
  804.         shr     al, cl
  805.         and     al, 3
  806. @@:
  807.         mov     [.shift], cl
  808.         block_byte_innerloop .palette2_2bit.extloop
  809.         ja      .palette2_2bit
  810.         jmp     .convert_done
  811. .palette2_1bit:
  812.         sub     ebx, 1
  813.         jc      .convert_done
  814.         add     esi, 1
  815.         sub     ebx, [.scanline_len]
  816.         jc      .convert_done
  817.         mov     ecx, [.width]
  818.         sub     ecx, [.starting_col]
  819.         mov     [.i], ecx
  820.         mov     [.shift], 0
  821. .palette2_1bit.extloop:
  822.         init_block
  823.         add     eax, edi
  824.         push    eax
  825.         mov     cl, [.shift]
  826.         dec     cl
  827.         jns     .palette2_1bit.shifted
  828.         mov     cl, 7
  829.         mov     al, [esi]
  830.         inc     esi
  831.         shr     al, cl
  832.         jmp     @f
  833. .palette2_1bit.shifted:
  834.         mov     al, [esi-1]
  835.         shr     al, cl
  836.         and     al, 1
  837. @@:
  838.         mov     [.shift], cl
  839.         block_byte_innerloop .palette2_1bit.extloop
  840.         ja      .palette2_1bit
  841.         jmp     .convert_done
  842. .grayscale2_16bit:
  843.         sub     ebx, 1
  844.         jc      .convert_done
  845.         add     esi, 1
  846.         sub     ebx, [.scanline_len]
  847.         jc      .convert_done
  848.         mov     ecx, [.width]
  849.         sub     ecx, [.starting_col]
  850.         mov     [.i], ecx
  851. .grayscale2_16bit.extloop:
  852.         init_block
  853.         add     eax, edi
  854.         push    eax
  855.         mov     ax, [esi]
  856.         add     esi, 2
  857.         convert_16_to_8
  858.         block_byte_innerloop .grayscale2_16bit.extloop
  859.         ja      .grayscale2_16bit
  860.         jmp     .convert_done
  861. .rgb2:
  862.         cmp     [.bit_depth], 16
  863.         jz      .rgb2_16bit
  864. .rgb2.next:
  865.         sub     ebx, 1
  866.         jc      .convert_done
  867.         add     esi, 1
  868.         sub     ebx, [.scanline_len]
  869.         jc      .convert_done
  870.         mov     ecx, [.width]
  871.         sub     ecx, [.starting_col]
  872.         mov     [.i], ecx
  873. .rgb2.extloop:
  874.         init_block
  875.         lea     eax, [eax*3]
  876.         add     eax, edi
  877.         push    eax
  878. .rgb2.innloop1:
  879.         push    edi
  880.         mov     ecx, ebx
  881. .rgb2.innloop2:
  882.         mov     al, [esi+2]
  883.         mov     [edi], al
  884.         mov     al, [esi+1]
  885.         mov     [edi+1], al
  886.         mov     al, [esi]
  887.         mov     [edi+2], al
  888.         add     edi, 3
  889.         dec     ecx
  890.         jnz     .rgb2.innloop2
  891.         pop     edi
  892.         add     edi, [.row_distance]
  893.         dec     edx
  894.         jnz     .rgb2.innloop1
  895.         pop     edi ebx
  896.         add     esi, 3
  897.         mov     eax, [.col_increment]
  898.         sub     [.i], eax
  899.         ja      .rgb2.extloop
  900.         add     edi, [.col_distance]
  901.         mov     eax, [.row_increment]
  902.         sub     [.j], eax
  903.         ja      .rgb2.next
  904.         jmp     .convert_done
  905. .rgb2_16bit:
  906.         sub     ebx, 1
  907.         jc      .convert_done
  908.         add     esi, 1
  909.         sub     ebx, [.scanline_len]
  910.         jc      .convert_done
  911.         mov     ecx, [.width]
  912.         sub     ecx, [.starting_col]
  913.         mov     [.i], ecx
  914. .rgb2_16bit.extloop:
  915.         init_block
  916.         lea     eax, [eax*3]
  917.         add     eax, edi
  918.         push    eax
  919. .rgb2_16bit.innloop1:
  920.         push    edi
  921.         mov     ecx, ebx
  922. .rgb2_16bit.innloop2:
  923.         mov     ax, [esi+4]
  924.         convert_16_to_8
  925.         mov     [edi], al
  926.         mov     ax, [esi+2]
  927.         convert_16_to_8
  928.         mov     [edi+1], al
  929.         mov     ax, [esi]
  930.         convert_16_to_8
  931.         mov     [edi+2], al
  932.         add     edi, 3
  933.         dec     ecx
  934.         jnz     .rgb2_16bit.innloop2
  935.         pop     edi
  936.         add     edi, [.row_distance]
  937.         dec     edx
  938.         jnz     .rgb2_16bit.innloop1
  939.         pop     edi ebx
  940.         add     esi, 6
  941.         mov     eax, [.col_increment]
  942.         sub     [.i], eax
  943.         ja      .rgb2_16bit.extloop
  944.         add     edi, [.col_distance]
  945.         mov     eax, [.row_increment]
  946.         sub     [.j], eax
  947.         ja      .rgb2_16bit
  948.         jmp     .convert_done
  949. .grayscale_alpha2:
  950.         call    .create_grayscale_palette
  951.         cmp     [.bit_depth], 16
  952.         jz      .grayscale_alpha2_16bit
  953. .grayscale_alpha2.next:
  954.         sub     ebx, 1
  955.         jc      .convert_done
  956.         add     esi, 1
  957.         sub     ebx, [.scanline_len]
  958.         jc      .convert_done
  959.         mov     ecx, [.width]
  960.         sub     ecx, [.starting_col]
  961.         mov     [.i], ecx
  962. .grayscale_alpha2.extloop:
  963.         init_block
  964.         add     eax, edi
  965.         push    eax
  966.         mov     al, [esi]
  967.         add     esi, 2
  968.         block_byte_innerloop .grayscale_alpha2.extloop
  969.         ja      .grayscale_alpha2.next
  970.         jmp     .convert_done
  971. .grayscale_alpha2_16bit:
  972.         sub     ebx, 1
  973.         jc      .convert_done
  974.         add     esi, 1
  975.         sub     ebx, [.scanline_len]
  976.         jc      .convert_done
  977.         mov     ecx, [.width]
  978.         sub     ecx, [.starting_col]
  979.         mov     [.i], ecx
  980. .grayscale_alpha2_16bit.extloop:
  981.         init_block
  982.         add     eax, edi
  983.         push    eax
  984.         mov     ax, [esi]
  985.         add     esi, 4
  986.         convert_16_to_8
  987.         block_byte_innerloop .grayscale_alpha2_16bit.extloop
  988.         ja      .grayscale_alpha2_16bit
  989. .convert_done:
  990. ; next interlace pass
  991. .deinterlace_next:
  992.         mov     eax, [.block_width]
  993.         cmp     eax, [.block_height]
  994.         jz      .deinterlace_dec_width
  995.         mov     [.block_height], eax
  996.         mov     [.col_increment], eax
  997.         dec     [.col_increment_shift]
  998.         mov     [.starting_row], eax
  999.         and     [.starting_col], 0
  1000.         jmp     .deinterlace_loop
  1001. .deinterlace_dec_width:
  1002.         shr     eax, 1
  1003.         jz      .deinterlace_done
  1004.         mov     [.block_width], eax
  1005.         mov     [.starting_col], eax
  1006.         add     eax, eax
  1007.         and     [.starting_row], 0
  1008.         mov     [.row_increment], eax
  1009.         bsf     eax, eax
  1010.         mov     [.row_increment_shift], al
  1011.         jmp     .deinterlace_loop
  1012. .deinterlace_done:
  1013.         mcall   68, 13, [.allocated]
  1014.         mov     esi, [.cur_chunk_ptr]
  1015.         add     esi, [.cur_chunk_size]
  1016.         push    [.length]
  1017.         jmp     .next_chunk
  1018.  
  1019. .deflate_callback:
  1020.         mov     ebp, [esp+4]
  1021.         mov     ebx, [esp+8]
  1022.         xor     eax, eax
  1023.         mov     esi, [.cur_chunk_size]
  1024.         mov     [ebx], esi
  1025.         test    esi, esi
  1026.         jz      .deflate_callback.ret
  1027.         mov     eax, [.cur_chunk_ptr]
  1028.         mov     ecx, [.length]
  1029.         add     esi, eax
  1030.         mov     [.cur_chunk_ptr], esi
  1031.         and     [.cur_chunk_size], 0
  1032. @@:
  1033.         sub     ecx, 12
  1034.         jb      .deflate_callback.ret
  1035.         cmp     dword [esi+4+4], 'IDAT'
  1036.         jnz     .deflate_callback.ret
  1037.         mov     edx, [esi+4]
  1038.         bswap   edx
  1039.         sub     ecx, edx
  1040.         jb      .deflate_callback.ret
  1041.         add     esi, 4+8
  1042.         test    edx, edx
  1043.         jz      @b
  1044.         mov     [.cur_chunk_size], edx
  1045.         mov     [.cur_chunk_ptr], esi
  1046.         mov     [.length], ecx
  1047. .deflate_callback.ret:
  1048.         ret     8
  1049.  
  1050. .create_grayscale_palette:
  1051.         push    edi edx
  1052.         mov     edi, [eax + Image.Palette]
  1053.         mov     ecx, [.bit_depth]
  1054.         cmp     cl, 16
  1055.         jnz     @f
  1056.         mov     cl, 8
  1057. @@:
  1058.         push    1
  1059.         pop     eax
  1060.         shl     eax, cl
  1061.         xchg    eax, ecx
  1062.         mov     edx, 0x010101
  1063.         cmp     al, 8
  1064.         jz      .graypal_common
  1065.         mov     edx, 0x111111
  1066.         cmp     al, 4
  1067.         jz      .graypal_common
  1068.         mov     edx, 0x555555
  1069.         cmp     al, 2
  1070.         jz      .graypal_common
  1071.         mov     edx, 0xFFFFFF
  1072. .graypal_common:
  1073.         xor     eax, eax
  1074. @@:
  1075.         stosd
  1076.         add     eax, edx
  1077.         loop    @b
  1078.         pop     edx edi
  1079.         ret
  1080. ;endp
  1081.  
  1082.  
  1083.  
  1084. ;;================================================================================================;;
  1085. align 4
  1086. proc img.encode.png uses ebx edx, _img:dword, _common:dword, _specific:dword
  1087. ;;------------------------------------------------------------------------------------------------;;
  1088. ;? Encode image into raw data in png format                                                       ;;
  1089. ;;------------------------------------------------------------------------------------------------;;
  1090. ;> [_img]      = pointer to image                                                                 ;;
  1091. ;> [_common]   = format independent options                                                       ;;
  1092. ;> [_specific] = 0 / pointer to the structure of format specific options                          ;;
  1093. ;;------------------------------------------------------------------------------------------------;;
  1094. ;< eax = 0 / pointer to encoded data                                                              ;;
  1095. ;< ecx = error code / the size of encoded data                                                    ;;
  1096. ;;================================================================================================;;
  1097. locals
  1098.         encoded_file rd 1
  1099.         encoded_file_size rd 1
  1100.         simag png_image
  1101. endl
  1102.         mov ebx,[_img]
  1103.         mov     eax,[ebx+Image.Type]
  1104.         cmp     eax,Image.bpp24
  1105.         je @f
  1106.                 mov     ecx,LIBIMG_ERROR_BIT_DEPTH
  1107.                 jmp     .error
  1108.         @@:
  1109.  
  1110.         mov edx,ebp
  1111.         sub edx,sizeof.png_image
  1112.         mov dword[edx+png_image.version],PNG_IMAGE_VERSION
  1113.         mov ecx,[ebx+Image.Width]
  1114.         mov [edx+png_image.width],ecx ;Image width in pixels (columns)
  1115.         mov eax,[ebx+Image.Height]
  1116.         mov [edx+png_image.height],eax ;Image height in pixels (rows)
  1117.         mov dword[edx+png_image.format],PNG_COLOR_TYPE_RGB
  1118.         ;mov dword[edx+png_image.flags],PNG_IMAGE_FLAG_???
  1119.  
  1120.         imul ecx,3
  1121.         mov edi,ecx
  1122.         imul edi,[ebx+Image.Height]
  1123.         cmp edi,4096
  1124.         jge @f
  1125.                 mov edi,4096 ;minimum memory size
  1126.         @@:
  1127.         mov [encoded_file_size],edi
  1128.         stdcall [mem.alloc],edi
  1129.         test eax,eax
  1130.         jnz     @f
  1131.                 mov     ecx,LIBIMG_ERROR_OUT_OF_MEMORY
  1132.                 jmp     .error
  1133.     @@:
  1134.         mov [encoded_file],eax
  1135.         mov edi,edx
  1136.         sub edi,4
  1137.         stdcall png_image_write_to_memory, edx,eax,edi,0,[ebx+Image.Data],ecx,0
  1138.         mov     eax,[encoded_file]
  1139.         mov     ecx,[encoded_file_size]
  1140.         jmp     .quit
  1141.  
  1142. .error:
  1143.         xor     eax,eax
  1144. .quit:
  1145.         ret
  1146. endp
  1147.