1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
/*
* 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 <stdint.h>
#include <stdlib.h>
#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<new_h)) {
xine_rle_elem_t *prevline;
int n;
if( (num_rle + elems_current_line + 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_y<old_h /* rounding error may add one line, filter it out */) {
for(old_x = 0; old_x < old_w;) {
old_x += old_rle->len;
old_rle++;
}
old_y++;
}
}
}
*rle_elems = num_rle;
return new_rle_start;
}
|