/* * rle.c: RLE utils * * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * * $Id: rle.c,v 1.1 2008-12-05 16:34:21 phintuka Exp $ * */ #include #include #include "../xine_osd_command.h" #include "rle.h" #undef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* * rle_compress() * */ int rle_compress(xine_rle_elem_t **rle_data, const uint8_t *data, int w, int h) { xine_rle_elem_t rle, *rle_p = 0, *rle_base; int x, y, num_rle = 0, rle_size = 8128; const uint8_t *c; rle_p = (xine_rle_elem_t*)malloc(4*rle_size); rle_base = rle_p; for( y = 0; y < h; y++ ) { rle.len = 0; rle.color = 0; c = data + y * w; for( x = 0; x < w; x++, c++ ) { if( rle.color != *c ) { if( rle.len ) { if( (num_rle + h-y+1) > rle_size ) { rle_size *= 2; rle_base = (xine_rle_elem_t*)realloc( rle_base, 4*rle_size ); rle_p = rle_base + num_rle; } *rle_p++ = rle; num_rle++; } rle.color = *c; rle.len = 1; } else { rle.len++; } } *rle_p++ = rle; num_rle++; } *rle_data = rle_base; return num_rle; } /* * rle_scale_nearest() * * - Simple nearest-neighbour scaling for RLE-compressed image * - fast scaling in compressed form without decompression */ xine_rle_elem_t *rle_scale_nearest(const xine_rle_elem_t *old_rle, int *rle_elems, int w, int h, int new_w, int new_h) { #define FACTORBASE 0x100 #define FACTOR2PIXEL(f) ((f)>>8) #define SCALEX(x) FACTOR2PIXEL(factor_x*(x)) #define SCALEY(y) FACTOR2PIXEL(factor_y*(y)) int old_w = w, old_h = h; int old_y = 0, new_y = 0; int factor_x = FACTORBASE*new_w/old_w; int factor_y = FACTORBASE*new_h/old_h; int rle_size = MAX(8128, *rle_elems * new_h/h ); /* guess ... */ int num_rle = 0; xine_rle_elem_t *new_rle = (xine_rle_elem_t*)malloc(sizeof(xine_rle_elem_t)*rle_size); xine_rle_elem_t *new_rle_start = new_rle; /* we assume rle elements are breaked at end of line */ while(old_y < old_h) { int elems_current_line = 0; int old_x = 0, new_x = 0; while(old_x < old_w) { int new_x_end = SCALEX(old_x + old_rle->len); if(new_x_end > new_w) { new_x_end = new_w; } new_rle->len = new_x_end - new_x; new_rle->color = old_rle->color; old_x += old_rle->len; old_rle++; /* may be incremented to last element + 1 (element is not accessed anymore) */ if(new_rle->len > 0) { new_x += new_rle->len; new_rle++; num_rle++; elems_current_line++; if( (num_rle + 1) >= rle_size ) { rle_size *= 2; new_rle_start = (xine_rle_elem_t*)realloc( new_rle_start, 4*rle_size); new_rle = new_rle_start + num_rle; } } } if(new_x < new_w) (new_rle-1)->len += new_w - new_x; old_y++; new_y++; if(factor_y > FACTORBASE) { /* scale up -- duplicate current line ? */ int dup = SCALEY(old_y) - new_y; /* if no lines left in (old) rle, copy all lines still missing from new */ if(old_y == old_h) dup = new_h - new_y - 1; while(dup-- && (new_y+1= rle_size ) { rle_size *= 2; new_rle_start = (xine_rle_elem_t*)realloc( new_rle_start, 4*rle_size); new_rle = new_rle_start + num_rle; } /* duplicate previous line */ prevline = new_rle - elems_current_line; for(n = 0; n < elems_current_line; n++) { *new_rle++ = *prevline++; num_rle++; } new_y++; } } else if(factor_y < FACTORBASE) { /* scale down -- drop next line ? */ int skip = new_y - SCALEY(old_y); if(old_y == old_h-1) { /* one (old) line left ; don't skip it if new rle is not complete */ if(new_y < new_h) skip = 0; } while(skip-- && old_ylen; old_rle++; } old_y++; } } } *rle_elems = num_rle; return new_rle_start; }