Perfectly Clear SDK Documentation  9.5.1.429
Examples (Windows)

Sample code for both C and C# projects are provided along with the SDK. The examples below demonstrate the general usage of the Perfectly Clear SDK.

Scenario #1 PCF_AutoCorrect

This is the simplest way to use Perfectly Clear library suite. This protocol is more suitable for developing a server type software project or in scenarios where every image will be corrected with one set of parameters (no user-facing option to adjust correction parameters).

  1. Setup the license protection:
    // if you have a license key, then call PFC_SetProtectionPath with the path
    // to your license files
    int code = PFC_SetProtectionPath("C:\\Protection\\sdk");
    if (bVerbose)
    printf("License Code Status is %d\n", code);
  2. Initialize parameters:
    PFCPARAM param;
    // Initialize PFCPARAM structure with user select preset.
    PFC_SetParam(param, presetID);
  3. Populate image data into PFCIMAGE structure:
    // Populate image information into PFCIMAGE structure.
    im.width = width; // Width of image.
    im.height = height; // Height of image.
    im.stride = pbd->Stride; // Stride of image.
    im.format = ((pbd->PixelFormat == PixelFormat24bppRGB) ? PFC_PixelFormat24bppRGB : PFC_PixelFormat32bppARGB);
    im.data = (unsigned char*)pbd->Scan0; // Location of image data.
  4. Perform full correction using the auto function:
    // Process image with Auto Correct function.
    int status = PFC_AutoCorrectPreset(&im, NULL, presetID);
    // Optionally you can check return status of the correction.
    if (bVerbose)
    {
    if (status == 0)
    {
    printf("Image processed successfully\n");
    }
    else if (status > 0)
    {
    printf(" Pre-calculation on noise returns %d\n", NRRETCODE(status));
    printf(" Core pre-calculation returns %d\n", CORERETCODE(status));
    printf(" Pre-calculation on face details returns %d\n",FBRETCODE(status));
    printf(" Pre-calculation on red eye returns %d\n", RERETCODE(status));
    }
    else if (status < 0)
    {
    printf("Image processed failed with return code: %d\n", status);
    }
    }

Scenario #2 Separate Calc and Apply

