1 #[cfg(all(test, feature = "c_bindings"))]
5 c_bindings::*, iccread::*, transform::DataType::*, transform::*,
6 transform_util::lut_inverse_interp16, Intent::Perceptual,
9 #[cfg(target_arch = "arm")]
10 use std::arch::is_arm_feature_detected;
11 #[cfg(target_arch = "aarch64")]
12 use std::arch::is_aarch64_feature_detected;
13 use std::ptr::null_mut;
15 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
16 use crate::transform_neon::{
17 qcms_transform_data_bgra_out_lut_neon, qcms_transform_data_rgb_out_lut_neon,
18 qcms_transform_data_rgba_out_lut_neon,
21 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
24 qcms_transform_data_bgra_out_lut_avx, qcms_transform_data_rgb_out_lut_avx,
25 qcms_transform_data_rgba_out_lut_avx,
28 qcms_transform_data_bgra_out_lut_sse2, qcms_transform_data_rgb_out_lut_sse2,
29 qcms_transform_data_rgba_out_lut_sse2,
34 fn test_lut_inverse_crash() {
35 let lutTable1: [u16; 128] = [
36 0x0000, 0x0000, 0x0000, 0x8000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
37 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
38 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
39 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
40 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
41 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
42 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
43 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
44 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
45 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
46 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
47 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
49 let lutTable2: [u16; 128] = [
50 0xFFF0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
51 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
52 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
53 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
54 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
55 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
56 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
57 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
58 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
59 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
60 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
61 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
66 lut_inverse_interp16(5, &lutTable1);
67 lut_inverse_interp16(5, &lutTable2);
71 fn test_lut_inverse() {
72 // mimic sRGB_v4_ICC mBA Output
79 let mut lutTable: [u16; 256] = [0; 256];
86 lutTable[i] = ((i - 20) * 0xFFFF / (200 - 20)) as u16;
89 for i in 200..lutTable.len() {
94 lut_inverse_interp16(i, &lutTable);
97 // Lookup the interesting points
99 value = lut_inverse_interp16(0, &lutTable);
100 assert!(value <= 20 * 256);
102 value = lut_inverse_interp16(1, &lutTable);
103 assert!(value > 20 * 256);
105 value = lut_inverse_interp16(65535, &lutTable);
106 assert!(value < 201 * 256);
109 // this test takes to long to run on miri
112 fn test_lut_inverse_non_monotonic() {
113 // Make sure we behave sanely for non monotic functions
117 let mut lutTable: [u16; 256] = [0; 256];
120 lutTable[i] = ((i - 0) * 0xFFFF / (100 - 0)) as u16;
124 lutTable[i] = ((i - 100) * 0xFFFF / (200 - 100)) as u16;
128 lutTable[i] = ((i - 200) * 0xFFFF / (256 - 200)) as u16;
132 lut_inverse_interp16(i, &lutTable);
135 // Make sure we don't crash, hang or let sanitizers do their magic
137 /* qcms_data_create_rgb_with_gamma is broken
139 fn profile_from_gamma() {
141 let white_point = qcms_CIE_xyY { x: 0.64, y: 0.33, Y: 1.};
142 let primaries = qcms_CIE_xyYTRIPLE {
143 red: qcms_CIE_xyY { x: 0.64, y: 0.33, Y: 1.},
144 green: qcms_CIE_xyY { x: 0.21, y: 0.71, Y: 1.},
145 blue: qcms_CIE_xyY { x: 0.15, y: 0.06, Y: 1.}
147 let mut mem: *mut libc::c_void = std::ptr::null_mut();
148 let mut size: size_t = 0;
149 unsafe { qcms_data_create_rgb_with_gamma(white_point, primaries, 2.2, &mut mem, &mut size); }
156 assert_eq!(std::mem::align_of::<qcms_transform>(), 16);
161 let sRGB_profile = crate::c_bindings::qcms_profile_sRGB();
163 let Rec709Primaries = qcms_CIE_xyYTRIPLE {
169 green: qcms_CIE_xyY {
180 let D65 = qcms_white_point_sRGB();
181 let other = unsafe { qcms_profile_create_rgb_with_gamma(D65, Rec709Primaries, 2.2) };
182 unsafe { qcms_profile_precache_output_transform(&mut *other) };
184 let transform = unsafe {
185 qcms_transform_create(&mut *sRGB_profile, RGB8, &mut *other, RGB8, Perceptual)
187 let mut data: [u8; 120] = [0; 120];
192 data.as_ptr() as *const libc::c_void,
193 data.as_mut_ptr() as *mut libc::c_void,
199 qcms_transform_release(transform);
200 qcms_profile_release(sRGB_profile);
201 qcms_profile_release(other);
207 let sRGB_profile = qcms_profile_sRGB();
208 let other = unsafe { qcms_profile_create_gray_with_gamma(2.2) };
209 unsafe { qcms_profile_precache_output_transform(&mut *other) };
211 let transform = unsafe {
212 qcms_transform_create(&mut *other, GrayA8, &mut *sRGB_profile, RGBA8, Perceptual)
214 assert!(!transform.is_null());
216 let in_data: [u8; 4] = [0, 255, 255, 0];
217 let mut out_data: [u8; 2 * 4] = [0; 8];
221 in_data.as_ptr() as *const libc::c_void,
222 out_data.as_mut_ptr() as *mut libc::c_void,
227 assert_eq!(out_data, [0, 0, 0, 255, 255, 255, 255, 0]);
229 qcms_transform_release(transform);
230 qcms_profile_release(sRGB_profile);
231 qcms_profile_release(other);
239 let mut d = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
244 "0220-ca351238d719fd07ef8607d326b398fe.icc",
245 "0372-973178997787ee780b4b58ee47cad683.icc",
246 "0744-0a5faafe175e682b10c590b03d3f093b.icc",
247 "0316-eb3f97ab646cd7b66bee80bdfe6098ac.icc",
248 "0732-80707d91aea0f8e64ef0286cc7720e99.icc",
249 "1809-2bd4b77651214ca6110fdbee2502671e.icc",
251 for s in samples.iter() {
252 let mut p = d.clone();
254 let mut file = std::fs::File::open(p.clone()).unwrap();
255 let mut data = Vec::new();
256 file.read_to_end(&mut data).unwrap();
258 unsafe { qcms_profile_from_memory(data.as_ptr() as *const c_void, data.len()) };
259 assert_ne!(profile, std::ptr::null_mut());
260 unsafe { qcms_profile_release(profile) };
269 let mut p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
272 // this profile was made by taking the lookup table profile from
273 // http://displaycal.net/icc-color-management-test/ and removing
274 // the unneeed tables using lcms
275 p.push("displaycal-lut-stripped.icc");
277 let mut file = std::fs::File::open(p).unwrap();
278 let mut data = Vec::new();
279 file.read_to_end(&mut data).unwrap();
281 unsafe { qcms_profile_from_memory(data.as_ptr() as *const c_void, data.len()) };
282 assert_ne!(profile, std::ptr::null_mut());
284 let srgb_profile = qcms_profile_sRGB();
285 assert_ne!(srgb_profile, std::ptr::null_mut());
287 unsafe { qcms_profile_precache_output_transform(&mut *srgb_profile) };
289 let intent = unsafe { qcms_profile_get_rendering_intent(&*profile) };
291 unsafe { qcms_transform_create(&*profile, RGB8, &*srgb_profile, RGB8, intent) };
293 assert_ne!(transform, std::ptr::null_mut());
295 const SRC_SIZE: usize = 4;
296 let src: [u8; SRC_SIZE * 3] = [
297 246, 246, 246, // gray
300 255, 255, 0, // yellow
302 let mut dst: [u8; SRC_SIZE * 3] = [0; SRC_SIZE * 3];
304 // the reference values here should be adjusted if the accuracy
305 // of the transformation changes
307 246, 246, 246, // gray
316 src.as_ptr() as *const libc::c_void,
317 dst.as_mut_ptr() as *mut libc::c_void,
322 assert_eq!(reference, dst);
323 unsafe { qcms_transform_release(transform) }
324 unsafe { qcms_profile_release(profile) }
325 unsafe { qcms_profile_release(srgb_profile) }
328 fn CmpRgbChannel(reference: &[u8], test: &[u8], index: usize) -> bool {
329 (reference[index] as i32 - test[index] as i32).abs() <= 1
339 let pixelSize = if hasAlpha { 4 } else { 3 };
340 if refBuffer[..pixels * pixelSize] == testBuffer[..pixels * pixelSize] {
344 let kRIndex = if kSwapRB { 2 } else { 0 };
346 let kBIndex = if kSwapRB { 0 } else { 2 };
349 let mut remaining = pixels;
350 let mut reference = &refBuffer[..];
351 let mut test = &testBuffer[..];
352 while remaining > 0 {
353 if !CmpRgbChannel(reference, test, kRIndex)
354 || !CmpRgbChannel(reference, test, kGIndex)
355 || !CmpRgbChannel(reference, test, kBIndex)
356 || (hasAlpha && reference[kAIndex] != test[kAIndex])
358 assert_eq!(test[kRIndex], reference[kRIndex]);
359 assert_eq!(test[kGIndex], reference[kGIndex]);
360 assert_eq!(test[kBIndex], reference[kBIndex]);
362 assert_eq!(test[kAIndex], reference[kAIndex]);
367 reference = &reference[pixelSize..];
368 test = &test[pixelSize..];
374 fn GetRgbInputBufferImpl(kSwapRB: bool, kHasAlpha: bool) -> (usize, Vec<u8>) {
375 let colorSamples = [0, 5, 16, 43, 101, 127, 182, 255];
376 let colorSampleMax = colorSamples.len();
377 let pixelSize = if kHasAlpha { 4 } else { 3 };
378 let pixelCount = colorSampleMax * colorSampleMax * 256 * 3;
380 let mut outBuffer = vec![0; pixelCount * pixelSize];
382 let kRIndex = if kSwapRB { 2 } else { 0 };
384 let kBIndex = if kSwapRB { 0 } else { 2 };
387 // Sample every red pixel value with a subset of green and blue.
388 // we use a u16 for r to avoid https://github.com/rust-lang/rust/issues/78283
389 let mut color: &mut [u8] = &mut outBuffer[..];
390 for r in 0..=255u16 {
391 for &g in colorSamples.iter() {
392 for &b in colorSamples.iter() {
393 color[kRIndex] = r as u8;
397 color[kAIndex] = 0x80;
399 color = &mut color[pixelSize..];
404 // Sample every green pixel value with a subset of red and blue.
405 let mut color = &mut outBuffer[..];
406 for &r in colorSamples.iter() {
407 for g in 0..=255u16 {
408 for &b in colorSamples.iter() {
410 color[kGIndex] = g as u8;
413 color[kAIndex] = 0x80;
415 color = &mut color[pixelSize..];
420 // Sample every blue pixel value with a subset of red and green.
421 let mut color = &mut outBuffer[..];
422 for &r in colorSamples.iter() {
423 for &g in colorSamples.iter() {
424 for b in 0..=255u16 {
427 color[kBIndex] = b as u8;
429 color[kAIndex] = 0x80;
431 color = &mut color[pixelSize..];
436 (pixelCount, outBuffer)
439 fn GetRgbInputBuffer() -> (usize, Vec<u8>) {
440 GetRgbInputBufferImpl(false, false)
443 fn GetRgbaInputBuffer() -> (usize, Vec<u8>) {
444 GetRgbInputBufferImpl(false, true)
447 fn GetBgraInputBuffer() -> (usize, Vec<u8>) {
448 GetRgbInputBufferImpl(true, true)
451 fn CmpRgbBuffer(refBuffer: &[u8], testBuffer: &[u8], pixels: usize) -> bool {
452 CmpRgbBufferImpl(refBuffer, testBuffer, pixels, false, false)
455 fn CmpRgbaBuffer(refBuffer: &[u8], testBuffer: &[u8], pixels: usize) -> bool {
456 CmpRgbBufferImpl(refBuffer, testBuffer, pixels, false, true)
459 fn CmpBgraBuffer(refBuffer: &[u8], testBuffer: &[u8], pixels: usize) -> bool {
460 CmpRgbBufferImpl(refBuffer, testBuffer, pixels, true, true)
463 fn ClearRgbBuffer(buffer: &mut [u8], pixels: usize) {
464 for i in 0..pixels * 3 {
469 fn ClearRgbaBuffer(buffer: &mut [u8], pixels: usize) {
470 for i in 0..pixels * 4 {
475 fn GetRgbOutputBuffer(pixels: usize) -> Vec<u8> {
479 fn GetRgbaOutputBuffer(pixels: usize) -> Vec<u8> {
483 struct QcmsProfileTest {
484 in_profile: *mut Profile,
485 out_profile: *mut Profile,
486 transform: *mut qcms_transform,
493 storage_type: DataType,
497 impl QcmsProfileTest {
498 fn new() -> QcmsProfileTest {
500 in_profile: null_mut(),
501 out_profile: null_mut(),
502 transform: null_mut(),
505 reference: Vec::new(),
513 fn SetUp(&mut self) {
517 unsafe fn TearDown(&mut self) {
518 if self.in_profile != null_mut() {
519 qcms_profile_release(self.in_profile)
522 if self.out_profile != null_mut() {
523 qcms_profile_release(self.out_profile)
526 if self.transform != null_mut() {
527 qcms_transform_release(self.transform)
531 unsafe fn SetTransform(&mut self, transform: *mut qcms_transform) -> bool {
532 if self.transform != null_mut() {
533 qcms_transform_release(self.transform)
535 self.transform = transform;
536 self.transform != null_mut()
539 unsafe fn SetTransformForType(&mut self, ty: DataType) -> bool {
540 self.SetTransform(qcms_transform_create(
549 unsafe fn SetBuffers(&mut self, ty: DataType) -> bool {
552 let (pixels, input) = GetRgbInputBuffer();
554 self.pixels = pixels;
555 self.reference = GetRgbOutputBuffer(self.pixels);
556 self.output = GetRgbOutputBuffer(self.pixels)
559 let (pixels, input) = GetBgraInputBuffer();
561 self.pixels = pixels;
562 self.reference = GetRgbaOutputBuffer(self.pixels);
563 self.output = GetRgbaOutputBuffer(self.pixels);
566 let (pixels, input) = GetRgbaInputBuffer();
568 self.pixels = pixels;
569 self.reference = GetRgbaOutputBuffer(self.pixels);
570 self.output = GetRgbaOutputBuffer(self.pixels);
572 _ => unreachable!("Unknown type!"),
574 self.storage_type = ty;
578 unsafe fn ClearOutputBuffer(&mut self) {
579 match self.storage_type {
580 RGB8 => ClearRgbBuffer(&mut self.output, self.pixels),
581 RGBA8 | BGRA8 => ClearRgbaBuffer(&mut self.output, self.pixels),
582 _ => unreachable!("Unknown type!"),
586 unsafe fn ProduceRef(&mut self, trans_fn: transform_fn_t) {
589 self.input.as_mut_ptr(),
590 self.reference.as_mut_ptr(),
595 fn CopyInputToRef(&mut self) {
596 let pixelSize = match self.storage_type {
599 _ => unreachable!("Unknown type!"),
602 .copy_from_slice(&self.input[..self.pixels * pixelSize])
605 unsafe fn ProduceOutput(&mut self, trans_fn: transform_fn_t) {
606 self.ClearOutputBuffer();
609 self.input.as_mut_ptr(),
610 self.output.as_mut_ptr(),
615 unsafe fn VerifyOutput(&self, buf: &[u8]) -> bool {
616 match self.storage_type {
617 RGB8 => CmpRgbBuffer(buf, &self.output, self.pixels),
618 RGBA8 => CmpRgbaBuffer(buf, &self.output, self.pixels),
619 BGRA8 => CmpBgraBuffer(buf, &self.output, self.pixels),
620 _ => unreachable!("Unknown type!"),
624 unsafe fn ProduceVerifyOutput(&mut self, trans_fn: transform_fn_t) -> bool {
625 self.ProduceOutput(trans_fn);
626 self.VerifyOutput(&self.reference)
629 unsafe fn PrecacheOutput(&mut self) {
630 qcms_profile_precache_output_transform(&mut *self.out_profile);
631 self.precache = true;
633 unsafe fn TransformPrecache(&mut self) {
634 assert_eq!(self.precache, false);
635 assert!(self.SetBuffers(RGB8));
636 assert!(self.SetTransformForType(RGB8));
637 self.ProduceRef(Some(qcms_transform_data_rgb_out_lut));
639 self.PrecacheOutput();
640 assert!(self.SetTransformForType(RGB8));
641 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgb_out_lut_precache)))
644 unsafe fn TransformPrecachePlatformExt(&mut self) {
645 self.PrecacheOutput();
647 // Verify RGB transforms.
648 assert!(self.SetBuffers(RGB8));
649 assert!(self.SetTransformForType(RGB8));
650 self.ProduceRef(Some(qcms_transform_data_rgb_out_lut_precache));
652 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
654 if is_x86_feature_detected!("sse2") {
655 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgb_out_lut_sse2)));
657 if is_x86_feature_detected!("avx") {
658 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgb_out_lut_avx)))
662 #[cfg(target_arch = "arm")]
664 if is_arm_feature_detected!("neon") {
665 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgb_out_lut_neon)))
669 #[cfg(target_arch = "aarch64")]
671 if is_aarch64_feature_detected!("neon") {
672 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgb_out_lut_neon)))
676 // Verify RGBA transform.
677 assert!(self.SetBuffers(RGBA8));
678 assert!(self.SetTransformForType(RGBA8));
679 self.ProduceRef(Some(qcms_transform_data_rgba_out_lut_precache));
681 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
683 if is_x86_feature_detected!("sse2") {
684 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgba_out_lut_sse2)));
686 if is_x86_feature_detected!("avx") {
687 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgba_out_lut_avx)))
691 #[cfg(target_arch = "arm")]
693 if is_arm_feature_detected!("neon") {
694 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgba_out_lut_neon)))
698 #[cfg(target_arch = "aarch64")]
700 if is_aarch64_feature_detected!("neon") {
701 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgba_out_lut_neon)))
705 // Verify BGRA transform.
706 assert!(self.SetBuffers(BGRA8));
707 assert!(self.SetTransformForType(BGRA8));
708 self.ProduceRef(Some(qcms_transform_data_bgra_out_lut_precache));
710 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
712 if is_x86_feature_detected!("sse2") {
713 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_bgra_out_lut_sse2)));
715 if is_x86_feature_detected!("avx") {
716 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_bgra_out_lut_avx)))
720 #[cfg(target_arch = "arm")]
722 if is_arm_feature_detected!("neon") {
723 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_bgra_out_lut_neon)))
727 #[cfg(target_arch = "aarch64")]
729 if is_aarch64_feature_detected!("neon") {
730 assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_bgra_out_lut_neon)))
737 fn sRGB_to_sRGB_precache() {
739 let mut pt = QcmsProfileTest::new();
741 pt.in_profile = qcms_profile_sRGB();
742 pt.out_profile = qcms_profile_sRGB();
743 pt.TransformPrecache();
749 fn sRGB_to_sRGB_transform_identity() {
751 let mut pt = QcmsProfileTest::new();
753 pt.in_profile = qcms_profile_sRGB();
754 pt.out_profile = qcms_profile_sRGB();
757 pt.SetTransformForType(RGB8);
760 pt.input.as_mut_ptr() as *mut c_void,
761 pt.output.as_mut_ptr() as *mut c_void,
764 assert!(pt.VerifyOutput(&pt.input));
769 fn profile_from_path(file: &str) -> *mut Profile {
771 let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
772 path.push("profiles");
774 let mut file = std::fs::File::open(path).unwrap();
775 let mut data = Vec::new();
776 file.read_to_end(&mut data).unwrap();
778 unsafe { qcms_profile_from_memory(data.as_ptr() as *const c_void, data.len()) };
779 assert_ne!(profile, std::ptr::null_mut());
784 fn sRGB_to_ThinkpadW540() {
786 let mut pt = QcmsProfileTest::new();
788 pt.in_profile = qcms_profile_sRGB();
789 pt.out_profile = profile_from_path("lcms_thinkpad_w540.icc");
790 pt.TransformPrecachePlatformExt();
796 fn sRGB_to_SamsungSyncmaster() {
798 let mut pt = QcmsProfileTest::new();
800 pt.in_profile = qcms_profile_sRGB();
801 pt.out_profile = profile_from_path("lcms_samsung_syncmaster.icc");
802 pt.TransformPrecachePlatformExt();
810 let input = qcms_profile_sRGB();
811 // B2A0-ident.icc was created from the profile in bug 1679621
812 // manually edited using iccToXML/iccFromXML
813 let output = profile_from_path("B2A0-ident.icc");
815 let transform = unsafe { qcms_transform_create(&*input, RGB8, &*output, RGB8, Perceptual) };
816 let src = [0u8, 60, 195];
817 let mut dst = [0u8, 0, 0];
821 src.as_ptr() as *const libc::c_void,
822 dst.as_mut_ptr() as *mut libc::c_void,
826 assert_eq!(dst, [15, 16, 122]);
828 qcms_transform_release(transform);
829 qcms_profile_release(input);
830 qcms_profile_release(output);
835 fn gray_smoke_test() {
836 let input = crate::Profile::new_gray_with_gamma(2.2);
837 let output = crate::Profile::new_sRGB();
839 transform_create(&input, GrayA8, &output, RGBA8, crate::Intent::default()).unwrap();
840 let src = [20u8, 20u8];
841 let mut dst = [0u8, 0, 0, 0];
845 src.as_ptr() as *const libc::c_void,
846 dst.as_mut_ptr() as *mut libc::c_void,
847 src.len() / GrayA8.bytes_per_pixel(),
853 fn data_create_rgb_with_gamma() {
854 let Rec709Primaries = qcms_CIE_xyYTRIPLE {
877 let D65 = qcms_white_point_sRGB();
878 let mut mem = std::ptr::null_mut();
881 qcms_data_create_rgb_with_gamma(D65, Rec709Primaries, 2.2, &mut mem, &mut size);
884 unsafe { libc::free(mem) };
890 use crate::{Profile, Transform};
893 let p1 = Profile::new_sRGB();
894 let p2 = Profile::new_sRGB();
896 Transform::new(&p1, &p2, crate::DataType::RGB8, crate::Intent::default()).unwrap();
897 let mut data = [4, 30, 80];
898 xfm.apply(&mut data);
899 assert_eq!(data, [4, 30, 80]);
903 let p1 = Profile::new_sRGB();
904 let p2 = Profile::new_XYZD50();
906 Transform::new(&p1, &p2, crate::DataType::RGB8, crate::Intent::default()).unwrap();
907 let mut data = [4, 30, 80];
908 xfm.apply(&mut data);
909 assert_eq!(data, [4, 4, 15]);
912 fn profile_from_path(file: &str) -> Box<Profile> {
914 let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
915 path.push("profiles");
917 let mut file = std::fs::File::open(path).unwrap();
918 let mut data = Vec::new();
919 file.read_to_end(&mut data).unwrap();
920 Profile::new_from_slice(&data, false).unwrap()
924 fn parametric_threshold() {
925 let src = profile_from_path("parametric-thresh.icc");
926 let dst = crate::Profile::new_sRGB();
928 Transform::new(&src, &dst, crate::DataType::RGB8, crate::Intent::default()).unwrap();
929 let mut data = [4, 30, 80];
930 xfm.apply(&mut data);
931 assert_eq!(data, [188, 188, 189]);
936 let input = profile_from_path("ps_cmyk_min.icc");
937 let output = Profile::new_sRGB();
938 let xfm = crate::Transform::new_to(
941 crate::DataType::CMYK,
942 crate::DataType::RGB8,
943 crate::Intent::default(),
946 let src = [4, 30, 80, 10];
947 let mut dst = [0, 0, 0];
948 xfm.convert(&src, &mut dst);
949 assert_eq!(dst, [252, 237, 211]);
953 fn sRGB_parametric() {
954 let src = Profile::new_sRGB();
955 let dst = Profile::new_sRGB_parametric();
957 Transform::new(&src, &dst, crate::DataType::RGB8, crate::Intent::default()).unwrap();
958 let mut data = [4, 30, 80];
959 xfm.apply(&mut data);
960 assert_eq!(data, [4, 30, 80]);