Skip to content

Commit

Permalink
Add the project
Browse files Browse the repository at this point in the history
  • Loading branch information
0xC0000054 committed Apr 12, 2021
1 parent 33dfd22 commit f160007
Show file tree
Hide file tree
Showing 45 changed files with 5,446 additions and 0 deletions.
1 change: 1 addition & 0 deletions 3rd-party/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*/
40 changes: 40 additions & 0 deletions 3rd-party/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
This directory contains the 3rd-party dependencies required to build the plug-in.

### Adobe Photoshop CS5 SDK

You will need to download the Adobe Photoshop CS5 SDK from http://www.adobe.com/devnet/photoshop/sdk.html and unzip it into this folder.

### AOM

Clone AOM from your preferred tag:

`git clone -b v3.0.0 --depth 1 https://aomedia.googlesource.com/aom`

Change into the `aom` directory and create a build directory.
In this example a 64-bit build using Visual Studio 2019 is used.

`cd aom`
`mkdir build64 && cd build64`
`cmake -G "Visual Studio 16 2019" -DCMAKE_BUILD_TYPE=Release -DENABLE_DOCS=0 -DENABLE_EXAMPLES=0 -DENABLE_TESTDATA=0 -DENABLE_TESTS=0 -DENABLE_TOOLS=0 ..`
`cmake --build .`

The generated AOM library should be located in `aom/build64/Release`, this library will be used when building `libheif`.

### libheif

Clone libheif from your preferred tag:

`git clone -b v1.11.0 --depth 1 https://github.com/strukturag/libheif`

Change into the `libheif` directory and create a build directory.
In this example a 64-bit build using Visual Studio 2019 is used.

`cd libheif`
`mkdir build64 && cd build64`
`cmake -G "Visual Studio 16 2019" -DBUILD_SHARED_LIBS=OFF -DWITH_EXAMPLES=OFF -DAOM_INCLUDE_DIR=..\..\aom -DAOM_LIBRARY=..\..\aom\build64\Release\aom.lib ..`
`cmake --build .`

You will need to add `LIBHEIF_STATIC_BUILD` to the preprocessor settings page in the libheif project properties,
and remove the `HAS_VISIBILITY` definition if present.

The generated libheif library should be located in `libheif/build64/Release`.
10 changes: 10 additions & 0 deletions src/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
root = true

[*]
end_of_line = crlf

[*.{cpp,h}]
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
202 changes: 202 additions & 0 deletions src/common/AvifFormat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
* This file is part of avif-format, an AV1 Image (AVIF) file format
* plug-in for Adobe Photoshop(R).
*
* Copyright (c) 2021 Nicholas Hayes
*
* avif-format is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* avif-format is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with avif-format. If not, see <http://www.gnu.org/licenses/>.
*/

#include "AvifFormat.h"
#include "FileIO.h"
#include <stdexcept>

namespace
{
OSErr CreateGlobals(FormatRecordPtr formatRecord, intptr_t* data)
{
Handle handle;

OSErr e = NewPIHandle(formatRecord, sizeof(Globals), &handle);

if (e == noErr)
{
*data = reinterpret_cast<intptr_t>(handle);
}

return e;
}

OSErr DoFilterFile(FormatRecordPtr formatRecord)
{
constexpr int bufferSize = 50;
uint8_t buffer[bufferSize] = {};

OSErr err = ReadData(formatRecord->dataFork, buffer, bufferSize);

if (err == noErr)
{
try
{
if (!heif_has_compatible_brand(buffer, bufferSize, "avif"))
{
err = formatCannotRead;
}
}
catch (const std::bad_alloc&)
{
err = memFullErr;
}
catch (...)
{
err = formatCannotRead;
}
}

return err;
}

void InitGlobals(Globals* globals)
{
globals->context = nullptr;
globals->imageHandle = nullptr;
globals->image = nullptr;
globals->saveOptions.quality = 85;
globals->saveOptions.chromaSubsampling = ChromaSubsampling::Yuv422;
globals->saveOptions.compressionSpeed = CompressionSpeed::Default;
globals->saveOptions.lossless = false;
globals->saveOptions.imageBitDepth = ImageBitDepth::Twelve; // The save UI will default to 8-bit if the image is 8-bit.
globals->saveOptions.keepColorProfile = false;
globals->saveOptions.keepExif = false;
globals->saveOptions.keepXmp = false;
}
}

