Codebase list frei0r / 5557743
Update upstream source from tag 'upstream/2.4.0' Update to upstream version '2.4.0' with Debian dir 968e5f4ede2448afe4896bbd904a48eeaf6b2f05 IOhannes m zmölnig (Debian/GNU) 9 months ago
109 changed file(s) with 3502 addition(s) and 1763 deletion(s). Raw diff Collapse all Expand all
2222 release: ${{ steps.tag_release.outputs.release }}
2323 version: ${{ steps.tag_release.outputs.version }}
2424 steps:
25 - uses: actions/checkout@v3
25 - uses: actions/checkout@v4
2626 - name: Setup Node.js
2727 uses: actions/setup-node@v3
2828 with:
5050 needs: [semantic-release]
5151 if: ${{ needs.semantic-release.outputs.release == 'True' }}
5252 steps:
53 - uses: actions/checkout@v3
53 - uses: actions/checkout@v4
5454 - name: apt install deps
5555 run: |
5656 sudo apt-get update -y -q
6161 cmake -G "Ninja" ../
6262 ninja
6363 - name: Upload linux filter
64 uses: actions/upload-artifact@v3
64 uses: actions/upload-artifact@v4
6565 with:
6666 name: release-linux-filter
6767 path: build/src/filter/**/*.so
6868 - name: Upload linux mixer2
69 uses: actions/upload-artifact@v3
69 uses: actions/upload-artifact@v4
7070 with:
7171 name: release-linux-mixer2
7272 path: build/src/mixer2/**/*.so
7373 - name: Upload linux mixer3
74 uses: actions/upload-artifact@v3
74 uses: actions/upload-artifact@v4
7575 with:
7676 name: release-linux-mixer3
7777 path: build/src/mixer3/**/*.so
7878 - name: Upload linux generator
79 uses: actions/upload-artifact@v3
79 uses: actions/upload-artifact@v4
8080 with:
8181 name: release-linux-generator
8282 path: build/src/generator/**/*.so
8787 needs: [semantic-release]
8888 if: ${{ needs.semantic-release.outputs.release == 'True' }}
8989 steps:
90 - uses: actions/checkout@v3
90 - uses: actions/checkout@v4
9191 - uses: ilammy/msvc-dev-cmd@v1
9292 - name: choco install deps
9393 uses: crazy-max/ghaction-chocolatey@v2
9999 cmake -G "NMake Makefiles" ../
100100 nmake
101101 - name: Upload win64 filter
102 uses: actions/upload-artifact@v3
102 uses: actions/upload-artifact@v4
103103 with:
104104 name: release-win64-filter
105105 path: build/src/filter/**/*.dll
106106 - name: Upload win64 mixer2
107 uses: actions/upload-artifact@v3
107 uses: actions/upload-artifact@v4
108108 with:
109109 name: release-win64-mixer2
110110 path: build/src/mixer2/**/*.dll
111111 - name: Upload win64 mixer3
112 uses: actions/upload-artifact@v3
112 uses: actions/upload-artifact@v4
113113 with:
114114 name: release-win64-mixer3
115115 path: build/src/mixer3/**/*.dll
116116 - name: Upload win64 generator
117 uses: actions/upload-artifact@v3
117 uses: actions/upload-artifact@v4
118118 with:
119119 name: release-win64-generator
120120 path: build/src/generator/**/*.dll
125125 needs: [semantic-release]
126126 if: ${{ needs.semantic-release.outputs.release == 'True' }}
127127 steps:
128 - uses: actions/checkout@v3
128 - uses: actions/checkout@v4
129129 - name: Update Homebrew
130130 run: |
131 brew update --preinstall
131 brew update
132132 - name: Install Homebrew dependencies
133133 run: |
134134 env HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 \
135 brew install cmake ninja cairo
135 brew install ninja cairo
136136 - name: Build using ninja
137137 run: |
138138 mkdir build && cd build
139139 cmake -G "Ninja" ../
140140 ninja
141141 - name: Upload osx filter
142 uses: actions/upload-artifact@v3
142 uses: actions/upload-artifact@v4
143143 with:
144144 name: release-osx-filter
145145 path: build/src/filter/**/*.so
146146 - name: Upload osx mixer2
147 uses: actions/upload-artifact@v3
147 uses: actions/upload-artifact@v4
148148 with:
149149 name: release-osx-mixer2
150150 path: build/src/mixer2/**/*.so
151151 - name: Upload osx mixer3
152 uses: actions/upload-artifact@v3
152 uses: actions/upload-artifact@v4
153153 with:
154154 name: release-osx-mixer3
155155 path: build/src/mixer3/**/*.so
156156 - name: Upload osx generator
157 uses: actions/upload-artifact@v3
157 uses: actions/upload-artifact@v4
158158 with:
159159 name: release-osx-generator
160160 path: build/src/generator/**/*.so
165165 if: ${{ needs.semantic-release.outputs.release == 'True' }}
166166 runs-on: ubuntu-latest
167167 steps:
168 - uses: actions/checkout@v3
168 - uses: actions/checkout@v4
169169 - name: download binary artifacts
170 uses: actions/download-artifact@v3
170 uses: actions/download-artifact@v4
171171 with:
172172 path: |
173173 frei0r-bin
182182 cp README.md $dst/README.txt
183183 cp COPYING $dst/LICENSE.txt
184184 cp ChangeLog $dst/ChangeLog.txt
185 cp AUTHORS $dst/AUTHORS.txt
185 cp AUTHORS.md $dst/AUTHORS.txt
186186 cp include/frei0r.h include/frei0r.hpp $dst/
187187 echo "${{ needs.semantic-release.outputs.version }}" > $dst/VERSION.txt
188188 zip -r -9 $dst.zip $dst
196196 cp README.md $dst/README.txt
197197 cp COPYING $dst/LICENSE.txt
198198 cp ChangeLog $dst/ChangeLog.txt
199 cp AUTHORS $dst/AUTHORS.txt
199 cp AUTHORS.md $dst/AUTHORS.txt
200200 cp include/frei0r.h include/frei0r.hpp $dst/
201201 echo "${{ needs.semantic-release.outputs.version }}" > $dst/VERSION.txt
202202 zip -r -9 $dst.zip $dst
210210 cp README.md $dst/README.txt
211211 cp COPYING $dst/LICENSE.txt
212212 cp ChangeLog $dst/ChangeLog.txt
213 cp AUTHORS $dst/AUTHORS.txt
213 cp AUTHORS.md $dst/AUTHORS.txt
214214 cp include/frei0r.h include/frei0r.hpp $dst/
215215 echo "${{ needs.semantic-release.outputs.version }}" > $dst/VERSION.txt
216216 tar cvfz $dst.tar.gz $dst
2626 # name: 🚨 REUSE Compliance
2727 # runs-on: ubuntu-latest
2828 # steps:
29 # - uses: actions/checkout@v3
29 # - uses: actions/checkout@v4
3030 # - uses: fsfe/reuse-action@v1
3131
3232 c-lint:
3434 runs-on: ubuntu-latest
3535 if: "!contains(github.event.pull_request.labels.*.name, 'skip-lint')"
3636 steps:
37 - uses: actions/checkout@v3
37 - uses: actions/checkout@v4
3838 - uses: reviewdog/action-cpplint@master
3939 env:
4040 REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6161 ,-whitespace/semicolon\
6262 ,-build/include_subdir\
6363 ,-build/include_order\
64 ,-build/header_guard\
6465 "
6566
6667 test-suite:
7374 fail-fast: false
7475 runs-on: ubuntu-latest
7576 steps:
76 - uses: actions/checkout@v3
77 - uses: actions/checkout@v4
7778 - name: install dependencies
7879 run: |
7980 sudo apt-get update -qy
8990 run: |
9091 cd test && make
9192 - name: ${{ matrix.compiler }} upload plugin analysis
92 uses: actions/upload-artifact@v3
93 uses: actions/upload-artifact@v4
9394 with:
9495 name: release-plugin-analysis
9596 path: test/*.json
96
+0
-51
AUTHORS less more
0 # Frei0r developers union
1
2 Read here an account of [Frei0r's project history](https://medium.com/think-do-tank/frei0r-the-free-and-open-source-video-effect-preservation-project-604134dde8b3).
3
4 Frei0r is maintained by [Jaromil](https://jaromil.dyne.org) for the Dyne.org Foundation.
5
6 ## Developers who contributed, in alphabetic order:
7
8 Akito Iwakura
9 Albert Frisch
10 Brendan Hack
11 Brian Matherly
12 Burkhard Plaum
13 Carlo E. Prelz
14 Christoph Willing
15 Dan Dennedy
16 Filippo Giunchedi
17 Gabriel Finch (Salsaman)
18 Georg Seidel
19 Henner Zeller
20 Hedde Bosman
21 IOhannes M. Zmölnig
22 Janne Liljeblad
23 Jean-Baptiste Mardelle
24 Jean-François Fortin Tam
25 Jean-Sebastien Senecal
26 Jerome Blanchi (d.j.a.y)
27 Joshua M. Doe
28 Luca Bigliardi
29 Maksim Golovkin (Максим Головкин)
30 Marko Cebokli
31 Martin Bayer
32 Mathieu Guindon
33 Matthias Schnoell
34 Nicolas Carion
35 Niels Elburg
36 Phillip Promesberger
37 Raphael Graf
38 Richard Spindler
39 Richard Ling (Chungzuwalla)
40 Robert Schweikert
41 Ross Lagerwall
42 Samuel Mimram
43 Simon A. Eugster
44 Sofian Audry
45 Stefano Sabatini
46 Steinar H. Gunderson
47 Thomas Coldrick
48 Thomas Perl
49 Till Theato
50 Vincent Pinon
0 # Frei0r developers union
01
1 Project initiated at the Piksel Festival in 2004
2 hosted by BEK - Bergen Senter for Elektronisk Kunst
3 Maintained at the Dyne.org Foundation
2 Read here an account of [Frei0r's project history](https://medium.com/think-do-tank/frei0r-the-free-and-open-source-video-effect-preservation-project-604134dde8b3).
43
5 Developers who contributed, in alphabetic order:
4 Frei0r is a Dyne.org project maintained by Denis "Jaromil" Roio and Dan Dennedy.
65
7 Akito Iwakura
8 Albert Frisch
9 Brian Matherly
10 Burkhard Plaum
11 Carlo E. Prelz
12 Christoph Willing
13 Dan Dennedy
14 Denis Roio (Jaromil)
15 Filippo Giunchedi
16 Gabriel Finch (Salsaman)
17 Georg Seidel
18 Henner Zeller
19 Hedde Bosman
20 IOhannes M. Zmölnig
21 Janne Liljeblad
22 Jean-Baptiste Mardelle
23 Jean-François Fortin Tam
24 Jean-Sebastien Senecal
25 Jerome Blanchi (d.j.a.y)
26 Joshua M. Doe
27 Luca Bigliardi
28 Maksim Golovkin (Максим Головкин)
29 Marko Cebokli
30 Martin Bayer
31 Mathieu Guindon
32 Matthias Schnoell
33 Nicolas Carion
34 Niels Elburg
35 Phillip Promesberger
36 Raphael Graf
37 Richard Spindler
38 Richard Ling (Chungzuwalla)
39 Robert Schweikert
40 Ross Lagerwall
41 Samuel Mimram
42 Simon A. Eugster
43 Sofian Audry
44 Stefano Sabatini
45 Steinar H. Gunderson
46 Thomas Coldrick
47 Thomas Perl
48 Till Theato
49 Vincent Pinon
6 ## Developers who contributed, in alphabetic order:
7
8 Akito Iwakura, Albert Frisch, Ajrat Makhmutov, Brendan Hack, Brian Matherly, Burkhard Plaum, Carlo E. Prelz, Christoph Willing, Erik Beck, Esmane, Filippo Giunchedi, Gabriel Finch (Salsaman), Georg Seidel, Henner Zeller, Hedde Bosman, IOhannes M. Zmölnig, Janne Liljeblad, Jean-Baptiste Mardelle, Jean-François Fortin Tam , Jean-Sebastien Senecal, Jerome Blanchi (d.j.a.y), Joshua M. Doe, Luca Bigliardi, Maksim Golovkin (Максим Головкин), Marko Cebokli, Martin Bayer, Mathieu Guindon, Matthias Schnoell, Nicolas Carion, Niels Elburg, Phillip Promesberger, Raphael Graf, Richard Spindler, Richard Ling (Chungzuwalla), Robert Schweikert, Ross Lagerwall, Samuel Mimram, Simon A. Eugster, Sofian Audry, Stefano Sabatini, Steinar H. Gunderson, Thomas Coldrick, Thomas Perl, Till Theato, Vincent Pinon.
0 cmake_minimum_required (VERSION 3.1)
0 cmake_minimum_required (VERSION 3.12...3.31)
11
22 list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
33
3434 # --- custom targets: ---
3535 INCLUDE( cmake/modules/TargetDistclean.cmake OPTIONAL)
3636
37 # See this thread for a ridiculous discussion about the simple question how to install a header file with CMake: http://www.cmake.org/pipermail/cmake/2009-October/032874.html
38 install (DIRECTORY include DESTINATION . FILES_MATCHING PATTERN "frei0r.h" PATTERN "msvc" EXCLUDE)
37 install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
3938
4039 # For code documentation run: doxygen doc/Doxyfile
4140 # add_subdirectory (doc)
22 # Jan Woetzel 04/2003
33 #
44
5 IF (UNIX)
6 ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution)
7 SET(DISTCLEANED
5 if(UNIX)
6 add_custom_target(distclean
7 COMMENT "cleaning for source distribution"
8 )
9 set(DISTCLEANED
810 cmake.depends
911 cmake.check_depends
1012 CMakeCache.txt
1517 gmon.out
1618 *~
1719 )
18
19 ADD_CUSTOM_COMMAND(
20 DEPENDS clean
20 add_custom_command(
21 POST_BUILD
22 COMMENT "running target clean"
23 TARGET distclean
24 COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target clean
25 )
26 add_custom_command(
27 POST_BUILD
2128 COMMENT "distribution clean"
2229 COMMAND rm
2330 ARGS -Rf CMakeTmp ${DISTCLEANED}
2431 TARGET distclean
2532 )
26 ENDIF(UNIX)
33 endif(UNIX)
2734
+0
-270
include/blur.h less more
0 /* blur.h
1 * Copyright (C) 2004--2005 Mathieu Guindon
2 * Julien Keable
3 * Jean-Sebastien Senecal (js@drone.ws)
4 *
5 * Modified by Richard Spindler (richard.spindler AT gmail.com) for blurring in
6 * the mask0mate Frei0r plugin.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <string.h>
26
27 #include "frei0r.h"
28
29 #define SIZE_RGBA 4
30
31 static inline int MAX(int a, int b)
32 {
33 return (a > b ? a : b);
34 }
35
36 static inline int MIN(int a, int b)
37 {
38 return (a < b ? a : b);
39 }
40
41 static inline void subtract_acc(uint32_t *dst, const uint32_t *src)
42 {
43 int n=SIZE_RGBA;
44 while (n--)
45 *dst++ -= *src++;
46 }
47
48 static inline void add_acc(uint32_t *dst, const uint32_t *src)
49 {
50 int n=SIZE_RGBA;
51 while (n--)
52 *dst++ += *src++;
53 }
54
55 static inline void divide(unsigned char *dst, const uint32_t *src, const unsigned int val)
56 {
57 int n=SIZE_RGBA;
58 while (n--)
59 *dst++ = *src++ / val;
60 }
61
62 typedef struct squareblur_instance
63 {
64 unsigned int width;
65 unsigned int height;
66 double kernel; /* the kernel size, as a percentage of the biggest of width and height */
67 uint32_t *mem; /* memory accumulation matrix of uint32_t (size = acc_width*acc_height*SIZE_RGBA) */
68 uint32_t **acc; /* accumulation matrix of pointers to SIZE_RGBA consecutive uint32_t in mem (size = acc_width*acc_height) */
69 } squareblur_instance_t;
70
71 /* Updates the summed area table. */
72 static void update_summed_area_table(squareblur_instance_t *inst, const uint32_t *src)
73 {
74 register unsigned char *iter_data;
75 register uint32_t *iter_mem;
76 register unsigned int i, x, y;
77
78 uint32_t acc_buffer[SIZE_RGBA]; /* accumulation buffer */
79
80 unsigned int row_width;
81 unsigned int width, height;
82 unsigned int cell_size;
83
84 /* Compute basic params. */
85 width = inst->width+1;
86 height = inst->height+1;
87 row_width = SIZE_RGBA * width;
88 cell_size = SIZE_RGBA * sizeof(uint32_t);
89
90 /* Init iterators. */
91 iter_data = (unsigned char*) src;
92 iter_mem = inst->mem;
93
94 /* Process first row (all zeros). */
95 memset(iter_mem, 0, row_width * cell_size);
96 iter_mem += row_width;
97
98 if (height >= 1)
99 {
100 /* Process second row. */
101 memset(acc_buffer, 0, cell_size);
102 memset(iter_mem, 0, cell_size); /* first column is void */
103 iter_mem += SIZE_RGBA;
104 for (x=1; x<width; ++x)
105 {
106 for (i=0; i<SIZE_RGBA; ++i)
107 *iter_mem++ = (acc_buffer[i] += *iter_data++);
108 }
109
110 /* Process other rows. */
111 for (y=2; y<height; ++y)
112 {
113 /* Copy upper line. */
114 memcpy(iter_mem, iter_mem - row_width, row_width * sizeof(uint32_t));
115
116 /* Process row. */
117 memset(acc_buffer, 0, cell_size);
118 memset(iter_mem, 0, cell_size); /* first column is void */
119 iter_mem += SIZE_RGBA;
120 for (x=1; x<width; ++x)
121 {
122 for (i=0; i<SIZE_RGBA; ++i)
123 *iter_mem++ += (acc_buffer[i] += *iter_data++);
124 }
125 }
126 }
127 }
128
129 static void blur_get_param_info(f0r_param_info_t* info, int param_index)
130 {
131 switch(param_index)
132 {
133 case 0:
134 info->name = "Kernel size";
135 info->type = F0R_PARAM_DOUBLE;
136 info->explanation = "The size of the kernel, as a proportion to its coverage of the image";
137 break;
138 }
139 }
140
141 static f0r_instance_t blur_construct(unsigned int width, unsigned int height)
142 {
143 squareblur_instance_t* inst =
144 (squareblur_instance_t*)malloc(sizeof(squareblur_instance_t));
145 unsigned int i;
146 unsigned int acc_width, acc_height = height+1;
147 uint32_t* iter_mem;
148 uint32_t** iter_acc;
149 /* set params */
150 inst->width = width; inst->height = height;
151 acc_width = width+1; acc_height = height+1;
152 inst->kernel = 0.0;
153 /* allocate memory for the summed-area-table */
154 inst->mem = (uint32_t*) malloc(acc_width*acc_height*SIZE_RGBA*sizeof(uint32_t));
155 inst->acc = (uint32_t**) malloc(acc_width*acc_height*sizeof(uint32_t*));
156 /* point at the right place */
157 iter_mem = inst->mem;
158 iter_acc = inst->acc;
159 for (i=0; i<acc_width*acc_height; ++i)
160 {
161 *iter_acc++ = iter_mem;
162 iter_mem += SIZE_RGBA;
163 }
164 return (f0r_instance_t)inst;
165 }
166
167 static void blur_destruct(f0r_instance_t instance)
168 {
169 squareblur_instance_t* inst =
170 (squareblur_instance_t*)instance;
171 free(inst->acc);
172 free(inst->mem);
173 free(instance);
174 }
175
176 static void blur_set_param_value(f0r_instance_t instance,
177 f0r_param_t param, int param_index)
178 {
179 assert(instance);
180 squareblur_instance_t* inst = (squareblur_instance_t*)instance;
181
182 switch(param_index)
183 {
184 case 0:
185 /* kernel size */
186 inst->kernel = *((double*)param);
187 break;
188 }
189 }
190
191 static void blur_get_param_value(f0r_instance_t instance,
192 f0r_param_t param, int param_index)
193 {
194 assert(instance);
195 squareblur_instance_t* inst = (squareblur_instance_t*)instance;
196
197 switch(param_index)
198 {
199 case 0:
200 *((double*)param) = inst->kernel;
201 break;
202 }
203 }
204
205 static void blur_update(f0r_instance_t instance, double time,
206 const uint32_t* inframe, uint32_t* outframe)
207 {
208 assert(instance);
209 squareblur_instance_t* inst = (squareblur_instance_t*)instance;
210
211 unsigned int width = inst->width;
212 unsigned int height = inst->height;
213 unsigned int acc_width = width+1; /* width of the summed area table */
214 unsigned int max = MAX(width, height);
215 unsigned int kernel_size = (unsigned int) (inst->kernel * max / 2.0);
216
217 unsigned int x, y;
218 unsigned int x0, x1, y0, y1;
219 unsigned int area;
220
221 if (kernel_size <= 0)
222 {
223 /* No blur, just copy image. */
224 memcpy(outframe, inframe, width*height*sizeof(uint32_t));
225 }
226 else
227 {
228 assert(inst->acc);
229 unsigned char* dst = (unsigned char*)outframe;
230 uint32_t** acc = inst->acc;
231 uint32_t sum[SIZE_RGBA];
232 unsigned int y0_offset, y1_offset;
233
234 /* Compute the summed area table. */
235 update_summed_area_table(inst, inframe);
236
237 /* Loop through the image's pixels. */
238 for (y=0;y<height;y++)
239 {
240 for (x=0;x<width;x++)
241 {
242 /* The kernel's coordinates. */
243 x0 = MAX(x - kernel_size, 0);
244 x1 = MIN(x + kernel_size + 1, width);
245 y0 = MAX(y - kernel_size, 0);
246 y1 = MIN(y + kernel_size + 1, height);
247
248 /* Get the sum in the current kernel. */
249 area = (x1-x0)*(y1-y0);
250
251 y0_offset = y0*acc_width;
252 y1_offset = y1*acc_width;
253
254 /* it is assumed that (x0,y0) <= (x1,y1) */
255 memcpy(sum, acc[y1_offset + x1], SIZE_RGBA*sizeof(uint32_t));
256 subtract_acc(sum, acc[y1_offset + x0]);
257 subtract_acc(sum, acc[y0_offset + x1]);
258 add_acc(sum, acc[y0_offset + x0]);
259
260 /* Take the mean and copy it to output. */
261 divide(dst, sum, area);
262
263 /* Increment iterator. */
264 dst += SIZE_RGBA;
265 }
266 }
267 }
268 }
269
0 /* blur.h
1 * Copyright (C) 2004--2005 Mathieu Guindon
2 * Julien Keable
3 * Jean-Sebastien Senecal (js@drone.ws)
4 *
5 * Modified by Richard Spindler (richard.spindler AT gmail.com) for blurring in
6 * the mask0mate Frei0r plugin.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <string.h>
26
27 #include "frei0r.h"
28
29 #define SIZE_RGBA 4
30
31 static inline int MAX(int a, int b)
32 {
33 return (a > b ? a : b);
34 }
35
36 static inline int MIN(int a, int b)
37 {
38 return (a < b ? a : b);
39 }
40
41 static inline void subtract_acc(uint32_t *dst, const uint32_t *src)
42 {
43 int n=SIZE_RGBA;
44 while (n--)
45 *dst++ -= *src++;
46 }
47
48 static inline void add_acc(uint32_t *dst, const uint32_t *src)
49 {
50 int n=SIZE_RGBA;
51 while (n--)
52 *dst++ += *src++;
53 }
54
55 static inline void divide(unsigned char *dst, const uint32_t *src, const unsigned int val)
56 {
57 int n=SIZE_RGBA;
58 while (n--)
59 *dst++ = *src++ / val;
60 }
61
62 typedef struct squareblur_instance
63 {
64 unsigned int width;
65 unsigned int height;
66 double kernel; /* the kernel size, as a percentage of the biggest of width and height */
67 uint32_t *mem; /* memory accumulation matrix of uint32_t (size = acc_width*acc_height*SIZE_RGBA) */
68 uint32_t **acc; /* accumulation matrix of pointers to SIZE_RGBA consecutive uint32_t in mem (size = acc_width*acc_height) */
69 } squareblur_instance_t;
70
71 /* Updates the summed area table. */
72 static void update_summed_area_table(squareblur_instance_t *inst, const uint32_t *src)
73 {
74 register unsigned char *iter_data;
75 register uint32_t *iter_mem;
76 register unsigned int i, x, y;
77
78 uint32_t acc_buffer[SIZE_RGBA]; /* accumulation buffer */
79
80 unsigned int row_width;
81 unsigned int width, height;
82 unsigned int cell_size;
83
84 /* Compute basic params. */
85 width = inst->width+1;
86 height = inst->height+1;
87 row_width = SIZE_RGBA * width;
88 cell_size = SIZE_RGBA * sizeof(uint32_t);
89
90 /* Init iterators. */
91 iter_data = (unsigned char*) src;
92 iter_mem = inst->mem;
93
94 /* Process first row (all zeros). */
95 memset(iter_mem, 0, row_width * cell_size);
96 iter_mem += row_width;
97
98 if (height >= 1)
99 {
100 /* Process second row. */
101 memset(acc_buffer, 0, cell_size);
102 memset(iter_mem, 0, cell_size); /* first column is void */
103 iter_mem += SIZE_RGBA;
104 for (x=1; x<width; ++x)
105 {
106 for (i=0; i<SIZE_RGBA; ++i)
107 *iter_mem++ = (acc_buffer[i] += *iter_data++);
108 }
109
110 /* Process other rows. */
111 for (y=2; y<height; ++y)
112 {
113 /* Copy upper line. */
114 memcpy(iter_mem, iter_mem - row_width, row_width * sizeof(uint32_t));
115
116 /* Process row. */
117 memset(acc_buffer, 0, cell_size);
118 memset(iter_mem, 0, cell_size); /* first column is void */
119 iter_mem += SIZE_RGBA;
120 for (x=1; x<width; ++x)
121 {
122 for (i=0; i<SIZE_RGBA; ++i)
123 *iter_mem++ += (acc_buffer[i] += *iter_data++);
124 }
125 }
126 }
127 }
128
129 static void blur_get_param_info(f0r_param_info_t* info, int param_index)
130 {
131 switch(param_index)
132 {
133 case 0:
134 info->name = "Kernel size";
135 info->type = F0R_PARAM_DOUBLE;
136 info->explanation = "The size of the kernel, as a proportion to its coverage of the image";
137 break;
138 }
139 }
140
141 static f0r_instance_t blur_construct(unsigned int width, unsigned int height)
142 {
143 squareblur_instance_t* inst =
144 (squareblur_instance_t*)malloc(sizeof(squareblur_instance_t));
145 unsigned int i;
146 unsigned int acc_width, acc_height = height+1;
147 uint32_t* iter_mem;
148 uint32_t** iter_acc;
149 /* set params */
150 inst->width = width; inst->height = height;
151 acc_width = width+1; acc_height = height+1;
152 inst->kernel = 0.0;
153 /* allocate memory for the summed-area-table */
154 inst->mem = (uint32_t*) malloc(acc_width*acc_height*SIZE_RGBA*sizeof(uint32_t));
155 inst->acc = (uint32_t**) malloc(acc_width*acc_height*sizeof(uint32_t*));
156 /* point at the right place */
157 iter_mem = inst->mem;
158 iter_acc = inst->acc;
159 for (i=0; i<acc_width*acc_height; ++i)
160 {
161 *iter_acc++ = iter_mem;
162 iter_mem += SIZE_RGBA;
163 }
164 return (f0r_instance_t)inst;
165 }
166
167 static void blur_destruct(f0r_instance_t instance)
168 {
169 squareblur_instance_t* inst =
170 (squareblur_instance_t*)instance;
171 free(inst->acc);
172 free(inst->mem);
173 free(instance);
174 }
175
176 static void blur_set_param_value(f0r_instance_t instance,
177 f0r_param_t param, int param_index)
178 {
179 assert(instance);
180 squareblur_instance_t* inst = (squareblur_instance_t*)instance;
181
182 switch(param_index)
183 {
184 case 0:
185 /* kernel size */
186 inst->kernel = *((double*)param);
187 break;
188 }
189 }
190
191 static void blur_get_param_value(f0r_instance_t instance,
192 f0r_param_t param, int param_index)
193 {
194 assert(instance);
195 squareblur_instance_t* inst = (squareblur_instance_t*)instance;
196
197 switch(param_index)
198 {
199 case 0:
200 *((double*)param) = inst->kernel;
201 break;
202 }
203 }
204
205 static void blur_update(f0r_instance_t instance, double time,
206 const uint32_t* inframe, uint32_t* outframe)
207 {
208 assert(instance);
209 squareblur_instance_t* inst = (squareblur_instance_t*)instance;
210
211 unsigned int width = inst->width;
212 unsigned int height = inst->height;
213 unsigned int acc_width = width+1; /* width of the summed area table */
214 unsigned int max = MAX(width, height);
215 unsigned int kernel_size = (unsigned int) (inst->kernel * max / 2.0);
216
217 unsigned int x, y;
218 unsigned int x0, x1, y0, y1;
219 unsigned int area;
220
221 if (kernel_size <= 0)
222 {
223 /* No blur, just copy image. */
224 memcpy(outframe, inframe, width*height*sizeof(uint32_t));
225 }
226 else
227 {
228 assert(inst->acc);
229 unsigned char* dst = (unsigned char*)outframe;
230 uint32_t** acc = inst->acc;
231 uint32_t sum[SIZE_RGBA];
232 unsigned int y0_offset, y1_offset;
233
234 /* Compute the summed area table. */
235 update_summed_area_table(inst, inframe);
236
237 /* Loop through the image's pixels. */
238 for (y=0;y<height;y++)
239 {
240 for (x=0;x<width;x++)
241 {
242 /* The kernel's coordinates. */
243 x0 = MAX(x - kernel_size, 0);
244 x1 = MIN(x + kernel_size + 1, width);
245 y0 = MAX(y - kernel_size, 0);
246 y1 = MIN(y + kernel_size + 1, height);
247
248 /* Get the sum in the current kernel. */
249 area = (x1-x0)*(y1-y0);
250
251 y0_offset = y0*acc_width;
252 y1_offset = y1*acc_width;
253
254 /* it is assumed that (x0,y0) <= (x1,y1) */
255 memcpy(sum, acc[y1_offset + x1], SIZE_RGBA*sizeof(uint32_t));
256 subtract_acc(sum, acc[y1_offset + x0]);
257 subtract_acc(sum, acc[y0_offset + x1]);
258 add_acc(sum, acc[y0_offset + x0]);
259
260 /* Take the mean and copy it to output. */
261 divide(dst, sum, area);
262
263 /* Increment iterator. */
264 dst += SIZE_RGBA;
265 }
266 }
267 }
268 }
269
0 /*
1 * frei0r/cairo.h
2 * Copyright 2012 Janne Liljeblad
3 *
4 * This file is part of Frei0r.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22 #include <cairo.h>
23 #include <string.h>
24 #include "frei0r/math.h"
25
26 /**
27 * String identifiers for gradient types available using Cairo.
28 */
29 #define GRADIENT_LINEAR "gradient_linear"
30 #define GRADIENT_RADIAL "gradient_radial"
31
32 /**
33 * String identifiers for blend modes available using Cairo.
34 */
35 #define NORMAL "normal"
36 #define ADD "add"
37 #define SATURATE "saturate"
38 #define MULTIPLY "multiply"
39 #define SCREEN "screen"
40 #define OVERLAY "overlay"
41 #define DARKEN "darken"
42 #define LIGHTEN "lighten"
43 #define COLORDODGE "colordodge"
44 #define COLORBURN "colorburn"
45 #define HARDLIGHT "hardlight"
46 #define SOFTLIGHT "softlight"
47 #define DIFFERENCE "difference"
48 #define EXCLUSION "exclusion"
49 #define HSLHUE "hslhue"
50 #define HSLSATURATION "hslsaturation"
51 #define HSLCOLOR "hslcolor"
52 #define HSLLUMINOSITY "hslluminosity"
53
54
55 /**
56 * frei0r_cairo_set_operator
57 * @cr: Cairo context
58 * @op: String identifier for a blend mode
59 *
60 * Sets cairo context to use the defined blend mode for all paint operations.
61 */
62 void frei0r_cairo_set_operator(cairo_t *cr, char *op)
63 {
64 if(strcmp(op, NORMAL) == 0)
65 {
66 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
67 }
68 else if(strcmp(op, ADD) == 0)
69 {
70 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
71 }
72 else if(strcmp(op, SATURATE) == 0)
73 {
74 cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE);
75 }
76 else if(strcmp(op, MULTIPLY) == 0)
77 {
78 cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY);
79 }
80 else if(strcmp(op, SCREEN) == 0)
81 {
82 cairo_set_operator (cr, CAIRO_OPERATOR_SCREEN);
83 }
84 else if(strcmp(op, OVERLAY) == 0)
85 {
86 cairo_set_operator (cr, CAIRO_OPERATOR_OVERLAY);
87 }
88 else if(strcmp(op, DARKEN) == 0)
89 {
90 cairo_set_operator (cr, CAIRO_OPERATOR_DARKEN);
91 }
92 else if(strcmp(op, LIGHTEN) == 0)
93 {
94 cairo_set_operator (cr, CAIRO_OPERATOR_LIGHTEN);
95 }
96 else if(strcmp(op, COLORDODGE) == 0)
97 {
98 cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_DODGE);
99 }
100 else if(strcmp(op, COLORBURN) == 0)
101 {
102 cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_BURN);
103 }
104 else if(strcmp(op, HARDLIGHT) == 0)
105 {
106 cairo_set_operator (cr, CAIRO_OPERATOR_HARD_LIGHT);
107 }
108 else if(strcmp(op, SOFTLIGHT) == 0)
109 {
110 cairo_set_operator (cr, CAIRO_OPERATOR_SOFT_LIGHT);
111 }
112 else if(strcmp(op, DIFFERENCE) == 0)
113 {
114 cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
115 }
116 else if(strcmp(op, EXCLUSION) == 0)
117 {
118 cairo_set_operator (cr, CAIRO_OPERATOR_EXCLUSION);
119 }
120 else if(strcmp(op, HSLHUE) == 0)
121 {
122 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_HUE);
123 }
124 else if(strcmp(op, HSLSATURATION) == 0)
125 {
126 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_SATURATION);
127 }
128 else if(strcmp(op, HSLCOLOR) == 0)
129 {
130 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_COLOR);
131 }
132 else if(strcmp(op, HSLLUMINOSITY ) == 0)
133 {
134 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_LUMINOSITY);
135 }
136 else
137 {
138 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
139 }
140 }
141
142
143 /**
144 * frei0r_cairo_set_rgba_LITTLE_ENDIAN
145 * @cr: Cairo context
146 * @red: red component, 0 - 1
147 * @green: green component, 0 - 1
148 * @blue: blue component, 0 - 1
149 * @alpha: opacity of color, 0 -1
150 *
151 * Sets cairo context to use the defined color paint operations.
152 * Switches red and blue channels to get correct color on little endian machines.
153 * This method only works correctly on little endian machines.
154 */
155 void frei0r_cairo_set_rgba_LITTLE_ENDIAN(cairo_t* cr, double red, double green, double blue, double alpha)
156 {
157 cairo_set_source_rgba (cr, blue, green, red, alpha);
158 }
159
160 /**
161 * frei0r_cairo_set_rgb_LITTLE_ENDIAN
162 * @cr: Cairo context
163 * @red: red component, 0 - 1
164 * @green: green component, 0 - 1
165 * @blue: blue component, 0 - 1
166 *
167 * Sets cairo context to use the defined color paint operations.
168 * Switches red and blue channels to get correct color on little endian machines.
169 * This method only works correctly on little endian machines.
170 */
171 void frei0r_cairo_set_rgb_LITTLE_ENDIAN(cairo_t* cr, double red, double green, double blue)
172 {
173 cairo_set_source_rgb (cr, blue, green, red);
174 }
175
176 /**
177 * freior_cairo_set_color_stop_rgba_LITTLE_ENDIAN(
178 * @pat: Cairo pattern
179 * @offset: offset of color position in pattern space, 0 - 1
180 * @red: red component, 0 - 1
181 * @green: green component, 0 - 1
182 * @blue: blue component, 0 - 1
183 * @alpha: opacity of color, 0 -1
184 *
185 * Sets color stop for cairo patterns.
186 * Switches red and blue channels to get correct color on little endian machines.
187 * This method only works correctly on little endian machines.
188 */
189 void freior_cairo_set_color_stop_rgba_LITTLE_ENDIAN(cairo_pattern_t *pat, double offset,
190 double red, double green, double blue, double alpha)
191 {
192 cairo_pattern_add_color_stop_rgba (pat, offset, blue, green, red, alpha);
193 }
194
195 /**
196 * frei0r_cairo_get_pixel_position
197 * @norm_pos: position in range 0 - 1, either x or y
198 * @dim: dimension, either witdh or height
199 *
200 * Converts double range [0 -> 1] to pixel range [-2*dim -> 3*dim]. Input 0.4 gives position 0.
201 *
202 * Returns: position in pixels
203 */
204 double frei0r_cairo_get_pixel_position (double norm_pos, int dim)
205 {
206 double pos_o = -(dim * 2.0);
207 return pos_o + norm_pos * dim * 5.0;
208 }
209
210 /**
211 * frei0r_cairo_get_scale
212 * @norm_scale: scale in range 0 - 1
213 *
214 * Converts double range [0 -> 1] to scale range [0 -> 5]. Input 0.2 gives scale 1.0.
215 *
216 * Returns: scale
217 */
218 double frei0r_cairo_get_scale (double norm_scale)
219 {
220 return norm_scale * 5.0;
221 }
222
223 /**
224 * Convert frei0r RGBA to pre-multiplied alpha as needed by Cairo.
225 *
226 * \param rgba the image buffer with format F0R_COLOR_MODEL_RGBA8888
227 * \param pixels the size of the image buffer in number of pixels
228 * \param alpha if >= 0, the alpha channel will be set to this value
229 * \see frei0r_cairo_unpremultiply_rgba
230 */
231 void frei0r_cairo_premultiply_rgba (unsigned char *rgba, int pixels, int alpha)
232 {
233 int i = pixels + 1;
234 while ( --i ) {
235 register unsigned char a = rgba[3];
236 if (a == 0) {
237 *((uint32_t *)rgba) = 0;
238 } else if (a < 0xff) {
239 rgba[0] = ( rgba[0] * a ) >> 8;
240 rgba[1] = ( rgba[1] * a ) >> 8;
241 rgba[2] = ( rgba[2] * a ) >> 8;
242 }
243 if (alpha >= 0) rgba[3] = alpha;
244 rgba += 4;
245 }
246 }
247
248 /**
249 * Convert Cairo ARGB pre-multiplied alpha to frei0r straight RGBA.
250 *
251 * \param rgba the image buffer with format CAIRO_FORMAT_ARGB32
252 * \param pixels the size of the image buffer in number of pixels
253 * \see frei0r_cairo_premultiply_rgba
254 */
255 void frei0r_cairo_unpremultiply_rgba (unsigned char *rgba, int pixels)
256 {
257 int i = pixels + 1;
258 while ( --i ) {
259 register unsigned char a = rgba[3];
260 if (a > 0 && a < 0xff) {
261 rgba[0] = MIN(( rgba[0] << 8 ) / a, 255);
262 rgba[1] = MIN(( rgba[1] << 8 ) / a, 255);
263 rgba[2] = MIN(( rgba[2] << 8 ) / a, 255);
264 }
265 rgba += 4;
266 }
267 }
268
269 /**
270 * Convert frei0r RGBA to pre-multiplied alpha as needed by Cairo.
271 *
272 * \param rgba the image buffer with format F0R_COLOR_MODEL_RGBA8888
273 * \param pixels the size of the image buffer in number of pixels
274 * \param alpha if >= 0, the alpha channel will be set to this value
275 * \see frei0r_cairo_premultiply_rgba
276 *
277 * This is the same as frei0r_cairo_premultiply_rgba but it writes the
278 * output to a different buffer.
279 */
280 void frei0r_cairo_premultiply_rgba2 (unsigned char *in, unsigned char *out,
281 int pixels, int alpha)
282 {
283 int i = pixels + 1;
284 while ( --i ) {
285 register unsigned char a = in[3];
286 if (a == 0) {
287 *((uint32_t *)out) = 0;
288 } else if (a == 0xff) {
289 memcpy(out, in, 4);
290 } else {
291 out[0] = ( in[0] * a ) >> 8;
292 out[1] = ( in[1] * a ) >> 8;
293 out[2] = ( in[2] * a ) >> 8;
294 if (alpha < 0)
295 out[3] = a;
296 }
297 if (alpha >= 0)
298 out[3] = alpha;
299 in += 4;
300 out += 4;
301 }
302 }
0 /* cfc.h
1 * uchar->float and float->uchar conversion for packed RGBA video
2 * with flexible gamma correction
3 *
4 * Copyright (C) 2012 Marko Cebokli http://lea.hamradio.si/~s57uuu
5 * This file is a part of the Frei0r package
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 // the float to uint8_t conversion is done
23 // using Spitzak type tables (upper 16 bits
24 // of a float value used as table index)
25 // see http://mysite.verizon.net/spitzak/conversion/
26
27 #include <math.h>
28 #include <inttypes.h>
29
30
31 typedef struct
32 {
33 float r;
34 float g;
35 float b;
36 float a;
37 } float_rgba;
38
39 //------------------------------------------------------
40 //the following gamma functions need not be speed optimized,
41 //as they are only used for table generation
42
43 //--------------------------------------------------------
44 //rec 709 gamma forward (linear to gamma)
45 //a = input, should be in the 0.0 to 1.0 range
46 static inline float gamma_709_f(float a)
47 {
48 return (a<=0.018) ? 4.5*a : 1.099*powf(a,0.45)-0.099;
49 }
50
51 //--------------------------------------------------------
52 //rec 709 gamma backward (gamma to linear)
53 //a = input, should be in the 0.0 to 1.0 range
54 static inline float gamma_709_b(float a)
55 {
56 return (a<=0.081) ? a/4.5 : powf((a+0.099)/1.099,1.0/0.45);
57 }
58
59 //----------------------------------------------------
60 //sRGB gamma forward (linear to gamma)
61 //a = input, should be in the 0.0 to 1.0 range
62 static inline float gamma_sRGB_f(float a)
63 {
64 return (a<=0.0031308) ? 12.92*a : 1.055*powf(a,1.0/2.4)-0.055;
65 }
66
67 //--------------------------------------------------------
68 //sRGB gamma backward (gamma to linear)
69 //a = input, should be in the 0.0 to 1.0 range
70 static inline float gamma_sRGB_b(float a)
71 {
72 return (a<=0.04045) ? a/12.92 : powf((a+0.055)/1.055,2.4);
73 }
74
75 //----------------------------------------------------
76 //plain gamma (power function) forward (linear to gamma)
77 //a = input, should be in the 0.0 to 1.0 range
78 static inline float gamma_plain_f(float a, float g)
79 {
80 return powf(a,1.0/g);
81 }
82
83 //--------------------------------------------------------
84 //plain gamma (power function) backward (gamma to linear)
85 //a = input, should be in the 0.0 to 1.0 range
86 static inline float gamma_plain_b(float a, float g)
87 {
88 return powf(a,g);
89 }
90
91 //--------------------------------------------------------
92 //dummy function for linear tables (no gamma)
93 //g = gamma value
94 static inline float gamma_none(float a)
95 {
96 return a;
97 }
98
99 //------------------------------------------------
100 //expand highlights using a modified Spitzak formula
101 //with limited max output value (250)
102 //(for values up to 2500 use 1.0001 and 0.493)
103 //input [0...1]
104 //output [0...250]
105 static inline float exp_hl(float a)
106 {
107 return (a<=0.4781) ? a : 0.25/(1.001-a);
108 }
109
110 //------------------------------------------------------------
111 //compress highlights using a modified Spitzak formula
112 //with limited max input value (250)
113 //(for values up to 2500 use 1.0001 and 0.493)
114 //input [0...250]
115 //output [0...1]
116 static inline float cps_hl(float a)
117 {
118 return (a<=0.4781) ? a : 1.001-0.25/a;
119 }
120
121 //----------------------------------------------------------
122 //float to char conversion is done using the upper 16 bits
123 //of the float number as an index into the conversion table.
124 //This union is used for type punning, to avoid problems
125 //with compiler optimizations, as the read access in the
126 //cfc_tab_8 function directly follows writing
127 typedef union
128 {
129 float a;
130 uint16_t i[2];
131 } flint;
132
133 //--------------------------------------------------------
134 //generate forward and backward conversion tables
135 //for 8 bit (uint8_t) video
136 //*ft = forward table (float to uchar, linear to gamma)
137 // must have space for 65536 char elements
138 //*bt = backward table (uchar to float, gamma to linear)
139 // must have space for 256 float elements
140 //type = what kind of gamma function will be used:
141 // 0 = linear (no gamma, just multiply/divide by 255)
142 // 1 = plain gamma (pure power function)
143 // 2 = rec 709 gamma
144 // 3 = sRGB gamma
145 // 4 = sRGB gamma with highlight expansion/compression
146 // types 0...3 map to [0...1] linear float range
147 // type 4 maps to [0...250] linear float range
148 //g = gamma value, 0.3 to 3.0 (only used with type=1)
149 static inline void cfc_tab_8(uint8_t *ft, float *bt, int type, float g)
150 {
151 uint16_t i;
152 float a;
153 flint fi;
154
155 // *** generate float to char conversion table ***
156 for (i=0;i<128;i++) //positive denormals map to zero
157 ft[i]=0;
158
159 for (i=128;i<=32639;i++) //positive numbers map to 0...255
160 {
161 //#if FREI0R_BYTE_ORDER == FREI0R_BIG_ENDIAN
162 // fi.i[0]=i; fi.i[1]=0x8000; //big endian
163 //#endif
164 //#if FREI0R_BYTE_ORDER == FREI0R_LITTLE_ENDIAN
165 fi.i[1]=i; fi.i[0]=0x8000; //little endian
166 //#endif
167 a=fi.a;
168 switch (type)
169 {
170 case 0: a=gamma_none(a); break;
171 case 1: a=gamma_plain_f(a,g); break;
172 case 2: a=gamma_709_f(a); break;
173 case 3: a=gamma_sRGB_f(a); break;
174 case 4: a=cps_hl(a); a=gamma_sRGB_f(a); break;
175 default: break;
176 }
177 if (a>0.9999) a=0.9999;
178 ft[i]=(uint8_t)(256.0*a);
179 }
180
181 for (i=32640;i<32768;i++) //positive NANs and infinite map to 255
182 ft[i]=255;
183 for (i=32768;i!=65535;i++) //everything negative maps to 0
184 ft[i]=0;
185 ft[65535]=0;
186
187
188 // *** generate char to float conversion table ***
189 for (i=0;i<=255;i++)
190 {
191 a=((float)i+0.5)/256.0;
192 switch (type)
193 {
194 case 0: a=gamma_none(a); break;
195 case 1: a=gamma_plain_b(a,g); break;
196 case 2: a=gamma_709_b(a); break;
197 case 3: a=gamma_sRGB_b(a); break;
198 case 4: a=gamma_sRGB_b(a); a=exp_hl(a); break;
199 default: break;
200 }
201 bt[i]=a;
202 }
203 }
204
205 //--------------------------------------------------------
206 //convert from paked uchar RGBA to packed float RGBA
207 //w,h are width and height of the image
208 //tab = table used for RGB conversion
209 //atab = table used for alpha converion (usually linear)
210 static inline void RGBA8_2_float(const uint32_t *in, float_rgba *out, int w, int h, float *tab, float *atab)
211 {
212 int i;
213 uint8_t *cin=(uint8_t *)in;
214
215 for (i=0;i<w*h;i++)
216 {
217 out[i].r=tab[*cin++];
218 out[i].g=tab[*cin++];
219 out[i].b=tab[*cin++];
220 out[i].a=atab[*cin++];
221 }
222 }
223
224 //--------------------------------------------------------
225 //convert from paked uchar RGBA to packed float RGBA,
226 //covert RGB only, SKIP ALPHA
227 //w,h are width and height of the image
228 //tab = table used for RGB conversion
229 static inline void RGB8_2_float(const uint32_t *in, float_rgba *out, int w, int h, float *tab)
230 {
231 int i;
232 uint8_t *cin=(uint8_t *)in;
233
234 for (i=0;i<w*h;i++)
235 {
236 out[i].r=tab[*cin++];
237 out[i].g=tab[*cin++];
238 out[i].b=tab[*cin++];
239 cin++;
240 }
241 }
242
243
244 //--------------------------------------------------------
245 //in the following conversions, we can afford "direct" type punning
246 //as the array already exists from well before (I hope :-)
247 //
248 //#if FREI0R_BYTE_ORDER == FREI0R_BIG_ENDIAN
249 //big endian most significant 16 bit word from 32bit float
250 //#define MSWF(x) *(uint16_t*)x
251 //#endif
252 //
253 //#if FREI0R_BYTE_ORDER == FREI0R_LITTLE_ENDIAN
254 //little endian most significant 16 bit word from 32bit float
255 #define MSWF(x) *((uint16_t*)x+1)
256 //#endif
257
258 //----------------------------------------------------------
259 //convert from packed float RGBA to packed uchar RGBA
260 //tab = table used for RGB conversion
261 //atab = table used for alpha converion (usually linear)
262 static inline void float_2_RGBA8(const float_rgba *in, uint32_t *out, int w, int h, uint8_t *tab, uint8_t *atab)
263 {
264 int i;
265 uint8_t *cout=(uint8_t *)out;
266
267 for (i=0;i<w*h;i++)
268 {
269 *cout++ = tab[MSWF(&in[i].r)];
270 *cout++ = tab[MSWF(&in[i].g)];
271 *cout++ = tab[MSWF(&in[i].b)];
272 *cout++ = atab[MSWF(&in[i].a)];
273 }
274 }
275
276 //----------------------------------------------------------
277 //convert from packed float RGBA to packed uchar RGBA
278 //covert RGB only, SKIP ALPHA
279 //tab = table used for RGB conversion
280 static inline void float_2_RGB8(const float_rgba *in, uint32_t *out, int w, int h, uint8_t *tab)
281 {
282 int i;
283 uint8_t *cout=(uint8_t *)out;
284
285 for (i=0;i<w*h;i++)
286 {
287 *cout++ = tab[MSWF(&in[i].r)];
288 *cout++ = tab[MSWF(&in[i].g)];
289 *cout++ = tab[MSWF(&in[i].b)];
290 cout++;
291 }
292 }
293
294 #undef MSWF
295
296
297 //--------------------------------------------------
298 // -- Single value conversion --
299 //there is no function for single uint8 to float, because
300 //that is just a simple table lookup
301 //
302 //because float_2_uint8() can be called immediately after
303 //the input value has been created, type punning has to be
304 //done properly, with a union
305
306 //#if FREI0R_BYTE_ORDER == FREI0R_LITTLE_ENDIAN
307 static inline uint8_t float_2_uint8(const float *in, uint8_t *tab)
308 {
309 return tab[((flint*)in)->i[1]];
310 }
311 //endif
312
313 //#if FREI0R_BYTE_ORDER == FREI0R_BIG_ENDIAN
314 //static inline float_2_uint8(const float *in, uint8_t *tab)
315 //{
316 //return tab[((flint*)in)->i[0]];
317 //}
318 //#endif
0 /* frei0r/colorspace.h
1 * Copyright (C) 2004 Mathieu Guindon, Julien Keable, Jean-Sebastien Senecal
2 * This file is part of Frei0r.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifndef INCLUDED_FREI0R_COLORSPACE_H
20 #define INCLUDED_FREI0R_COLORSPACE_H
21
22 #include "frei0r/math.h"
23 #include <stdlib.h>
24 #include <math.h>
25
26 // # Basic colorspace convert functions (from the Gimp gimpcolorspace.h) ####
27
28 /* int functions */
29
30 /**
31 * rgb_to_hsv_int
32 * @red: The red channel value, returns the Hue channel
33 * @green: The green channel value, returns the Saturation channel
34 * @blue: The blue channel value, returns the Value channel
35 *
36 * The arguments are pointers to int representing channel values in
37 * the RGB colorspace, and the values pointed to are all in the range
38 * [0, 255].
39 *
40 * The function changes the arguments to point to the HSV value
41 * corresponding, with the returned values in the following
42 * ranges: H [0, 360], S [0, 255], V [0, 255].
43 **/
44 inline void
45 rgb_to_hsv_int (int *red /* returns hue */,
46 int *green /* returns saturation */,
47 int *blue /* returns value */)
48 {
49 double r, g, b;
50 double h, s, v;
51 double min;
52 double delta;
53
54 r = *red;
55 g = *green;
56 b = *blue;
57
58 if (r > g)
59 {
60 v = MAX (r, b);
61 min = MIN (g, b);
62 }
63 else
64 {
65 v = MAX (g, b);
66 min = MIN (r, b);
67 }
68
69 delta = v - min;
70
71 if (v == 0.0)
72 s = 0.0;
73 else
74 s = delta / v;
75
76 if (s == 0.0)
77 h = 0.0;
78 else
79 {
80 if (r == v)
81 h = 60.0 * (g - b) / delta;
82 else if (g == v)
83 h = 120 + 60.0 * (b - r) / delta;
84 else
85 h = 240 + 60.0 * (r - g) / delta;
86
87 if (h < 0.0)
88 h += 360.0;
89 if (h > 360.0)
90 h -= 360.0;
91 }
92
93 *red = ROUND (h);
94 *green = ROUND (s * 255.0);
95 *blue = ROUND (v);
96 }
97
98 /**
99 * hsv_to_rgb_int
100 * @hue: The hue channel, returns the red channel
101 * @saturation: The saturation channel, returns the green channel
102 * @value: The value channel, returns the blue channel
103 *
104 * The arguments are pointers to int, with the values pointed to in the
105 * following ranges: H [0, 360], S [0, 255], V [0, 255].
106 *
107 * The function changes the arguments to point to the RGB value
108 * corresponding, with the returned values all in the range [0, 255].
109 **/
110 inline void
111 hsv_to_rgb_int (int *hue /* returns red */,
112 int *saturation /* returns green */,
113 int *value /* returns blue */)
114 {
115 double h, s, v, h_temp;
116 double f, p, q, t;
117 int i;
118
119 if (*saturation == 0)
120 {
121 *hue = *value;
122 *saturation = *value;
123 // *value = *value;
124 }
125 else
126 {
127 h = *hue;
128 s = *saturation / 255.0;
129 v = *value / 255.0;
130
131 if (h == 360)
132 h_temp = 0;
133 else
134 h_temp = h;
135
136 h_temp = h_temp / 60.0;
137 i = (int) floor (h_temp);
138 f = h_temp - i;
139 p = v * (1.0 - s);
140 q = v * (1.0 - (s * f));
141 t = v * (1.0 - (s * (1.0 - f)));
142
143 switch (i)
144 {
145 case 0:
146 *hue = ROUND (v * 255.0);
147 *saturation = ROUND (t * 255.0);
148 *value = ROUND (p * 255.0);
149 break;
150
151 case 1:
152 *hue = ROUND (q * 255.0);
153 *saturation = ROUND (v * 255.0);
154 *value = ROUND (p * 255.0);
155 break;
156
157 case 2:
158 *hue = ROUND (p * 255.0);
159 *saturation = ROUND (v * 255.0);
160 *value = ROUND (t * 255.0);
161 break;
162
163 case 3:
164 *hue = ROUND (p * 255.0);
165 *saturation = ROUND (q * 255.0);
166 *value = ROUND (v * 255.0);
167 break;
168
169 case 4:
170 *hue = ROUND (t * 255.0);
171 *saturation = ROUND (p * 255.0);
172 *value = ROUND (v * 255.0);
173 break;
174
175 case 5:
176 *hue = ROUND (v * 255.0);
177 *saturation = ROUND (p * 255.0);
178 *value = ROUND (q * 255.0);
179 break;
180 }
181 }
182 }
183
184 /**
185 * rgb_to_hsl_int
186 * @red: Red channel, returns Hue channel
187 * @green: Green channel, returns Lightness channel
188 * @blue: Blue channel, returns Saturation channel
189 *
190 * The arguments are pointers to int representing channel values in the
191 * RGB colorspace, and the values pointed to are all in the range [0, 255].
192 *
193 * The function changes the arguments to point to the corresponding HLS
194 * value with the values pointed to in the following ranges: H [0, 360],
195 * L [0, 255], S [0, 255].
196 **/
197 inline void
198 rgb_to_hsl_int (unsigned int *red /* returns red */,
199 unsigned int *green /* returns green */,
200 unsigned int *blue /* returns blue */)
201 {
202 unsigned int r, g, b;
203 double h, s, l;
204 unsigned int min, max;
205 unsigned int delta;
206
207 r = *red;
208 g = *green;
209 b = *blue;
210
211 if (r > g)
212 {
213 max = MAX (r, b);
214 min = MIN (g, b);
215 }
216 else
217 {
218 max = MAX (g, b);
219 min = MIN (r, b);
220 }
221
222 l = (max + min) / 2.0;
223
224 if (max == min)
225 {
226 s = 0.0;
227 h = 0.0;
228 }
229 else
230 {
231 delta = (max - min);
232
233 if (l < 128)
234 s = 255 * (double) delta / (double) (max + min);
235 else
236 s = 255 * (double) delta / (double) (511 - max - min);
237
238 if (r == max)
239 h = (g - b) / (double) delta;
240 else if (g == max)
241 h = 2 + (b - r) / (double) delta;
242 else
243 h = 4 + (r - g) / (double) delta;
244
245 h = h * 42.5;
246
247 if (h < 0)
248 h += 255;
249 else if (h > 255)
250 h -= 255;
251 }
252
253 *red = ROUND (h);
254 *green = ROUND (s);
255 *blue = ROUND (l);
256 }
257
258 inline int
259 hsl_value_int (double n1,
260 double n2,
261 double hue)
262 {
263 double value;
264
265 if (hue > 255)
266 hue -= 255;
267 else if (hue < 0)
268 hue += 255;
269
270 if (hue < 42.5)
271 value = n1 + (n2 - n1) * (hue / 42.5);
272 else if (hue < 127.5)
273 value = n2;
274 else if (hue < 170)
275 value = n1 + (n2 - n1) * ((170 - hue) / 42.5);
276 else
277 value = n1;
278
279 return ROUND (value * 255.0);
280 }
281
282 /**
283 * hsl_to_rgb_int
284 * @hue: Hue channel, returns Red channel
285 * @saturation: Saturation channel, returns Green channel
286 * @lightness: Lightness channel, returns Blue channel
287 *
288 * The arguments are pointers to int, with the values pointed to in the
289 * following ranges: H [0, 360], L [0, 255], S [0, 255].
290 *
291 * The function changes the arguments to point to the RGB value
292 * corresponding, with the returned values all in the range [0, 255].
293 **/
294 inline void
295 hsl_to_rgb_int (unsigned int *hue /* returns red */,
296 unsigned int *saturation /* returns green */,
297 unsigned int *lightness /* returns blue */)
298 {
299 double h, s, l;
300
301 h = *hue;
302 s = *saturation;
303 l = *lightness;
304
305 if (s == 0)
306 {
307 /* achromatic case */
308 *hue = (int)l;
309 *lightness = (int)l;
310 *saturation = (int)l;
311 }
312 else
313 {
314 double m1, m2;
315
316 if (l < 128)
317 m2 = (l * (255 + s)) / 65025.0;
318 else
319 m2 = (l + s - (l * s) / 255.0) / 255.0;
320
321 m1 = (l / 127.5) - m2;
322
323 /* chromatic case */
324 *hue = hsl_value_int (m1, m2, h + 85);
325 *saturation = hsl_value_int (m1, m2, h);
326 *lightness = hsl_value_int (m1, m2, h - 85);
327 }
328 }
329
330 /**
331 * gimp_rgb_to_cmyk_int:
332 * @red: the red channel; returns the cyan value (0-255)
333 * @green: the green channel; returns the magenta value (0-255)
334 * @blue: the blue channel; returns the yellow value (0-255)
335 * @pullout: the percentage of black to pull out (0-100); returns
336 * the black value (0-255)
337 *
338 * Does a naive conversion from RGB to CMYK colorspace. A simple
339 * formula that doesn't take any color-profiles into account is used.
340 * The amount of black pullout how can be controlled via the @pullout
341 * parameter. A @pullout value of 0 makes this a conversion to CMY.
342 * A value of 100 causes the maximum amount of black to be pulled out.
343 **/
344 inline void
345 gimp_rgb_to_cmyk_int (int *red,
346 int *green,
347 int *blue,
348 int *pullout)
349 {
350 int c, m, y;
351
352 c = 255 - *red;
353 m = 255 - *green;
354 y = 255 - *blue;
355
356 if (*pullout == 0)
357 {
358 *red = c;
359 *green = m;
360 *blue = y;
361 }
362 else
363 {
364 int k = 255;
365
366 if (c < k) k = c;
367 if (m < k) k = m;
368 if (y < k) k = y;
369
370 k = (k * CLAMP (*pullout, 0, 100)) / 100;
371
372 *red = ((c - k) << 8) / (256 - k);
373 *green = ((m - k) << 8) / (256 - k);
374 *blue = ((y - k) << 8) / (256 - k);
375 *pullout = k;
376 }
377 }
378
379 /**
380 * gimp_cmyk_to_rgb_int:
381 * @cyan: the cyan channel; returns the red value (0-255)
382 * @magenta: the magenta channel; returns the green value (0-255)
383 * @yellow: the yellow channel; returns the blue value (0-255)
384 * @black: the black channel (0-255); doesn't change
385 *
386 * Does a naive conversion from CMYK to RGB colorspace. A simple
387 * formula that doesn't take any color-profiles into account is used.
388 **/
389 inline void
390 cmyk_to_rgb_int (int *cyan,
391 int *magenta,
392 int *yellow,
393 int *black)
394 {
395 int c, m, y, k;
396
397 c = *cyan;
398 m = *magenta;
399 y = *yellow;
400 k = *black;
401
402 if (k)
403 {
404 c = ((c * (256 - k)) >> 8) + k;
405 m = ((m * (256 - k)) >> 8) + k;
406 y = ((y * (256 - k)) >> 8) + k;
407 }
408
409 *cyan = 255 - c;
410 *magenta = 255 - m;
411 *yellow = 255 - y;
412 }
413
414
415 #endif
0 #ifndef INCLUDED_FREI0R_MATH_H
1 #define INCLUDED_FREI0R_MATH_H
2
3 /*
4
5 Code stripped from The Gimp:
6 INT_MULT(a,b,t)
7 INT_MULT3(a,b,c,t)
8 INT_BLEND(a,b,alpha,tmp)
9 CLAMP
10 ROUND
11 MAX255
12
13 Code stripped from Drone:
14 CLAMP0255
15 SQR
16 */
17
18 /* Clamps a int32-range int between 0 and 255 inclusive. */
19 #ifndef CLAMP0255
20 static inline unsigned char CLAMP0255(int32_t a)
21 {
22 return (unsigned char)
23 ( (((-a) >> 31) & a) // 0 if the number was negative
24 | (255 - a) >> 31); // -1 if the number was greater than 255
25 }
26 #endif
27
28 /* Provided temporary int t, returns a * b / 255 */
29 #ifndef INT_MULT
30 #define INT_MULT(a,b,t) ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
31 #endif
32
33 /* This version of INT_MULT3 is very fast, but suffers from some
34 slight roundoff errors. It returns the correct result 99.987
35 percent of the time */
36 #ifndef INT_MULT3
37 #define INT_MULT3(a,b,c,t) ((t) = (a) * (b) * (c) + 0x7F5B, \
38 ((((t) >> 7) + (t)) >> 16))
39 #endif
40
41 #ifndef INT_BLEND
42 #define INT_BLEND(a,b,alpha,tmp) (INT_MULT((a) - (b), alpha, tmp) + (b))
43 #endif
44
45 #ifndef CLAMP
46 //! Clamp x at min and max
47 #define CLAMP(x,min,max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
48 #endif
49
50 #ifndef ROUND
51 //! Round.
52 #define ROUND(x) ((int32_t)((x)+0.5))
53 #endif
54
55 #ifndef SQR
56 //! Square.
57 #define SQR(x) ((x) * (x))
58 #endif
59
60 #ifndef MAX255
61 //! Limit a (0->511) int to 255.
62 uint8_t MAX255(uint32_t a) { return (uint8_t) (a | ((a & 256) - ((a & 256) >> 8))); }
63 #endif
64
65 #ifndef MIN
66 #define MIN(x, y) ((x) < (y) ? (x) : (y))
67 #endif
68
69 #ifndef MAX
70 #define MAX(x, y) ((x) > (y) ? (x) : (y))
71 #endif
72
73 #endif
100100 {
101101 case F0R_PARAM_BOOL :
102102 *static_cast<f0r_param_bool*>(param)
103 = *static_cast<f0r_param_bool*>(ptr) > 0.5 ? 1.0 : 0.0;
103 = *static_cast<bool*>(ptr) ? 1.0 : 0.0;
104104 break;
105105 case F0R_PARAM_DOUBLE:
106106 *static_cast<f0r_param_double*>(param)
+0
-303
include/frei0r_cairo.h less more
0 /*
1 * frei0r_cairo.h
2 * Copyright 2012 Janne Liljeblad
3 *
4 * This file is part of Frei0r.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22 #include <cairo.h>
23 #include <string.h>
24 #include "frei0r_math.h"
25
26 /**
27 * String identifiers for gradient types available using Cairo.
28 */
29 #define GRADIENT_LINEAR "gradient_linear"
30 #define GRADIENT_RADIAL "gradient_radial"
31
32 /**
33 * String identifiers for blend modes available using Cairo.
34 */
35 #define NORMAL "normal"
36 #define ADD "add"
37 #define SATURATE "saturate"
38 #define MULTIPLY "multiply"
39 #define SCREEN "screen"
40 #define OVERLAY "overlay"
41 #define DARKEN "darken"
42 #define LIGHTEN "lighten"
43 #define COLORDODGE "colordodge"
44 #define COLORBURN "colorburn"
45 #define HARDLIGHT "hardlight"
46 #define SOFTLIGHT "softlight"
47 #define DIFFERENCE "difference"
48 #define EXCLUSION "exclusion"
49 #define HSLHUE "hslhue"
50 #define HSLSATURATION "hslsaturation"
51 #define HSLCOLOR "hslcolor"
52 #define HSLLUMINOSITY "hslluminosity"
53
54
55 /**
56 * frei0r_cairo_set_operator
57 * @cr: Cairo context
58 * @op: String identifier for a blend mode
59 *
60 * Sets cairo context to use the defined blend mode for all paint operations.
61 */
62 void frei0r_cairo_set_operator(cairo_t *cr, char *op)
63 {
64 if(strcmp(op, NORMAL) == 0)
65 {
66 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
67 }
68 else if(strcmp(op, ADD) == 0)
69 {
70 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
71 }
72 else if(strcmp(op, SATURATE) == 0)
73 {
74 cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE);
75 }
76 else if(strcmp(op, MULTIPLY) == 0)
77 {
78 cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY);
79 }
80 else if(strcmp(op, SCREEN) == 0)
81 {
82 cairo_set_operator (cr, CAIRO_OPERATOR_SCREEN);
83 }
84 else if(strcmp(op, OVERLAY) == 0)
85 {
86 cairo_set_operator (cr, CAIRO_OPERATOR_OVERLAY);
87 }
88 else if(strcmp(op, DARKEN) == 0)
89 {
90 cairo_set_operator (cr, CAIRO_OPERATOR_DARKEN);
91 }
92 else if(strcmp(op, LIGHTEN) == 0)
93 {
94 cairo_set_operator (cr, CAIRO_OPERATOR_LIGHTEN);
95 }
96 else if(strcmp(op, COLORDODGE) == 0)
97 {
98 cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_DODGE);
99 }
100 else if(strcmp(op, COLORBURN) == 0)
101 {
102 cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_BURN);
103 }
104 else if(strcmp(op, HARDLIGHT) == 0)
105 {
106 cairo_set_operator (cr, CAIRO_OPERATOR_HARD_LIGHT);
107 }
108 else if(strcmp(op, SOFTLIGHT) == 0)
109 {
110 cairo_set_operator (cr, CAIRO_OPERATOR_SOFT_LIGHT);
111 }
112 else if(strcmp(op, DIFFERENCE) == 0)
113 {
114 cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
115 }
116 else if(strcmp(op, EXCLUSION) == 0)
117 {
118 cairo_set_operator (cr, CAIRO_OPERATOR_EXCLUSION);
119 }
120 else if(strcmp(op, HSLHUE) == 0)
121 {
122 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_HUE);
123 }
124 else if(strcmp(op, HSLSATURATION) == 0)
125 {
126 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_SATURATION);
127 }
128 else if(strcmp(op, HSLCOLOR) == 0)
129 {
130 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_COLOR);
131 }
132 else if(strcmp(op, HSLLUMINOSITY ) == 0)
133 {
134 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_LUMINOSITY);
135 }
136 else
137 {
138 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
139 }
140 }
141
142
143 /**
144 * frei0r_cairo_set_rgba_LITTLE_ENDIAN
145 * @cr: Cairo context
146 * @red: red component, 0 - 1
147 * @green: green component, 0 - 1
148 * @blue: blue component, 0 - 1
149 * @alpha: opacity of color, 0 -1
150 *
151 * Sets cairo context to use the defined color paint operations.
152 * Switches red and blue channels to get correct color on little endian machines.
153 * This method only works correctly on little endian machines.
154 */
155 void frei0r_cairo_set_rgba_LITTLE_ENDIAN(cairo_t* cr, double red, double green, double blue, double alpha)
156 {
157 cairo_set_source_rgba (cr, blue, green, red, alpha);
158 }
159
160 /**
161 * frei0r_cairo_set_rgb_LITTLE_ENDIAN
162 * @cr: Cairo context
163 * @red: red component, 0 - 1
164 * @green: green component, 0 - 1
165 * @blue: blue component, 0 - 1
166 *
167 * Sets cairo context to use the defined color paint operations.
168 * Switches red and blue channels to get correct color on little endian machines.
169 * This method only works correctly on little endian machines.
170 */
171 void frei0r_cairo_set_rgb_LITTLE_ENDIAN(cairo_t* cr, double red, double green, double blue)
172 {
173 cairo_set_source_rgb (cr, blue, green, red);
174 }
175
176 /**
177 * freior_cairo_set_color_stop_rgba_LITTLE_ENDIAN(
178 * @pat: Cairo pattern
179 * @offset: offset of color position in pattern space, 0 - 1
180 * @red: red component, 0 - 1
181 * @green: green component, 0 - 1
182 * @blue: blue component, 0 - 1
183 * @alpha: opacity of color, 0 -1
184 *
185 * Sets color stop for cairo patterns.
186 * Switches red and blue channels to get correct color on little endian machines.
187 * This method only works correctly on little endian machines.
188 */
189 void freior_cairo_set_color_stop_rgba_LITTLE_ENDIAN(cairo_pattern_t *pat, double offset,
190 double red, double green, double blue, double alpha)
191 {
192 cairo_pattern_add_color_stop_rgba (pat, offset, blue, green, red, alpha);
193 }
194
195 /**
196 * frei0r_cairo_get_pixel_position
197 * @norm_pos: position in range 0 - 1, either x or y
198 * @dim: dimension, either witdh or height
199 *
200 * Converts double range [0 -> 1] to pixel range [-2*dim -> 3*dim]. Input 0.4 gives position 0.
201 *
202 * Returns: position in pixels
203 */
204 double frei0r_cairo_get_pixel_position (double norm_pos, int dim)
205 {
206 double pos_o = -(dim * 2.0);
207 return pos_o + norm_pos * dim * 5.0;
208 }
209
210 /**
211 * frei0r_cairo_get_scale
212 * @norm_scale: scale in range 0 - 1
213 *
214 * Converts double range [0 -> 1] to scale range [0 -> 5]. Input 0.2 gives scale 1.0.
215 *
216 * Returns: scale
217 */
218 double frei0r_cairo_get_scale (double norm_scale)
219 {
220 return norm_scale * 5.0;
221 }
222
223 /**
224 * Convert frei0r RGBA to pre-multiplied alpha as needed by Cairo.
225 *
226 * \param rgba the image buffer with format F0R_COLOR_MODEL_RGBA8888
227 * \param pixels the size of the image buffer in number of pixels
228 * \param alpha if >= 0, the alpha channel will be set to this value
229 * \see frei0r_cairo_unpremultiply_rgba
230 */
231 void frei0r_cairo_premultiply_rgba (unsigned char *rgba, int pixels, int alpha)
232 {
233 int i = pixels + 1;
234 while ( --i ) {
235 register unsigned char a = rgba[3];
236 if (a == 0) {
237 *((uint32_t *)rgba) = 0;
238 } else if (a < 0xff) {
239 rgba[0] = ( rgba[0] * a ) >> 8;
240 rgba[1] = ( rgba[1] * a ) >> 8;
241 rgba[2] = ( rgba[2] * a ) >> 8;
242 }
243 if (alpha >= 0) rgba[3] = alpha;
244 rgba += 4;
245 }
246 }
247
248 /**
249 * Convert Cairo ARGB pre-multiplied alpha to frei0r straight RGBA.
250 *
251 * \param rgba the image buffer with format CAIRO_FORMAT_ARGB32
252 * \param pixels the size of the image buffer in number of pixels
253 * \see frei0r_cairo_premultiply_rgba
254 */
255 void frei0r_cairo_unpremultiply_rgba (unsigned char *rgba, int pixels)
256 {
257 int i = pixels + 1;
258 while ( --i ) {
259 register unsigned char a = rgba[3];
260 if (a > 0 && a < 0xff) {
261 rgba[0] = MIN(( rgba[0] << 8 ) / a, 255);
262 rgba[1] = MIN(( rgba[1] << 8 ) / a, 255);
263 rgba[2] = MIN(( rgba[2] << 8 ) / a, 255);
264 }
265 rgba += 4;
266 }
267 }
268
269 /**
270 * Convert frei0r RGBA to pre-multiplied alpha as needed by Cairo.
271 *
272 * \param rgba the image buffer with format F0R_COLOR_MODEL_RGBA8888
273 * \param pixels the size of the image buffer in number of pixels
274 * \param alpha if >= 0, the alpha channel will be set to this value
275 * \see frei0r_cairo_premultiply_rgba
276 *
277 * This is the same as frei0r_cairo_premultiply_rgba but it writes the
278 * output to a different buffer.
279 */
280 void frei0r_cairo_premultiply_rgba2 (unsigned char *in, unsigned char *out,
281 int pixels, int alpha)
282 {
283 int i = pixels + 1;
284 while ( --i ) {
285 register unsigned char a = in[3];
286 if (a == 0) {
287 *((uint32_t *)out) = 0;
288 } else if (a == 0xff) {
289 memcpy(out, in, 4);
290 } else {
291 out[0] = ( in[0] * a ) >> 8;
292 out[1] = ( in[1] * a ) >> 8;
293 out[2] = ( in[2] * a ) >> 8;
294 if (alpha < 0)
295 out[3] = a;
296 }
297 if (alpha >= 0)
298 out[3] = alpha;
299 in += 4;
300 out += 4;
301 }
302 }
+0
-319
include/frei0r_cfc.h less more
0 /* cfc.h
1 * uchar->float and float->uchar conversion for packed RGBA video
2 * with flexible gamma correction
3 *
4 * Copyright (C) 2012 Marko Cebokli http://lea.hamradio.si/~s57uuu
5 * This file is a part of the Frei0r package
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 // the float to uint8_t conversion is done
23 // using Spitzak type tables (upper 16 bits
24 // of a float value used as table index)
25 // see http://mysite.verizon.net/spitzak/conversion/
26
27 #include <math.h>
28 #include <inttypes.h>
29
30
31 typedef struct
32 {
33 float r;
34 float g;
35 float b;
36 float a;
37 } float_rgba;
38
39 //------------------------------------------------------
40 //the following gamma functions need not be speed optimized,
41 //as they are only used for table generation
42
43 //--------------------------------------------------------
44 //rec 709 gamma forward (linear to gamma)
45 //a = input, should be in the 0.0 to 1.0 range
46 static inline float gamma_709_f(float a)
47 {
48 return (a<=0.018) ? 4.5*a : 1.099*powf(a,0.45)-0.099;
49 }
50
51 //--------------------------------------------------------
52 //rec 709 gamma backward (gamma to linear)
53 //a = input, should be in the 0.0 to 1.0 range
54 static inline float gamma_709_b(float a)
55 {
56 return (a<=0.081) ? a/4.5 : powf((a+0.099)/1.099,1.0/0.45);
57 }
58
59 //----------------------------------------------------
60 //sRGB gamma forward (linear to gamma)
61 //a = input, should be in the 0.0 to 1.0 range
62 static inline float gamma_sRGB_f(float a)
63 {
64 return (a<=0.0031308) ? 12.92*a : 1.055*powf(a,1.0/2.4)-0.055;
65 }
66
67 //--------------------------------------------------------
68 //sRGB gamma backward (gamma to linear)
69 //a = input, should be in the 0.0 to 1.0 range
70 static inline float gamma_sRGB_b(float a)
71 {
72 return (a<=0.04045) ? a/12.92 : powf((a+0.055)/1.055,2.4);
73 }
74
75 //----------------------------------------------------
76 //plain gamma (power function) forward (linear to gamma)
77 //a = input, should be in the 0.0 to 1.0 range
78 static inline float gamma_plain_f(float a, float g)
79 {
80 return powf(a,1.0/g);
81 }
82
83 //--------------------------------------------------------
84 //plain gamma (power function) backward (gamma to linear)
85 //a = input, should be in the 0.0 to 1.0 range
86 static inline float gamma_plain_b(float a, float g)
87 {
88 return powf(a,g);
89 }
90
91 //--------------------------------------------------------
92 //dummy function for linear tables (no gamma)
93 //g = gamma value
94 static inline float gamma_none(float a)
95 {
96 return a;
97 }
98
99 //------------------------------------------------
100 //expand highlights using a modified Spitzak formula
101 //with limited max output value (250)
102 //(for values up to 2500 use 1.0001 and 0.493)
103 //input [0...1]
104 //output [0...250]
105 static inline float exp_hl(float a)
106 {
107 return (a<=0.4781) ? a : 0.25/(1.001-a);
108 }
109
110 //------------------------------------------------------------
111 //compress highlights using a modified Spitzak formula
112 //with limited max input value (250)
113 //(for values up to 2500 use 1.0001 and 0.493)
114 //input [0...250]
115 //output [0...1]
116 static inline float cps_hl(float a)
117 {
118 return (a<=0.4781) ? a : 1.001-0.25/a;
119 }
120
121 //----------------------------------------------------------
122 //float to char conversion is done using the upper 16 bits
123 //of the float number as an index into the conversion table.
124 //This union is used for type punning, to avoid problems
125 //with compiler optimizations, as the read access in the
126 //cfc_tab_8 function directly follows writing
127 typedef union
128 {
129 float a;
130 uint16_t i[2];
131 } flint;
132
133 //--------------------------------------------------------
134 //generate forward and backward conversion tables
135 //for 8 bit (uint8_t) video
136 //*ft = forward table (float to uchar, linear to gamma)
137 // must have space for 65536 char elements
138 //*bt = backward table (uchar to float, gamma to linear)
139 // must have space for 256 float elements
140 //type = what kind of gamma function will be used:
141 // 0 = linear (no gamma, just multiply/divide by 255)
142 // 1 = plain gamma (pure power function)
143 // 2 = rec 709 gamma
144 // 3 = sRGB gamma
145 // 4 = sRGB gamma with highlight expansion/compression
146 // types 0...3 map to [0...1] linear float range
147 // type 4 maps to [0...250] linear float range
148 //g = gamma value, 0.3 to 3.0 (only used with type=1)
149 static inline void cfc_tab_8(uint8_t *ft, float *bt, int type, float g)
150 {
151 uint16_t i;
152 float a;
153 flint fi;
154
155 // *** generate float to char conversion table ***
156 for (i=0;i<128;i++) //positive denormals map to zero
157 ft[i]=0;
158
159 for (i=128;i<=32639;i++) //positive numbers map to 0...255
160 {
161 //#if FREI0R_BYTE_ORDER == FREI0R_BIG_ENDIAN
162 // fi.i[0]=i; fi.i[1]=0x8000; //big endian
163 //#endif
164 //#if FREI0R_BYTE_ORDER == FREI0R_LITTLE_ENDIAN
165 fi.i[1]=i; fi.i[0]=0x8000; //little endian
166 //#endif
167 a=fi.a;
168 switch (type)
169 {
170 case 0: a=gamma_none(a); break;
171 case 1: a=gamma_plain_f(a,g); break;
172 case 2: a=gamma_709_f(a); break;
173 case 3: a=gamma_sRGB_f(a); break;
174 case 4: a=cps_hl(a); a=gamma_sRGB_f(a); break;
175 default: break;
176 }
177 if (a>0.9999) a=0.9999;
178 ft[i]=(uint8_t)(256.0*a);
179 }
180
181 for (i=32640;i<32768;i++) //positive NANs and infinite map to 255
182 ft[i]=255;
183 for (i=32768;i!=65535;i++) //everything negative maps to 0
184 ft[i]=0;
185 ft[65535]=0;
186
187
188 // *** generate char to float conversion table ***
189 for (i=0;i<=255;i++)
190 {
191 a=((float)i+0.5)/256.0;
192 switch (type)
193 {
194 case 0: a=gamma_none(a); break;
195 case 1: a=gamma_plain_b(a,g); break;
196 case 2: a=gamma_709_b(a); break;
197 case 3: a=gamma_sRGB_b(a); break;
198 case 4: a=gamma_sRGB_b(a); a=exp_hl(a); break;
199 default: break;
200 }
201 bt[i]=a;
202 }
203 }
204
205 //--------------------------------------------------------
206 //convert from paked uchar RGBA to packed float RGBA
207 //w,h are width and height of the image
208 //tab = table used for RGB conversion
209 //atab = table used for alpha converion (usually linear)
210 static inline void RGBA8_2_float(const uint32_t *in, float_rgba *out, int w, int h, float *tab, float *atab)
211 {
212 int i;
213 uint8_t *cin=(uint8_t *)in;
214
215 for (i=0;i<w*h;i++)
216 {
217 out[i].r=tab[*cin++];
218 out[i].g=tab[*cin++];
219 out[i].b=tab[*cin++];
220 out[i].a=atab[*cin++];
221 }
222 }
223
224 //--------------------------------------------------------
225 //convert from paked uchar RGBA to packed float RGBA,
226 //covert RGB only, SKIP ALPHA
227 //w,h are width and height of the image
228 //tab = table used for RGB conversion
229 static inline void RGB8_2_float(const uint32_t *in, float_rgba *out, int w, int h, float *tab)
230 {
231 int i;
232 uint8_t *cin=(uint8_t *)in;
233
234 for (i=0;i<w*h;i++)
235 {
236 out[i].r=tab[*cin++];
237 out[i].g=tab[*cin++];
238 out[i].b=tab[*cin++];
239 cin++;
240 }
241 }
242
243
244 //--------------------------------------------------------
245 //in the following conversions, we can afford "direct" type punning
246 //as the array already exists from well before (I hope :-)
247 //
248 //#if FREI0R_BYTE_ORDER == FREI0R_BIG_ENDIAN
249 //big endian most significant 16 bit word from 32bit float
250 //#define MSWF(x) *(uint16_t*)x
251 //#endif
252 //
253 //#if FREI0R_BYTE_ORDER == FREI0R_LITTLE_ENDIAN
254 //little endian most significant 16 bit word from 32bit float
255 #define MSWF(x) *((uint16_t*)x+1)
256 //#endif
257
258 //----------------------------------------------------------
259 //convert from packed float RGBA to packed uchar RGBA
260 //tab = table used for RGB conversion
261 //atab = table used for alpha converion (usually linear)
262 static inline void float_2_RGBA8(const float_rgba *in, uint32_t *out, int w, int h, uint8_t *tab, uint8_t *atab)
263 {
264 int i;
265 uint8_t *cout=(uint8_t *)out;
266
267 for (i=0;i<w*h;i++)
268 {
269 *cout++ = tab[MSWF(&in[i].r)];
270 *cout++ = tab[MSWF(&in[i].g)];
271 *cout++ = tab[MSWF(&in[i].b)];
272 *cout++ = atab[MSWF(&in[i].a)];
273 }
274 }
275
276 //----------------------------------------------------------
277 //convert from packed float RGBA to packed uchar RGBA
278 //covert RGB only, SKIP ALPHA
279 //tab = table used for RGB conversion
280 static inline void float_2_RGB8(const float_rgba *in, uint32_t *out, int w, int h, uint8_t *tab)
281 {
282 int i;
283 uint8_t *cout=(uint8_t *)out;
284
285 for (i=0;i<w*h;i++)
286 {
287 *cout++ = tab[MSWF(&in[i].r)];
288 *cout++ = tab[MSWF(&in[i].g)];
289 *cout++ = tab[MSWF(&in[i].b)];
290 cout++;
291 }
292 }
293
294 #undef MSWF
295
296
297 //--------------------------------------------------
298 // -- Single value conversion --
299 //there is no function for single uint8 to float, because
300 //that is just a simple table lookup
301 //
302 //because float_2_uint8() can be called immediately after
303 //the input value has been created, type punning has to be
304 //done properly, with a union
305
306 //#if FREI0R_BYTE_ORDER == FREI0R_LITTLE_ENDIAN
307 static inline uint8_t float_2_uint8(const float *in, uint8_t *tab)
308 {
309 return tab[((flint*)in)->i[1]];
310 }
311 //endif
312
313 //#if FREI0R_BYTE_ORDER == FREI0R_BIG_ENDIAN
314 //static inline float_2_uint8(const float *in, uint8_t *tab)
315 //{
316 //return tab[((flint*)in)->i[0]];
317 //}
318 //#endif
+0
-416
include/frei0r_colorspace.h less more
0 /* frei0r_colorspace.h
1 * Copyright (C) 2004 Mathieu Guindon, Julien Keable, Jean-Sebastien Senecal
2 * This file is part of Frei0r.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifndef INCLUDED_FREI0R_COLORSPACE_H
20 #define INCLUDED_FREI0R_COLORSPACE_H
21
22 #include "frei0r_math.h"
23 #include <stdlib.h>
24 #include <math.h>
25
26 // # Basic colorspace convert functions (from the Gimp gimpcolorspace.h) ####
27
28 /* int functions */
29
30 /**
31 * rgb_to_hsv_int
32 * @red: The red channel value, returns the Hue channel
33 * @green: The green channel value, returns the Saturation channel
34 * @blue: The blue channel value, returns the Value channel
35 *
36 * The arguments are pointers to int representing channel values in
37 * the RGB colorspace, and the values pointed to are all in the range
38 * [0, 255].
39 *
40 * The function changes the arguments to point to the HSV value
41 * corresponding, with the returned values in the following
42 * ranges: H [0, 360], S [0, 255], V [0, 255].
43 **/
44 inline void
45 rgb_to_hsv_int (int *red /* returns hue */,
46 int *green /* returns saturation */,
47 int *blue /* returns value */)
48 {
49 double r, g, b;
50 double h, s, v;
51 double min;
52 double delta;
53
54 r = *red;
55 g = *green;
56 b = *blue;
57
58 if (r > g)
59 {
60 v = MAX (r, b);
61 min = MIN (g, b);
62 }
63 else
64 {
65 v = MAX (g, b);
66 min = MIN (r, b);
67 }
68
69 delta = v - min;
70
71 if (v == 0.0)
72 s = 0.0;
73 else
74 s = delta / v;
75
76 if (s == 0.0)
77 h = 0.0;
78 else
79 {
80 if (r == v)
81 h = 60.0 * (g - b) / delta;
82 else if (g == v)
83 h = 120 + 60.0 * (b - r) / delta;
84 else
85 h = 240 + 60.0 * (r - g) / delta;
86
87 if (h < 0.0)
88 h += 360.0;
89 if (h > 360.0)
90 h -= 360.0;
91 }
92
93 *red = ROUND (h);
94 *green = ROUND (s * 255.0);
95 *blue = ROUND (v);
96 }
97
98 /**
99 * hsv_to_rgb_int
100 * @hue: The hue channel, returns the red channel
101 * @saturation: The saturation channel, returns the green channel
102 * @value: The value channel, returns the blue channel
103 *
104 * The arguments are pointers to int, with the values pointed to in the
105 * following ranges: H [0, 360], S [0, 255], V [0, 255].
106 *
107 * The function changes the arguments to point to the RGB value
108 * corresponding, with the returned values all in the range [0, 255].
109 **/
110 inline void
111 hsv_to_rgb_int (int *hue /* returns red */,
112 int *saturation /* returns green */,
113 int *value /* returns blue */)
114 {
115 double h, s, v, h_temp;
116 double f, p, q, t;
117 int i;
118
119 if (*saturation == 0)
120 {
121 *hue = *value;
122 *saturation = *value;
123 // *value = *value;
124 }
125 else
126 {
127 h = *hue;
128 s = *saturation / 255.0;
129 v = *value / 255.0;
130
131 if (h == 360)
132 h_temp = 0;
133 else
134 h_temp = h;
135
136 h_temp = h_temp / 60.0;
137 i = (int) floor (h_temp);
138 f = h_temp - i;
139 p = v * (1.0 - s);
140 q = v * (1.0 - (s * f));
141 t = v * (1.0 - (s * (1.0 - f)));
142
143 switch (i)
144 {
145 case 0:
146 *hue = ROUND (v * 255.0);
147 *saturation = ROUND (t * 255.0);
148 *value = ROUND (p * 255.0);
149 break;
150
151 case 1:
152 *hue = ROUND (q * 255.0);
153 *saturation = ROUND (v * 255.0);
154 *value = ROUND (p * 255.0);
155 break;
156
157 case 2:
158 *hue = ROUND (p * 255.0);
159 *saturation = ROUND (v * 255.0);
160 *value = ROUND (t * 255.0);
161 break;
162
163 case 3:
164 *hue = ROUND (p * 255.0);
165 *saturation = ROUND (q * 255.0);
166 *value = ROUND (v * 255.0);
167 break;
168
169 case 4:
170 *hue = ROUND (t * 255.0);
171 *saturation = ROUND (p * 255.0);
172 *value = ROUND (v * 255.0);
173 break;
174
175 case 5:
176 *hue = ROUND (v * 255.0);
177 *saturation = ROUND (p * 255.0);
178 *value = ROUND (q * 255.0);
179 break;
180 }
181 }
182 }
183
184 /**
185 * rgb_to_hsl_int
186 * @red: Red channel, returns Hue channel
187 * @green: Green channel, returns Lightness channel
188 * @blue: Blue channel, returns Saturation channel
189 *
190 * The arguments are pointers to int representing channel values in the
191 * RGB colorspace, and the values pointed to are all in the range [0, 255].
192 *
193 * The function changes the arguments to point to the corresponding HLS
194 * value with the values pointed to in the following ranges: H [0, 360],
195 * L [0, 255], S [0, 255].
196 **/
197 inline void
198 rgb_to_hsl_int (unsigned int *red /* returns red */,
199 unsigned int *green /* returns green */,
200 unsigned int *blue /* returns blue */)
201 {
202 unsigned int r, g, b;
203 double h, s, l;
204 unsigned int min, max;
205 unsigned int delta;
206
207 r = *red;
208 g = *green;
209 b = *blue;
210
211 if (r > g)
212 {
213 max = MAX (r, b);
214 min = MIN (g, b);
215 }
216 else
217 {
218 max = MAX (g, b);
219 min = MIN (r, b);
220 }
221
222 l = (max + min) / 2.0;
223
224 if (max == min)
225 {
226 s = 0.0;
227 h = 0.0;
228 }
229 else
230 {
231 delta = (max - min);
232
233 if (l < 128)
234 s = 255 * (double) delta / (double) (max + min);
235 else
236 s = 255 * (double) delta / (double) (511 - max - min);
237
238 if (r == max)
239 h = (g - b) / (double) delta;
240 else if (g == max)
241 h = 2 + (b - r) / (double) delta;
242 else
243 h = 4 + (r - g) / (double) delta;
244
245 h = h * 42.5;
246
247 if (h < 0)
248 h += 255;
249 else if (h > 255)
250 h -= 255;
251 }
252
253 *red = ROUND (h);
254 *green = ROUND (s);
255 *blue = ROUND (l);
256 }
257
258 inline int
259 hsl_value_int (double n1,
260 double n2,
261 double hue)
262 {
263 double value;
264
265 if (hue > 255)
266 hue -= 255;
267 else if (hue < 0)
268 hue += 255;
269
270 if (hue < 42.5)
271 value = n1 + (n2 - n1) * (hue / 42.5);
272 else if (hue < 127.5)
273 value = n2;
274 else if (hue < 170)
275 value = n1 + (n2 - n1) * ((170 - hue) / 42.5);
276 else
277 value = n1;
278
279 return ROUND (value * 255.0);
280 }
281
282 /**
283 * hsl_to_rgb_int
284 * @hue: Hue channel, returns Red channel
285 * @saturation: Saturation channel, returns Green channel
286 * @lightness: Lightness channel, returns Blue channel
287 *
288 * The arguments are pointers to int, with the values pointed to in the
289 * following ranges: H [0, 360], L [0, 255], S [0, 255].
290 *
291 * The function changes the arguments to point to the RGB value
292 * corresponding, with the returned values all in the range [0, 255].
293 **/
294 inline void
295 hsl_to_rgb_int (unsigned int *hue /* returns red */,
296 unsigned int *saturation /* returns green */,
297 unsigned int *lightness /* returns blue */)
298 {
299 double h, s, l;
300
301 h = *hue;
302 s = *saturation;
303 l = *lightness;
304
305 if (s == 0)
306 {
307 /* achromatic case */
308 *hue = (int)l;
309 *lightness = (int)l;
310 *saturation = (int)l;
311 }
312 else
313 {
314 double m1, m2;
315
316 if (l < 128)
317 m2 = (l * (255 + s)) / 65025.0;
318 else
319 m2 = (l + s - (l * s) / 255.0) / 255.0;
320
321 m1 = (l / 127.5) - m2;
322
323 /* chromatic case */
324 *hue = hsl_value_int (m1, m2, h + 85);
325 *saturation = hsl_value_int (m1, m2, h);
326 *lightness = hsl_value_int (m1, m2, h - 85);
327 }
328 }
329
330 /**
331 * gimp_rgb_to_cmyk_int:
332 * @red: the red channel; returns the cyan value (0-255)
333 * @green: the green channel; returns the magenta value (0-255)
334 * @blue: the blue channel; returns the yellow value (0-255)
335 * @pullout: the percentage of black to pull out (0-100); returns
336 * the black value (0-255)
337 *
338 * Does a naive conversion from RGB to CMYK colorspace. A simple
339 * formula that doesn't take any color-profiles into account is used.
340 * The amount of black pullout how can be controlled via the @pullout
341 * parameter. A @pullout value of 0 makes this a conversion to CMY.
342 * A value of 100 causes the maximum amount of black to be pulled out.
343 **/
344 inline void
345 gimp_rgb_to_cmyk_int (int *red,
346 int *green,
347 int *blue,
348 int *pullout)
349 {
350 int c, m, y;
351
352 c = 255 - *red;
353 m = 255 - *green;
354 y = 255 - *blue;
355
356 if (*pullout == 0)
357 {
358 *red = c;
359 *green = m;
360 *blue = y;
361 }
362 else
363 {
364 int k = 255;
365
366 if (c < k) k = c;
367 if (m < k) k = m;
368 if (y < k) k = y;
369
370 k = (k * CLAMP (*pullout, 0, 100)) / 100;
371
372 *red = ((c - k) << 8) / (256 - k);
373 *green = ((m - k) << 8) / (256 - k);
374 *blue = ((y - k) << 8) / (256 - k);
375 *pullout = k;
376 }
377 }
378
379 /**
380 * gimp_cmyk_to_rgb_int:
381 * @cyan: the cyan channel; returns the red value (0-255)
382 * @magenta: the magenta channel; returns the green value (0-255)
383 * @yellow: the yellow channel; returns the blue value (0-255)
384 * @black: the black channel (0-255); doesn't change
385 *
386 * Does a naive conversion from CMYK to RGB colorspace. A simple
387 * formula that doesn't take any color-profiles into account is used.
388 **/
389 inline void
390 cmyk_to_rgb_int (int *cyan,
391 int *magenta,
392 int *yellow,
393 int *black)
394 {
395 int c, m, y, k;
396
397 c = *cyan;
398 m = *magenta;
399 y = *yellow;
400 k = *black;
401
402 if (k)
403 {
404 c = ((c * (256 - k)) >> 8) + k;
405 m = ((m * (256 - k)) >> 8) + k;
406 y = ((y * (256 - k)) >> 8) + k;
407 }
408
409 *cyan = 255 - c;
410 *magenta = 255 - m;
411 *yellow = 255 - y;
412 }
413
414
415 #endif
+0
-74
include/frei0r_math.h less more
0 #ifndef INCLUDED_FREI0R_MATH_H
1 #define INCLUDED_FREI0R_MATH_H
2
3 /*
4
5 Code stripped from The Gimp:
6 INT_MULT(a,b,t)
7 INT_MULT3(a,b,c,t)
8 INT_BLEND(a,b,alpha,tmp)
9 CLAMP
10 ROUND
11 MAX255
12
13 Code stripped from Drone:
14 CLAMP0255
15 SQR
16 */
17
18 /* Clamps a int32-range int between 0 and 255 inclusive. */
19 #ifndef CLAMP0255
20 static inline unsigned char CLAMP0255(int32_t a)
21 {
22 return (unsigned char)
23 ( (((-a) >> 31) & a) // 0 if the number was negative
24 | (255 - a) >> 31); // -1 if the number was greater than 255
25 }
26 #endif
27
28 /* Provided temporary int t, returns a * b / 255 */
29 #ifndef INT_MULT
30 #define INT_MULT(a,b,t) ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
31 #endif
32
33 /* This version of INT_MULT3 is very fast, but suffers from some
34 slight roundoff errors. It returns the correct result 99.987
35 percent of the time */
36 #ifndef INT_MULT3
37 #define INT_MULT3(a,b,c,t) ((t) = (a) * (b) * (c) + 0x7F5B, \
38 ((((t) >> 7) + (t)) >> 16))
39 #endif
40
41 #ifndef INT_BLEND
42 #define INT_BLEND(a,b,alpha,tmp) (INT_MULT((a) - (b), alpha, tmp) + (b))
43 #endif
44
45 #ifndef CLAMP
46 //! Clamp x at min and max
47 #define CLAMP(x,min,max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
48 #endif
49
50 #ifndef ROUND
51 //! Round.
52 #define ROUND(x) ((int32_t)((x)+0.5))
53 #endif
54
55 #ifndef SQR
56 //! Square.
57 #define SQR(x) ((x) * (x))
58 #endif
59
60 #ifndef MAX255
61 //! Limit a (0->511) int to 255.
62 uint8_t MAX255(uint32_t a) { return (uint8_t) (a | ((a & 256) - ((a & 256) >> 8))); }
63 #endif
64
65 #ifndef MIN
66 #define MIN(x, y) ((x) < (y) ? (x) : (y))
67 #endif
68
69 #ifndef MAX
70 #define MAX(x, y) ((x) > (y) ? (x) : (y))
71 #endif
72
73 #endif
1111 if (${Cairo_FOUND})
1212 add_subdirectory (cairoimagegrid)
1313 add_subdirectory (cairogradient)
14 add_subdirectory (mirr0r)
1415 endif (${Cairo_FOUND})
1516
1617 add_subdirectory (3dflippo)
6869 add_subdirectory (nervous)
6970 add_subdirectory (normaliz0r)
7071 add_subdirectory (nosync0r)
72 add_subdirectory (ntsc)
7173 add_subdirectory (perspective)
7274 add_subdirectory (pixeliz0r)
7375 add_subdirectory (pixs0r)
2121 *
2222 */
2323 #include "frei0r.hpp"
24 #include "frei0r_math.h"
24 #include "frei0r/math.h"
2525
2626 #include <string.h>
2727 #include <climits>
2828
2929 //#include <stdio.h>
3030 #include <frei0r.h>
31 #include <frei0r_math.h>
31 #include <frei0r/math.h>
3232 #include <stdlib.h>
3333 #include <math.h>
3434 #include <assert.h>
2727 #include <stdio.h>
2828
2929 #include "frei0r.h"
30 #include "frei0r_math.h"
30 #include "frei0r/math.h"
3131
3232 static const float bbWB[][3] =
3333 {
6868
6969 #include <sys/types.h>
7070 #include <string.h>
71 #include "frei0r_math.h"
71 #include "frei0r/math.h"
7272
7373 //---------------------------------------------------------
7474 //koeficienti za biquad lowpass iz f in q
2020 #include <assert.h>
2121
2222 #include "frei0r.h"
23 #include "frei0r_math.h"
23 #include "frei0r/math.h"
2424
2525 typedef struct brightness_instance
2626 {
2727 #include <frei0r.h>
2828 #include <string.h>
2929 #include <math.h>
30 #include "frei0r_math.h"
30 #include "frei0r/math.h"
3131 #include "interp.h"
3232
3333 //----------------------------------------
2626 #include <math.h>
2727
2828 #include "frei0r.h"
29 #include "frei0r_cairo.h"
29 #include "frei0r/cairo.h"
3030
3131 typedef struct cairo_gradient_instance
3232 {
2323 #include <cairo.h>
2424
2525 #include "frei0r.h"
26 #include "frei0r_cairo.h"
26 #include "frei0r/cairo.h"
2727
2828 #define MAX_ROWS 20
2929 #define MAX_COLUMNS 20
2323 #include <stdio.h>
2424
2525 #include "frei0r.h"
26 #include "frei0r_math.h"
26 #include "frei0r/math.h"
2727
2828 #define MAXNUM 40
2929
8787 #endif
8888
8989 #include "frei0r.h"
90 #include "frei0r_math.h"
90 #include "frei0r/math.h"
9191
9292 enum ParamIndex {
9393 NEUTRAL_COLOR,
2222 #include <stdio.h>
2323
2424 #include "frei0r.h"
25 #include "frei0r_math.h"
25 #include "frei0r/math.h"
2626
2727 typedef struct colordistance_instance
2828 {
2626 #include <stdio.h>
2727 #include <math.h>
2828 #include "frei0r.h"
29 #include "frei0r_math.h"
29 #include "frei0r/math.h"
3030
3131 double PI=3.14159265358979;
3232
3131 #include <assert.h>
3232
3333 #include "frei0r.h"
34 #include "frei0r_math.h"
34 #include "frei0r/math.h"
3535
3636 #define GIMP_RGB_LUMINANCE_RED (0.2126)
3737 #define GIMP_RGB_LUMINANCE_GREEN (0.7152)
2121 #include <stdio.h>
2222
2323 #include "frei0r.h"
24 #include "frei0r_math.h"
24 #include "frei0r/math.h"
2525
2626 typedef struct contrast0r_instance
2727 {
2727 #include <stdio.h>
2828
2929 #include "frei0r.h"
30 #include "frei0r_math.h"
30 #include "frei0r/math.h"
3131
3232 #define MAX3(a, b, c) ( ( a > b && a > c) ? a : (b > c ? b : c) )
3333 #define MIN3(a, b, c) ( ( a < b && a < c) ? a : (b < c ? b : c) )
2626 #include <math.h>
2727
2828 #include "frei0r.h"
29 #include "frei0r_math.h"
29 #include "frei0r/math.h"
3030
3131 int ditherMagic2x2Matrix[] = {
3232 0, 2,
1717 */
1818
1919 #include "frei0r.hpp"
20 #include "frei0r_math.h"
20 #include "frei0r/math.h"
2121 #include <stdlib.h>
2222
2323 class edgeglow : public frei0r::filter
2626 #include <math.h>
2727
2828 #include "frei0r.h"
29 #include "frei0r_math.h"
29 #include "frei0r/math.h"
3030
3131 double PI = 3.14159;
3232 double pixelScale = 255.9;
1717 */
1818
1919 #include "frei0r.hpp"
20 #include "frei0r_math.h"
20 #include "frei0r/math.h"
2121 #include <string.h>
2222
2323 #include <cstring>
1919 #include <string.h>
2020 #include <opencv2/opencv.hpp>
2121 #include "frei0r.hpp"
22 #include "frei0r_math.h"
22 #include "frei0r/math.h"
2323
2424 class TrackedObj {
2525 public:
2121 #include <string.h>
2222 #include <opencv2/opencv.hpp>
2323 #include "frei0r.hpp"
24 #include "frei0r_math.h"
24 #include "frei0r/math.h"
2525
2626 #define USE_ROI
2727 #define PAD (40)
00 #include <stdlib.h>
11 #include "frei0r.h"
2 #include "frei0r_math.h"
2 #include "frei0r/math.h"
33
44
55 typedef struct flimgrain_instance
2121 #include <assert.h>
2222
2323 #include "frei0r.h"
24 #include "frei0r_math.h"
24 #include "frei0r/math.h"
2525
2626 #define MAX_GAMMA 4.0
2727
00 #include <stdlib.h>
11 #include <math.h>
22 #include "frei0r.h"
3 #include "frei0r_math.h"
3 #include "frei0r/math.h"
44
55
66 // let's try to walk through everything because i'm a moron
2424 #include <time.h>
2525
2626 #include "frei0r.h"
27 #include "frei0r_math.h"
27 #include "frei0r/math.h"
2828
2929 /* cheap & fast randomizer (by Fukuchi Kentarou) */
3030 static uint32_t randval;
1919 #include <math.h>
2020 #include "frei0r.h"
2121 #include <stdlib.h>
22 #include "blur.h"
22 #include "frei0r/blur.h"
2323
2424 typedef struct glow_instance {
2525 double blur;
66 *
77 * Paul Haeberli - 1993
88 */
9 #include "frei0r_math.h"
9 #include "frei0r/math.h"
1010 #include <math.h>
1111 #include <stdio.h>
1212
2121 #include <assert.h>
2222
2323 #include "frei0r.h"
24 #include "frei0r_math.h"
24 #include "frei0r/math.h"
2525
2626 typedef struct lenscorrection_instance
2727 {
00 # Set C99 flag for gcc
11 if (CMAKE_COMPILER_IS_GNUCC)
2 set(CMAKE_C_FLAGS "-std=c99")
2 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
33 endif (CMAKE_COMPILER_IS_GNUCC)
44
55 set (SOURCES levels.c)
2323 #include <stdio.h>
2424
2525 #include "frei0r.h"
26 #include "frei0r_math.h"
26 #include "frei0r/math.h"
2727
2828 enum ChannelChoice
2929 {
2121 #include <assert.h>
2222
2323 #include "frei0r.h"
24 #include "frei0r_math.h"
24 #include "frei0r/math.h"
2525
2626 #define MAX_SATURATION 8.0
2727
1919 #include <math.h>
2020 #include "frei0r.h"
2121 #include <stdlib.h>
22 #include "blur.h"
22 #include "frei0r/blur.h"
2323
2424 typedef struct mask0mate_instance {
2525 double left, top, right, bottom;
0 set (SOURCES mirr0r.cpp)
1 set (TARGET mirr0r)
2
3 include_directories(${Cairo_INCLUDE_DIR})
4 set(LIBS ${LIBS} ${Cairo_LIBRARY})
5
6 if (MSVC)
7 set (SOURCES ${SOURCES} ${FREI0R_DEF})
8 endif (MSVC)
9
10 add_library (${TARGET} MODULE ${SOURCES})
11
12 set_target_properties (${TARGET} PROPERTIES PREFIX "")
13 target_link_libraries(mirr0r ${LIBS})
14 install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
0 /*
1 * Copyright (C) 2024 Johann JEG (johannjeg1057@gmail.com)
2 *
3 * This file is a Frei0r plugin.
4 *
5 * This program is free software: you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation, either version 3 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "frei0r.hpp"
20 #include <cairo.h>
21 #define _USE_MATH_DEFINES
22 #include <cmath>
23
24 class Mirr0r : public frei0r::filter {
25
26 private:
27
28 unsigned int width;
29 unsigned int height;
30 double x_offset;
31 double y_offset;
32 double zoom;
33 double rotation;
34
35 public:
36
37 Mirr0r(unsigned int width, unsigned int height){
38 register_param(this->x_offset, "x_offset", "Horizontal offset for image positioning.");
39 register_param(this->y_offset, "y_offset", "Vertical offset for image positioning.");
40 register_param(this->zoom, "zoom", "Zoom level for image scaling.");
41 register_param(this->rotation, "rotation", "Rotation angle in degrees.");
42
43 this->width = width;
44 this->height = height;
45 this->x_offset = 0.0;
46 this->y_offset = 0.0;
47 this->zoom = 0.5;
48 this->rotation = 0.0;
49 }
50
51 ~Mirr0r(){
52
53 }
54
55 void clearScreen(cairo_t* cr, int width, int height) {
56 cairo_save (cr);
57 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
58 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
59 cairo_paint (cr);
60 cairo_restore (cr);
61 }
62
63 virtual void update(double time, uint32_t* out, const uint32_t* in) {
64
65 int w = this->width;
66 int h = this->height;
67
68 // Calculate the stride for the image surface based on width and format
69 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w);
70
71 // Create a Cairo surface for the destination image
72 cairo_surface_t* dest_image = cairo_image_surface_create_for_data((unsigned char*)out,
73 CAIRO_FORMAT_ARGB32,
74 w,
75 h,
76 stride);
77
78 // Create a Cairo drawing context for the destination surface
79 cairo_t *cr = cairo_create(dest_image);
80
81 // Clear the screen
82 clearScreen(cr, w, h);
83
84 // Create a Cairo surface for the source image
85 cairo_surface_t *image = cairo_image_surface_create_for_data((unsigned char*)in,
86 CAIRO_FORMAT_ARGB32,
87 w,
88 h,
89 stride);
90 // Create a pattern from the source image surface
91 cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image);
92 // Set the pattern extend mode to reflect (mirror) when the pattern is out of bounds
93 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT);
94
95 // Initialize the transformation matrix
96 cairo_matrix_t matrix;
97 cairo_matrix_init_identity(&matrix);
98
99 // Calculate the center coordinates of the destination image
100 float center_x = (float)w / 2.0f;
101 float center_y = (float)h / 2.0f;
102
103 float scale_factor = 1.5f - this->zoom;
104
105 // Apply transformations
106 cairo_matrix_translate(&matrix, center_x - (this->x_offset) * w, center_y - (this->y_offset) * h);
107 cairo_matrix_scale(&matrix, scale_factor, scale_factor);
108 cairo_matrix_rotate(&matrix, this->rotation * M_PI);
109 cairo_matrix_translate(&matrix, -center_x, -center_y);
110
111 // Set the transformation matrix for the pattern
112 cairo_pattern_set_matrix(pattern, &matrix);
113 // Set the source pattern to be used for drawing
114 cairo_set_source(cr, pattern);
115
116 // Draw a rectangle covering the entire image area
117 cairo_rectangle(cr, 0, 0, w, h);
118 // Fill the rectangle with the source pattern
119 cairo_fill(cr);
120
121 // Clean up resources
122 cairo_pattern_destroy (pattern);
123 cairo_surface_destroy (image);
124 cairo_surface_destroy (dest_image);
125 cairo_destroy (cr);
126 }
127 };
128
129 frei0r::construct<Mirr0r> plugin(
130 "Mirr0r",
131 "Repeats and flips the input image when it goes out of bounds, allowing for adjustable offset, zoom and rotation. A versatile tool for creative video effects.",
132 "Johann JEG",
133 1, 0,
134 F0R_COLOR_MODEL_RGBA8888);
135
1818 #include <cairo.h>
1919 #endif
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222 #include "gradientlut.hpp"
2323 #include <string>
2424 #include <stdlib.h>
7373 #include <stdio.h>
7474
7575 #include "frei0r.h"
76 #include "frei0r_math.h"
76 #include "frei0r/math.h"
7777
7878 #define MAX_HISTORY_LEN 128
7979
99 {
1010 hsync = 0.0;
1111 register_param(hsync,"HSync","the hsync offset");
12 vsync = 0.0;
13 register_param(vsync,"VSync","the vsync offset");
1214 }
1315
1416 virtual void update(double time,
1517 uint32_t* out,
1618 const uint32_t* in)
1719 {
18 unsigned int
19 first_line=static_cast<unsigned int>(height*std::fmod(std::fabs(hsync),1.0));
20 if (hsync == 0.0 && vsync == 0.0) {
21 std::copy(in, in+width*height, out);
22 } else if (vsync == 0.0) {
23 unsigned int
24 first_line=static_cast<unsigned int>(height*std::fmod(std::fabs(hsync),1.0));
2025
21 std::copy(in+width*first_line, in+width*height, out);
22 std::copy(in, in+width*first_line, out+width*(height-first_line));
26 std::copy(in+width*first_line, in+width*height, out);
27 std::copy(in, in+width*first_line, out+width*(height-first_line));
28 } else {
29 unsigned int hoffset=static_cast<unsigned int>(height*std::fmod(std::fabs(hsync),1.0));
30 unsigned int voffset=static_cast<unsigned int>(width*std::fmod(std::fabs(vsync),1.0));
31 for (unsigned int src_line = 0; src_line < height; src_line++) {
32 unsigned int dst_line = (src_line + hoffset) % height;
33 const uint32_t* src_pix = in + (width * src_line);
34 uint32_t* dst_pix = out + (width * dst_line);
35 std::copy(src_pix, src_pix + width - voffset, dst_pix + voffset);
36 std::copy(src_pix + width - voffset, src_pix + width, dst_pix);
37 }
38 }
2339 }
2440
2541 private:
2642 double hsync;
43 double vsync;
2744 };
2845
2946
0 set (SOURCES crt_core.c crt_ntsc.c ntsc-effect.c)
1 set (TARGET ntsc)
2
3 if (MSVC)
4 set (SOURCES ${SOURCES} ${FREI0R_DEF})
5 endif (MSVC)
6
7 add_library (${TARGET} MODULE ${SOURCES})
8 set_target_properties (${TARGET} PROPERTIES PREFIX "")
9
10 install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
0 /*****************************************************************************/
1 /*
2 * NTSC/CRT - integer-only NTSC video signal encoding / decoding emulation
3 *
4 * by EMMIR 2018-2023
5 *
6 * YouTube: https://www.youtube.com/@EMMIR_KC/videos
7 * Discord: https://discord.com/invite/hdYctSmyQJ
8 */
9 /*****************************************************************************/
10 #include "crt_core.h"
11
12 #include <stdlib.h>
13 #include <string.h>
14
15 /* ensure negative values for x get properly modulo'd */
16 #define POSMOD(x, n) (((x) % (n) + (n)) % (n))
17
18 static int sigpsin15[18] = { /* significant points on sine wave (15-bit) */
19 0x0000,
20 0x0c88,0x18f8,0x2528,0x30f8,0x3c50,0x4718,0x5130,0x5a80,
21 0x62f0,0x6a68,0x70e0,0x7640,0x7a78,0x7d88,0x7f60,0x8000,
22 0x7f60
23 };
24
25 static int
26 sintabil8(int n)
27 {
28 int f, i, a, b;
29
30 /* looks scary but if you don't change T14_2PI
31 * it won't cause out of bounds memory reads
32 */
33 f = n >> 0 & 0xff;
34 i = n >> 8 & 0xff;
35 a = sigpsin15[i];
36 b = sigpsin15[i + 1];
37 return (a + ((b - a) * f >> 8));
38 }
39
40 /* 14-bit interpolated sine/cosine */
41 extern void
42 crt_sincos14(int *s, int *c, int n)
43 {
44 int h;
45
46 n &= T14_MASK;
47 h = n & ((T14_2PI >> 1) - 1);
48
49 if (h > ((T14_2PI >> 2) - 1)) {
50 *c = -sintabil8(h - (T14_2PI >> 2));
51 *s = sintabil8((T14_2PI >> 1) - h);
52 } else {
53 *c = sintabil8((T14_2PI >> 2) - h);
54 *s = sintabil8(h);
55 }
56 if (n > ((T14_2PI >> 1) - 1)) {
57 *c = -*c;
58 *s = -*s;
59 }
60 }
61
62 /*****************************************************************************/
63 /********************************* FILTERS ***********************************/
64 /*****************************************************************************/
65
66 /* convolution is much faster but the EQ looks softer, more authentic, and more analog */
67 #define USE_CONVOLUTION 0
68 #define USE_7_SAMPLE_KERNEL 1
69 #define USE_6_SAMPLE_KERNEL 0
70 #define USE_5_SAMPLE_KERNEL 0
71
72 #if (CRT_CC_SAMPLES != 4)
73 /* the current convolutions do not filter properly at > 4 samples */
74 #undef USE_CONVOLUTION
75 #define USE_CONVOLUTION 0
76 #endif
77
78 #if USE_CONVOLUTION
79
80 /* NOT 3 band equalizer, faster convolution instead.
81 * eq function names preserved to keep code clean
82 */
83 static struct EQF {
84 int h[7];
85 } eqY, eqI, eqQ;
86
87 /* params unused to keep the function the same */
88 static void
89 init_eq(struct EQF *f,
90 int f_lo, int f_hi, int rate,
91 int g_lo, int g_mid, int g_hi)
92 {
93 memset(f, 0, sizeof(struct EQF));
94 }
95
96 static void
97 reset_eq(struct EQF *f)
98 {
99 memset(f->h, 0, sizeof(f->h));
100 }
101
102 static int
103 eqf(struct EQF *f, int s)
104 {
105 int i;
106 int *h = f->h;
107
108 for (i = 6; i > 0; i--) {
109 h[i] = h[i - 1];
110 }
111 h[0] = s;
112 #if USE_7_SAMPLE_KERNEL
113 /* index : 0 1 2 3 4 5 6 */
114 /* weight: 1 4 7 8 7 4 1 */
115 return (s + h[6] + ((h[1] + h[5]) * 4) + ((h[2] + h[4]) * 7) + (h[3] * 8)) >> 5;
116 #elif USE_6_SAMPLE_KERNEL
117 /* index : 0 1 2 3 4 5 */
118 /* weight: 1 3 4 4 3 1 */
119 return (s + h[5] + 3 * (h[1] + h[4]) + 4 * (h[2] + h[3])) >> 4;
120 #elif USE_5_SAMPLE_KERNEL
121 /* index : 0 1 2 3 4 */
122 /* weight: 1 2 2 2 1 */
123 return (s + h[4] + ((h[1] + h[2] + h[3]) << 1)) >> 3;
124 #else
125 /* index : 0 1 2 3 */
126 /* weight: 1 1 1 1*/
127 return (s + h[3] + h[1] + h[2]) >> 2;
128 #endif
129 }
130
131 #else
132
133 #define HISTLEN 3
134 #define HISTOLD (HISTLEN - 1) /* oldest entry */
135 #define HISTNEW 0 /* newest entry */
136
137 #define EQ_P 16 /* if changed, the gains will need to be adjusted */
138 #define EQ_R (1 << (EQ_P - 1)) /* rounding */
139 /* three band equalizer */
140 static struct EQF {
141 int lf, hf; /* fractions */
142 int g[3]; /* gains */
143 int fL[4];
144 int fH[4];
145 int h[HISTLEN]; /* history */
146 } eqY, eqI, eqQ;
147
148 /* f_lo - low cutoff frequency
149 * f_hi - high cutoff frequency
150 * rate - sampling rate
151 * g_lo, g_mid, g_hi - gains
152 */
153 static void
154 init_eq(struct EQF *f,
155 int f_lo, int f_hi, int rate,
156 int g_lo, int g_mid, int g_hi)
157 {
158 int sn, cs;
159
160 memset(f, 0, sizeof(struct EQF));
161
162 f->g[0] = g_lo;
163 f->g[1] = g_mid;
164 f->g[2] = g_hi;
165
166 crt_sincos14(&sn, &cs, T14_PI * f_lo / rate);
167 #if (EQ_P >= 15)
168 f->lf = 2 * (sn << (EQ_P - 15));
169 #else
170 f->lf = 2 * (sn >> (15 - EQ_P));
171 #endif
172 crt_sincos14(&sn, &cs, T14_PI * f_hi / rate);
173 #if (EQ_P >= 15)
174 f->hf = 2 * (sn << (EQ_P - 15));
175 #else
176 f->hf = 2 * (sn >> (15 - EQ_P));
177 #endif
178 }
179
180 static void
181 reset_eq(struct EQF *f)
182 {
183 memset(f->fL, 0, sizeof(f->fL));
184 memset(f->fH, 0, sizeof(f->fH));
185 memset(f->h, 0, sizeof(f->h));
186 }
187
188 static int
189 eqf(struct EQF *f, int s)
190 {
191 int i, r[3];
192
193 f->fL[0] += (f->lf * (s - f->fL[0]) + EQ_R) >> EQ_P;
194 f->fH[0] += (f->hf * (s - f->fH[0]) + EQ_R) >> EQ_P;
195
196 for (i = 1; i < 4; i++) {
197 f->fL[i] += (f->lf * (f->fL[i - 1] - f->fL[i]) + EQ_R) >> EQ_P;
198 f->fH[i] += (f->hf * (f->fH[i - 1] - f->fH[i]) + EQ_R) >> EQ_P;
199 }
200
201 r[0] = f->fL[3];
202 r[1] = f->fH[3] - f->fL[3];
203 r[2] = f->h[HISTOLD] - f->fH[3];
204
205 for (i = 0; i < 3; i++) {
206 r[i] = (r[i] * f->g[i]) >> EQ_P;
207 }
208
209 for (i = HISTOLD; i > 0; i--) {
210 f->h[i] = f->h[i - 1];
211 }
212 f->h[HISTNEW] = s;
213
214 return (r[0] + r[1] + r[2]);
215 }
216
217 #endif
218
219 /*****************************************************************************/
220 /***************************** PUBLIC FUNCTIONS ******************************/
221 /*****************************************************************************/
222
223 extern void
224 crt_resize(struct CRT *v, int w, int h, unsigned char *out)
225 {
226 v->outw = w;
227 v->outh = h;
228 v->out = out;
229 }
230
231 extern void
232 crt_reset(struct CRT *v)
233 {
234 v->hue = 0;
235 v->saturation = 10;
236 v->brightness = 0;
237 v->contrast = 180;
238 v->black_point = 0;
239 v->white_point = 100;
240 v->hsync = 0;
241 v->vsync = 0;
242
243 v->scanlines = 0; /* leave gaps between lines if necessary */
244 v->blend = 0; /* blend new field onto previous image */
245
246 // these options were previously #defined in crt_core.h
247 v->crt_do_vsync = 1;
248 v->crt_do_hsync = 1;
249 v->do_vhs_noise = 0;
250 }
251
252 extern void
253 crt_init(struct CRT *v, int w, int h, unsigned char *out)
254 {
255 memset(v, 0, sizeof(struct CRT));
256 crt_resize(v, w, h, out);
257 crt_reset(v);
258 v->rn = 194;
259
260 /* kilohertz to line sample conversion */
261 #define kHz2L(kHz) (CRT_HRES * (kHz * 100) / L_FREQ)
262
263 /* band gains are pre-scaled as 16-bit fixed point
264 * if you change the EQ_P define, you'll need to update these gains too
265 */
266 #if (CRT_CC_SAMPLES == 4)
267 init_eq(&eqY, kHz2L(1500), kHz2L(3000), CRT_HRES, 65536, 8192, 9175);
268 init_eq(&eqI, kHz2L(80), kHz2L(1150), CRT_HRES, 65536, 65536, 1311);
269 init_eq(&eqQ, kHz2L(80), kHz2L(1000), CRT_HRES, 65536, 65536, 0);
270 #elif (CRT_CC_SAMPLES == 5)
271 init_eq(&eqY, kHz2L(1500), kHz2L(3000), CRT_HRES, 65536, 12192, 7775);
272 init_eq(&eqI, kHz2L(80), kHz2L(1150), CRT_HRES, 65536, 65536, 1311);
273 init_eq(&eqQ, kHz2L(80), kHz2L(1000), CRT_HRES, 65536, 65536, 0);
274 #else
275 #error "NTSC-CRT currently only supports 4 or 5 samples per chroma period."
276 #endif
277
278 }
279
280 extern void
281 crt_demodulate(struct CRT *v, int noise)
282 {
283 /* made static so all this data does not go on the stack */
284 static struct {
285 int y, i, q;
286 } out[AV_LEN + 1], *yiqA, *yiqB;
287 int i, j, line, rn;
288 signed char *sig;
289 int s = 0;
290 int field, ratio;
291 int *ccr; /* color carrier signal */
292 int huesn, huecs;
293 int xnudge = -3, ynudge = 3;
294 int bright = v->brightness - (BLACK_LEVEL + v->black_point);
295 int pitch;
296
297 pitch = v->outw * BPP;
298
299 crt_sincos14(&huesn, &huecs, ((v->hue % 360) + 33) * 8192 / 180);
300 huesn >>= 11; /* make 4-bit */
301 huecs >>= 11;
302
303 rn = v->rn;
304 if(!v->crt_do_vsync)
305 {
306 /* determine field before we add noise,
307 * otherwise it's not reliably recoverable
308 */
309 for (i = -CRT_VSYNC_WINDOW; i < CRT_VSYNC_WINDOW; i++) {
310 line = POSMOD(v->vsync + i, CRT_VRES);
311 sig = v->analog + line * CRT_HRES;
312 s = 0;
313 for (j = 0; j < CRT_HRES; j++) {
314 s += sig[j];
315 if (s <= (CRT_VSYNC_THRESH * SYNC_LEVEL)) {
316 goto found_field;
317 }
318 }
319 }
320 found_field:
321 /* if vsync signal was in second half of line, odd field */
322 field = (j > (CRT_HRES / 2));
323 v->vsync = -3;
324 }
325 if(v->do_vhs_noise)
326 {
327 line = ((rand() % 8) - 4) + 14;
328 }
329 for (i = 0; i < CRT_INPUT_SIZE; i++) {
330 int nn = noise;
331 if(v->do_vhs_noise)
332 {
333 rn = rand();
334 if (i > (CRT_INPUT_SIZE - CRT_HRES * (16 + ((rand() % 20) - 10))) &&
335 i < (CRT_INPUT_SIZE - CRT_HRES * (5 + ((rand() % 8) - 4)))) {
336 int ln, sn, cs;
337
338 ln = (i * line) / CRT_HRES;
339 crt_sincos14(&sn, &cs, ln * 8192 / 180);
340 nn = cs >> 8;
341 }
342 }
343 else
344 {
345 rn = (214019 * rn + 140327895);
346 }
347 /* signal + noise */
348 s = v->analog[i] + (((((rn >> 16) & 0xff) - 0x7f) * nn) >> 8);
349 if (s > 127) { s = 127; }
350 if (s < -127) { s = -127; }
351 v->inp[i] = s;
352 }
353 v->rn = rn;
354
355 if(v->crt_do_vsync)
356 {
357 /* Look for vertical sync.
358 *
359 * This is done by integrating the signal and
360 * seeing if it exceeds a threshold. The threshold of
361 * the vertical sync pulse is much higher because the
362 * vsync pulse is a lot longer than the hsync pulse.
363 * The signal needs to be integrated to lessen
364 * the noise in the signal.
365 */
366 for (i = -CRT_VSYNC_WINDOW; i < CRT_VSYNC_WINDOW; i++) {
367 line = POSMOD(v->vsync + i, CRT_VRES);
368 sig = v->inp + line * CRT_HRES;
369 s = 0;
370 for (j = 0; j < CRT_HRES; j++) {
371 s += sig[j];
372 /* increase the multiplier to make the vsync
373 * more stable when there is a lot of noise
374 */
375 if (s <= (CRT_VSYNC_THRESH * SYNC_LEVEL)) {
376 goto vsync_found;
377 }
378 }
379 }
380 vsync_found:
381 v->vsync = line; /* vsync found (or gave up) at this line */
382 /* if vsync signal was in second half of line, odd field */
383 field = (j > (CRT_HRES / 2));
384 }
385
386 /* ratio of output height to active video lines in the signal */
387 ratio = (v->outh << 16) / CRT_LINES;
388 ratio = (ratio + 32768) >> 16;
389
390 field = (field * (ratio / 2));
391
392 for (line = CRT_TOP; line < CRT_BOT; line++) {
393 unsigned pos, ln, scanR;
394 int scanL, dx;
395 int L, R;
396 unsigned char *cL, *cR;
397 #if (CRT_CC_SAMPLES == 4)
398 int wave[CRT_CC_SAMPLES];
399 #else
400 int waveI[CRT_CC_SAMPLES];
401 int waveQ[CRT_CC_SAMPLES];
402 #endif
403 int dci, dcq; /* decoded I, Q */
404 int xpos, ypos;
405 int beg, end;
406 int phasealign;
407
408 beg = (line - CRT_TOP + 0) * (v->outh + v->v_fac) / CRT_LINES + field;
409 end = (line - CRT_TOP + 1) * (v->outh + v->v_fac) / CRT_LINES + field;
410
411 if (beg >= v->outh) { continue; }
412 if (end > v->outh) { end = v->outh; }
413
414 /* Look for horizontal sync.
415 * See comment above regarding vertical sync.
416 */
417 ln = (POSMOD(line + v->vsync, CRT_VRES)) * CRT_HRES;
418 sig = v->inp + ln + v->hsync;
419 s = 0;
420 for (i = -CRT_HSYNC_WINDOW; i < CRT_HSYNC_WINDOW; i++) {
421 s += sig[SYNC_BEG + i];
422 if (s <= (CRT_HSYNC_THRESH * SYNC_LEVEL)) {
423 break;
424 }
425 }
426 if(v->crt_do_hsync)
427 {
428 v->hsync = POSMOD(i + v->hsync, CRT_HRES);
429 }
430 else
431 {
432 v->hsync = 0;
433 }
434
435 xpos = POSMOD(AV_BEG + v->hsync + xnudge, CRT_HRES);
436 ypos = POSMOD(line + v->vsync + ynudge, CRT_VRES);
437 pos = xpos + ypos * CRT_HRES;
438
439 ccr = v->ccf[ypos % CRT_CC_VPER];
440 #if (CRT_CC_SAMPLES == 4)
441 sig = v->inp + ln + (v->hsync & ~3); /* faster */
442 #else
443 sig = v->inp + ln + (v->hsync - (v->hsync % CRT_CC_SAMPLES));
444 #endif
445 for (i = CB_BEG; i < CB_BEG + (CB_CYCLES * CRT_CB_FREQ); i++) {
446 int p, n;
447 p = ccr[i % CRT_CC_SAMPLES] * 127 / 128; /* fraction of the previous */
448 n = sig[i]; /* mixed with the new sample */
449 ccr[i % CRT_CC_SAMPLES] = p + n;
450 }
451
452 phasealign = POSMOD(v->hsync, CRT_CC_SAMPLES);
453
454 #if (CRT_CC_SAMPLES == 4)
455 /* amplitude of carrier = saturation, phase difference = hue */
456 dci = ccr[(phasealign + 1) & 3] - ccr[(phasealign + 3) & 3];
457 dcq = ccr[(phasealign + 2) & 3] - ccr[(phasealign + 0) & 3];
458
459 wave[0] = ((dci * huecs - dcq * huesn) >> 4) * v->saturation;
460 wave[1] = ((dcq * huecs + dci * huesn) >> 4) * v->saturation;
461 wave[2] = -wave[0];
462 wave[3] = -wave[1];
463 #elif (CRT_CC_SAMPLES == 5)
464 {
465 int dciA, dciB;
466 int dcqA, dcqB;
467 int ang = (v->hue % 360);
468 int off180 = CRT_CC_SAMPLES / 2;
469 int off90 = CRT_CC_SAMPLES / 4;
470 int peakA = phasealign + off90;
471 int peakB = phasealign + 0;
472 dciA = dciB = dcqA = dcqB = 0;
473 /* amplitude of carrier = saturation, phase difference = hue */
474 dciA = ccr[(peakA) % CRT_CC_SAMPLES];
475 /* average */
476 dciB = (ccr[(peakA + off180) % CRT_CC_SAMPLES]
477 + ccr[(peakA + off180 + 1) % CRT_CC_SAMPLES]) / 2;
478 dcqA = ccr[(peakB + off180) % CRT_CC_SAMPLES];
479 dcqB = ccr[(peakB) % CRT_CC_SAMPLES];
480 dci = dciA - dciB;
481 dcq = dcqA - dcqB;
482 /* create wave tables and rotate them by the hue adjustment angle */
483 for (i = 0; i < CRT_CC_SAMPLES; i++) {
484 int sn, cs;
485 crt_sincos14(&sn, &cs, ang * 8192 / 180);
486 waveI[i] = ((dci * cs + dcq * sn) >> 15) * v->saturation;
487 /* Q is offset by 90 */
488 crt_sincos14(&sn, &cs, (ang + 90) * 8192 / 180);
489 waveQ[i] = ((dci * cs + dcq * sn) >> 15) * v->saturation;
490 ang += (360 / CRT_CC_SAMPLES);
491 }
492 }
493 #endif
494 sig = v->inp + pos;
495
496 dx = ((AV_LEN - 1) << 12) / v->outw;
497 scanL = 0;
498 scanR = (AV_LEN - 1) << 12;
499 L = 0;
500 R = AV_LEN;
501
502 reset_eq(&eqY);
503 reset_eq(&eqI);
504 reset_eq(&eqQ);
505
506 #if (CRT_CC_SAMPLES == 4)
507 for (i = L; i < R; i++) {
508 out[i].y = eqf(&eqY, sig[i] + bright) << 4;
509 out[i].i = eqf(&eqI, sig[i] * wave[(i + 0) & 3] >> 9) >> 3;
510 out[i].q = eqf(&eqQ, sig[i] * wave[(i + 3) & 3] >> 9) >> 3;
511 }
512 #else
513 for (i = L; i < R; i++) {
514 out[i].y = eqf(&eqY, sig[i] + bright) << 4;
515 out[i].i = eqf(&eqI, sig[i] * waveI[i % CRT_CC_SAMPLES] >> 9) >> 3;
516 out[i].q = eqf(&eqQ, sig[i] * waveQ[i % CRT_CC_SAMPLES] >> 9) >> 3;
517 }
518 #endif
519
520 cL = v->out + (beg * pitch);
521 cR = cL + pitch;
522
523 for (pos = scanL; pos < scanR && cL < cR; pos += dx) {
524 int y, i, q;
525 int r, g, b;
526 int aa, bb;
527
528 R = pos & 0xfff;
529 L = 0xfff - R;
530 s = pos >> 12;
531
532 yiqA = out + s;
533 yiqB = out + s + 1;
534
535 /* interpolate between samples if needed */
536 y = ((yiqA->y * L) >> 2) + ((yiqB->y * R) >> 2);
537 i = ((yiqA->i * L) >> 14) + ((yiqB->i * R) >> 14);
538 q = ((yiqA->q * L) >> 14) + ((yiqB->q * R) >> 14);
539
540 /* YIQ to RGB */
541 r = (((y + 3879 * i + 2556 * q) >> 12) * v->contrast) >> 8;
542 g = (((y - 1126 * i - 2605 * q) >> 12) * v->contrast) >> 8;
543 b = (((y - 4530 * i + 7021 * q) >> 12) * v->contrast) >> 8;
544
545 if (r < 0) r = 0;
546 if (g < 0) g = 0;
547 if (b < 0) b = 0;
548 if (r > 255) r = 255;
549 if (g > 255) g = 255;
550 if (b > 255) b = 255;
551
552 if (v->blend) {
553 aa = (r << 16 | g << 8 | b);
554 bb = cL[0] << 16 | cL[1] << 8 | cL[2];
555
556
557 /* blend with previous color there */
558 bb = (((aa & 0xfefeff) >> 1) + ((bb & 0xfefeff) >> 1));
559 } else {
560 bb = (r << 16 | g << 8 | b);
561 }
562
563 cL[0] = bb >> 16 & 0xff;
564 cL[1] = bb >> 8 & 0xff;
565 cL[2] = bb >> 0 & 0xff;
566 cL[3] = 0xff;
567
568 cL += BPP;
569 }
570
571 /* duplicate extra lines */
572 for (s = beg + 1; s < (end - v->scanlines); s++) {
573 memcpy(v->out + s * pitch, v->out + (s - 1) * pitch, pitch);
574 }
575 }
576 }
0 /*****************************************************************************/
1 /*
2 * NTSC/CRT - integer-only NTSC video signal encoding / decoding emulation
3 *
4 * by EMMIR 2018-2023
5 *
6 * YouTube: https://www.youtube.com/@EMMIR_KC/videos
7 * Discord: https://discord.com/invite/hdYctSmyQJ
8 */
9 /*****************************************************************************/
10 #ifndef _CRT_CORE_H_
11 #define _CRT_CORE_H_
12
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16
17 /* crt_core.h
18 *
19 * The demodulator. This is also where you can define which system to emulate.
20 *
21 */
22
23 /* library version */
24 #define CRT_MAJOR 2
25 #define CRT_MINOR 3
26 #define CRT_PATCH 2
27
28 #include "crt_ntsc.h"
29
30 // frei0r always uses 4 bits per pixel so it is pointless for there to be any other possibilities
31 #define BPP 4
32
33 struct CRT {
34 signed char analog[CRT_INPUT_SIZE];
35 signed char inp[CRT_INPUT_SIZE]; /* CRT input, can be noisy */
36
37 int outw, outh; /* output width/height */
38 unsigned char *out; /* output image */
39
40 int hue, brightness, contrast, saturation; /* common monitor settings */
41 int black_point, white_point; /* user-adjustable */
42 int scanlines; /* leave gaps between lines if necessary */
43 int blend; /* blend new field onto previous image */
44 unsigned v_fac; /* factor to stretch img vertically onto the output img */
45
46 // these options were previously #defined in crt_core.h
47 int crt_do_vsync;
48 int crt_do_hsync;
49 int do_vhs_noise; /* 0 = no additional vhs noise, 1 = with additional vhs noise */
50
51 /* internal data */
52 int ccf[CRT_CC_VPER][CRT_CC_SAMPLES]; /* faster color carrier convergence */
53 int hsync, vsync; /* keep track of sync over frames */
54 int rn; /* seed for the 'random' noise */
55 };
56
57 /* Initializes the library. Sets up filters.
58 * w - width of the output image
59 * h - height of the output image
60 * f - format of the output image
61 * out - pointer to output image data
62 */
63 extern void crt_init(struct CRT *v, int w, int h, unsigned char *out);
64
65 /* Updates the output image parameters
66 * w - width of the output image
67 * h - height of the output image
68 * f - format of the output image
69 * out - pointer to output image data
70 */
71 extern void crt_resize(struct CRT *v, int w, int h, unsigned char *out);
72
73 /* Resets the CRT settings back to their defaults */
74 extern void crt_reset(struct CRT *v);
75
76 /* Modulates RGB image into an analog NTSC signal
77 * s - struct containing settings to apply to this field
78 */
79 extern void crt_modulate(struct CRT *v, struct NTSC_SETTINGS *s);
80
81 /* Demodulates the NTSC signal generated by crt_modulate()
82 * noise - the amount of noise added to the signal (0 - inf)
83 */
84 extern void crt_demodulate(struct CRT *v, int noise);
85
86 /*****************************************************************************/
87 /*************************** FIXED POINT SIN/COS *****************************/
88 /*****************************************************************************/
89
90 #define T14_2PI 16384
91 #define T14_MASK (T14_2PI - 1)
92 #define T14_PI (T14_2PI / 2)
93
94 extern void crt_sincos14(int *s, int *c, int n);
95
96 #ifdef __cplusplus
97 }
98 #endif
99
100 #endif
0 /*****************************************************************************/
1 /*
2 * NTSC/CRT - integer-only NTSC video signal encoding / decoding emulation
3 *
4 * by EMMIR 2018-2023
5 *
6 * YouTube: https://www.youtube.com/@EMMIR_KC/videos
7 * Discord: https://discord.com/invite/hdYctSmyQJ
8 */
9 /*****************************************************************************/
10
11 #include "crt_core.h"
12
13 #if (CRT_SYSTEM == CRT_SYSTEM_NTSCVHS)
14 #include <stdlib.h>
15 #include <string.h>
16
17 #if (CRT_CHROMA_PATTERN == 1)
18 /* 227.5 subcarrier cycles per line means every other line has reversed phase */
19 #define CC_PHASE(ln) (((ln) & 1) ? -1 : 1)
20 #else
21 #define CC_PHASE(ln) (1)
22 #endif
23
24 #define EXP_P 11
25 #define EXP_ONE (1 << EXP_P)
26 #define EXP_MASK (EXP_ONE - 1)
27 #define EXP_PI 6434
28 #define EXP_MUL(x, y) (((x) * (y)) >> EXP_P)
29 #define EXP_DIV(x, y) (((x) << EXP_P) / (y))
30
31 static int e11[] = {
32 EXP_ONE,
33 5567, /* e */
34 15133, /* e^2 */
35 41135, /* e^3 */
36 111817 /* e^4 */
37 };
38
39 /* fixed point e^x */
40 static int
41 expx(int n)
42 {
43 int neg, idx, res;
44 int nxt, acc, del;
45 int i;
46
47 if (n == 0) {
48 return EXP_ONE;
49 }
50 neg = n < 0;
51 if (neg) {
52 n = -n;
53 }
54 idx = n >> EXP_P;
55 res = EXP_ONE;
56 for (i = 0; i < idx / 4; i++) {
57 res = EXP_MUL(res, e11[4]);
58 }
59 idx &= 3;
60 if (idx > 0) {
61 res = EXP_MUL(res, e11[idx]);
62 }
63
64 n &= EXP_MASK;
65 nxt = EXP_ONE;
66 acc = 0;
67 del = 1;
68 for (i = 1; i < 17; i++) {
69 acc += nxt / del;
70 nxt = EXP_MUL(nxt, n);
71 del *= i;
72 if (del > nxt || nxt <= 0 || del <= 0) {
73 break;
74 }
75 }
76 res = EXP_MUL(res, acc);
77
78 if (neg) {
79 res = EXP_DIV(EXP_ONE, res);
80 }
81 return res;
82 }
83
84 /*****************************************************************************/
85 /********************************* FILTERS ***********************************/
86 /*****************************************************************************/
87
88 /* infinite impulse response low pass filter for bandlimiting YIQ */
89 static struct IIRLP {
90 int c;
91 int h; /* history */
92 } iirY, iirI, iirQ;
93
94 /* freq - total bandwidth
95 * limit - max frequency
96 */
97 static void
98 init_iir(struct IIRLP *f, int freq, int limit)
99 {
100 int rate; /* cycles/pixel rate */
101
102 memset(f, 0, sizeof(struct IIRLP));
103 rate = (freq << 9) / limit;
104 f->c = EXP_ONE - expx(-((EXP_PI << 9) / rate));
105 }
106
107 static void
108 reset_iir(struct IIRLP *f)
109 {
110 f->h = 0;
111 }
112
113 /* hi-pass for debugging */
114 #define HIPASS 0
115
116 static int
117 iirf(struct IIRLP *f, int s)
118 {
119 f->h += EXP_MUL(s - f->h, f->c);
120 #if HIPASS
121 return s - f->h;
122 #else
123 return f->h;
124 #endif
125 }
126
127 extern void
128 crt_modulate(struct CRT *v, struct NTSC_SETTINGS *s)
129 {
130 int x, y, xo, yo;
131 int destw = AV_LEN;
132 int desth = ((CRT_LINES * 64500) >> 16);
133 int iccf[CRT_CC_SAMPLES];
134 int ccmodI[CRT_CC_SAMPLES]; /* color phase for mod */
135 int ccmodQ[CRT_CC_SAMPLES]; /* color phase for mod */
136 int ccburst[CRT_CC_SAMPLES]; /* color phase for burst */
137 int sn, cs, n, ph;
138 int inv_phase = 0;
139 int aberration = 0;
140
141 if (!s->iirs_initialized) {
142 int y_freq = Y_FREQ_OFF;
143 int i_freq = I_FREQ_OFF;
144 int q_freq = Q_FREQ_OFF;
145
146 switch(s->vhs_mode)
147 {
148 case VHS_OFF:
149 break;
150 case VHS_SP:
151 y_freq = Y_FREQ_SP;
152 i_freq = I_FREQ_SP;
153 q_freq = Q_FREQ_SP;
154 break;
155 case VHS_LP:
156 y_freq = Y_FREQ_LP;
157 i_freq = I_FREQ_LP;
158 q_freq = Q_FREQ_LP;
159 break;
160 case VHS_EP:
161 y_freq = Y_FREQ_EP;
162 i_freq = I_FREQ_EP;
163 q_freq = Q_FREQ_EP;
164 break;
165 default:
166 break;
167 }
168
169 init_iir(&iirY, L_FREQ, y_freq);
170 init_iir(&iirI, L_FREQ, i_freq);
171 init_iir(&iirQ, L_FREQ, q_freq);
172 s->iirs_initialized = 1;
173 }
174 if (s->raw) {
175 destw = s->w;
176 desth = s->h;
177 if (destw > AV_LEN) {
178 destw = AV_LEN;
179 }
180 if (desth > ((CRT_LINES * 64500) >> 16)) {
181 desth = ((CRT_LINES * 64500) >> 16);
182 }
183 }
184
185 if (s->as_color) {
186 for (x = 0; x < CRT_CC_SAMPLES; x++) {
187 n = s->hue + x * (360 / CRT_CC_SAMPLES);
188 crt_sincos14(&sn, &cs, (n + 33) * 8192 / 180);
189 ccburst[x] = sn >> 10;
190 crt_sincos14(&sn, &cs, n * 8192 / 180);
191 ccmodI[x] = sn >> 10;
192 crt_sincos14(&sn, &cs, (n - 90) * 8192 / 180);
193 ccmodQ[x] = sn >> 10;
194 }
195 } else {
196 memset(ccburst, 0, sizeof(ccburst));
197 memset(ccmodI, 0, sizeof(ccmodI));
198 memset(ccmodQ, 0, sizeof(ccmodQ));
199 }
200
201 xo = AV_BEG + s->xoffset + (AV_LEN - destw) / 2;
202 yo = CRT_TOP + s->yoffset + (CRT_LINES - desth) / 2;
203
204 s->field &= 1;
205 s->frame &= 1;
206 inv_phase = (s->field == s->frame);
207 ph = CC_PHASE(inv_phase);
208
209 /* align signal */
210 xo = (xo & ~3);
211 if (s->do_aberration) {
212 aberration = ((rand() % 12) - 8) + 14;
213 }
214 for (n = 0; n < CRT_VRES; n++) {
215 int t; /* time */
216 signed char *line = &v->analog[n * CRT_HRES];
217
218 t = LINE_BEG;
219
220 if (n <= 3 || (n >= 7 && n <= 9)) {
221 /* equalizing pulses - small blips of sync, mostly blank */
222 while (t < (4 * CRT_HRES / 100)) line[t++] = SYNC_LEVEL;
223 while (t < (50 * CRT_HRES / 100)) line[t++] = BLANK_LEVEL;
224 while (t < (54 * CRT_HRES / 100)) line[t++] = SYNC_LEVEL;
225 while (t < (100 * CRT_HRES / 100)) line[t++] = BLANK_LEVEL;
226 } else if (n >= 4 && n <= 6) {
227 int even[4] = { 46, 50, 96, 100 };
228 int odd[4] = { 4, 50, 96, 100 };
229 int *offs = even;
230 if (s->field == 1) {
231 offs = odd;
232 }
233 /* vertical sync pulse - small blips of blank, mostly sync */
234 while (t < (offs[0] * CRT_HRES / 100)) line[t++] = SYNC_LEVEL;
235 while (t < (offs[1] * CRT_HRES / 100)) line[t++] = BLANK_LEVEL;
236 while (t < (offs[2] * CRT_HRES / 100)) line[t++] = SYNC_LEVEL;
237 while (t < (offs[3] * CRT_HRES / 100)) line[t++] = BLANK_LEVEL;
238 } else {
239 int cb;
240 if (n < (CRT_VRES - aberration)) {
241 /* video line */
242 while (t < SYNC_BEG) line[t++] = BLANK_LEVEL; /* FP */
243 while (t < BW_BEG) line[t++] = SYNC_LEVEL; /* SYNC */
244 }
245 while (t < AV_BEG) line[t++] = BLANK_LEVEL; /* BW + CB + BP */
246
247 if (n < CRT_TOP) {
248 while (t < CRT_HRES) line[t++] = BLANK_LEVEL;
249 }
250
251 /* CB_CYCLES of color burst at 3.579545 Mhz */
252 for (t = CB_BEG; t < CB_BEG + (CB_CYCLES * CRT_CB_FREQ); t++) {
253 #if (CRT_CHROMA_PATTERN == 1)
254 int off180 = CRT_CC_SAMPLES / 2;
255 cb = ccburst[(t + inv_phase * off180) % CRT_CC_SAMPLES];
256 #else
257 cb = ccburst[t % CRT_CC_SAMPLES];
258 #endif
259 line[t] = (BLANK_LEVEL + (cb * BURST_LEVEL)) >> 5;
260 iccf[t % CRT_CC_SAMPLES] = line[t];
261 }
262 }
263 }
264
265 if(s->vhs_mode != VHS_OFF)
266 {
267 /* reset hsync every frame so only the bottom part is warped */
268 v->hsync = 0;
269 }
270
271 for (y = 0; y < desth; y++) {
272 int field_offset;
273 int sy;
274
275 field_offset = (s->field * s->h + desth) / desth / 2;
276 sy = (y * s->h) / desth;
277
278 sy += field_offset;
279
280 if (sy >= s->h) sy = s->h;
281
282 sy *= s->w;
283
284 reset_iir(&iirY);
285 reset_iir(&iirI);
286 reset_iir(&iirQ);
287
288 for (x = 0; x < destw; x++) {
289 int fy, fi, fq;
290 int rA, gA, bA;
291 const unsigned char *pix;
292 int ire; /* composite signal */
293 int xoff;
294
295 pix = s->data + ((((x * s->w) / destw) + sy) * BPP);
296 rA = pix[0];
297 gA = pix[1];
298 bA = pix[2];
299
300
301 /* RGB to YIQ */
302 fy = (19595 * rA + 38470 * gA + 7471 * bA) >> 14;
303 fi = (39059 * rA - 18022 * gA - 21103 * bA) >> 14;
304 fq = (13894 * rA - 34275 * gA + 20382 * bA) >> 14;
305 ire = BLACK_LEVEL + v->black_point;
306
307 xoff = (x + xo) % CRT_CC_SAMPLES;
308 /* bandlimit Y,I,Q */
309 fy = iirf(&iirY, fy);
310 fi = iirf(&iirI, fi) * ph * ccmodI[xoff] >> 4;
311 fq = iirf(&iirQ, fq) * ph * ccmodQ[xoff] >> 4;
312 ire += (fy + fi + fq) * (WHITE_LEVEL * v->white_point / 100) >> 10;
313 if (ire < 0) ire = 0;
314 if (ire > 110) ire = 110;
315
316 v->analog[(x + xo) + (y + yo) * CRT_HRES] = ire;
317 }
318 }
319 for (n = 0; n < CRT_CC_VPER; n++) {
320 for (x = 0; x < CRT_CC_SAMPLES; x++) {
321 if(s->vhs_mode != VHS_OFF)
322 {
323 v->ccf[n][x] = 0;
324 }
325 else
326 {
327 v->ccf[n][x] = iccf[x] << 7;
328 }
329 }
330 }
331 }
332 #endif
0 /*****************************************************************************/
1 /*
2 * NTSC/CRT - integer-only NTSC video signal encoding / decoding emulation
3 *
4 * by EMMIR 2018-2023
5 *
6 * YouTube: https://www.youtube.com/@EMMIR_KC/videos
7 * Discord: https://discord.com/invite/hdYctSmyQJ
8 */
9 /*****************************************************************************/
10 #ifndef _CRT_NTSC_VHS_H_
11 #define _CRT_NTSC_VHS_H_
12
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16
17 /* crt_ntscvhs.h
18 *
19 * An interface to convert a digital image to an analog NTSC signal with VHS
20 * quality and some optional signal aberration at the bottom.
21 *
22 */
23 /* 0 = vertical chroma (228 chroma clocks per line) */
24 /* 1 = checkered chroma (227.5 chroma clocks per line) */
25 #define CRT_CHROMA_PATTERN 1
26
27 /* chroma clocks (subcarrier cycles) per line */
28 #if (CRT_CHROMA_PATTERN == 1)
29 #define CRT_CC_LINE 2275
30 #else
31 /* this will give the 'rainbow' effect in the famous waterfall scene */
32 #define CRT_CC_LINE 2280
33 #endif
34
35 /* NOTE, in general, increasing CRT_CB_FREQ reduces blur and bleed */
36 #define CRT_CB_FREQ 4 /* carrier frequency relative to sample rate */
37 #define CRT_HRES (CRT_CC_LINE * CRT_CB_FREQ / 10) /* horizontal res */
38 #define CRT_VRES 262 /* vertical resolution */
39 #define CRT_INPUT_SIZE (CRT_HRES * CRT_VRES)
40
41 #define CRT_TOP 21 /* first line with active video */
42 #define CRT_BOT 261 /* final line with active video */
43 #define CRT_LINES (CRT_BOT - CRT_TOP) /* number of active video lines */
44
45 #define CRT_CC_SAMPLES 4 /* samples per chroma period (samples per 360 deg) */
46 #define CRT_CC_VPER 1 /* vertical period in which the artifacts repeat */
47
48 /* search windows, in samples */
49 #define CRT_HSYNC_WINDOW 8
50 #define CRT_VSYNC_WINDOW 8
51
52 /* accumulated signal threshold required for sync detection.
53 * Larger = more stable, until it's so large that it is never reached in which
54 * case the CRT won't be able to sync
55 */
56 #define CRT_HSYNC_THRESH 4
57 #define CRT_VSYNC_THRESH 94
58
59 /*
60 * FULL HORIZONTAL LINE SIGNAL (~63500 ns)
61 * |---------------------------------------------------------------------------|
62 * HBLANK (~10900 ns) ACTIVE VIDEO (~52600 ns)
63 * |-------------------||------------------------------------------------------|
64 *
65 *
66 * WITHIN HBLANK PERIOD:
67 *
68 * FP (~1500 ns) SYNC (~4700 ns) BW (~600 ns) CB (~2500 ns) BP (~1600 ns)
69 * |--------------||---------------||------------||-------------||-------------|
70 * BLANK SYNC BLANK BLANK BLANK
71 *
72 */
73 #define LINE_BEG 0
74 #define FP_ns 1500 /* front porch */
75 #define SYNC_ns 4700 /* sync tip */
76 #define BW_ns 600 /* breezeway */
77 #define CB_ns 2500 /* color burst */
78 #define BP_ns 1600 /* back porch */
79 #define AV_ns 52600 /* active video */
80 #define HB_ns (FP_ns + SYNC_ns + BW_ns + CB_ns + BP_ns) /* h blank */
81 /* line duration should be ~63500 ns */
82 #define LINE_ns (FP_ns + SYNC_ns + BW_ns + CB_ns + BP_ns + AV_ns)
83
84 /* convert nanosecond offset to its corresponding point on the sampled line */
85 #define ns2pos(ns) ((ns) * CRT_HRES / LINE_ns)
86 /* starting points for all the different pulses */
87 #define FP_BEG ns2pos(0)
88 #define SYNC_BEG ns2pos(FP_ns)
89 #define BW_BEG ns2pos(FP_ns + SYNC_ns)
90 #define CB_BEG ns2pos(FP_ns + SYNC_ns + BW_ns)
91 #define BP_BEG ns2pos(FP_ns + SYNC_ns + BW_ns + CB_ns)
92 #define AV_BEG ns2pos(HB_ns)
93 #define AV_LEN ns2pos(AV_ns)
94
95 /* somewhere between 7 and 12 cycles */
96 #define CB_CYCLES 10
97
98 #define VHS_OFF 0
99 #define VHS_SP 1
100 #define VHS_LP 2
101 #define VHS_EP 3
102
103 #define VHS_MODE VHS_OFF
104
105 /* frequencies for bandlimiting */
106 #define L_FREQ 1431818 /* full line */
107
108 #define Y_FREQ_OFF 420000 /* Luma (Y) 4.2 MHz of the 14.31818 MHz */
109 #define I_FREQ_OFF 150000 /* Chroma (I) 1.5 MHz of the 14.31818 MHz */
110 #define Q_FREQ_OFF 55000 /* Chroma (Q) 0.55 MHz of the 14.31818 MHz */
111
112 #define Y_FREQ_SP 300000 /* Luma (Y) 3.0 MHz of the 14.31818 MHz */
113 #define I_FREQ_SP 62700 /* Chroma (I) 627 kHz of the 14.31818 MHz */
114 #define Q_FREQ_SP 62700 /* Chroma (Q) 627 kHz of the 14.31818 MHz */
115
116 #define Y_FREQ_LP 240000 /* Luma (Y) 2.4 MHz of the 14.31818 MHz */
117 #define I_FREQ_LP 40000 /* Chroma (I) 400 kHz of the 14.31818 MHz */
118 #define Q_FREQ_LP 40000 /* Chroma (Q) 400 kHz of the 14.31818 MHz */
119
120 #define Y_FREQ_EP 200000 /* Luma (Y) 2.0 MHz of the 14.31818 MHz */
121 #define I_FREQ_EP 37000 /* Chroma (I) 370 kHz of the 14.31818 MHz */
122 #define Q_FREQ_EP 37000 /* Chroma (Q) 370 kHz of the 14.31818 MHz */
123
124
125 /* IRE units (100 = 1.0V, -40 = 0.0V) */
126 #define WHITE_LEVEL 100
127 #define BURST_LEVEL 20
128 #define BLACK_LEVEL 7
129 #define BLANK_LEVEL 0
130 #define SYNC_LEVEL -40
131
132 struct NTSC_SETTINGS {
133 const unsigned char *data; /* image data */
134 int w, h; /* width and height of image */
135 int raw; /* 0 = scale image to fit monitor, 1 = don't scale */
136 int as_color; /* 0 = monochrome, 1 = full color */
137 int field; /* 0 = even, 1 = odd */
138 int frame; /* 0 = even, 1 = odd */
139 int hue; /* 0-359 */
140 int xoffset; /* x offset in sample space. 0 is minimum value */
141 int yoffset; /* y offset in # of lines. 0 is minimum value */
142 int do_aberration; /* 0 = no aberration, 1 = with aberration */
143
144 // these are changed by the vhs mode
145 int vhs_mode;
146 int y_freq;
147 int i_freq;
148 int q_freq;
149
150 /* make sure your NTSC_SETTINGS struct is zeroed out before you do anything */
151 int iirs_initialized; /* internal state */
152 };
153
154 #ifdef __cplusplus
155 }
156 #endif
157
158 #endif
0 #include <stdlib.h>
1
2 #include "frei0r.h"
3 #include "frei0r/math.h"
4
5 #include "crt_core.h"
6
7 // the actual NTSC emulation code is modified from here: https://github.com/LMP88959/NTSC-CRT
8
9 typedef struct ntsc_instance
10 {
11 // image dimensions
12 int width;
13 int height;
14
15 // parameters
16 struct CRT crt;
17 struct NTSC_SETTINGS ntsc_settings;
18
19 int noise;
20 double vhs_speed;
21
22 int field;
23 int progressive;
24
25 } ntsc_instance_t;
26
27 // these functions are for frei0r
28 // mostly copy/paste/slightly modified from the other frei0r effects
29 int f0r_init()
30 {
31 return 1;
32 }
33
34 void f0r_deinit()
35 {}
36
37 void f0r_get_plugin_info(f0r_plugin_info_t* info)
38 {
39 info->name = "NTSC";
40 info->author = "EMMIR, esmane";
41 info->explanation = "Simulates NTSC analog video.";
42 info->plugin_type = F0R_PLUGIN_TYPE_FILTER;
43 info->color_model = F0R_COLOR_MODEL_RGBA8888;
44 info->frei0r_version = FREI0R_MAJOR_VERSION;
45 info->major_version = 0;
46 info->minor_version = 1;
47 info->num_params = 8;
48 }
49
50 void f0r_get_param_info(f0r_param_info_t* info, int param_index)
51 {
52 switch(param_index)
53 {
54 case 0:
55 info->name = "Signal Noise";
56 info->explanation = "Amount of noise introduced into the NTSC signal.";
57 info->type = F0R_PARAM_DOUBLE;
58 break;
59
60 case 1:
61 info->name = "VHS Speed";
62 info->explanation = "Simulates VHS. 0 = off, 1 = SP, 2 = LP, 3 = EP";
63 info->type = F0R_PARAM_DOUBLE;
64 break;
65
66 case 2:
67 info->name = "VHS Noise";
68 info->explanation = "Toggles VHS noise at the bottom of the screen";
69 info->type = F0R_PARAM_BOOL;
70 break;
71
72 case 3:
73 info->name = "Aberration";
74 info->explanation = "Toggles VHS aberration at the bottom of the screen. Not visible if V-sync is on.";
75 info->type = F0R_PARAM_BOOL;
76 break;
77
78 case 4:
79 info->name = "Force V-sync";
80 info->explanation = "Forces V-sync even when the signal is really noisy.";
81 info->type = F0R_PARAM_BOOL;
82 break;
83
84 case 5:
85 info->name = "Force H-sync";
86 info->explanation = "Forces V-sync even when the signal is really noisy.";
87 info->type = F0R_PARAM_BOOL;
88 break;
89
90 case 6:
91 info->name = "Progressive Scan";
92 info->explanation = "Toggles progressive scan (Interlaced if off).";
93 info->type = F0R_PARAM_BOOL;
94 break;
95
96 case 7:
97 info->name = "Blend";
98 info->explanation = "Blends frames.";
99 info->type = F0R_PARAM_BOOL;
100 break;
101 }
102 }
103
104 f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
105 {
106 ntsc_instance_t* inst = (ntsc_instance_t*)calloc(1, sizeof(*inst));
107
108 inst->width = width;
109 inst->height = height;
110
111 inst->vhs_speed = 0.0;
112 inst->field = 0;
113 inst->progressive = 1;
114
115 crt_init(&(inst->crt), width, height, NULL);
116
117 // init NTSC_SETTINGS
118 inst->ntsc_settings.data = NULL;
119 inst->ntsc_settings.w = width;
120 inst->ntsc_settings.h = height;
121 inst->ntsc_settings.raw = 0;
122 inst->ntsc_settings.as_color = 1;
123 inst->ntsc_settings.field = 0;
124 inst->ntsc_settings.frame = 0;
125 inst->ntsc_settings.hue = 0;
126 inst->ntsc_settings.xoffset = 0;
127 inst->ntsc_settings.yoffset = 0;
128 inst->ntsc_settings.do_aberration = 0;
129
130 // these are changed by the vhs mode
131 inst->ntsc_settings.vhs_mode = 0;
132 inst->ntsc_settings.y_freq = 0;
133 inst->ntsc_settings.i_freq = 0;
134 inst->ntsc_settings.q_freq = 0;
135
136 /* make sure your NTSC_SETTINGS struct is zeroed out before you do anything */
137 inst->ntsc_settings.iirs_initialized = 0;
138
139 inst->noise = 0;
140
141 return (f0r_instance_t)inst;
142 }
143
144 void f0r_destruct(f0r_instance_t instance)
145 {
146 ntsc_instance_t* inst = (ntsc_instance_t*)instance;
147 free(instance);
148 }
149
150
151 void f0r_set_param_value(f0r_instance_t instance, f0r_param_t param, int param_index)
152 {
153 ntsc_instance_t* inst = (ntsc_instance_t*)instance;
154 switch(param_index)
155 {
156 case 0:
157 inst->noise = *((double*)param) * 100;
158 break;
159 case 1:
160 inst->ntsc_settings.vhs_mode = (int)CLAMP(*((double*)param) * 4, 0, 4);
161 inst->ntsc_settings.iirs_initialized = 0;
162 break;
163 case 2:
164 inst->crt.do_vhs_noise = (*((double*)param) >= 0.5);
165 break;
166 case 3:
167 inst->ntsc_settings.do_aberration = (*((double*)param) >= 0.5);
168 break;
169 case 4:
170 inst->crt.crt_do_vsync = !(*((double*)param) >= 0.5);
171 break;
172 case 5:
173 inst->crt.crt_do_hsync = !(*((double*)param) >= 0.5);
174 break;
175 case 6:
176 inst->progressive = (*((double*)param) >= 0.5);
177 break;
178 case 7:
179 inst->crt.blend = (*((double*)param) >= 0.5);
180 break;
181 }
182 }
183
184 void f0r_get_param_value(f0r_instance_t instance, f0r_param_t param, int param_index)
185 {
186 ntsc_instance_t* inst = (ntsc_instance_t*)instance;
187 switch(param_index)
188 {
189 case 0:
190 *((double*)param) = (inst->noise / 100);
191 break;
192 case 1:
193 *((double*)param) = (inst->ntsc_settings.vhs_mode / 4);
194 break;
195 case 2:
196 *((double*)param) = (inst->crt.do_vhs_noise ? 1.0 : 0.0);
197 break;
198 case 3:
199 *((double*)param) = (inst->ntsc_settings.do_aberration ? 1.0 : 0.0);
200 break;
201 case 4:
202 *((double*)param) = !(inst->crt.crt_do_vsync ? 1.0 : 0.0);
203 break;
204 case 5:
205 *((double*)param) = !(inst->crt.crt_do_hsync ? 1.0 : 0.0);
206 break;
207 case 6:
208 *((double*)param) = (inst->progressive ? 1.0 : 0.0);
209 break;
210 case 7:
211 *((double*)param) = (inst->crt.blend ? 1.0 : 0.0);
212 break;
213 }
214 }
215
216
217 void f0r_update(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe)
218 {
219 ntsc_instance_t* inst = (ntsc_instance_t*)instance;
220
221 inst->crt.out = (char*)outframe;
222 inst->ntsc_settings.data = (const char*)inframe;
223
224 inst->ntsc_settings.field = inst->field & 1;
225 if (inst->ntsc_settings.field == 0) {
226 /* a frame is two fields */
227 inst->ntsc_settings.frame ^= 1;
228 }
229
230 crt_modulate(&(inst->crt), &(inst->ntsc_settings));
231 crt_demodulate(&(inst->crt), inst->noise);
232 if(!inst->progressive)
233 {
234 inst->field ^= 1;
235 }
236 }
00 #include "frei0r.h"
1 #include "frei0r_math.h"
1 #include "frei0r/math.h"
22 #include <stdlib.h>
33 #include <string.h>
44 #include <assert.h>
55
66 static uint32_t average(const uint32_t* start,
7 int bxsize,
8 int bysize, int xsize);
7 int bxsize,
8 int bysize, int xsize);
99
1010 static void fill_block(uint32_t* start,
1111 int bxsize,
1515
1616 typedef struct pixelizer_instance
1717 {
18 unsigned int width;
19 unsigned int height;
20 unsigned int block_size_x;
21 unsigned int block_size_y;
18 unsigned int width;
19 unsigned int height;
20 unsigned int block_size_x;
21 unsigned int block_size_y;
22 unsigned char pass_alpha;
2223 } pixelizer_instance_t;
2324
2425 int f0r_init()
2526 {
26 return 1;
27 return 1;
2728 }
2829
2930 void f0r_deinit()
3132
3233 void f0r_get_plugin_info(f0r_plugin_info_t* pixelizerInfo)
3334 {
34 pixelizerInfo->name = "pixeliz0r";
35 pixelizerInfo->author = "Gephex crew";
36 pixelizerInfo->plugin_type = F0R_PLUGIN_TYPE_FILTER;
37 pixelizerInfo->color_model = F0R_COLOR_MODEL_PACKED32;
38 pixelizerInfo->frei0r_version = FREI0R_MAJOR_VERSION;
39 pixelizerInfo->major_version = 1;
40 pixelizerInfo->minor_version = 0;
41 pixelizerInfo->num_params = 2;
42 pixelizerInfo->explanation = "Pixelize input image.";
35 pixelizerInfo->name = "pixeliz0r";
36 pixelizerInfo->author = "Gephex crew";
37 pixelizerInfo->plugin_type = F0R_PLUGIN_TYPE_FILTER;
38 pixelizerInfo->color_model = F0R_COLOR_MODEL_PACKED32;
39 pixelizerInfo->frei0r_version = FREI0R_MAJOR_VERSION;
40 pixelizerInfo->major_version = 2;
41 pixelizerInfo->minor_version = 0;
42 pixelizerInfo->num_params = 3;
43 pixelizerInfo->explanation = "Pixelize input image.";
4344 }
4445
4546 void f0r_get_param_info(f0r_param_info_t* info, int param_index)
4647 {
47 switch(param_index)
48 switch(param_index)
4849 {
4950 case 0:
50 info->name = "Block width";
51 info->type = F0R_PARAM_DOUBLE;
52 info->explanation = "Horizontal size of one 'pixel'";
53 break;
51 info->name = "Block width";
52 info->type = F0R_PARAM_DOUBLE;
53 info->explanation = "Horizontal size of one 'pixel'";
54 break;
5455 case 1:
55 info->name = "Block height";
56 info->type = F0R_PARAM_DOUBLE;
57 info->explanation = "Vertical size of one 'pixel'";
58 break;
56 info->name = "Block height";
57 info->type = F0R_PARAM_DOUBLE;
58 info->explanation = "Vertical size of one 'pixel'";
59 break;
60 case 2:
61 info->name = "Pass-through alpha";
62 info->type = F0R_PARAM_BOOL;
63 info->explanation = "Do not average the alpha channel over each block";
64 break;
5965 }
6066 }
6167
6268 f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
6369 {
64 pixelizer_instance_t* inst = (pixelizer_instance_t*)calloc(1, sizeof(*inst));
65 inst->width = width; inst->height = height;
66 inst->block_size_x = 8; inst->block_size_y = 8;
67 return (f0r_instance_t)inst;
70 pixelizer_instance_t* inst = (pixelizer_instance_t*)calloc(1, sizeof(*inst));
71 inst->width = width; inst->height = height;
72 inst->block_size_x = 8; inst->block_size_y = 8;
73 return (f0r_instance_t)inst;
6874 }
6975
7076 void f0r_destruct(f0r_instance_t instance)
7177 {
72 free(instance);
78 free(instance);
7379 }
7480
7581 void f0r_set_param_value(f0r_instance_t instance,
76 f0r_param_t param, int param_index)
82 f0r_param_t param, int param_index)
7783 {
78 assert(instance);
79 pixelizer_instance_t* inst = (pixelizer_instance_t*)instance;
80
81 switch(param_index)
84 assert(instance);
85 pixelizer_instance_t* inst = (pixelizer_instance_t*)instance;
86
87 switch(param_index)
8288 {
8389 case 0:
84 // scale to [1..width]
85 inst->block_size_x = MAX(1 + ( *((double*)param) * (inst->width/2)), 1);
86 break;
90 // scale to [1..width]
91 inst->block_size_x = MAX(1 + ( *((double*)param) * (inst->width/2)), 1);
92 break;
8793 case 1:
88 // scale to [1..height]
89 inst->block_size_y = MAX(1 + ( *((double*)param) * (inst->height/2)), 1);
90 break;
91 }
94 // scale to [1..height]
95 inst->block_size_y = MAX(1 + ( *((double*)param) * (inst->height/2)), 1);
96 break;
97 case 2:
98 inst->pass_alpha = *((double*)param) >= 0.5;
99 break;
100 }
92101 }
93102
94103 void f0r_get_param_value(f0r_instance_t instance,
95 f0r_param_t param, int param_index)
104 f0r_param_t param, int param_index)
96105 {
97 assert(instance);
98 pixelizer_instance_t* inst = (pixelizer_instance_t*)instance;
99
100 switch(param_index)
106 assert(instance);
107 pixelizer_instance_t* inst = (pixelizer_instance_t*)instance;
108
109 switch(param_index)
101110 {
102111 case 0:
103 // scale back to [0..1]
104 *((double*)param) = (double)(inst->block_size_x-1)/(inst->width/2);
105 break;
112 // scale back to [0..1]
113 *((double*)param) = (double)(inst->block_size_x-1)/(inst->width/2);
114 break;
106115 case 1:
107 // scale back to [0..1]
108 *((double*)param) = (double)(inst->block_size_y-1)/(inst->height/2);
109 break;
110 }
116 // scale back to [0..1]
117 *((double*)param) = (double)(inst->block_size_y-1)/(inst->height/2);
118 break;
119 case 2:
120 *((double*)param) = inst->pass_alpha ? 1.0 : 0.0;
121 break;
122 }
111123 }
112124
113125 void f0r_update(f0r_instance_t instance, double time,
114 const uint32_t* inframe, uint32_t* outframe)
115 {
116 assert(instance);
117 pixelizer_instance_t* inst = (pixelizer_instance_t*)instance;
118 unsigned int xsize = inst->width;
119 unsigned int ysize = inst->height;
120 unsigned int bsizex = inst->block_size_x;
121 unsigned int bsizey = inst->block_size_y;
122 unsigned int offset = 0;
123 unsigned int blocks_x, blocks_y, xrest, yrest, xi, yi;
124
125
126 blocks_x = xsize / bsizex;
127 blocks_y = ysize / bsizey;
128 xrest = xsize - blocks_x*bsizex;
129 yrest = ysize - blocks_y*bsizey;
130
131 uint32_t* dst = outframe;
132 const uint32_t* src = inframe;
133
134
135 if (bsizex == 1 && bsizey == 1)
136 {
137 memcpy(dst, src, xsize*ysize*sizeof(uint32_t));
138 }
139
140
141 // now get average for every block and write the average color to the output
142 for (yi = 0; yi < blocks_y; ++yi)
126 const uint32_t* inframe, uint32_t* outframe)
127 {
128 assert(instance);
129 pixelizer_instance_t* inst = (pixelizer_instance_t*)instance;
130 unsigned int xsize = inst->width;
131 unsigned int ysize = inst->height;
132 unsigned int bsizex = inst->block_size_x;
133 unsigned int bsizey = inst->block_size_y;
134 unsigned int offset = 0;
135 unsigned int blocks_x, blocks_y, xrest, yrest, xi, yi;
136
137 blocks_x = xsize / bsizex;
138 blocks_y = ysize / bsizey;
139 xrest = xsize - blocks_x*bsizex;
140 yrest = ysize - blocks_y*bsizey;
141
142 uint32_t* dst = outframe;
143 const uint32_t* src = inframe;
144
145
146 if (bsizex == 1 && bsizey == 1)
147 {
148 memcpy(dst, src, xsize*ysize*sizeof(uint32_t));
149 }
150
151
152 // now get average for every block and write the average color to the output
153 for (yi = 0; yi < blocks_y; ++yi)
143154 {
144 offset = yi*bsizey*xsize;
145 for (xi = 0; xi < blocks_x; ++xi)
146 {
147 uint32_t col = average(src + offset, bsizex, bsizey, xsize);
148 fill_block(dst + offset, bsizex, bsizey, xsize, col);
149 offset += bsizex;
150 }
151 if (xrest > 0)
152 {
153 uint32_t col = average(src + offset, xrest, bsizey, xsize);
154 fill_block(dst + offset, xrest, bsizey, xsize, col);
155 }
156 }
157 // check for last line
158 if (yrest > 0)
159 {
160 offset = blocks_y*bsizey*xsize;
161 for (xi = 0; xi < blocks_x; ++xi)
162 {
163 uint32_t col = average(src + offset, bsizex, yrest, xsize);
164 fill_block(dst + offset, bsizex, yrest, xsize, col);
165 offset += bsizex;
166 }
167 if (xrest > 0)
168 {
169 uint32_t col = average(src + offset, xrest, yrest, xsize);
170 fill_block(dst + offset, xrest, yrest, xsize, col);
171 }
172 }
155 offset = yi*bsizey*xsize;
156 for (xi = 0; xi < blocks_x; ++xi)
157 {
158 uint32_t col = average(src + offset, bsizex, bsizey, xsize);
159 fill_block(dst + offset, bsizex, bsizey, xsize, col);
160 offset += bsizex;
161 }
162 if (xrest > 0)
163 {
164 uint32_t col = average(src + offset, xrest, bsizey, xsize);
165 fill_block(dst + offset, xrest, bsizey, xsize, col);
166 }
167 }
168 // check for last line
169 if (yrest > 0)
170 {
171 offset = blocks_y*bsizey*xsize;
172 for (xi = 0; xi < blocks_x; ++xi)
173 {
174 uint32_t col = average(src + offset, bsizex, yrest, xsize);
175 fill_block(dst + offset, bsizex, yrest, xsize, col);
176 offset += bsizex;
177 }
178 if (xrest > 0)
179 {
180 uint32_t col = average(src + offset, xrest, yrest, xsize);
181 fill_block(dst + offset, xrest, yrest, xsize, col);
182 }
183 }
184 if (inst->pass_alpha)
185 {
186 for (xi = 0; xi < inst->width * inst->height; ++xi)
187 {
188 dst[xi] = (src[xi] & 0xff000000) | (dst[xi] & 0x00ffffff);
189 }
190 }
173191 }
174192
175193
176194 static uint32_t average(const uint32_t* start,
177 int bxsize, int bysize, int xsize)
178 {
179 const uint32_t* p = start;
180 uint32_t alpha = 0, red = 0, green = 0, blue = 0;
181 uint32_t avg_alpha, avg_red, avg_green, avg_blue;
182 int x, y;
183 const uint32_t* pp;
184 uint32_t c;
185
186 for (y = 0; y < bysize; ++y)
187 {
188 pp = p;
189 for (x = 0; x < bxsize; ++x)
190 {
191 c = *(pp++);
192 alpha += (c & 0xff000000) >> 24;
193 red += (c & 0x00ff0000) >> 16;
194 green += (c & 0x0000ff00) >> 8;
195 blue += (c & 0x000000ff);
196 }
197 p += xsize;
198 }
199
200 avg_alpha = (alpha / (bxsize*bysize)) & 0xff;
201 avg_red = (red / (bxsize*bysize)) & 0xff;
202 avg_green = (green / (bxsize*bysize)) & 0xff;
203 avg_blue = (blue / (bxsize*bysize)) & 0xff;
204
205 return (avg_alpha << 24) + (avg_red << 16) + (avg_green << 8) + avg_blue;
195 int bxsize, int bysize, int xsize)
196 {
197 const uint32_t* p = start;
198 uint32_t alpha = 0, red = 0, green = 0, blue = 0;
199 uint32_t avg_alpha, avg_red, avg_green, avg_blue;
200 int x, y;
201 const uint32_t* pp;
202 uint32_t c;
203
204 for (y = 0; y < bysize; ++y)
205 {
206 pp = p;
207 for (x = 0; x < bxsize; ++x)
208 {
209 c = *(pp++);
210 alpha += (c & 0xff000000) >> 24;
211 red += (c & 0x00ff0000) >> 16;
212 green += (c & 0x0000ff00) >> 8;
213 blue += (c & 0x000000ff);
214 }
215 p += xsize;
216 }
217
218 avg_alpha = (alpha / (bxsize*bysize)) & 0xff;
219 avg_red = (red / (bxsize*bysize)) & 0xff;
220 avg_green = (green / (bxsize*bysize)) & 0xff;
221 avg_blue = (blue / (bxsize*bysize)) & 0xff;
222
223 return (avg_alpha << 24) + (avg_red << 16) + (avg_green << 8) + avg_blue;
206224 }
207225
208226 static void fill_block(uint32_t* start, int bxsize, int bysize,
209227 int xsize, uint32_t col)
210228 {
211 uint32_t* p = start;
212 int x, y;
213 uint32_t* pp;
214
215 for (y = 0; y < bysize; ++y)
216 {
217 pp = p;
218 for (x = 0; x < bxsize; ++x)
219 {
220 *(pp++) = col;
221 }
222 p += xsize;
223 }
224
225 }
226
229 uint32_t* p = start;
230 int x, y;
231 uint32_t* pp;
232
233 for (y = 0; y < bysize; ++y)
234 {
235 pp = p;
236 for (x = 0; x < bxsize; ++x)
237 {
238 *(pp++) = col;
239 }
240 p += xsize;
241 }
242
243 }
244
2525 #include <assert.h>
2626
2727 #include "frei0r.h"
28 #include "frei0r_math.h"
28 #include "frei0r/math.h"
2929
3030 typedef struct posterize_instance
3131 {
1616 */
1717
1818 #include "frei0r.hpp"
19 #include "frei0r_math.h"
19 #include "frei0r/math.h"
2020
2121 class Premultiply : public frei0r::filter
2222 {
2626 #include <assert.h>
2727 #include <math.h>
2828 #include "frei0r.h"
29 #include "frei0r_math.h"
29 #include "frei0r/math.h"
3030
3131 static int MY_MAX_RAND = 32767;// I assume RAND_MAX to be at least this big.
3232 static double gaussian_lookup[32767];
2020 #include <assert.h>
2121
2222 #include "frei0r.h"
23 #include "frei0r_math.h"
23 #include "frei0r/math.h"
2424
2525 #define MAX_SATURATION 8.0
2626
2525 #include <stdio.h>
2626 #include <math.h>
2727 #include "frei0r.h"
28 #include "frei0r_math.h"
28 #include "frei0r/math.h"
2929
3030 #define SIGMOIDAL_BASE 2
3131 #define SIGMOIDAL_RANGE 20
1717 */
1818
1919 #include "frei0r.hpp"
20 #include "frei0r_math.h"
20 #include "frei0r/math.h"
2121 #include <stdlib.h>
2222
2323 class sobel : public frei0r::filter
2626 #include <assert.h>
2727 #include <math.h>
2828 #include "frei0r.h"
29 #include "blur.h"
30 #include "frei0r_math.h"
29 #include "frei0r/blur.h"
30 #include "frei0r/math.h"
3131
3232 #define SIGMOIDAL_BASE 2
3333 #define SIGMOIDAL_RANGE 20
1919 #include <math.h>
2020 #include <stdlib.h>
2121 #include "frei0r.hpp"
22 #include "frei0r_math.h"
22 #include "frei0r/math.h"
2323
2424 /**
2525 This filter implements a standard way of color correction proposed by
2323 #include <string.h>
2424
2525 #include "frei0r.h"
26 #include "blur.h"
26 #include "frei0r/blur.h"
2727
2828 int f0r_init()
2929 {
00 # Set C99 flag for gcc
11 if (CMAKE_COMPILER_IS_GNUCC)
2 set(CMAKE_C_FLAGS "-std=c99")
2 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
33 endif (CMAKE_COMPILER_IS_GNUCC)
44
55 set (SOURCES three_point_balance.c)
2323 #include <stdio.h>
2424
2525 #include "frei0r.h"
26 #include "frei0r_math.h"
26 #include "frei0r/math.h"
2727
2828 typedef struct three_point_balance_instance
2929 {
2020 #include <assert.h>
2121
2222 #include "frei0r.h"
23 #include "frei0r_math.h"
23 #include "frei0r/math.h"
2424
2525 typedef struct tint0r_instance
2626 {
00 #include "frei0r.h"
1 #include "frei0r_math.h"
1 #include "frei0r/math.h"
22 #include <stdlib.h>
33 #include <assert.h>
44
2121 #endif /* _MSC_VER */
2222 #include <cmath>
2323 #include "frei0r.hpp"
24 #include "frei0r_math.h"
24 #include "frei0r/math.h"
2525
2626
2727 /**
1818 add_subdirectory (difference)
1919 add_subdirectory (divide)
2020 add_subdirectory (dodge)
21 add_subdirectory (euclid_eraser)
2122 add_subdirectory (grain_extract)
2223 add_subdirectory (grain_merge)
2324 add_subdirectory (hardlight)
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1919 */
2020
2121 #include "frei0r.hpp"
22 #include "frei0r_math.h"
22 #include "frei0r/math.h"
2323
2424 #define NBYTES 4
2525 #define ALPHA 3
1717 */
1818
1919 #include "frei0r.hpp"
20 #include "frei0r_math.h"
20 #include "frei0r/math.h"
2121
2222 #include <algorithm>
2323
1717 */
1818
1919 #include "frei0r.hpp"
20 #include "frei0r_math.h"
20 #include "frei0r/math.h"
2121
2222 #include <algorithm>
2323
1717 */
1818
1919 #include "frei0r.hpp"
20 #include "frei0r_math.h"
20 #include "frei0r/math.h"
2121
2222 #include <algorithm>
2323
1717 */
1818
1919 #include "frei0r.hpp"
20 #include "frei0r_math.h"
20 #include "frei0r/math.h"
2121
2222 #include <algorithm>
2323
1717 */
1818
1919 #include "frei0r.hpp"
20 #include "frei0r_math.h"
20 #include "frei0r/math.h"
2121
2222 #include <algorithm>
2323
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
2626 #include <math.h>
2727
2828 #include "frei0r.h"
29 #include "frei0r_cairo.h"
29 #include "frei0r/cairo.h"
3030
3131 double PI=3.14159265358979;
3232
2525 #include <string.h>
2626
2727 #include "frei0r.h"
28 #include "frei0r_cairo.h"
28 #include "frei0r/cairo.h"
2929
3030 typedef struct cairo_blend_instance
3131 {
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
22 #include "frei0r_colorspace.h"
21 #include "frei0r/math.h"
22 #include "frei0r/colorspace.h"
2323
2424 #define NBYTES 4
2525
2020 #include <assert.h>
2121
2222 #include "frei0r.h"
23 #include "frei0r_math.h"
23 #include "frei0r/math.h"
2424
2525 typedef struct composition_instance
2626 {
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
0 set (SOURCES euclid_eraser.cpp)
1 set (TARGET euclid_eraser)
2
3 if (MSVC)
4 set (SOURCES ${SOURCES} ${FREI0R_1_1_DEF})
5 endif (MSVC)
6
7 add_library (${TARGET} MODULE ${SOURCES})
8 set_target_properties (${TARGET} PROPERTIES PREFIX "")
9
10 install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
0 // SPDX-License-Identifier: GPL-2.0-or-later
1 // Copyright (C) 2024 Erik H. Beck, bacon@tahomasoft.com
2 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
3
4 /* This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA
18 *
19 * Also see:
20 *
21 * https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
22 *
23 */
24
25 /** This is the source file for the euclid eraser two-input mixer for
26 frei0r. It uses euclidean distance to remove a static background
27 from a video. See file ./euclid_eraser.md for more info
28 */
29
30 #include <math.h>
31 #include "frei0r.hpp"
32 #include "frei0r/math.h"
33
34 #define NBYTES 4
35 #define CHANNELS 3 // Actually 4; 0-3
36
37 double euclidDistance(uint8_t x_r, uint8_t x_g, uint8_t x_b,
38 uint8_t y_r, uint8_t y_g, uint8_t y_b)
39 {
40 //calculating color channel differences for next steps
41 double red_d = x_r - y_r;
42 double green_d = x_g - y_g;
43 double blue_d = x_b - y_b;
44
45 double sq_sum, dist;
46
47 //calculating Euclidean distance
48 sq_sum = pow(red_d, 2) + pow(green_d, 2) + pow (blue_d, 2);
49 dist = sqrt(sq_sum);
50
51 return dist;
52 }
53
54
55 class euclid_eraser : public frei0r::mixer2
56 {
57
58 public:
59 euclid_eraser(unsigned int width, unsigned int height)
60 {
61 threshold = 5.6; // Default distance threshold value
62 register_param(threshold, "threshold", "Matching Threshold");
63 }
64
65 void update(double time,
66 uint32_t* out,
67 const uint32_t* in1,
68 const uint32_t* in2)
69 {
70
71 const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1); //frst track (0)
72 const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2); //second trk (1)
73 uint8_t *dst = reinterpret_cast<uint8_t*>(out);
74
75 double e_dist;
76
77 uint32_t sizeCounter = size;
78 uint32_t b;
79
80 while (sizeCounter--)
81 {
82
83 // Loop over rgb
84 // Copy pixels from src2 to destination
85
86 for (b=0; b<3; b++)
87 {
88 dst[b]=src2[b];
89 }
90 e_dist=euclidDistance(src1[0],src1[1],src1[2],
91 src2[0],src2[1],src2[2]);
92
93 if (e_dist <= euclid_eraser::threshold) {
94 // Make alpha channel for pixel fully transparent
95 dst[3]=0;
96 }
97 else {
98 // Make alpha channel for the pixel fully opaque
99 dst[3]=255;
100 }
101
102 src1 += NBYTES;
103 src2 += NBYTES;
104 dst += NBYTES;
105 }
106
107 }
108 private:
109 double threshold;
110
111 };
112
113 frei0r::construct<euclid_eraser> plugin("euclid_eraser",
114 "Erasing backgrounds with euclidian distance",
115 "Erik H. Beck",
116 0,1,
117 F0R_COLOR_MODEL_RGBA8888);
118
0 # Euclid Eraser Notes #
1
2 ## Overview ##
3 This is about the Euclid Eraser mixer.
4
5
6 ## Description ##
7
8 This class is intended to operate as a mixer, taking two inputs and
9 yielding one output.
10
11 The first input is a reference input, such as a single image or a
12 stretched video of a single image.
13
14 The second input is the video stream to operate on.
15
16 The output is a clone of the RGB data of the second input, but with
17 the alpha channel modified.
18
19 This mixer takes the (first) reference input, such as a static
20 background, and removes it from every frame in the video stream of the
21 second input.
22
23 The alpha channel on the output is based on the euclidian distance of
24 the two input coordinates in 3-d RGB space. If the calculated distance
25 betwen the two inputs for a given pixel is less than a provided
26 (variable) threshold amount, that indicates the pixel in the
27 background (reference) image is the same or similar enough to the
28 operational (second) input that is part of the background to be
29 removed, and the transparency is set to fully transparent via the
30 alpha channel (set to 0).
31
32 If the calcuated distance exceeds the threshold, then that pixel is
33 part of the foreground image to be retained, and the transparency
34 of it is set to be fully opaque (alpha channel for that pixel set
35 to 255).
36
37 ## Basic Algorithm ##
38 The basic comparison algorithm is:
39
40
41 x is reference image
42 y is comparison image to remove reference image from
43
44
45 ```
46 float euclidDistance (int x_r, int x_g, int x_b, int y_r, int y_g, int y_b)
47 {
48 //calculating color channel differences for next steps
49 float red_d = x_r - y_r;
50 float green_d = x_g - y_g;
51 float blue_d = x_b - y_b;
52
53 float sq_sum, dist;
54
55 //calculating Euclidean distance
56 sq_sum = pow(red_d, 2) + pow(green_d, 2) + pow (blue_d)
57 dist = sqrt(sq_sum);
58
59 return dist;
60 }
61 ```
62
63 ## Note ##
64
65 Here's a handy reminder on how the bits map up.
66
67 ```
68 red_src1 = src1[0];
69 green_src1 = src1[1];
70 blue_src1 = src1[2];
71 alpha_src1 = src1[3]
72
73 red_src2 = src2[0];
74 green_src2 = src2[1];
75 blue_src2 = src2[2];
76 alpha_src2 = src2[3]
77 ```
78 ## Further Work ##
79
80 Some potential improvements are:
81
82 - Faster performance (math calculations, others)
83 - Options beyond binary for alpha
84
85
86
87
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
22 #include "frei0r_colorspace.h"
21 #include "frei0r/math.h"
22 #include "frei0r/colorspace.h"
2323
2424 #define NBYTES 4
2525
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
22 #include "frei0r_colorspace.h"
21 #include "frei0r/math.h"
22 #include "frei0r/colorspace.h"
2323
2424 #define NBYTES 4
2525
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
21 #include "frei0r/math.h"
2222
2323 #define NBYTES 4
2424 #define ALPHA 3
1818 */
1919
2020 #include "frei0r.hpp"
21 #include "frei0r_math.h"
22 #include "frei0r_colorspace.h"
21 #include "frei0r/math.h"
22 #include "frei0r/colorspace.h"
2323
2424 #define NBYTES 4
2525