X86 bmp fading with linear interpolation

Challenge: Thicken the top of the 24 Bpp.BMP image to white so that each pixel color is linearly interpolated between its original color and white based on its distance from the top edge. Distance pixels> = dist have not disappeared.

I created all the code and tried to guess something. It only seems to work for distances that have a power of 2, so 32,64,128, etc. I am using linear interpolation equality and I have no idea why it doesn't work for other numbers. Any ideas?:.)

Image example:

before

After fading away, I get ... after

global fadetop

; parm.
%define     img         [ebp+8]
%define     width       [ebp+12]
%define     height      [ebp+16]
%define     dist        [ebp+20]
; local
%define     row_bytes      [ebp-4]
%define     dist_counter   [ebp-8]

fadetop:
; create stack frame
push    ebp
mov     ebp, esp
sub     esp, 8

; push register on stack
push    ebx
push    esi
push    edi

; calculate size of row 
mov     edx, width              
lea     edx, [edx+edx*2]        
add     edx, 3                  
and     edx, 0fffffffch         
mov     row_bytes, edx          

; address of datas -calculations to write pixels from top left corner
mov eax,height
mul edx
sub eax ,row_bytes
add eax,3
mov     esi, img
add esi,eax

;line couter 

xor edx, edx
mov dist_counter , edx
line:    
; pixel counter in line 
mov     edi, width

; index rexister 
xor     ebx, ebx

; INTERPOlATION STARTS NOW !!!


convert:                                  
movzx   eax, byte [esi+ebx+0]   ; take color 1
sub     eax, 255        ; sub white value
mov     ecx, dist_counter   
imul    ecx         ;color * actual position  
cdq
mov     ecx, dist       ; devide by full fade operation distance 
idiv    ecx
add     eax, 255        ; add 255 
mov     [esi+ebx+0], al     ;put in this place  

movzx   eax,byte [esi+ebx+1]    ; take color 2
sub     eax, 255
mov     ecx , dist_counter
mul     ecx
cdq
mov     ecx, dist
div     ecx
add     eax, 255
mov     [esi+ebx+1], al

movzx   eax,byte [esi+ebx+2]    ; take color 3
sub     eax, 255
mov     ecx , dist_counter
mul     ecx
cdq
mov     ecx, dist
div     ecx
add     eax, 255
mov     [esi+ebx+2], al

;________________________________________________________________
                    ;if still in one line 
    add     ebx, 3
    dec     edi
    jnz     convert

                        ; if next line 
sub     esi, row_bytes
mov     edx,dist_counter
inc     edx
mov     dist_counter,edx
mov     eax, dist
cmp     eax, edx      
jnz     line


    ; pop registers
    pop     edi
    pop     esi
    pop     ebx

    ; return trace         
    mov     esp, ebp
    pop     ebp
    ret

      

code in C for those who would like to run it and try fading out:

#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

void fadetop(void* img, int width, int height ,int dist );

int main (int argc, char** argv) {

    char* buff;

    if (argc != 3 ) {
        printf("Use file: %s [file]\n",argv[0]);
        return 1;

    }

    struct stat st;
    stat(argv[1], &st);

    buff = (char *) malloc(st.st_size);
    if (buff == NULL) {
        printf("Memory error!!\n");

        return 1;
    }

    int fd = open(argv[1], O_RDONLY, 0);
    if (fd == -1) {
        printf("File access error\n");
        free(buff);

        return 1;
    }

    int size = read(fd, buff, st.st_size);
    uint32_t offset    = *(uint32_t *) (buff + 0x0a);
    uint32_t width    = *(uint32_t *) (buff + 0x12);
    uint32_t height    = *(uint32_t *) (buff + 0x16);
    uint16_t bpp    = *(uint16_t *) (buff + 0x1c);

    if (bpp == 24) {
        int fd_out;
        printf("worked dist: %d , heigh: %d\n", atoi(argv[2]), height);
        fadetop(buff + offset, width , height , atoi(argv[2]) );
        fd_out = creat("fade.bmp", 0644);
        write(fd_out, buff, size);
        close(fd_out);

        printf("Image faded.\n");
    }
    else {
        printf("Invalid BMP\n");
    }

    close(fd);
    free(buff);

    return 0;
}

      

+3


source to share


1 answer


Your formula seems to be correct: you have something like

 color_new = (color-255)*dist_counter/dist + 255

      

although I would suggest a little simpler

color *= dist_counter/dist             ; scale original color over current dist
color += 256*(dist-dist_counter)/dist  ; add white, scaled over current dist

      

(which at least visually gives the same result). The main mistake is that, since you are adding the current value, you may overflow the maximum value of 255. After the calculations, check if color > 255

and the clamp if there is.

In assembly (cannot be verified, so I hope I get it right at first):



    movzx   eax, byte [esi+ebx+0]   ; take color 1
    mov     ecx, dist_counter   
    imul    ecx         ;color * current position
    cdq
    mov     ecx, dist       ; devide by full fade operation distance 
    idiv    ecx

    mov     ebx, eax        ; save result so far

    mov     eax, dist       ; calculate 2nd half
    mov     ecx, eax
    sub     eax, dist_counter
    shl     eax, 8
    idiv    ecx

    add     eax, ebx
    test    ah, ah
    jz      skip_clamp
    mov     al, 255
skip_clamp:
    mov     [esi+ebx+0], al     ;put in this place

      

.. repeats for your tricolor components.

A few additional notes that might be helpful:

  • My second line of calculation color

    is a constant for each line. So you only need to compute it in your y-loop and store it somewhere.

  • You don't actually need to repeat the above code for each of the color per pixel components. Just repeat the x 3 * loop width

    :

    mov     edi, width
    lea     edi, [edi+2*edi]
    
          

  • Your starting position looks like not only a few lines, but a few pixels. This is partly due to add eax,3

    here:

    sub eax ,row_bytes
    add eax,3
    
          

    but I'm not sure where the big mistake is coming from, because your addition calculation is correct. I couldn't verify your actual code, so I implemented it in bare C, and with that I get the following output to input ./a.out flower.bmp 400

    :

partially faded flower

+1


source







All Articles