void PluginMain(const short selector, FormatRecordPtr formatRecord, intptr_t* data, short* result)
{
if (selector == formatSelectorAbout)
{
DoAbout(reinterpret_cast<AboutRecordPtr>(formatRecord));
*result = noErr;
}
else
{
if (formatRecord->HostSupports32BitCoordinates)
{
formatRecord->PluginUsing32BitCoordinates = true;
}

Globals* globals;
if (*data == 0)
{
*result = CreateGlobals(formatRecord, data);
if (*result != noErr)
{
return;
}

globals = reinterpret_cast<Globals*>(LockPIHandle(formatRecord, reinterpret_cast<Handle>(*data), false));
InitGlobals(globals);
}
else
{
globals = reinterpret_cast<Globals*>(LockPIHandle(formatRecord, reinterpret_cast<Handle>(*data), false));
}

switch (selector)
{
case formatSelectorReadPrepare:
*result = DoReadPrepare(formatRecord);
break;
case formatSelectorReadStart:
*result = DoReadStart(formatRecord, globals);
break;
case formatSelectorReadContinue:
*result = DoReadContinue(formatRecord, globals);
break;
case formatSelectorReadFinish:
*result = DoReadFinish(globals);
break;

case formatSelectorOptionsPrepare:
*result = DoOptionsPrepare(formatRecord);
break;
case formatSelectorOptionsStart:
*result = DoOptionsStart(formatRecord, globals);
break;
case formatSelectorOptionsContinue:
*result = DoOptionsContinue();
break;
case formatSelectorOptionsFinish:
*result = DoOptionsFinish();
break;

case formatSelectorEstimatePrepare:
*result = DoEstimatePrepare(formatRecord);
break;
case formatSelectorEstimateStart:
*result = DoEstimateStart(formatRecord);
break;
case formatSelectorEstimateContinue:
*result = DoEstimateContinue();
break;
case formatSelectorEstimateFinish:
*result = DoEstimateFinish();
break;

case formatSelectorWritePrepare:
*result = DoWritePrepare(formatRecord);
break;
case formatSelectorWriteStart:
*result = DoWriteStart(formatRecord, globals->saveOptions);
break;
case formatSelectorWriteContinue:
*result = DoWriteContinue();
break;
case formatSelectorWriteFinish:
*result = DoWriteFinish(formatRecord, globals->saveOptions);
break;

case formatSelectorFilterFile:
*result = DoFilterFile(formatRecord);
break;

default:
*result = formatBadParameters;
}

UnlockPIHandle(formatRecord, reinterpret_cast<Handle>(*data));
}
}

OSErr HandleErrorMessage(FormatRecordPtr formatRecord, const char* const message, OSErr fallbackErrorCode)
{
if (formatRecord->errorString != nullptr)
{
const size_t length = strlen(message);

if (length <= 254)
{
uint8* errorReportString = reinterpret_cast<uint8*>(formatRecord->errorString);

errorReportString[0] = static_cast<uint8>(length);
memcpy(&errorReportString[1], message, length);
errorReportString[length + 1] = 0;

return errReportString;
}
}

return ShowErrorDialog(formatRecord, message, fallbackErrorCode);
}
126 changes: 126 additions & 0 deletions src/common/AvifFormat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* This file is part of avif-format, an AV1 Image (AVIF) file format
* plug-in for Adobe Photoshop(R).
*
* Copyright (c) 2021 Nicholas Hayes
*
* avif-format is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* avif-format is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with avif-format. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef AVIFFORMAT_H
#define AVIFFORMAT_H

