Category : Files from Magazines
Archive   : CUJ0894.ZIP
Filename : FAXASM.ASM

 
Output of file : FAXASM.ASM contained in archive : CUJ0894.ZIP
;***************************************************************
;* file: FAXASM.ASM
;* This is the production version of FAXSCALE.C in assembly
;* Refer to FAXSCALE.C for more information.
;* purpose: Minimalist scaler. Scales images over a range of
;* 3% to 3200% with a worst case precision of 1/32. This code
;* was designed to minimize data, stack and code requirements
;* while being reasonably fast and accurate. Since the intended
;* use is in fax machine, the scaled lines are clipped or white
;* filled to FAX_WIDTH bytes. Refer to the function headers for
;* more detailed information. Image lines follow the usual
;* monochromatic format of 1 being black, 0 being white and
;* bit 7 of each byte being the leftmost pixel.
;* environment: MASM 5.1 tested
;* contains:
;* init_fax_scale() - initializes the scaler
;* scale_fax_line() - scales a single image line
;* copyright: 1992 by David Weber. Unlimited use is granted for
;* noncommercial use or for commercial distribution in EXE, OBJ,
;* or LIB formats. Do not sell as source without asking first.
;* history:
;* 06-09-92 - initial code
;* 04-04-94 - polished, reformatted, retested, condensed
;**************************************************************/

;#include
;#include
;#include

.186 ;using immediate shifts
.model small,c

;* since this is a device driver it will act like the tiny
;* memory model in that data and code are stored in one segment

.code

;* data types and defines */

;typedef unsigned long ROTATOR; ;* rotator type sets scaling
; * range and precision */
PRECISION equ 32 ;* bit width of ROTATOR
SCALE_MAX equ (PRECISION * 100) ;* upper limit of scaler in % */
SCALE_MIN equ (100 / PRECISION) ;* lower limit of scaler in % */
FAX_WIDTH equ 216 ;* hardwired byte width of a fax line */


;* ROMmable const data */
;* sequential increase in bits per byte: do not change
;* without looking closely at init_rotator() */
pattern db 000h,010h,044h,094h,0aah,0dah,0eeh,0feh,0ffh,0ffh


;* RAM data */
x_rotator dd ? ;* rotating horizontal pattern */
y_rotator dd ? ;* rotating vertical pattern */
source_width dw ? ;* number of bytes in a source line */
x_base db ? ;* n/8 basis for x_rotator */
y_base db ? ;* n/8 basis for y_rotator */
bit_repeat_count dw ? ;* repeat total for byte */
bit_repeat_pattern db ? ;* pattern for count */


;* local functions */
;static int init_rotator(int scale,ROTATOR *rotator,unsigned char *base);


;************************************************
;* function: int init_fax_scale(int x_scale,int y_scale,unsigned int source_byte_width)
;* Validate the scaling ranges and initialize the scaler. You
;* must call this function first before you can use the scaler.
;* parameters: horizontal and vertical scaling in percent followed
;* by the byte width of a source line.
;* returns: 1 if Ok or 0 if either scale is out of range
;************************************************/
;int init_fax_scale(int x_scale,int y_scale,unsigned int source_byte_width)
public init_fax_scale
init_fax_scale proc uses ds si di, x_scale: word, y_scale: word, source_byte_width: word
; {
; int index;
mov ax,cs
mov ds,ax
assume ds:_TEXT
; index = init_rotator(x_scale,&x_rotator,&x_base); /* set up x_rotator */
; if (index == -1)
; return 0;
mov ax,x_scale
mov bx,offset x_base
mov cx,offset x_rotator
call near ptr init_rotator
js init_error
; bit_repeat_count = x_base * 8 + index;
mov cl,x_base
xor ch,ch
shl cx,3
add cx,ax
mov bit_repeat_count,cx
; bit_repeat_pattern = pattern[index];
mov bx,ax
mov al,pattern[bx]
mov bit_repeat_pattern,al
; if (init_rotator(y_scale,&y_rotator,&y_base) == -1)
; return 0; ;* set up y_rotator */
mov ax,y_scale
mov bx,offset y_base
mov cx,offset y_rotator
call near ptr init_rotator
js init_error
; source_width = source_byte_width; ;* save width */
; if (((long)source_width * (long)x_scale) / 100L > FAX_WIDTH)
; source_width = FAX_WIDTH; ;* clip to fax line */
mov cx,source_byte_width
mov ax,x_scale
cwd
mul cx
mov bx,100
div bx
cmp ax,FAX_WIDTH
jbe width_ok
mov cx,FAX_WIDTH
width_ok:
mov source_width,cx
; return 1;
mov ax,1
ret
init_error:
xor ax,ax
ret
; }
init_fax_scale endp