More advanced way to use Perfectly Clear library suite. This protocol is more suitable for developing a desktop photo editing type software where user parameters will vary under the same session of an image.

  1. Setup the license protection:
    // if you have a license key, then call PFC_SetProtectionPath with the path
    // to your license files
    int code = PFC_SetProtectionPath("C:\\Protection\\sdk");
    if (bVerbose)
    printf("License Code Status is %d\n", code);
  2. Create process engine:
    // Create PFCENGINE instance for use in this session.
    if (bVerbose)
    {
    // Optionally, check status of the created engine instance.
    if (pEngine->status == ENGINESTATUS_OK)
    {
    printf("Engine created successfully.\n");
    }
    else
    {
    {
    printf("Face Beautification library not available.");
    }
    }
    }
  3. Initialize the parameter structure (using default parameter values): The parameters can be imported from a preset file.
    // Optionally, the process parameters can be imported from a .preset file.
    // (The .preset file can be exported from Athentech's desktop applications. e.g. Workbench.)
    std::string profilenameUtf8 = utf8FromW(std::wstring(profilename));
    int ret = PFC_ReadPresets(param, (char*)profilenameUtf8.c_str());
    if (bVerbose)
    printf("PFC_ReadPresets returns %d\n", ret);
    Alternatively the parameters can be initialized using PFC_SetParam() function.
    // Use default parameters.
    PFC_SetParam(param);
    Example:
    // Set process parameters.
    PFCPARAM param;
    if (profilename != NULL)
    {
    // Optionally, the process parameters can be imported from a .preset file.
    // (The .preset file can be exported from Athentech's desktop applications. e.g. Workbench.)
    std::string profilenameUtf8 = utf8FromW(std::wstring(profilename));
    int ret = PFC_ReadPresets(param, (char*)profilenameUtf8.c_str());
    if (bVerbose)
    printf("PFC_ReadPresets returns %d\n", ret);
    if (ret != 0)
    {
    if (ret == -2) // preset file not found
    {
    // Use default parameters if preset file not found.
    PFC_SetParam(param);
    printf("Unable to open preset file %s. Using default settings.\n", profilename);
    }
    else if (ret == -8)
    {
    printf("Invalid preset file.\n");
    exit(0);
    }
    else
    {
    printf("Unable to read preset file.\n");
    exit(0);
    }
    }
    }
    else
    {
    // Use default parameters.
    PFC_SetParam(param);
    }
  4. Populate image data into PFCIMAGE structure:
    // Populate image information into PFCIMAGE structure.
    im.width = width; // Width of image.
    im.height = height; // Height of image.
    im.stride = pbd->Stride; // Stride of image.
    im.format = ((pbd->PixelFormat == PixelFormat24bppRGB) ? PFC_PixelFormat24bppRGB : PFC_PixelFormat32bppARGB);
    im.data = (unsigned char*)pbd->Scan0; // Location of image data.
  5. Perform pre-calculation of image specific profile:
    // Analyze image and obtain image specific profile.
    PFCPROFILE pProfile = PFC_Calc(&im, NULL, pEngine, CALC_ALL, -1, NULL, NULL, bVerbose ? myStatus : NULL);
    // Optinally, check precalc status.
    if (bVerbose)
    {
    if (pProfile->Status != 0)
    {
    if (pProfile->Status & CALC_NR)
    {
    printf(" Pre-calculation on noise returns %d\n", pProfile->NR_Status);
    }
    if (pProfile->Status & CALC_CORE)
    {
    printf(" Core pre-calculation returns %d\n", pProfile->CORE_Status);
    }
    if (pProfile->Status & CALC_FB)
    {
    printf(" Pre-calculation on face details returns %d\n", pProfile->FB_Status);
    }
    if (pProfile->Status & CALC_RE)
    {
    printf(" Pre-calculation on red eye returns %d\n", pProfile->RE_Status);
    }
    }
    printf("Calc returns %d\n", pProfile->Status);
    }
    (pEngine is created from step 1.)
  6. Apply the calculated profile and parameters to the image.
    // Process image with parameters.
    PFCAPPLYSTATUS status = PFC_Apply(&im, pEngine, pProfile, param, bVerbose ? myStatus : NULL);
    // Optionally, check process status.
    if (bVerbose)
    {
    if (status == APPLY_SUCCESS)
    {
    printf("Image processed successfully.\n");
    }
    else if (status > APPLY_SUCCESS)
    {
    int code;
    // Check return code for Noise Removal
    code = NRRETCODE(status);
    printf("Noise removal status %d\n", code);
    // Check return code for Perfectly Clear Core correction
    code = CORERETCODE(status);
    printf("Perfectly Clear correction status %d\n", code);
    // Check return code for Face Beautification
    code = FBRETCODE(status);
    printf("Face beautification status %d\n", code);
    // Check return code for Red Eye Removal
    code = RERETCODE(status);
    printf("Red eye removal status %d\n", code);
    }
    else
    {
    printf("Image processing failed with return code: %d\n", status);
    }
    }
  7. Release resources used by PFCPROFILE:
    // Release Profile
    PFC_ReleaseProfile(pProfile);
  8. Release the engine to release resource:
    // Destroy engine. It is important that PFCENGINE is destroyed after
    // all the profiles are released.

Scenario #3 .NET Core Samples

We have included two samples that run in .NET Core v3.1. These are essentially the same applications as Sample 2 shown above. In DotNetCore_Sample2 - we use standard windows bitmaps to load and save the image data, greatly simplified here:

Bitmap bm = new Bitmap(inname);
Pfc.Calc(ref bm, PerfectlyClearAdapter.PFCFEATURE.CALC_ALL, -1, null);
Pfc.Apply(ref bm, 100);
bm.Save(outname);

In DotNetCore_Sample3, we use the PfCImageFile class instead, shown in a simplified form here:

file.LoadImage(inname);
Pfc.Calc(ref file, PerfectlyClearAdapter.PFCFEATURE.CALC_ALL, -1, null);
Pfc.Apply(ref file, 100);
file.SaveImageFile(outname,90, false, false);

If you are incorporating Perfectly Clear into an application that already is using BitMaps, then Sample2 will make it easy to incorporate Perfectly Clear into it.

Sample 3's use of the PfCImageFile class will handle color space conversion and metadata management automatically

Scenario #4 Using MemoryStreams

In SDK v8.5, we have introduced the ability to read and write image data using .NET native MemoryStreams. If the application you are working on already has image file data loaded into MemoryStreams, this method allows you to use those directly, instead of needing to write image files to disk.

