Skip to content

Commit 9a2e3cb

Browse files
committed
ICC Profiles (#16)
Add parsing support for some icc profiles so that the cmyk conversion is better. This also creates some types for handling colors better instead of as vec3's, and also adds a library for handling buffer reading, since that has been duplicated a bunch. The other code will be moved to the color library and buffer library in separate commits.
1 parent 6b53f5d commit 9a2e3cb

44 files changed

Lines changed: 3296 additions & 59 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
/*.bmp
66
/*.svg
77
/test-files/*.pdf
8+
/test-files/*.icc

.zed/debug.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
"program": "$ZED_WORKTREE_ROOT/build/examples/pdf-example",
1010
"request": "launch",
1111
"adapter": "CodeLLDB",
12+
"preRunCommands": [
13+
"type format add -f decimal uint8_t",
14+
"type format add -f decimal 'unsigned char'",
15+
],
1216
"env": { "ASAN_OPTIONS": "detect_leaks=0" },
1317
},
1418
{
@@ -21,6 +25,26 @@
2125
"program": "$ZED_WORKTREE_ROOT/build/examples/font-example",
2226
"request": "launch",
2327
"adapter": "CodeLLDB",
28+
"preRunCommands": [
29+
"type format add -f decimal uint8_t",
30+
"type format add -f decimal 'unsigned char'",
31+
],
32+
"env": { "ASAN_OPTIONS": "detect_leaks=0" },
33+
},
34+
{
35+
"label": "Debug icc-example",
36+
"build": {
37+
"command": "scripts/dev-build.sh",
38+
"args": [],
39+
"cwd": "$ZED_WORKTREE_ROOT",
40+
},
41+
"program": "$ZED_WORKTREE_ROOT/build/examples/icc-example",
42+
"request": "launch",
43+
"adapter": "CodeLLDB",
44+
"preRunCommands": [
45+
"type format add -f decimal uint8_t",
46+
"type format add -f decimal 'unsigned char'",
47+
],
2448
"env": { "ASAN_OPTIONS": "detect_leaks=0" },
2549
},
2650
{
@@ -33,6 +57,10 @@
3357
"program": "$ZED_WORKTREE_ROOT/build/examples/tessellation-example",
3458
"request": "launch",
3559
"adapter": "CodeLLDB",
60+
"preRunCommands": [
61+
"type format add -f decimal uint8_t",
62+
"type format add -f decimal 'unsigned char'",
63+
],
3664
"env": { "ASAN_OPTIONS": "detect_leaks=0" },
3765
},
3866
{
@@ -45,6 +73,10 @@
4573
"program": "$ZED_WORKTREE_ROOT/build/examples/cmap-example",
4674
"request": "launch",
4775
"adapter": "CodeLLDB",
76+
"preRunCommands": [
77+
"type format add -f decimal uint8_t",
78+
"type format add -f decimal 'unsigned char'",
79+
],
4880
"env": { "ASAN_OPTIONS": "detect_leaks=0" },
4981
},
5082
{
@@ -60,6 +92,10 @@
6092
"program": "$ZED_WORKTREE_ROOT/build/libs/test/pdf-test-main",
6193
"request": "launch",
6294
"adapter": "CodeLLDB",
95+
"preRunCommands": [
96+
"type format add -f decimal uint8_t",
97+
"type format add -f decimal 'unsigned char'",
98+
],
6399
"env": { "ASAN_OPTIONS": "detect_leaks=0" },
64100
},
65101
]

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ So far the following have been implemented:
1717
- A minimal postscript interpreter for parsing cmap files and running pdf functions
1818
- This only implements the operators needed for these tasks
1919
- A simple (incomplete) renderer
20+
- A minimal ICC parser
2021
- A SVG canvas
2122

2223
Future expansions:
2324

2425
- Type1 font parser
2526
- Support for patterns and shadings
2627
- Image support
27-
- ICC parser
2828
- Raster canvas backend
2929

3030
# Resources
@@ -40,3 +40,4 @@ Future expansions:
4040
- [Partitioning a Polygon into _y_-monotone Pieces](https://www.youtube.com/watch?v=IkA-2Y9lBvM)
4141
- [DEFLATE Compressed Data Format Specification](https://datatracker.ietf.org/doc/html/rfc1951)
4242
- [ZLIB Compressed Data Format Specification](https://datatracker.ietf.org/doc/html/rfc1950)
43+
- [ICC Specification](https://www.color.org/specification/ICC.1-2022-05.pdf)
8.27 KB
Binary file not shown.
59.5 KB
Binary file not shown.

examples/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ if (NOT MSVC)
1414
target_link_options(cmap-example PRIVATE -fsanitize=address,undefined)
1515
endif()
1616

17+
add_executable(icc-example icc.c)
18+
target_link_libraries(icc-example PRIVATE arena logger color)
19+
target_compile_definitions(icc-example PRIVATE DEBUG TEST)
20+
if (NOT MSVC)
21+
target_compile_options(icc-example PRIVATE -fsanitize=address,undefined)
22+
target_link_options(icc-example PRIVATE -fsanitize=address,undefined)
23+
endif()
24+
1725
add_executable(font-example font.c)
1826
target_link_libraries(font-example PRIVATE err logger sfnt)
1927
target_compile_definitions(font-example PRIVATE DEBUG TEST)

examples/icc.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include "color/icc.h"
2+
3+
#include <stdbool.h>
4+
#include <stdint.h>
5+
6+
#include "arena/arena.h"
7+
#include "arena/common.h"
8+
#include "color/icc_color.h"
9+
#include "err/error.h"
10+
#include "logger/log.h"
11+
#include "parse_ctx/ctx.h"
12+
13+
int main(void) {
14+
Arena* arena = arena_new(128);
15+
16+
size_t swop_buffer_len;
17+
const uint8_t* swop_buffer = load_file_to_buffer(
18+
arena,
19+
"assets/icc-profiles/CGATS001Compat-v2-micro.icc",
20+
&swop_buffer_len
21+
);
22+
23+
size_t srgb_buffer_len;
24+
const uint8_t* srgb_buffer = load_file_to_buffer(
25+
arena,
26+
"assets/icc-profiles/sRGB_v4_ICC_preference.icc",
27+
&srgb_buffer_len
28+
);
29+
30+
ParseCtx swop_ctx = parse_ctx_new(swop_buffer, swop_buffer_len);
31+
IccProfile swop_profile;
32+
REQUIRE(icc_parse_profile(swop_ctx, arena, &swop_profile));
33+
34+
ParseCtx srgb_ctx = parse_ctx_new(srgb_buffer, srgb_buffer_len);
35+
IccProfile srgb_profile;
36+
REQUIRE(icc_parse_profile(srgb_ctx, arena, &srgb_profile));
37+
38+
IccColor input = {
39+
.channels = {0.4, 0.5, 0.6, 0.2},
40+
.color_space = ICC_COLOR_SPACE_CMYK
41+
};
42+
43+
LOG_DIAG(
44+
INFO,
45+
EXAMPLE,
46+
"Naive conversion: %f, %f, %f",
47+
(1.0 - input.channels[0]) * (1.0 - input.channels[3]),
48+
(1.0 - input.channels[1]) * (1.0 - input.channels[3]),
49+
(1.0 - input.channels[2]) * (1.0 - input.channels[3])
50+
);
51+
52+
IccRenderingIntent intent = ICC_INTENT_PERCEPTUAL;
53+
54+
IccPcsColor src_pcs, dst_pcs;
55+
REQUIRE(icc_device_to_pcs(swop_profile, intent, input, &src_pcs));
56+
REQUIRE(icc_pcs_to_pcs(
57+
swop_profile,
58+
srgb_profile,
59+
false,
60+
intent,
61+
src_pcs,
62+
&dst_pcs
63+
));
64+
65+
IccColor mapped_color;
66+
REQUIRE(icc_pcs_to_device(&srgb_profile, intent, dst_pcs, &mapped_color));
67+
RELEASE_ASSERT(mapped_color.color_space == ICC_COLOR_SPACE_RGB);
68+
69+
LOG_DIAG(
70+
INFO,
71+
EXAMPLE,
72+
"Output sRGB: r=%f, g=%f, b=%f",
73+
mapped_color.channels[0],
74+
mapped_color.channels[1],
75+
mapped_color.channels[2]
76+
);
77+
78+
arena_free(arena);
79+
return 0;
80+
}

libs/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ add_subdirectory(arena)
22
add_subdirectory(canvas)
33
add_subdirectory(cff)
44
add_subdirectory(codec)
5+
add_subdirectory(color)
56
add_subdirectory(geom)
67
add_subdirectory(logger)
8+
add_subdirectory(parse_ctx)
79
add_subdirectory(pdf)
810
add_subdirectory(err)
911
add_subdirectory(postscript)

libs/color/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
add_library(color
2+
src/cie.c
3+
src/conversion.c
4+
src/icc.c
5+
src/icc_types.c
6+
src/icc_cache.c
7+
src/icc_color.c
8+
src/icc_curve.c
9+
src/icc_lut.c
10+
src/icc_tags.c
11+
src/rgb.c)
12+
target_include_directories(color PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
13+
target_link_libraries(color PUBLIC geom parse-ctx)
14+
target_link_libraries(color PRIVATE pdf-test)
15+
target_compile_features(color PUBLIC c_std_11)
16+
if (NOT MSVC)
17+
target_compile_options(color PRIVATE -fsanitize=address,undefined)
18+
target_link_options(color PRIVATE -fsanitize=address,undefined)
19+
endif()

libs/color/include/color/cie.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#pragma once
2+
3+
#include "geom/vec3.h"
4+
5+
typedef struct {
6+
double x;
7+
double y;
8+
double z;
9+
} CieXYZ;
10+
11+
typedef struct {
12+
double l;
13+
double a;
14+
double b;
15+
} CieLab;
16+
17+
CieXYZ cie_xyz_new(double x, double y, double z);
18+
CieLab cie_lab_new(double l, double a, double b);
19+
20+
CieXYZ cie_xyz_from_geom(GeomVec3 vec);
21+
GeomVec3 cie_xyz_to_geom(CieXYZ cie_xyz);
22+
23+
CieLab cie_lab_from_geom(GeomVec3 vec);
24+
GeomVec3 cie_lab_to_geom(CieLab cie_lab);
25+
26+
CieLab cie_xyz_to_cie_lab(CieXYZ cie_xyz, CieXYZ reference_illuminant);
27+
CieXYZ cie_lab_to_cie_xyz(CieLab cie_lab, CieXYZ reference_illuminant);

0 commit comments

Comments
 (0)