;************************************************

;* function: static int init_rotator(int scale,ROTATOR *rotator,unsigned char *base)
;* local function calculates the rotator and basis.
;* parameters: scale factor in percent in AX, pointer to rotator in CX,
;* pointer to basis in BX. note: CS == DS
;* returns: repeat index if Ok or -1 ('S' set) if scale is out of range
;* destroys SI and DI
;************************************************/
error_init:
mov ax,-1
or ax,ax
ret
init_rotator:
assume ds:_TEXT
;static int init_rotator(int scale,ROTATOR *rotator,unsigned char *base)
; {
; unsigned int index,mix,i;

;* check scaling range */
; if (scale < SCALE_MIN || scale > SCALE_MAX)
; return -1;
cmp ax,SCALE_MIN
jl error_init
cmp ax,SCALE_MAX
jg error_init
;* set basis */
; *base = scale / 100;
push cx
mov cx,100
cwd
div cx
mov [bx],al
;* get index into pattern */
; scale %= 100;
; index = (scale * 8) / 100;
shl dx,3
mov ax,dx
cwd
div cx
mov bx,ax
mov di,ax
;* How we mix 2 consecutive patterns to achieve balance.
;* Express it this way to handle round off. */
; mix = pattern[((((scale * 8) % 100) + 4) * 8) / 100];
add dx,4
shl dx,3
mov ax,dx
cwd
div cx
mov si,ax
mov al,pattern[si]
;* for each byte in the rotator, select an appropriate
;* pattern byte based on the index and the mix */
; *rotator = 0;
; for (i = sizeof(ROTATOR) ; i > 0 ; i--)
; {
; *rotator <<= 8;
; *rotator |= pattern[index + (mix & 0x01)];
; mix >>= 1;
; }
; assert((*rotator + *base) != 0);
; assert(*base <= PRECISION);
mov ah,bl ;al has mix, ah has index
pop si ;si has &rotator
xor bh,bh
mov cx,PRECISION/8
rotator_init:
mov bl,al
and bl,1
add bl,ah
mov dl,pattern[bx]
mov byte ptr [si],dl
inc si
shr al,1
loop rotator_init
; return 1;
mov ax,di
or ax,ax
ret
; }