// create a PFCImageFile called 'file' we will load into below
// Read input file to a MemoryStream and check if image opened successfully
// Typically, the MemoryStream would already exist in the application you are developing
MemoryStream inMemoryCopy = new MemoryStream();
using (FileStream fs = File.OpenRead(inname))
{
fs.CopyTo(inMemoryCopy);
}
// remember to set the right position to begin reading
inMemoryCopy.Position = 0;
// Call ExpandImageBuffer to read the MemoryStream and load into the 'file' PFCImageFile
if (file.ExpandImageBuffer(inMemoryCopy, PFCImageFile.PFC_FILETYPE.PFC_JPEG, true, "") != PFCImageFile.PFC_FILE_LOAD_STATUS.LOAD_OK)
{
Console.WriteLine("Unable to open image.");
ShowHelp();
return;
}

Now, you can process the PFCImageFile like in the other samples, the most simple way would be:

Pfc.AutoCorrect(ref file, "my_preset.preset");

Now, the 'file' object has been corrected, so to get the corrected image data back into a MemoryStream:

// Read from the corrected 'file' PFCImageFile and write contents to a MemoryStream
// Perform JPEG compression, color management, and embed EXIF metadata from the original file
using (MemoryStream outStream = file.CompressImageBuffer(PFCImageFile.PFC_FILETYPE.PFC_JPEG, 90, false, true))
{
// seek to the beginning, then write to a file, or pass along to further operations
// within your application
outStream.Seek(0, SeekOrigin.Begin);
FileStream outFile = File.Create(outname);
outStream.CopyTo(outFile);
}

.NET Core Version Issues

In the .NET Core examples, there are PreBuildEvent steps to copy the required libraries into the proper build location. For example:

<PropertyGroup>
<PreBuildEvent>
xcopy /C /E /Y /R ..\..\..\..\..\bin\x64\PerfectlyClearPro.dll .\PerfectlyClearPro.dll*
xcopy /C /E /Y /R ..\..\..\..\..\bin\x64\PerfectlyClearAdapter.dll .
xcopy /C /E /Y /R ..\..\..\..\..\bin\x64\PFCImageFile.dll .
xcopy /C /E /Y /R ..\..\..\..\..\bin\x64\exiv2.dll .
</PreBuildEvent>
</PropertyGroup>

Depending on which version of Visual Studio and .NET Core version you are using, these steps might cause errors when you build. This is due to an extra folder level that Visual Studio builds in some cases. The solution is to remove one set of "..\" from these steps, like this:

