/**************************************************************** * alc.c * * Copyright (C) 1995-2002 Klaus Ehrenfried * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *************************************************************************/ #include #include "apro.h" static int change[FLI_MAX_X]; static int val[FLI_MAX_X]; static int work[FLI_MAX_X]; int make_lc_line ( unsigned char *preprevious_line, unsigned char *previous_line, unsigned char *current_line, unsigned char *lc_line, int start_flag ); static int improve_lc_line(); static int test_lc_skip(); static int test_lc_packets(); static int new_pixels; static int merge_count; /**************************************************************** * make_lc_chunk ****************************************************************/ int make_lc_chunk ( unsigned char *preprevious, /* pre previous image */ unsigned char *previous, /* previous image */ unsigned char *current /* current image */ ) { int skip_count, start_flag, last_mod; unsigned char *lc_line; int chunk_count, line_count; int j, line_size, help; float change_factor; new_pixels=0; chunk_count=10; /* 4 bytes for total size of chunk (header)*/ /* 2 bytes for chunk type (header)*/ /* 2 bytes for number of skipped lines */ /* 2 bytes for number of modified lines */ skip_count=-1; last_mod=-1; start_flag=0; for (j=0; j < fli_height; j++) { lc_line = &pixel_chunk_buffer[chunk_count]; line_size = make_lc_line(preprevious, previous, current, lc_line, start_flag); preprevious += fli_width; previous += fli_width; current += fli_width; if (line_size > 0) /* yes, we got a new line */ { chunk_count += line_size; if (skip_count == -1) skip_count = j; start_flag=1; } if (line_size > 1) last_mod = j; } if (last_mod == -1) /* no lines no chunk */ return(0); line_count=last_mod - skip_count + 1; if ((chunk_count % 2) == 1) add_bytes(pixel_chunk_buffer, &chunk_count, 0x0000, IOM_UBYTE); help=0; add_bytes(pixel_chunk_buffer, &help, chunk_count, IOM_LONG); add_bytes(pixel_chunk_buffer, &help, FLI_LC, IOM_UWORD); add_bytes(pixel_chunk_buffer, &help, skip_count, IOM_UWORD); add_bytes(pixel_chunk_buffer, &help, line_count, IOM_UWORD); change_factor=100.0*((float)new_pixels)/(fli_width*fli_height); fprintf(stdout," LC chunk: %d bytes new pixels: %.2f %%\n", chunk_count,change_factor); return(chunk_count); } /**************************************************************** * make_lc_line ****************************************************************/ int make_lc_line ( unsigned char *preprevious_line, unsigned char *previous_line, unsigned char *current_line, unsigned char *lc_line, int start_flag ) { int skip_count, size_count, packets; int i, m, ipos, help, ch_flag; ch_flag = 0; for (i=0; i < fli_width; i++) { val[i]=current_line[i]; if ((previous_line[i] != current_line[i]) || ((double_buffer == 1) && (preprevious_line[i] != current_line[i]))) { change[i]=1; /* yes, update */ ch_flag=1; } else { change[i]=0; /* no update */ } } if (ch_flag == 0) { if (start_flag == 0) return(0); *lc_line = 0; return(1); } if (change[fli_width-1] != 0) { work[fli_width-1]=1; new_pixels++; } else { work[fli_width-1]=0; } for (i=(fli_width-2); i >= 0; i--) { if (change[i] != 0) { new_pixels++; if (val[i] == val[i+1]) { if (work[i+1] < 0) { work[i]=work[i+1]-1; if (work[i] < -127) work[i]=-1; } else if (work[i+1] == 0) { work[i]=1; } else { work[i+1]=-1; work[i]=-2; } } else /* count nonequal bytes */ { if (work[i+1] > 0) { work[i]=work[i+1]+1; if (work[i] > 127) work[i]=1; } else { work[i]=1; } } } else { work[i]=0; } } test_lc_skip(); merge_count = 1; while (merge_count > 0) { merge_count=0; improve_lc_line(); } test_lc_packets(); packets=0; skip_count=0; i=0; ipos=1; while (i < fli_width) /* assemble output */ { if (work[i] != 0) /* add data packet */ { packets++; size_count=work[i]; add_bytes(lc_line, &ipos, skip_count, IOM_UBYTE); add_bytes(lc_line, &ipos, size_count, IOM_SBYTE); if (size_count < 0) { m=i; add_bytes(lc_line, &ipos, val[i], IOM_UBYTE); i -= size_count; } else { for (m=0; m < size_count; m++) { add_bytes(lc_line, &ipos, val[i++], IOM_UBYTE); } } skip_count=0; } else { skip_count++; i++; } } /* printf("(%d %d) ",packets,ipos); */ help=0; add_bytes(lc_line, &help, packets, IOM_UBYTE); return(ipos); /* return number of bytes */ } /**************************************************************** * get_packet_start ****************************************************************/ static int get_packet_start(int i) { int j,igo; igo=0; if (work[i] > 0) { for (j=i; j > 0; j--) { if (work[j-1] != work[j]+1) { igo=j; break; } } } else { for (j=i; j > 0; j--) { if (work[j-1] != work[j]-1) { igo=j; break; } } } return(igo); } /**************************************************************** * merge_packets ****************************************************************/ static int merge_packets(int igo1, int igo2, int m) { int j, len; len = igo2-igo1+1; if (len > 127) return(0); merge_count++; if (m == 1) for (j=igo2; j >= igo1; j--) work[j] = m++; else if (m == -1) for (j=igo2; j >= igo1; j--) work[j] = m--; return(m); } /**************************************************************** * improve_lc_line ****************************************************************/ static int improve_lc_line() { int i,igo1,igo2; for (i=0; i < fli_width-1; i++) /* | +1 | -2 | */ { /* | +1 | -3 | */ if ((work[i] == 1) && ((work[i+1] == -2) || (work[i+1] == -3))) { igo1 = get_packet_start(i); igo2 = i-work[i+1]; merge_packets(igo1,igo2,1); } } for (i=0; i < fli_width-2; i++) /* | XX | -2 | -1 | +N | */ { if ((work[i] == -2) && (work[i+2] > 0) && ((i == 0) || (work[i-1] != -3))) { igo1 = i; igo2 = i+1+work[i+2]; merge_packets(igo1,igo2,1); } } for (i=0; i < fli_width-3; i++) /* | XX | -3 | -2 | -1 | +N | */ { if ((work[i] == -3) && (work[i+3] > 0) && ((i == 0) || (work[i-1] != -4))) { igo1 = i; igo2 = i+2+work[i+3]; merge_packets(igo1,igo2,1); } } for (i=0; i < fli_width-2; i++) /* | XX | -2 | -1 | -2 | */ { if ((work[i] == -2) && (work[i+2] == -2) && ((i == 0) || work[i-1] != -3)) { igo1 = i; igo2 = i+3; merge_packets(igo1,igo2,1); } } for (i=0; i < fli_width-2; i++) /* | +1 | 0 | +N | */ { if ((work[i] == 1) && (work[i+1] == 0) && (work[i+2] > 0)) { igo1 = get_packet_start(i); igo2 = i+1+work[i+2]; merge_packets(igo1,igo2,1); } } for (i=0; i < fli_width-2; i++) /* | -1 | 0 | -N | */ { if ((work[i] == -1) && (work[i+1] == 0) && (work[i+2] < 0) && (val[i] == val[i+1]) && (val[i] == val[i+2])) { igo1 = get_packet_start(i); igo2 = i+1-work[i+2]; merge_packets(igo1,igo2,-1); } } for (i=0; i < fli_width-3; i++) /* | XX | -2 | -1 | 0 | +N | */ { if ((work[i] == -2) && (work[i+2] == 0) && (work[i+3] > 0) && ((i == 0) || (work[i-1] != -3))) { igo1=i; igo2 = i+2+work[i+2]; merge_packets(igo1,igo2,1); } } for (i=0; i < fli_width-2; i++) /* | +1 | 0 | -2 | */ { if ((work[i] == 1) && (work[i+1] == 0) && (work[i+2] == -2)) { igo1 = get_packet_start(i); igo2 = i+3; merge_packets(igo1,igo2,1); } } for (i=0; i < fli_width-3; i++) /* | +1 | 0 | 0 | +N | */ { if ((work[i] == 1) && (work[i+1] == 0) && (work[i+2] == 0) && (work[i+3] > 0)) { igo1 = get_packet_start(i); igo2 = i+2+work[i+2]; merge_packets(igo1,igo2,1); } } for (i=0; i < fli_width-3; i++) /* | -1 | 0 | 0 | -N | */ { if ((work[i] == -1) && (work[i+1] == 0) && (work[i+2] == 0) && (work[i+3] < 0) && (val[i] == val[i+1]) && (val[i] == val[i+2]) && (val[i] == val[i+3])) { igo1 = get_packet_start(i); igo2 = i+2-work[i+2]; merge_packets(igo1,igo2,-1); } } for (i=0; i < fli_width-1; i++) /* | +1 | +N | */ { if ((work[i] == 1) && (work[i+1] > 0)) { igo1 = get_packet_start(i); igo2 = i+work[i+1]; merge_packets(igo1,igo2,1); } } return(1); } /**************************************************************** * test_lc_skip ****************************************************************/ static int test_lc_skip() { int i, iend, ic; iend=-1; for (i=fli_width-1; i >= 0; i--) if (work[i] != 0) { iend=i; break; } ic=0; for (i=0; i <= iend; i++) { if (work[i] == 0) { ic++; if (ic >= 256) { work[i]=1; ic=0; } } else ic=0; } return(iend); } /**************************************************************** * test_lc_packets ****************************************************************/ static int test_lc_packets() { int packets,i, igo1,igo2, istart,iend; packets=0; for (i = 0; i < fli_width; i++) if ((work[i] == 1) || (work[i] == -1)) packets++; if (packets < 256) return(packets); istart=0; iend=0; for (i=0; i < fli_width; i++) if (work[i] != 0) { istart=i; break; } for (i=fli_width-1; i >= 0; i--) if (work[i] != 0) { iend=i; break; } igo1=istart; while (igo1 <= iend) { igo2=i+125; if (igo2 > iend) igo2=iend; merge_packets(igo1,igo2,1); igo1=igo2+1; } return(-1); }