#include "Common.h"

enum class ChromaSubsampling
{
Yuv420,
Yuv422,
Yuv444
};

enum class CompressionSpeed
{
Fastest,
Default,
Slowest
};

enum class ImageBitDepth
{
Eight,
Ten,
Twelve
};

struct SaveUIOptions
{
int quality;
ChromaSubsampling chromaSubsampling;
CompressionSpeed compressionSpeed;
ImageBitDepth imageBitDepth;
bool lossless;
bool keepColorProfile;
bool keepExif;
bool keepXmp;
};

struct Globals
{
heif_context* context;
heif_image_handle* imageHandle;
heif_image* image;

SaveUIOptions saveOptions;
};

DLLExport MACPASCAL void PluginMain(
const short selector,
FormatRecordPtr formatParamBlock,
intptr_t* data,
short* result);


OSErr HandleErrorMessage(FormatRecordPtr formatRecord, const char* const message, OSErr fallbackErrorCode);

VPoint GetImageSize(const FormatRecordPtr formatRecord);
void SetRect(FormatRecordPtr formatRecord, int32 top, int32 left, int32 bottom, int32 right);

OSErr NewPIHandle(const FormatRecordPtr formatRecord, int32 size, Handle* handle);
void DisposePIHandle(const FormatRecordPtr formatRecord, Handle handle);
Ptr LockPIHandle(const FormatRecordPtr formatRecord, Handle handle, Boolean moveHigh);
void UnlockPIHandle(const FormatRecordPtr formatRecord, Handle handle);

// Platform-specific UI methods

void DoAbout(const AboutRecordPtr aboutRecord);
bool DoSaveUI(const FormatRecordPtr formatRecord, SaveUIOptions& options);
OSErr ShowErrorDialog(const FormatRecordPtr formatRecord, const char* const message, OSErr fallbackErrorCode);

// File Format API callbacks

OSErr DoReadPrepare(FormatRecordPtr formatRecord);
OSErr DoReadStart(FormatRecordPtr formatRecord, Globals* globals);
OSErr DoReadContinue(FormatRecordPtr formatRecord, Globals* globals);
OSErr DoReadFinish(Globals* globals);

OSErr DoOptionsPrepare(FormatRecordPtr formatRecord);
OSErr DoOptionsStart(FormatRecordPtr formatRecord, Globals* globals);
OSErr DoOptionsContinue();
OSErr DoOptionsFinish();

OSErr DoEstimatePrepare(FormatRecordPtr formatRecord);
OSErr DoEstimateStart(FormatRecordPtr formatRecord);
OSErr DoEstimateContinue();
OSErr DoEstimateFinish();

OSErr DoWritePrepare(FormatRecordPtr formatRecord);
OSErr DoWriteStart(FormatRecordPtr formatRecord, SaveUIOptions& options);
OSErr DoWriteContinue();
OSErr DoWriteFinish(FormatRecordPtr formatRecord, const SaveUIOptions& options);

// Scripting

OSErr ReadScriptParamsOnWrite(FormatRecordPtr formatRecord, SaveUIOptions& options, Boolean* showDialog);
OSErr WriteScriptParamsOnWrite(FormatRecordPtr formatRecord, const SaveUIOptions& options);

// Utility functions

bool DescriptorSuiteIsAvaliable(const FormatRecordPtr formatRecord);
bool HandleSuiteIsAvailable(const FormatRecordPtr formatRecord);
bool HostImageModeSupported(const FormatRecordPtr formatRecord);
bool HostSupportsRequiredFeatures(const FormatRecordPtr formatRecord);
bool PropertySuiteIsAvailable(const FormatRecordPtr formatRecord);

#endif // !AVIFFORMAT_H
Loading

0 comments on commit f160007

Please sign in to comment.