<PropertyGroup>
<PreBuildEvent>
xcopy /C /E /Y /R ..\..\..\..\bin\x64\PerfectlyClearPro.dll .\PerfectlyClearPro.dll*
xcopy /C /E /Y /R ..\..\..\..\bin\x64\PerfectlyClearAdapter.dll .
xcopy /C /E /Y /R ..\..\..\..\bin\x64\PFCImageFile.dll .
xcopy /C /E /Y /R ..\..\..\..\bin\x64\exiv2.dll .
</PreBuildEvent>
</PropertyGroup>
ENGINESTATUS_FB_LIBRARY_LOAD_FAIL
@ ENGINESTATUS_FB_LIBRARY_LOAD_FAIL
If set, the library is unable to load the SFB library.
Definition: PerfectlyClearPro.h:153
CALC_FB
@ CALC_FB
Calculates for Face Beautification.
Definition: PerfectlyClearPro.h:161
PFC_SetProtectionPath
int PFC_SetProtectionPath(const char *utf8FolderPath, const char *liceseCode=NULL)
Set path to location of SDK License files This enables license protection and allows activation using...
APPLY_SUCCESS
@ APPLY_SUCCESS
0 Success.
Definition: PerfectlyClearPro.h:383
PFC_PixelFormat32bppARGB
@ PFC_PixelFormat32bppARGB
Definition: PerfectlyClearPro.h:119
CORERETCODE
#define CORERETCODE(x)
Decode return status of Core correction from master return code.
Definition: PerfectlyClearPro.h:21
PFCPARAM
Struct PFCPARAM the master structure of all processing parameters.
Definition: PerfectlyClearPro.h:572
PFC_AutoCorrectPreset
int PFC_AutoCorrectPreset(PFCIMAGE *pImage, PFCIMAGE *pImageds, PFCPRESETID id=PRESET_IAUTO_21, int iISO=-1, char *pCameraModel=NULL, BOOL bFastFAE=FALSE, PFC_PROGRESS progfn=NULL, PFCENGINE *pEngineAI=NULL)
Single function to perform Perfectly Clear corrections.
PFCIMAGE::height
int height
Pixel height of image.
Definition: PerfectlyClearPro.h:248
CALC_ALL
@ CALC_ALL
Calculates for all of the above.
Definition: PerfectlyClearPro.h:163
RERETCODE
#define RERETCODE(x)
Decode return status of Red Eye correction from master return code.
Definition: PerfectlyClearPro.h:25
CALC_RE
@ CALC_RE
Calculates for Red Eye Removal.
Definition: PerfectlyClearPro.h:162
PerfectlyClearAdapter.PFCImageFile.LoadImage
PFC_FILE_LOAD_STATUS LoadImage(string filename, bool bConvertToSRGB=false, string iccFolderPath=null)
Load JPEG from file on disk.
Definition: PerfectlyClearAdapter.cs:2382
PFCIMAGE::stride
int stride
Byte width of each scanline.
Definition: PerfectlyClearPro.h:249
PFCAPPLYSTATUS
PFCAPPLYSTATUS
Enumeration defining return code from the Apply() function.
Definition: PerfectlyClearPro.h:382
PFC_PixelFormat24bppRGB
@ PFC_PixelFormat24bppRGB
Definition: PerfectlyClearPro.h:48
PFCPROFILE
#define PFCPROFILE
Define.
Definition: PerfectlyClearPro.h:606
PFCIMAGE::width
int width
Pixel width of image.
Definition: PerfectlyClearPro.h:247
PFCIMAGE::data
unsigned char * data
Pointer pointing to the first byte of image data buffer.
Definition: PerfectlyClearPro.h:251
PFCImageFile::PFC_FILETYPE
PFC_FILETYPE
Type for compressing/decomrpessing a buffer.
Definition: PFCImageFile.h:73
PFCIMAGE
Struct defining an image to be used in PFC library.
Definition: PerfectlyClearPro.h:246
ENGINESTATUS_OK
@ ENGINESTATUS_OK
Engine created successfully.
Definition: PerfectlyClearPro.h:152
PFCENGINE
Struct defining an PFC engine instance.
Definition: PerfectlyClearPro.h:240
PFC_DestroyEngine
void PFC_DestroyEngine(PFCENGINE *p)
Destroy PFCENGINE instance and release associated resources.
PFC_ReleaseProfile
void PFC_ReleaseProfile(PFCPROFILE pProfile)
Release PFCPROFILE instance.
PFC_Apply
PFCAPPLYSTATUS PFC_Apply(PFCIMAGE *pImage, PFCENGINE *pEngine, PFCPROFILE pImageProfile, PFCPARAM &param, PFC_PROGRESS progfn=NULL, int iOpacity=100, void *pBGProfile=NULL)
Correct image with parameters.
NRRETCODE
#define NRRETCODE(x)
Decode return status of Noise Removal from master return code.
Definition: PerfectlyClearPro.h:19
CALC_CORE
@ CALC_CORE
Calculates for Perfectly Clear Core correction.
Definition: PerfectlyClearPro.h:159
PFC_CreateEngine
PFCENGINE * PFC_CreateEngine()
Create PFCENGINE instance.
PFCIMAGE::format
PFCPIXELFORMAT format
Defines byte order of input buffer.
Definition: PerfectlyClearPro.h:250
PFC_Calc
PFCPROFILE PFC_Calc(PFCIMAGE *pImage, PFCIMAGE *pImageds, PFCENGINE *pEngine, unsigned int feature=CALC_ALL, int iISO=-1, char *pCameraModel=NULL, PFCPROFILE pImageProfile=NULL, PFC_PROGRESS progfn=NULL, int iRejectOption=PFC_REJECT_CLIPART, PFCENGINE *pEngineAI=NULL)
Perform initial analysis on images.
CALC_NR
@ CALC_NR
Calculates for Perfectly Clear Noise Removal.
Definition: PerfectlyClearPro.h:160
PFCENGINE::status
PFCENGINESTATUS status
Status of engine defined in PFCENGINESTATUS. For NO-SFB version the status will always be ENGINESTATU...
Definition: PerfectlyClearPro.h:242
PFC_SetParam
void PFC_SetParam(PFCPARAM &param, PFCPRESETID id=PRESET_IAUTO_21)
Initialize a PFCPARAM structure.
PFCImageFile
PFCImageFile Class to encapsulate file handling.
Definition: PFCImageFile.h:69
PerfectlyClearAdapter.PFCImageFile
PFCImageFile Class to encapsulate file handling.
Definition: PerfectlyClearAdapter.cs:2324
PFC_ReadPresets
int PFC_ReadPresets(PFCPARAM &param, char *filename)
Load image processing settings from a .preset file. Use this function to load image processing settin...
FBRETCODE
#define FBRETCODE(x)
Decode return status of Face Beautification from master return code.
Definition: PerfectlyClearPro.h:23
PerfectlyClearAdapter
Definition: PerfectlyClearAdapter.cs:16