;************************************************
;* function: int scale_fax_line(unsigned char *dest, unsigned char *src)
;* Scale the line from src to dest. dest will always be FAX_WIDTH
;* wide even if it requires clipping or whiting out the tail. The
;* return value indicates the number of times to repeat the line.
;* A 0 return means skip it. This was done to keep buffer control in
;* the caller. Call scale_fax_line() once for each source line.
;* parameters: pointer to destination and source
;* returns: number of times to repeat the line (0 to PRECISION)
;* NOTE: The C code uses right rotates, this uses left rotates
;* cuz they are easier in assembly. The direction is not important
;* just as long as you are consistent.
;************************************************/
vector_end_line: ;short jump way station
jmp end_line
public scale_fax_line
scale_fax_line proc uses ds si di, dest: near ptr byte, src: near ptr byte
;int scale_fax_line(unsigned char *dest, unsigned char *src)
; {
; int y_repeat,x_repeat,i,bit;
; unsigned int accum;
; unsigned char byte;
; unsigned char *start;
; ROTATOR rotator;

assume ds:nothing
;* get line repeat value and rotate to next */
; y_repeat = y_base + (y_rotator & 0x01);
; _ror(y_rotator);
; if (y_repeat)
; {
mov ax,word ptr cs:y_rotator
add ax,ax
rcl word ptr cs:y_rotator+2,1
adc ax,0
mov word ptr cs:y_rotator,ax
and ax,1
add al,cs:y_base
jnz line_ok
jmp no_line
line_ok:
push bp
push ax
;* if anything to do */
mov si,ds ;large model data use lds and les
mov es,si
mov si,src
mov di,dest
; rotator = x_rotator;
mov bx,word ptr cs:x_rotator
mov dx,word ptr cs:x_rotator+2
; for (i=source_width, accum=1, start=dest ; i > 0 ; i--, src++)
mov bp,cs:source_width
mov ah,1
push di
; { ;* each byte in the source line */
byte_loop:
dec bp
js vector_end_line
lodsb
; if (*src)
or al,al
jz all_white
; { ;* if it has black bits */
; for (bit=8, byte=*src ; bit > 0 ; bit--)
; { ;* for each bit in the byte */
; x_repeat = x_base + (rotator & 1);
; _ror(rotator); ;* get repeat count and rotate */
; while (x_repeat--)
; { ;* for each repeat */
; accum <<= 1; ;* copy bit into accumulator */
; accum += ((byte & 0x80) != 0);
; if (accum & 0x100)
; { ;* output a byte and reset sentinel */
; *dest++ = (unsigned char) accum;
; accum = 1;
; }
; }
; byte <<= 1;
mov cl,8
bit_loop:
xor ch,ch
add bx,bx
adc dx,dx
adc ch,0
add bl,ch
add ch,cs:x_base
or ch,ch
jz bit_next
bit_repeat:
cmp al,80h
cmc
adc ah,ah
jc bit_update
repeat_next:
dec ch
jnz bit_repeat
bit_next:
add al,al
dec cl
jnz bit_loop
jmp short byte_loop
bit_update:
xchg al,ah
stosb
xchg al,ah
mov ah,1
jmp short repeat_next
; }
; }
; else
; { ;* no black bits, just spin it out. */
all_white:
;* how many repeats? */
; x_repeat = bit_repeat_count + ((rotator & 0xff) > bit_repeat_pattern);
xor cx,cx
cmp cs:bit_repeat_pattern,dh
adc cx,cs:bit_repeat_count
;* rotate by 8 */
; rotator = (rotator << (PRECISION-8)) | (rotator >> 8);
xchg bl,bh
xchg bl,dl
xchg bl,dh
;* do it */
; while (x_repeat--)
; {
; accum <<= 1;
; if (accum & 0x100)
; {
; *dest++ = (unsigned char) accum;
; accum = 1;
; }
; }
jcxz byte_loop
white_loop:
add ax,ax
jc white_update
loop white_loop
jmp byte_loop
white_update:
xchg al,ah
stosb
xchg al,ah
mov ah,1
loop white_loop
jmp byte_loop
; }
; }
; if (accum > 1)
; { ;* handle fragment */
; while ((accum & 0x100) == 0)
; accum <<= 1;
; *dest++ = (unsigned char) accum;
; }
end_line:
cmp ah,1
jbe no_fragment
fragment_loop:
add ah,ah
jnc fragment_loop
stosb
no_fragment:
; while (dest < start + FAX_WIDTH)
; { ;* white out tail */
; *dest++ = 0;
; }
; }
pop ax
sub ax,di
add ax,FAX_WIDTH
jle no_tail
mov cx,ax
xor ax,ax
shr cx,1
rep stosw
adc cx,0
rep stosb
no_tail:
; return y_repeat;
pop ax
pop bp
no_line:
ret
; }
scale_fax_line endp

end


  3 Responses to “Category : Files from Magazines
Archive   : CUJ0894.ZIP
Filename : FAXASM.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/