Nokia Imaging SDK – Reading Photoshop ACV file format

As mentioned in a previous post we recently switched our in-house made photo effect framework to the Nokia Imaging SDK.

The Nokia SDK has a curve filter, that works in the same way as the ones in professional photo editors, like Gimp or Photoshop.

This blog post describes how to use a Photoshop acv file as input to the filter.

You specify a few points of the curve and the filter does a cubic spline interpolation to obtain the final adjustment curve.

To obtain the curve points we implemented an importer, that can read photoshops ACV files. These files can be exported from the photoshop curve adjustment filter, as shown:

 

Untitled

 

So without further ado, here is the code!

The following class is the return type of the ACV file reader, it contains the spline points for the curves of the color channels red, green, blue and RGB.

The RGB property is for all 3 channels and is not applicable for the Nokia SDK curves.

 

/// <summary>
/// Stores the spline points for each color channel curve.
/// </summary>
public class CurveSplinePoints
{
	public List<Point> R { get; set; }
	public List<Point> G { get; set; }
	public List<Point> B { get; set; }
	public List<Point> Rgb { get; set; }
}

The following method reads the actual ACV file.

Pass in a stream and get those curve spline points returned.

/// <summary>
/// Reads the curve spline points from an ACV file.
/// </summary>
/// <param name="acvFileStream"></param>
/// <returns></returns>
public static CurveSplinePoints ReadAcvCurveFile(Stream acvFileStream)
{
    acvFileStream.Seek(0, SeekOrigin.Begin);

    var curves = new List<Point>[5];

    using (var reader = new BinaryReader(acvFileStream))
    {
        int version = reader.ReadInt16();

        int curveCount = ReadSwapped(reader);

        for (int i = 0; i < curveCount; i++)
        {
            int numPoints = ReadSwapped(reader);

            curves[i] = new List<Point>();

            for (int j = 0; j < numPoints; j++)
            {
                int x = ReadSwapped(reader);
                int y = ReadSwapped(reader);

                curves[i].Add(new Point(y, x));
            }
        }
    }

    return new CurveSplinePoints
    {
        Rgb = curves[0],
        R = curves[1],
        G = curves[2],
        B = curves[3],
    };
}

// read a Int16 and swap the bytes.
static int ReadSwapped(BinaryReader br)
{
    int x = br.ReadInt16();
    return ((x >> 8) & 0xFF) | (x & 0xFF) << 8;
}

And last but not least, the code to obtain the Nokia SDK curve from the imported spline points.

The following example creates a curve for the red color channel, this needs to be done for all 3 channels:

var curve = ReadAcvCurveFile(stream);

var nokiaCurveRed = new Nokia.Graphics.Imaging.Curve(CurveInterpolation.NaturalCubicSpline);

for (int i = 0; i < curve.R.Count; i++)
{
    var p = curve.R[i];
    nokiaCurveRed.SetPoint(new Point(p.X, p.Y));
}