+ if (fabs(white_balance.r - 1.0f) > 1e-3 ||
+ fabs(white_balance.g - 1.0f) > 1e-3 ||
+ fabs(white_balance.b - 1.0f) > 1e-3) {
+ // Convert from (linear) RGB to XYZ.
+ Matrix3d rgb_to_xyz_matrix = movit::ColorspaceConversionEffect::get_xyz_matrix(COLORSPACE_sRGB);
+ Vector3d xyz = rgb_to_xyz_matrix * Vector3d(white_balance.r, white_balance.g, white_balance.b);
+
+ // Convert from XYZ to xyz by normalizing.
+ xyz /= (xyz[0] + xyz[1] + xyz[2]);
+
+ // Create a very rudimentary EXIF header to hold our white point.
+ string exif;
+
+ // Exif header, followed by some padding.
+ exif = "Exif";
+ push16(0, &exif);
+
+ // TIFF header first:
+ exif += "MM"; // Big endian.
+
+ // Magic number.
+ push16(42, &exif);
+
+ // Offset of first IFD (relative to the MM, immediately after the header).
+ push32(exif.size() - 6 + 4, &exif);
+
+ // Now the actual IFD.
+
+ // One entry.
+ push16(1, &exif);
+
+ // WhitePoint tag ID.
+ push16(0x13e, &exif);
+
+ // Rational type.
+ push16(5, &exif);
+
+ // Two values (x and y; z is implicit due to normalization).
+ push32(2, &exif);
+
+ // Offset (relative to the MM, immediately after the last IFD).
+ push32(exif.size() - 6 + 8, &exif);
+
+ // No more IFDs.
+ push32(0, &exif);
+
+ // The actual values.
+ push32(lrintf(xyz[0] * 10000.0f), &exif);
+ push32(10000, &exif);
+ push32(lrintf(xyz[1] * 10000.0f), &exif);
+ push32(10000, &exif);
+
+ jpeg_write_marker(cinfo, JPEG_APP0 + 1, (const JOCTET *)exif.data(), exif.size());
+ }
+