x86 汇编衰落 bmp 与线性插值
x86 assembly fading bmp with linear interpolation
任务是:将 24 bpp .BMP 图像的顶部淡化为白色,以便对每个像素的颜色进行线性插值
根据其距离形成顶部边缘,在其原始颜色和白色之间。距离像素 >=
dist 没有褪色。
我创建了所有代码并尝试淡化某些内容。它似乎只适用于 2 的幂的距离,所以 32,64,128 等等......
我正在使用线性插值方程,我不知道为什么它不适用于其他数字。
有任何想法吗 ? :).
示例图片:
褪色后我得到...
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
为那些想要 运行 它并尝试淡化的人编写 C 代码:
#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;
}
你的公式似乎是正确的:你有类似的东西
color_new = (color-255)*dist_counter/dist + 255
尽管我建议更简单一些
color *= dist_counter/dist ; scale original color over current dist
color += 256*(dist-dist_counter)/dist ; add white, scaled over current dist
(至少在视觉上给出了相同的结果)。您的主要错误是因为您正在 将 添加到当前值,您可能会溢出最大值 255。计算后,测试是否 color > 255
并在它是时钳制.
在汇编中(无法测试所以我希望我第一次做对):
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
.. 重复你的 3 个颜色分量。
一些可能有用的附加说明:
我第二行计算color
是每行一个常量。所以你只需要在你的y循环中计算它并将它保存在某个地方。
您实际上不必为每个像素的每个颜色分量重复上述代码。只需重复 x 循环 3*width
:
mov edi, width
lea edi, [edi+2*edi]
您的起始位置似乎偏离了几个 行 ,而且还偏离了几个 像素 。这部分是因为这里的add eax,3
:
sub eax ,row_bytes
add eax,3
但我不确定较大的错误来自何处,因为您的填充计算是正确的。我无法测试你的实际代码,所以我用裸 C 实现了它,并且我得到了输入 ./a.out flower.bmp 400
:
的以下输出
任务是:将 24 bpp .BMP 图像的顶部淡化为白色,以便对每个像素的颜色进行线性插值 根据其距离形成顶部边缘,在其原始颜色和白色之间。距离像素 >= dist 没有褪色。
我创建了所有代码并尝试淡化某些内容。它似乎只适用于 2 的幂的距离,所以 32,64,128 等等...... 我正在使用线性插值方程,我不知道为什么它不适用于其他数字。 有任何想法吗 ? :).
示例图片:
褪色后我得到...
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
为那些想要 运行 它并尝试淡化的人编写 C 代码:
#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;
}
你的公式似乎是正确的:你有类似的东西
color_new = (color-255)*dist_counter/dist + 255
尽管我建议更简单一些
color *= dist_counter/dist ; scale original color over current dist
color += 256*(dist-dist_counter)/dist ; add white, scaled over current dist
(至少在视觉上给出了相同的结果)。您的主要错误是因为您正在 将 添加到当前值,您可能会溢出最大值 255。计算后,测试是否 color > 255
并在它是时钳制.
在汇编中(无法测试所以我希望我第一次做对):
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
.. 重复你的 3 个颜色分量。
一些可能有用的附加说明:
我第二行计算
color
是每行一个常量。所以你只需要在你的y循环中计算它并将它保存在某个地方。您实际上不必为每个像素的每个颜色分量重复上述代码。只需重复 x 循环 3*
width
:mov edi, width lea edi, [edi+2*edi]
您的起始位置似乎偏离了几个 行 ,而且还偏离了几个 像素 。这部分是因为这里的
add eax,3
:sub eax ,row_bytes add eax,3
但我不确定较大的错误来自何处,因为您的填充计算是正确的。我无法测试你的实际代码,所以我用裸 C 实现了它,并且我得到了输入
./a.out flower.bmp 400
: 的以下输出