├── 3rd-party
├── .gitignore
└── README.md
├── .github
└── FUNDING.yml
├── src
├── win
│ ├── PiPL.rc
│ ├── UIWin.cpp
│ ├── version.rc
│ ├── AvifFormat.rc
│ ├── MemoryWin.h
│ ├── FileIOWin.h
│ ├── MemoryWin.cpp
│ ├── resource.h
│ └── FileIOWin.cpp
├── common
│ ├── YUVCoefficiants.cpp
│ ├── YuvLookupTables.cpp
│ ├── ColorProfileGeneration.cpp
│ ├── version.h
│ ├── AlphaState.h
│ ├── ExifParser.h
│ ├── ColorProfileDetection.h
│ ├── YUVCoefficiants.h
│ ├── ColorProfileGeneration.h
│ ├── ReadMetadata.h
│ ├── FileIO.h
│ ├── WriteMetadata.h
│ ├── HostMetadata.h
│ ├── YUVLookupTables.h
│ ├── Common.cpp
│ ├── PremultipliedAlpha.h
│ ├── OSErrException.h
│ ├── Utilities.h
│ ├── FileIO.cpp
│ ├── LibHeifException.h
│ ├── Common.h
│ ├── ColorTransfer.h
│ ├── Options.cpp
│ ├── ReadHeifImage.h
│ ├── WriteHeifImage.h
│ ├── ScopedHeif.h
│ ├── ColorProfileConversion.h
│ ├── AvifFormatTerminology.h
│ ├── Estimate.cpp
│ ├── Memory.cpp
│ ├── HostMetadata.cpp
│ ├── PremultipliedAlpha.cpp
│ ├── ScopedBufferSuite.h
│ ├── YUVDecode.h
│ ├── ScopedHandleSuite.h
│ ├── ScopedLcms.h
│ ├── AvifFormat.h
│ ├── ReadMetadata.cpp
│ ├── ExifParser.cpp
│ ├── WriteMetadata.cpp
│ ├── AvifFormat.cpp
│ ├── ColorTransfer.cpp
│ ├── AvifFormat.r
│ ├── ColorProfileConversion.cpp
│ ├── ColorProfileDetection.cpp
│ └── Write.cpp
└── .editorconfig
├── vcpkg.json
├── vs
├── AvifFormat.sln.licenseheader
├── AvifFormat.sln
└── AvifFormat.vcxproj.filters
├── .gitattributes
├── README.md
├── Third Party Notices.txt
├── .gitignore
└── LICENSE.md
/3rd-party/.gitignore:
--------------------------------------------------------------------------------
1 | */
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 |
2 | custom: https://paypal.me/0xC0000054
3 |
--------------------------------------------------------------------------------
/src/win/PiPL.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xC0000054/avif-format/HEAD/src/win/PiPL.rc
--------------------------------------------------------------------------------
/src/win/UIWin.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xC0000054/avif-format/HEAD/src/win/UIWin.cpp
--------------------------------------------------------------------------------
/src/win/version.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xC0000054/avif-format/HEAD/src/win/version.rc
--------------------------------------------------------------------------------
/src/win/AvifFormat.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xC0000054/avif-format/HEAD/src/win/AvifFormat.rc
--------------------------------------------------------------------------------
/src/common/YUVCoefficiants.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xC0000054/avif-format/HEAD/src/common/YUVCoefficiants.cpp
--------------------------------------------------------------------------------
/src/common/YuvLookupTables.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xC0000054/avif-format/HEAD/src/common/YuvLookupTables.cpp
--------------------------------------------------------------------------------
/src/common/ColorProfileGeneration.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xC0000054/avif-format/HEAD/src/common/ColorProfileGeneration.cpp
--------------------------------------------------------------------------------
/src/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = crlf
5 |
6 | [*.{cpp,h}]
7 | indent_size = 4
8 | indent_style = space
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
--------------------------------------------------------------------------------
/vcpkg.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "avif-format",
3 | "version": "1.0.0",
4 | "description": "An AV1 Image (AVIF) file format plug-in",
5 | "homepage": "https://github.com/0xC0000054/avif-format",
6 | "dependencies": [
7 | "lcms"
8 | ],
9 | "builtin-baseline": "e3a3942a9eb0cb47c12898e5fd819f258441b6f6"
10 | }
--------------------------------------------------------------------------------
/vs/AvifFormat.sln.licenseheader:
--------------------------------------------------------------------------------
1 | extensions: designer.cs generated.cs
2 | extensions: .cs .cpp .h
3 | /*
4 | * This file is part of avif-format, an AV1 Image (AVIF) file format
5 | * plug-in for Adobe Photoshop(R).
6 | *
7 | * Copyright (c) 2021 Nicholas Hayes
8 | *
9 | * avif-format is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Lesser General Public License as
11 | * published by the Free Software Foundation, either version 3 of
12 | * the License, or (at your option) any later version.
13 | *
14 | * avif-format is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Lesser General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Lesser General Public License
20 | * along with avif-format. If not, see .
21 | */
22 |
--------------------------------------------------------------------------------
/src/common/version.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef VERSION_H
22 | #define VERSION_H
23 |
24 | #define VI_VERSION 1,0,7,0
25 | #define VI_VERSION_STR "1.0.7.0"
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/src/common/AlphaState.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef ALPHASTATE_H
22 | #define ALPHASTATE_H
23 |
24 | enum class AlphaState
25 | {
26 | None,
27 | Straight,
28 | Premultiplied
29 | };
30 |
31 | #endif // !ALPHASTATE_H
32 |
--------------------------------------------------------------------------------
/src/win/MemoryWin.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef MEMORYWIN_H
22 | #define MEMORYWIN_H
23 |
24 | #include "Common.h"
25 |
26 | Handle NewHandle(int32 size);
27 | void DisposeHandle(Handle handle);
28 |
29 | #endif // MEMORYWIN_H
30 |
--------------------------------------------------------------------------------
/src/common/ExifParser.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef EXIFPARSER_H
22 | #define EXIFPARSER_H
23 |
24 | #include "Common.h"
25 |
26 | bool CheckTiffFileSignature(const uint8* data, size_t dataLength);
27 |
28 | void SetExifOrientationToTopLeft(uint8* data, size_t dataLength);
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/src/common/ColorProfileDetection.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef COLORPROFILEDETECTION_H
22 | #define COLORPROFILEDETECTION_H
23 |
24 | #include "lcms2.h"
25 |
26 | bool IsRec2020ColorProfile(cmsHPROFILE profile);
27 |
28 | bool IsSRGBColorProfile(cmsHPROFILE profile);
29 |
30 | #endif // !COLORPROFILEDETECTION_H
31 |
--------------------------------------------------------------------------------
/src/common/YUVCoefficiants.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef YUVCOEFFICIANTS_H
22 | #define YUVCOEFFICIANTS_H
23 |
24 | #include "Common.h"
25 |
26 | struct YUVCoefficiants
27 | {
28 | float kr;
29 | float kg;
30 | float kb;
31 | };
32 |
33 | void GetYUVCoefficiants(
34 | const heif_color_profile_nclx* colorInfo,
35 | YUVCoefficiants& yuvData);
36 |
37 | #endif // !YUVCOEFFICIANTS_H
38 |
--------------------------------------------------------------------------------
/src/common/ColorProfileGeneration.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef COLORPROFILEGENERATION_H
22 | #define COLORPROFILEGENERATION_H
23 |
24 | #include "Common.h"
25 | #include "ScopedLcms.h"
26 |
27 | ScopedLcmsProfile CreateRec2020LinearRGBProfile(cmsContext context);
28 |
29 | void SetIccProfileFromNclx(FormatRecord* formatRecord, const heif_color_profile_nclx* nclx);
30 |
31 | #endif // !COLORPROFILEGENERATION_H
32 |
--------------------------------------------------------------------------------
/src/common/ReadMetadata.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef READMETADATA_H
22 | #define READMETADATA_H
23 |
24 | #include "Common.h"
25 |
26 | void ReadExifMetadata(const FormatRecordPtr formatRecord, const heif_image_handle* handle);
27 |
28 | void ReadIccProfileMetadata(const FormatRecordPtr formatRecord, const heif_image_handle* handle);
29 |
30 | void ReadXmpMetadata(const FormatRecordPtr formatRecord, const heif_image_handle* handle);
31 |
32 | #endif // !READMETADATA_H
33 |
--------------------------------------------------------------------------------
/src/common/FileIO.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef FILEIO_H
22 | #define FILEIO_H
23 |
24 | #include "Common.h"
25 |
26 | OSErr GetFilePosition(intptr_t refNum, int64& position);
27 |
28 | OSErr GetFileSize(intptr_t refNum, int64& size);
29 |
30 | OSErr ReadData(intptr_t refNum, void* buffer, size_t size);
31 |
32 | OSErr SetFilePosition(intptr_t refNum, int64 position);
33 |
34 | OSErr WriteData(intptr_t refNum, const void* buffer, size_t size);
35 |
36 | #endif // !FILEIO_H
37 |
--------------------------------------------------------------------------------
/src/win/FileIOWin.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef FILEIOWIN_H
22 | #define FILEIOWIN_H
23 |
24 | #include "Common.h"
25 |
26 | OSErr GetFilePositionNative(intptr_t refNum, int64& position);
27 |
28 | OSErr GetFileSizeNative(intptr_t refNum, int64& size);
29 |
30 | OSErr ReadDataNative(intptr_t refNum, void* buffer, size_t size);
31 |
32 | OSErr SetFilePositionNative(intptr_t refNum, int64 position);
33 |
34 | OSErr WriteDataNative(intptr_t refNum, const void* buffer, size_t size);
35 |
36 | #endif // !FILEIOWIN_H
37 |
--------------------------------------------------------------------------------
/src/common/WriteMetadata.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef WRITEMETADATA_H
22 | #define WRITEMETADATA_H
23 |
24 | #include "AvifFormat.h"
25 |
26 | void AddColorProfileToImage(const FormatRecordPtr formatRecord, heif_image* image, const SaveUIOptions& saveOptions);
27 |
28 | void AddExifMetadata(const FormatRecordPtr formatRecord, heif_context* context, heif_image_handle* imageHandle);
29 |
30 | void AddXmpMetadata(const FormatRecordPtr formatRecord, heif_context* context, heif_image_handle* imageHandle);
31 |
32 | #endif // !WRITEMETADATA_H
33 |
--------------------------------------------------------------------------------
/src/common/HostMetadata.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef HOSTMETADATA_H
22 | #define HOSTMETADATA_H
23 |
24 | #include "AvifFormat.h"
25 | #include "ScopedHandleSuite.h"
26 |
27 | ScopedHandleSuiteHandle GetExifMetadata(const FormatRecordPtr formatRecord);
28 | ScopedHandleSuiteHandle GetXmpMetadata(const FormatRecordPtr formatRecord);
29 |
30 | bool HasColorProfileMetadata(const FormatRecordPtr formatRecord);
31 | bool HasExifMetadata(const FormatRecordPtr formatRecord);
32 | bool HasXmpMetadata(const FormatRecordPtr formatRecord);
33 |
34 | #endif // !HOSTMETADATA_H
35 |
--------------------------------------------------------------------------------
/src/common/YUVLookupTables.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef YUVLOOKUPTABLES_H
22 | #define YUVLOOKUPTABLES_H
23 |
24 | #include "Common.h"
25 | #include
26 |
27 | struct YUVLookupTables
28 | {
29 | std::unique_ptr unormFloatTableY;
30 | std::unique_ptr unormFloatTableUV;
31 | std::unique_ptr unormFloatTableAlpha;
32 | const int yuvMaxChannel;
33 |
34 | YUVLookupTables(const heif_color_profile_nclx* nclx, int32_t bitDepth, bool monochrome, bool hasAlpha);
35 | };
36 |
37 | #endif // !YUVLOOKUPTABLES_H
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/common/Common.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "Common.h"
22 | #include
23 | #include
24 |
25 | #if DEBUG_BUILD
26 | void DebugOut(const char* fmt, ...) noexcept
27 | {
28 | #if __PIWin__
29 | va_list argp;
30 | char dbg_out[4096] = {};
31 |
32 | va_start(argp, fmt);
33 | vsprintf_s(dbg_out, fmt, argp);
34 | va_end(argp);
35 |
36 | OutputDebugStringA(dbg_out);
37 | OutputDebugStringA("\n");
38 | #else
39 | #error "Debug output has not been configured for this platform."
40 | #endif // __PIWin__
41 | }
42 | #endif // DEBUG_BUILD
43 |
--------------------------------------------------------------------------------
/src/common/PremultipliedAlpha.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef PREMULTIPLIEDALPHA_H
22 | #define PREMULTIPLIEDALPHA_H
23 |
24 | #include "Common.h"
25 |
26 | float PremultiplyColor(float color, float alpha, float maxValue);
27 |
28 | uint8_t PremultiplyColor(uint8_t color, uint8_t alpha);
29 |
30 | uint16_t PremultiplyColor(uint16_t color, uint16_t alpha, uint16_t maxValue);
31 |
32 | float UnpremultiplyColor(float color, float alpha, float maxValue);
33 |
34 | uint8_t UnpremultiplyColor(uint8_t color, uint8_t alpha);
35 |
36 | uint16_t UnpremultiplyColor(uint16_t color, uint16_t alpha, uint16_t maxValue);
37 |
38 | #endif // PREMULTIPLIEDALPHA_H
39 |
--------------------------------------------------------------------------------
/src/common/OSErrException.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef OSERREXCEPTION_H
22 | #define OSERREXCEPTION_H
23 |
24 | #include "PITypes.h"
25 | #include
26 |
27 | class OSErrException : public std::exception
28 | {
29 | public:
30 | explicit OSErrException(OSErr err) noexcept : error(err)
31 | {
32 | }
33 |
34 | OSErr GetErrorCode() const noexcept
35 | {
36 | return error;
37 | }
38 |
39 | static void ThrowIfError(OSErr err)
40 | {
41 | if (err != noErr)
42 | {
43 | throw OSErrException(err);
44 | }
45 | }
46 |
47 | private:
48 | OSErr error;
49 | };
50 |
51 | #endif // !OSERREXCEPTION_H
52 |
--------------------------------------------------------------------------------
/src/common/Utilities.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef UTILITIES_H
22 | #define UTILITIES_H
23 |
24 | #include "Common.h"
25 |
26 | VPoint GetImageSize(const FormatRecordPtr formatRecord);
27 | void SetRect(FormatRecordPtr formatRecord, int32 top, int32 left, int32 bottom, int32 right);
28 |
29 | bool HasAlphaChannel(const FormatRecordPtr formatRecord);
30 | bool IsMonochromeImage(const FormatRecordPtr formatRecord);
31 |
32 | bool DescriptorSuiteIsAvailable(const FormatRecordPtr formatRecord);
33 | bool HandleSuiteIsAvailable(const FormatRecordPtr formatRecord);
34 | bool HostImageModeSupported(const FormatRecordPtr formatRecord);
35 | bool HostSupportsRequiredFeatures(const FormatRecordPtr formatRecord);
36 | bool PropertySuiteIsAvailable(const FormatRecordPtr formatRecord);
37 |
38 | #endif // !UTILITIES_H
39 |
--------------------------------------------------------------------------------
/src/common/FileIO.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "FileIO.h"
22 |
23 | #if __PIWin__
24 | #include "FileIOWin.h"
25 | #else
26 | #error "Missing a native file I/O header for this platform."
27 | #endif
28 |
29 | OSErr GetFilePosition(intptr_t refNum, int64& position)
30 | {
31 | return GetFilePositionNative(refNum, position);
32 | }
33 |
34 | OSErr GetFileSize(intptr_t refNum, int64& size)
35 | {
36 | return GetFileSizeNative(refNum, size);
37 | }
38 |
39 | OSErr ReadData(intptr_t refNum, void* buffer, size_t size)
40 | {
41 | return ReadDataNative(refNum, buffer, size);
42 | }
43 |
44 | OSErr SetFilePosition(intptr_t refNum, int64 position)
45 | {
46 | return SetFilePositionNative(refNum, position);
47 | }
48 |
49 | OSErr WriteData(intptr_t refNum, const void* buffer, size_t size)
50 | {
51 | return WriteDataNative(refNum, buffer, size);
52 | }
53 |
--------------------------------------------------------------------------------
/src/common/LibHeifException.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef LIBHEIFEXCEPTION_H
22 | #define LIBHEIFEXCEPTION_H
23 |
24 | #include
25 | #include
26 |
27 | class LibHeifException : public std::runtime_error
28 | {
29 | public:
30 |
31 | LibHeifException(const heif_error& e) : std::runtime_error(e.message), code(e.code), subCode(e.subcode)
32 | {
33 | }
34 |
35 | heif_error_code GetErrorCode() const
36 | {
37 | return code;
38 | }
39 |
40 | heif_suberror_code GetSubCode() const
41 | {
42 | return subCode;
43 | }
44 |
45 | static void ThrowIfError(const heif_error& e)
46 | {
47 | if (e.code != heif_error_Ok)
48 | {
49 | if (e.code == heif_error_Memory_allocation_error && e.subcode == heif_suberror_Unspecified)
50 | {
51 | throw std::bad_alloc();
52 | }
53 | else
54 | {
55 | throw LibHeifException(e);
56 | }
57 | }
58 | }
59 |
60 | private:
61 |
62 | heif_error_code code;
63 | heif_suberror_code subCode;
64 | };
65 |
66 | #endif
67 |
--------------------------------------------------------------------------------
/src/common/Common.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef COMMON_H
22 | #define COMMON_H
23 |
24 | #if defined(_MSC_VER)
25 | #pragma warning(push)
26 | // Disable uninitialized variable warnings in the SDK headers.
27 | #pragma warning(disable: 26495)
28 | // Suppress C4121: 'FormatRecord': alignment of a member was sensitive to packing
29 | #pragma warning(disable: 4121)
30 | #endif // _MSC_VER)
31 |
32 | #include "PIDefines.h"
33 | #include "PITypes.h"
34 | #include "PIFormat.h"
35 | #include "PIAbout.h"
36 |
37 | #if defined(_MSC_VER)
38 | #pragma warning(pop)
39 | #endif
40 |
41 | // PITypes.h may define a few C++ reserved keywords
42 | #if defined(false)
43 | #undef false
44 | #endif // defined(false)
45 |
46 | #if defined(true)
47 | #undef true
48 | #endif // defined(true)
49 |
50 | #include "libheif/heif.h"
51 |
52 | #if defined(DEBUG) || defined(_DEBUG)
53 | #define DEBUG_BUILD 1
54 | #else
55 | #define DEBUG_BUILD 0
56 | #endif
57 |
58 | #if DEBUG_BUILD
59 | void DebugOut(const char* fmt, ...) noexcept;
60 | #else
61 | #define DebugOut(fmt, ...)
62 | #endif // DEBUG_BUILD
63 |
64 | #define PrintFunctionName() DebugOut(__FUNCTION__)
65 |
66 | #endif // !COMMON_H
67 |
--------------------------------------------------------------------------------
/src/win/MemoryWin.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "MemoryWin.h"
22 | #include
23 | #include
24 |
25 | // The following methods were adapted from WinUtilities.cpp in the PS6 SDK:
26 |
27 | #define signatureSize 4
28 | static char cSig[signatureSize] = { 'O', 'T', 'O', 'F' };
29 |
30 | #pragma warning(disable: 6387)
31 | #pragma warning(disable: 28183)
32 |
33 | Handle NewHandle(int32 size)
34 | {
35 | Handle mHand;
36 | char* p;
37 |
38 | mHand = (Handle)GlobalAllocPtr(GHND, (sizeof(Handle) + signatureSize));
39 |
40 | if (mHand)
41 | *mHand = (Ptr)GlobalAllocPtr(GHND, size);
42 |
43 | if (!mHand || !(*mHand))
44 | {
45 | return NULL;
46 | }
47 |
48 | // put the signature after the pointer
49 | p = (char*)mHand;
50 | p += sizeof(Handle);
51 | memcpy(p, cSig, signatureSize);
52 |
53 | return mHand;
54 |
55 | }
56 |
57 | void DisposeHandle(Handle handle)
58 | {
59 | if (handle)
60 | {
61 | Ptr p;
62 |
63 | p = *handle;
64 |
65 | if (p)
66 | GlobalFreePtr(p);
67 |
68 | GlobalFreePtr((Ptr)handle);
69 | }
70 | }
71 |
72 | #pragma warning(default: 6387)
73 | #pragma warning(default: 28183)
74 |
--------------------------------------------------------------------------------
/src/common/ColorTransfer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef COLORTRANSFER_H
22 | #define COLORTRANSFER_H
23 |
24 | #include
25 | #include
26 | #include
27 |
28 | enum class ColorTransferFunction
29 | {
30 | PQ,
31 | HLG,
32 | SMPTE428,
33 | Clip
34 | };
35 |
36 | struct HLGLumaCoefficiants
37 | {
38 | float red;
39 | float green;
40 | float blue;
41 | };
42 |
43 | HLGLumaCoefficiants GetHLGLumaCoefficients(heif_color_primaries primaries);
44 |
45 | ColorTransferFunction GetTransferFunctionFromNclx(heif_transfer_characteristics transferCharacteristics);
46 |
47 | float LinearToPQ(float value, float imageMaxLuminanceLevel);
48 |
49 | float PQToLinear(float value, float imageMaxLuminanceLevel);
50 |
51 | float LinearToSMPTE428(float value);
52 |
53 | float SMPTE428ToLinear(float value);
54 |
55 | float LinearToHLG(float value);
56 |
57 | float HLGToLinear(float value);
58 |
59 | void ApplyHLGOOTF(
60 | float* rgb,
61 | const HLGLumaCoefficiants& lumaCoefficiants,
62 | float displayGamma,
63 | float nominalPeakBrightness);
64 |
65 | void ApplyInverseHLGOOTF(
66 | float* rgb,
67 | const HLGLumaCoefficiants& lumaCoefficiants,
68 | float displayGamma,
69 | float nominalPeakBrightness);
70 |
71 | #endif // !COLORTRANSFER_H
72 |
--------------------------------------------------------------------------------
/vs/AvifFormat.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31129.286
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AvifFormat", "AvifFormat.vcxproj", "{78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B4C7A3AD-33C9-40BF-A6D4-570726DC1DF0}"
9 | ProjectSection(SolutionItems) = preProject
10 | ..\src\.editorconfig = ..\src\.editorconfig
11 | EndProjectSection
12 | EndProject
13 | Global
14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
15 | Debug|ARM64 = Debug|ARM64
16 | Debug|x64 = Debug|x64
17 | Debug|x86 = Debug|x86
18 | Release|ARM64 = Release|ARM64
19 | Release|x64 = Release|x64
20 | Release|x86 = Release|x86
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Debug|ARM64.ActiveCfg = Debug|ARM64
24 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Debug|ARM64.Build.0 = Debug|ARM64
25 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Debug|x64.ActiveCfg = Debug|x64
26 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Debug|x64.Build.0 = Debug|x64
27 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Debug|x86.ActiveCfg = Debug|Win32
28 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Debug|x86.Build.0 = Debug|Win32
29 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Release|ARM64.ActiveCfg = Release|ARM64
30 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Release|ARM64.Build.0 = Release|ARM64
31 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Release|x64.ActiveCfg = Release|x64
32 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Release|x64.Build.0 = Release|x64
33 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Release|x86.ActiveCfg = Release|Win32
34 | {78CFC9B1-79F2-4B05-8DD8-852E32B06EF6}.Release|x86.Build.0 = Release|Win32
35 | EndGlobalSection
36 | GlobalSection(SolutionProperties) = preSolution
37 | HideSolutionNode = FALSE
38 | EndGlobalSection
39 | GlobalSection(ExtensibilityGlobals) = postSolution
40 | SolutionGuid = {FD40C7D7-77FB-45F8-AC02-7325480C6804}
41 | EndGlobalSection
42 | EndGlobal
43 |
--------------------------------------------------------------------------------
/src/common/Options.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "AvifFormat.h"
22 |
23 | OSErr DoOptionsPrepare(FormatRecordPtr formatRecord)
24 | {
25 | PrintFunctionName();
26 |
27 | OSErr err = noErr;
28 |
29 | if (!HostSupportsRequiredFeatures(formatRecord))
30 | {
31 | err = errPlugInHostInsufficient;
32 | }
33 | else if (!HostImageModeSupported(formatRecord))
34 | {
35 | err = formatBadParameters;
36 | }
37 |
38 | if (err == noErr)
39 | {
40 | formatRecord->maxData = 0;
41 | }
42 |
43 | return err;
44 | }
45 |
46 | OSErr DoOptionsStart(FormatRecordPtr formatRecord, Globals* globals)
47 | {
48 | PrintFunctionName();
49 |
50 | formatRecord->data = nullptr;
51 | SetRect(formatRecord, 0, 0, 0, 0);
52 |
53 | Boolean showDialog;
54 | ReadScriptParamsOnWrite(formatRecord, globals->saveOptions, &showDialog);
55 |
56 | OSErr err = noErr;
57 |
58 | if (showDialog)
59 | {
60 | if (DoSaveUI(formatRecord, globals->saveOptions))
61 | {
62 | WriteScriptParamsOnWrite(formatRecord, globals->saveOptions);
63 | }
64 | else
65 | {
66 | err = userCanceledErr;
67 | }
68 | }
69 |
70 | return err;
71 | }
72 |
73 | OSErr DoOptionsContinue()
74 | {
75 | PrintFunctionName();
76 |
77 | return noErr;
78 | }
79 |
80 | OSErr DoOptionsFinish()
81 | {
82 | PrintFunctionName();
83 |
84 | return noErr;
85 | }
86 |
--------------------------------------------------------------------------------
/src/common/ReadHeifImage.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef READHEIFIMAGE_H
22 | #define READHEIFIMAGE_H
23 |
24 | #include "AvifFormat.h"
25 | #include "AlphaState.h"
26 |
27 | void ReadHeifImageGrayEightBit(
28 | const heif_image* image,
29 | AlphaState alphaState,
30 | const heif_color_profile_nclx* nclxProfile,
31 | FormatRecordPtr formatRecord);
32 |
33 | void ReadHeifImageRGBEightBit(
34 | const heif_image* image,
35 | AlphaState alphaState,
36 | const heif_color_profile_nclx* nclxProfile,
37 | FormatRecordPtr formatRecord);
38 |
39 | void ReadHeifImageGraySixteenBit(
40 | const heif_image* image,
41 | AlphaState alphaState,
42 | const heif_color_profile_nclx* nclxProfile,
43 | FormatRecordPtr formatRecord);
44 |
45 | void ReadHeifImageRGBSixteenBit(
46 | const heif_image* image,
47 | AlphaState alphaState,
48 | const heif_color_profile_nclx* nclxProfile,
49 | FormatRecordPtr formatRecord);
50 |
51 | void ReadHeifImageGrayThirtyTwoBit(
52 | const heif_image* image,
53 | AlphaState alphaState,
54 | const heif_color_profile_nclx* nclxProfile,
55 | const LoadUIOptions& loadOptions,
56 | FormatRecordPtr formatRecord);
57 |
58 | void ReadHeifImageRGBThirtyTwoBit(
59 | const heif_image* image,
60 | AlphaState alphaState,
61 | const heif_color_profile_nclx* nclxProfile,
62 | const LoadUIOptions& loadOptions,
63 | FormatRecordPtr formatRecord);
64 |
65 | #endif // !READHEIFIMAGE_H
66 |
--------------------------------------------------------------------------------
/src/common/WriteHeifImage.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef WRITEHEIFIMAGE_H
22 | #define WRITEHEIFIMAGE_H
23 |
24 | #include "AvifFormat.h"
25 | #include "AlphaState.h"
26 | #include "ColorTransfer.h"
27 | #include "ScopedHeif.h"
28 |
29 | ScopedHeifImage CreateHeifImageGrayEightBit(
30 | FormatRecordPtr formatRecord,
31 | AlphaState alphaState,
32 | const VPoint& imageSize,
33 | const SaveUIOptions& saveOptions);
34 |
35 | ScopedHeifImage CreateHeifImageGraySixteenBit(
36 | FormatRecordPtr formatRecord,
37 | AlphaState alphaState,
38 | const VPoint& imageSize,
39 | const SaveUIOptions& saveOptions);
40 |
41 | ScopedHeifImage CreateHeifImageGrayThirtyTwoBit(
42 | FormatRecordPtr formatRecord,
43 | AlphaState alphaState,
44 | const VPoint& imageSize,
45 | const SaveUIOptions& saveOptions);
46 |
47 | ScopedHeifImage CreateHeifImageRGBEightBit(
48 | FormatRecordPtr formatRecord,
49 | AlphaState alphaState,
50 | const VPoint& imageSize,
51 | const SaveUIOptions& saveOptions);
52 |
53 | ScopedHeifImage CreateHeifImageRGBSixteenBit(
54 | FormatRecordPtr formatRecord,
55 | AlphaState alphaState,
56 | const VPoint& imageSize,
57 | const SaveUIOptions& saveOptions);
58 |
59 | ScopedHeifImage CreateHeifImageRGBThirtyTwoBit(
60 | FormatRecordPtr formatRecord,
61 | AlphaState alphaState,
62 | const VPoint& imageSize,
63 | const SaveUIOptions& saveOptions);
64 |
65 | #endif // !WRITEHEIFIMAGE_H
66 |
67 |
--------------------------------------------------------------------------------
/src/common/ScopedHeif.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef SCOPEDHEIF_H
22 | #define SCOPEDHEIF_H
23 |
24 | #include "libheif/heif.h"
25 | #include
26 |
27 | namespace detail
28 | {
29 | struct context_deleter { void operator()(heif_context* h) noexcept { if (h) heif_context_free(h); } };
30 |
31 | struct encoder_deleter { void operator()(heif_encoder* h) noexcept { if (h) heif_encoder_release(h); } };
32 |
33 | struct encoding_options_deleter { void operator()(heif_encoding_options* h) noexcept { if (h) heif_encoding_options_free(h); } };
34 |
35 | struct image_handle_deleter { void operator()(heif_image_handle* h) noexcept { if (h) heif_image_handle_release(h); } };
36 |
37 | struct image_deleter { void operator()(heif_image* h) noexcept { if (h) heif_image_release(h); } };
38 |
39 | struct nclx_profile_deleter { void operator()(heif_color_profile_nclx* h) noexcept { if (h) heif_nclx_color_profile_free(h); } };
40 | }
41 |
42 | using ScopedHeifContext = std::unique_ptr;
43 |
44 | using ScopedHeifEncoder = std::unique_ptr;
45 |
46 | using ScopedHeifEncodingOptions = std::unique_ptr;
47 |
48 | using ScopedHeifImageHandle = std::unique_ptr;
49 |
50 | using ScopedHeifImage = std::unique_ptr;
51 |
52 | using ScopedHeifNclxProfile = std::unique_ptr;
53 |
54 | #endif
55 |
--------------------------------------------------------------------------------
/src/common/ColorProfileConversion.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef COLORPROFILECONVERSION_H
22 | #define COLORPROFILECONVERSION_H
23 |
24 | #include "Common.h"
25 | #include "AlphaState.h"
26 | #include "ColorTransfer.h"
27 | #include "ScopedLcms.h"
28 | #include
29 |
30 | class ColorProfileConversion
31 | {
32 | public:
33 |
34 | ColorProfileConversion(
35 | const FormatRecordPtr formatRecord,
36 | bool hasAlpha,
37 | ColorTransferFunction transferFunction,
38 | bool keepEmbeddedColorProfile);
39 |
40 | ColorProfileConversion(
41 | const FormatRecordPtr formatRecord,
42 | bool hasAlpha,
43 | int hostBitsPerChannel,
44 | bool keepEmbeddedColorProfile);
45 |
46 | void ConvertRow(void* row, cmsUInt32Number pixelsPerLine, cmsUInt32Number bytesPerLine);
47 |
48 | private:
49 |
50 | void ConvertSixteenBitRowToLcms(uint16_t* row, cmsUInt32Number pixelCount);
51 |
52 | void ConvertSixteenBitRowToHost(uint16_t* row, cmsUInt32Number pixelCount);
53 |
54 | void InitializeForRec2020Conversion(bool hasAlpha);
55 |
56 | void InitializeForSRGBConversion(bool hasAlpha, int hostBitsPerChannel);
57 |
58 | ScopedLcmsContext context;
59 | ScopedLcmsProfile documentProfile;
60 | ScopedLcmsProfile outputImageProfile;
61 | ScopedLcmsTransform transform;
62 | const size_t numberOfChannels;
63 | const bool isSixteenBitMode;
64 | std::vector hostToLcmsLookupTable;
65 | std::vector lcmsToHostLookupTable;
66 | };
67 |
68 | #endif // !COLORPROFILECONVERSION_H
69 |
70 |
71 |
--------------------------------------------------------------------------------
/src/common/AvifFormatTerminology.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef AVIFFORMATTERMINOLOGY_H
22 | #define AVIFFORMATTERMINOLOGY_H
23 |
24 | #include "PITerminology.h"
25 | #include "PIActions.h"
26 |
27 | #ifndef NULLID
28 | #define NULLID 0
29 | #endif
30 |
31 | // Dictionary (aete) resources:
32 |
33 | #define vendorName "0xC0000054"
34 | #define plugInAETEComment "AV1 Image format module"
35 |
36 | #define plugInSuiteID 'av1F'
37 | #define plugInClassID plugInSuiteID
38 | #define plugInEventID typeNull // must be this
39 |
40 | #define keyApplyHLGOOTF 'ooTf'
41 | #define keyHLGDisplayGamma keyGamma
42 | #define keyHLGNominalPeakBrightness keyBrightness
43 | #define keyPQNominalPeakBrightness 'pqBr'
44 |
45 | // keyQuality is defined in PITerminology.h
46 | #define keyCompressionSpeed 'av1S'
47 | #define keyLosslessCompression 'av1L'
48 | #define keyChromaSubsampling 'av1C'
49 | #define keyKeepColorProfile 'kpmC'
50 | #define keyKeepEXIF 'kpmE'
51 | #define keyKeepXMP 'kpmX'
52 | #define keyLosslessAlpha 'losA'
53 | #define keyPremultipliedAlpha 'pmAl'
54 | #define keyImageBitDepth 'av1B'
55 | #define keyHDRTransferFunction 'hTrf'
56 |
57 | #define typeCompressionSpeed 'coSp'
58 |
59 | #define compressionSpeedFastest 'csP0'
60 | #define compressionSpeedDefault 'csP1'
61 | #define compressionSpeedSlowest 'csP2'
62 |
63 | #define typeChromaSubsampling 'chSu'
64 |
65 | #define chromaSubsampling420 'chS0'
66 | #define chromaSubsampling422 'chS1'
67 | #define chromaSubsampling444 'chS2'
68 |
69 | #define typeImageBitDepth 'imBd'
70 |
71 | #define imageBitDepthEight 'iBd0'
72 | #define imageBitDepthTen 'iBd1'
73 | #define imageBitDepthTwelve 'iBd2'
74 |
75 | #define typeHDRTransferFunction 'hdRt'
76 | #define hdrTransferFunctionPQ 'trF0'
77 | //#define hdrTransferFunctionHLG 'trF1'
78 | #define hdrTransferFunctionSMPTE428 'trF2'
79 | #define hdrTransferFunctionClip 'trF3'
80 |
81 | #endif
82 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
65 | # GitHub Linguist override
66 | *.r linguist-language=C
67 |
--------------------------------------------------------------------------------
/src/win/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by AvifFormat.rc
4 | //
5 | #define IDD_SAVE 101
6 | #define IDD_ABOUT 102
7 | #define IDS_CHROMA_SUBSAMPLING_420 105
8 | #define IDS_CHROMA_SUBSAMPLING_422 106
9 | #define IDD_HLGLOAD 106
10 | #define IDS_CHROMA_SUBSAMPLING_444 107
11 | #define IDS_CHROMA_SUBSAMPLING_400 108
12 | #define IDD_PQLOAD 108
13 | #define IDS_HDR_TRANSFER_CHARACTERISTICS_CLIP 109
14 | #define IDC_QUALITY 1000
15 | #define IDC_QUALITY_SLIDER 1000
16 | #define ABOUTFORMAT 1001
17 | #define IDC_QUALITYGB 1001
18 | #define IDC_ABOUTOK 1002
19 | #define IDC_QUALITY_EDIT 1003
20 | #define IDC_QUALITY_EDIT_SPIN 1004
21 | #define IDC_LOSSLESS_CHECK 1005
22 | #define IDC_COMPRESSION_SPEED_GROUP 1006
23 | #define IDC_COMPRESSION_SPEED_FASTEST_RADIO 1007
24 | #define IDC_COMPRESSION_SPEED_DEFAULT_RADIO 1008
25 | #define IDC_COMPRESSION_SPEED_SLOWEST_RADIO 1009
26 | #define IDC_CHROMA_SUBSAMPLING_GROUP 1010
27 | #define IDC_CHROMA_SUBSAMPLING_COMBO 1011
28 | #define IDC_METADATA_GROUP 1012
29 | #define IDC_KEEP_COLOR_PROFILE_CHECK 1013
30 | #define IDC_KEEP_EXIF_CHECK 1014
31 | #define IDC_KEEP_XMP_CHECK 1015
32 | #define IDC_IMAGE_DEPTH_GROUP 1016
33 | #define IDC_IMAGE_DEPTH_COMBO 1017
34 | #define IDC_PROJECT_HOMEPAGE_LINK 1018
35 | #define IDC_CREDITS_LINK 1019
36 | #define IDC_LIBHEIFVERSION 1020
37 | #define IDC_AOMVERSION 1021
38 | #define IDC_PREMULTIPLIED_ALPHA_CHECK 1022
39 | #define IDC_ALPHAOPTIONS 1023
40 | #define IDC_LOSSLESS_ALPHA_CHECK 1024
41 | #define IDC_HDRINFOLABEL 1025
42 | #define IDC_CHROMA_SUBSAMPLING_LABEL 1026
43 | #define IDC_IMAGE_DEPTH_LABEL 1027
44 | #define IDC_HDR_OPTIONS 1028
45 | #define IDC_HDR_TRANSFER_CHARACTERISTICS_LABEL 1029
46 | #define IDC_HDR_TRANSFER_CHARACTERISTICS_COMBO 1030
47 | #define IDC_APPLY_HLG_OOTF 1031
48 | #define IDC_DISPLAY_GAMMA_LABEL 1032
49 | #define IDC_DISPLAY_GAMMA_EDIT 1033
50 | #define IDC_PEAK_BRIGHTNESS_LABEL 1034
51 | #define IDC_PEAK_BRIGHTNESS_EDIT 1035
52 | #define IDC_PEAK_BRIGHTNESS_SPIN 1036
53 | #define IDC_PEAK_BRIGHTNESS_UNIT_LABEL 1037
54 |
55 | // Next default values for new objects
56 | //
57 | #ifdef APSTUDIO_INVOKED
58 | #ifndef APSTUDIO_READONLY_SYMBOLS
59 | #define _APS_NEXT_RESOURCE_VALUE 110
60 | #define _APS_NEXT_COMMAND_VALUE 40001
61 | #define _APS_NEXT_CONTROL_VALUE 1038
62 | #define _APS_NEXT_SYMED_VALUE 101
63 | #endif
64 | #endif
65 |
--------------------------------------------------------------------------------
/src/common/Estimate.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "AvifFormat.h"
22 | #include
23 |
24 | namespace
25 | {
26 | int32 EstimateUncompressedSize(const FormatRecordPtr formatRecord)
27 | {
28 | VPoint imageSize = GetImageSize(formatRecord);
29 |
30 | const unsigned64 width = static_cast(imageSize.h);
31 | const unsigned64 height = static_cast(imageSize.v);
32 |
33 | unsigned64 imageDataSize = width * height * static_cast(formatRecord->planes);
34 |
35 | if (formatRecord->depth == 16 || formatRecord->depth == 32)
36 | {
37 | imageDataSize *= 2; // 2 bytes per pixel.
38 | }
39 |
40 | // Assume that the AVIF format overhead is 512 bytes.
41 |
42 | unsigned64 totalSize = 512 + imageDataSize;
43 |
44 | return static_cast(std::min(totalSize, static_cast(std::numeric_limits::max())));
45 | }
46 | }
47 |
48 | OSErr DoEstimatePrepare(FormatRecordPtr formatRecord)
49 | {
50 | PrintFunctionName();
51 |
52 | OSErr err = noErr;
53 |
54 | if (!HostSupportsRequiredFeatures(formatRecord))
55 | {
56 | err = errPlugInHostInsufficient;
57 | }
58 | else if (!HostImageModeSupported(formatRecord))
59 | {
60 | err = formatBadParameters;
61 | }
62 |
63 | if (err == noErr)
64 | {
65 | formatRecord->maxData = 0;
66 | }
67 |
68 | return err;
69 | }
70 |
71 | OSErr DoEstimateStart(FormatRecordPtr formatRecord)
72 | {
73 | PrintFunctionName();
74 |
75 | const int32 uncompressedSize = EstimateUncompressedSize(formatRecord);
76 |
77 | formatRecord->minDataBytes = uncompressedSize / 2;
78 | formatRecord->maxDataBytes = uncompressedSize;
79 | formatRecord->data = nullptr;
80 |
81 | return noErr;
82 | }
83 |
84 | OSErr DoEstimateContinue()
85 | {
86 | PrintFunctionName();
87 |
88 | return noErr;
89 | }
90 |
91 | OSErr DoEstimateFinish()
92 | {
93 | PrintFunctionName();
94 |
95 | return noErr;
96 | }
97 |
--------------------------------------------------------------------------------
/src/common/Memory.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "AvifFormat.h"
22 |
23 | #if __PIWin__
24 | #include "MemoryWin.h"
25 | #else
26 | #include "LowMem.h"
27 | #endif // __PIWin__
28 |
29 | // The following methods were adapted from the Host*Handle methods in the PS6 SDK:
30 |
31 | OSErr NewPIHandle(const FormatRecordPtr formatRecord, int32 size, Handle* handle)
32 | {
33 | if (handle == nullptr)
34 | {
35 | return nilHandleErr;
36 | }
37 |
38 | if (HandleSuiteIsAvailable(formatRecord))
39 | {
40 | *handle = formatRecord->handleProcs->newProc(size);
41 | }
42 | else
43 | {
44 | *handle = NewHandle(size);
45 | }
46 |
47 | return *handle != nullptr ? noErr : memFullErr;
48 | }
49 |
50 | void DisposePIHandle(const FormatRecordPtr formatRecord, Handle handle)
51 | {
52 | if (HandleSuiteIsAvailable(formatRecord))
53 | {
54 | formatRecord->handleProcs->disposeProc(handle);
55 | }
56 | else
57 | {
58 | DisposeHandle(handle);
59 | }
60 | }
61 |
62 | Ptr LockPIHandle(const FormatRecordPtr formatRecord, Handle handle, Boolean moveHigh)
63 | {
64 | if (HandleSuiteIsAvailable(formatRecord))
65 | {
66 | return formatRecord->handleProcs->lockProc(handle, moveHigh);
67 | }
68 | else
69 | {
70 | // Use OS routines:
71 |
72 | #ifdef __PIMac__
73 | if (moveHigh)
74 | MoveHHi(handle);
75 | HLock(handle);
76 |
77 | return *handle; // dereference and return pointer
78 |
79 | #else // Windows
80 |
81 | return (Ptr)GlobalLock(handle);
82 |
83 | #endif
84 | }
85 | }
86 |
87 | void UnlockPIHandle(const FormatRecordPtr formatRecord, Handle handle)
88 | {
89 | if (HandleSuiteIsAvailable(formatRecord))
90 | {
91 | formatRecord->handleProcs->unlockProc(handle);
92 | }
93 | else
94 | {
95 | // Use OS routines:
96 | #ifdef __PIMac__
97 |
98 | HUnlock(handle);
99 |
100 | #else // Windows
101 |
102 | GlobalUnlock(handle);
103 |
104 | #endif
105 | }
106 | }
107 |
108 |
--------------------------------------------------------------------------------
/src/common/HostMetadata.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "HostMetadata.h"
22 | #include "PIProperties.h"
23 |
24 | namespace
25 | {
26 | Handle GetComplexProperty(const FormatRecordPtr formatRecord, int32 propertyKey)
27 | {
28 | Handle handle = nullptr;
29 |
30 | if (formatRecord->propertyProcs->getPropertyProc(kPhotoshopSignature, propertyKey, 0, nullptr, &handle) != noErr)
31 | {
32 | handle = nullptr;
33 | }
34 |
35 | return handle;
36 | }
37 | }
38 |
39 | ScopedHandleSuiteHandle GetExifMetadata(const FormatRecordPtr formatRecord)
40 | {
41 | Handle exifHandle = nullptr;
42 |
43 | if (HandleSuiteIsAvailable(formatRecord) && PropertySuiteIsAvailable(formatRecord))
44 | {
45 | exifHandle = GetComplexProperty(formatRecord, propEXIFData);
46 | }
47 |
48 | return ScopedHandleSuiteHandle(formatRecord->handleProcs, exifHandle);
49 | }
50 |
51 | ScopedHandleSuiteHandle GetXmpMetadata(const FormatRecordPtr formatRecord)
52 | {
53 | Handle xmpHandle = nullptr;
54 |
55 | if (HandleSuiteIsAvailable(formatRecord) && PropertySuiteIsAvailable(formatRecord))
56 | {
57 | xmpHandle = GetComplexProperty(formatRecord, propXMP);
58 | }
59 |
60 | return ScopedHandleSuiteHandle(formatRecord->handleProcs, xmpHandle);
61 | }
62 |
63 | bool HasColorProfileMetadata(const FormatRecordPtr formatRecord)
64 | {
65 | return (HandleSuiteIsAvailable(formatRecord) &&
66 | formatRecord->canUseICCProfiles &&
67 | formatRecord->iCCprofileData != nullptr &&
68 | formatRecord->iCCprofileSize > 0);
69 | }
70 |
71 | bool HasExifMetadata(const FormatRecordPtr formatRecord)
72 | {
73 | bool result = false;
74 |
75 | ScopedHandleSuiteHandle exif = GetExifMetadata(formatRecord);
76 |
77 | if (exif != nullptr)
78 | {
79 | result = exif.size() > 0;
80 | }
81 |
82 | return result;
83 | }
84 |
85 | bool HasXmpMetadata(const FormatRecordPtr formatRecord)
86 | {
87 | bool result = false;
88 |
89 | ScopedHandleSuiteHandle xmp = GetXmpMetadata(formatRecord);
90 |
91 | if (xmp != nullptr)
92 | {
93 | result = xmp.size() > 0;
94 | }
95 |
96 | return result;
97 | }
98 |
--------------------------------------------------------------------------------
/3rd-party/README.md:
--------------------------------------------------------------------------------
1 | This directory contains the 3rd-party dependencies required to build the plug-in.
2 |
3 | ### Adobe Photoshop Plug-In and Connection SDK
4 |
5 | You will need to download the latest Adobe Photoshop Plug-In and Connection SDK from http://www.adobe.com/devnet/photoshop/sdk.html and unzip it into this folder.
6 | Extract the downloaded SDK and rename the folder to `adobe_photoshop_sdk`.
7 |
8 | ### AOM
9 |
10 | Clone AOM from your preferred tag:
11 |
12 | `git clone -b v3.6.0 --depth 1 https://aomedia.googlesource.com/aom`
13 |
14 | Change into the `aom` directory and create a build directory.
15 |
16 | `cd aom`
17 |
18 | The build directory name and CMake build commands will depend on the target platform.
19 |
20 | Windows x86 (32-bit):
21 |
22 | `mkdir build-x86 && cd build-x86`
23 | `cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_BUILD_TYPE=Release -DENABLE_DOCS=0 -DENABLE_EXAMPLES=0 -DENABLE_TESTDATA=0 -DENABLE_TESTS=0 -DENABLE_TOOLS=0 ..`
24 | `cmake --build .`
25 |
26 | Windows x64:
27 |
28 | `mkdir build-x64 && cd build-x64`
29 | `cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release -DENABLE_DOCS=0 -DENABLE_EXAMPLES=0 -DENABLE_TESTDATA=0 -DENABLE_TESTS=0 -DENABLE_TOOLS=0 ..`
30 | `cmake --build .`
31 |
32 | Windows ARM64:
33 |
34 | `mkdir build-arm64 && cd build-arm64`
35 | `cmake -G "Visual Studio 16 2019" -A ARM64 -DCMAKE_SYSTEM_PROCESSOR=arm64 -DCONFIG_RUNTIME_CPU_DETECT=0 -DAOM_TARGET_CPU=generic -DCMAKE_BUILD_TYPE=Release -DENABLE_DOCS=0 -DENABLE_EXAMPLES=0 -DENABLE_TESTDATA=0 -DENABLE_TESTS=0 -DENABLE_TOOLS=0 ..`
36 | `cmake --build .`
37 |
38 | The generated AOM library should be located in `aom/build-/Release`, this library will be used when building `libheif`.
39 |
40 | ### libheif
41 |
42 | Clone libheif from your preferred tag:
43 |
44 | `git clone -b v1.14.0 --depth 1 https://github.com/strukturag/libheif`
45 |
46 | Change into the `libheif` directory and create a build directory.
47 |
48 | `cd libheif`
49 |
50 | The build directory name and CMake build commands will depend on the target platform.
51 |
52 | Windows x86 (32-bit):
53 |
54 | `mkdir build-x86 && cd build-x86`
55 | `cmake -G "Visual Studio 16 2019" -A Win32 -DBUILD_SHARED_LIBS=OFF -DWITH_EXAMPLES=OFF -DAOM_INCLUDE_DIR=..\..\aom -DAOM_LIBRARY=..\..\aom\build-x86\Release\aom.lib ..`
56 | `cmake --build .`
57 |
58 | Windows x64:
59 |
60 | `mkdir build-x64 && cd build-x64`
61 | `cmake -G "Visual Studio 16 2019" -A x64 -DBUILD_SHARED_LIBS=OFF -DWITH_EXAMPLES=OFF -DAOM_INCLUDE_DIR=..\..\aom -DAOM_LIBRARY=..\..\aom\build-x64\Release\aom.lib ..`
62 | `cmake --build .`
63 |
64 | Windows ARM64:
65 |
66 | `mkdir build-arm64 && cd build-arm64`
67 | `cmake -G "Visual Studio 16 2019" -A ARM64 -DBUILD_SHARED_LIBS=OFF -DWITH_EXAMPLES=OFF -DAOM_INCLUDE_DIR=..\..\aom -DAOM_LIBRARY=..\..\aom\build-arm64\Release\aom.lib ..`
68 | `cmake --build .
69 |
70 | You will need to add `LIBHEIF_STATIC_BUILD` to the preprocessor settings page in the libheif project properties,
71 | and remove the `HAS_VISIBILITY` definition if present.
72 |
73 | The generated libheif library should be located in `libheif/build-/Release`.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # avif-format
2 |
3 | An AV1 Image (AVIF) file format plug-in for Adobe® Photoshop®.
4 |
5 | Single images can be loaded and saved using 8, 10 or 12 bits-per-channel, image sequences and animations are not supported.
6 |
7 | Monochrome images will be loaded using the Grayscale image mode.
8 | To save an image as monochrome the document must be using the Grayscale image mode (either 8-bit or 16-bit).
9 |
10 | HDR files that use the Rec. 2100 PQ, Rec. 2100 HLG and SMPTE 428-1 transfer characteristics can be loaded and edited as 32-bits-per-channel documents.
11 |
12 | 32-bits-per-channel RGB documents can be saved as HDR AVIF files using the following transfer characteristics and bit-depths:
13 | * Rec. 2100 PQ using either 10-bits-per-channel or 12-bits-per-channel.
14 | * SMPTE 428-1 using 12-bits-per-channel.
15 |
16 | 32-bits-per-channel documents can also be saved as 10-bit or 12-bit SDR AVIF files using the `None, clip` transfer characteristic.
17 |
18 | The support for HDR images with an alpha channel (transparency) may differ between applications.
19 | While this plug-in can load and save HDR images that include transparency, it may not be handled correctly by other applications.
20 | It is also possible that this plug-in may not correctly handle HDR images that include transparency from other applications.
21 |
22 | This plug-in uses [libheif](https://github.com/strukturag/libheif) with the [AOM](https://aomedia.googlesource.com/aom/) decoder and encoder.
23 |
24 | The latest version can be downloaded from the [Releases](https://github.com/0xC0000054/avif-format/releases) tab.
25 |
26 | ### System Requirements
27 |
28 | * Windows 7, 8, 10 or 11.
29 | * A compatible 32-bit or 64-bit host application.
30 |
31 | ## Installation
32 |
33 | 1. Close your host application.
34 | 2. Place `Av1Image.8bi` in the folder that your host application searches for file format plug-ins.
35 | 3. Restart your host application.
36 | 4. The plug-in will now be available as the `AV1 Image` item in the Open and Save dialogs.
37 |
38 | ### Installation in Specific Hosts
39 |
40 | #### Photoshop
41 |
42 | Photoshop CC common install folder: `C:\Program Files\Common Files\Adobe\Plug-ins\CC`
43 | Version-specific install folder: `C:\Program Files\Adobe\Photoshop [version]\Plug-ins`
44 |
45 | ### Updating
46 |
47 | Follow the installation instructions above and allow any existing files to be replaced.
48 |
49 | ## License
50 |
51 | This project is licensed under the terms of the GNU Lesser General Public License version 3.0.
52 | See [License.md](License.md) for more information.
53 |
54 | # Source code
55 |
56 | ## Prerequisites
57 |
58 | * Visual Studio 2019
59 | * The dependencies in the 3rd-party folder, see the [read-me](3rd-party/README.md) in that folder for more details.
60 |
61 | ## Building the plug-in
62 |
63 | * Open the solution in the `vs` folder
64 | * Update the post build events to copy the build output to the file formats folder of your host application
65 | * Build the solution
66 |
67 | ```
68 | Adobe and Photoshop are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries.
69 | Windows is a registered trademark of Microsoft Corporation in the United States and other countries.
70 | All other trademarks are the property of their respective owners.
71 | ```
--------------------------------------------------------------------------------
/src/win/FileIOWin.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "FileIOWin.h"
22 | #include
23 |
24 | OSErr GetFilePositionNative(intptr_t refNum, int64& position)
25 | {
26 | LARGE_INTEGER distanceToMove;
27 | distanceToMove.QuadPart = 0;
28 |
29 | LARGE_INTEGER currentFilePosition;
30 |
31 | if (!SetFilePointerEx(reinterpret_cast(refNum), distanceToMove, ¤tFilePosition, FILE_CURRENT))
32 | {
33 | return readErr;
34 | }
35 |
36 | position = currentFilePosition.QuadPart;
37 | return noErr;
38 | }
39 |
40 | OSErr GetFileSizeNative(intptr_t refNum, int64& size)
41 | {
42 | LARGE_INTEGER currentFileSize;
43 |
44 | if (!GetFileSizeEx(reinterpret_cast(refNum), ¤tFileSize))
45 | {
46 | return readErr;
47 | }
48 |
49 | size = currentFileSize.QuadPart;
50 | return noErr;
51 | }
52 |
53 | OSErr ReadDataNative(intptr_t refNum, void* buffer, size_t size)
54 | {
55 | size_t totalBytesRead = 0;
56 |
57 | HANDLE hFile = reinterpret_cast(refNum);
58 |
59 | uint8_t* dataBuffer = static_cast(buffer);
60 |
61 | while (totalBytesRead < size)
62 | {
63 | DWORD bytesToRead = static_cast(std::min(size - totalBytesRead, static_cast(2147483648)));
64 |
65 | DWORD bytesRead;
66 |
67 | if (!ReadFile(hFile, dataBuffer + totalBytesRead, bytesToRead, &bytesRead, nullptr))
68 | {
69 | return readErr;
70 | }
71 |
72 | if (bytesRead == 0)
73 | {
74 | return eofErr;
75 | }
76 |
77 | totalBytesRead += bytesRead;
78 | }
79 |
80 | return noErr;
81 | }
82 |
83 | OSErr SetFilePositionNative(intptr_t refNum, int64 position)
84 | {
85 | LARGE_INTEGER distanceToMove;
86 | distanceToMove.QuadPart = position;
87 |
88 | if (!SetFilePointerEx(reinterpret_cast(refNum), distanceToMove, nullptr, FILE_BEGIN))
89 | {
90 | return readErr;
91 | }
92 |
93 | return noErr;
94 | }
95 |
96 | OSErr WriteDataNative(intptr_t refNum, const void* buffer, size_t size)
97 | {
98 | size_t totalBytesWritten = 0;
99 |
100 | HANDLE hFile = reinterpret_cast(refNum);
101 |
102 | const uint8_t* dataBuffer = static_cast(buffer);
103 |
104 | while (totalBytesWritten < size)
105 | {
106 | DWORD bytesToWrite = static_cast(std::min(size - totalBytesWritten, static_cast(2147483648)));
107 |
108 | DWORD bytesWritten;
109 |
110 | if (!WriteFile(hFile, dataBuffer + totalBytesWritten, bytesToWrite, &bytesWritten, nullptr))
111 | {
112 | return writErr;
113 | }
114 |
115 | if (bytesWritten != bytesToWrite)
116 | {
117 | return writErr;
118 | }
119 |
120 | totalBytesWritten += bytesWritten;
121 | }
122 |
123 | return noErr;
124 | }
125 |
--------------------------------------------------------------------------------
/src/common/PremultipliedAlpha.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 | // Portions of this file has been adapted from libavif, https://github.com/AOMediaCodec/libavif
21 | /*
22 | Copyright 2020 Joe Drago. All rights reserved.
23 |
24 | Redistribution and use in source and binary forms, with or without
25 | modification, are permitted provided that the following conditions are met:
26 |
27 | 1. Redistributions of source code must retain the above copyright notice, this
28 | list of conditions and the following disclaimer.
29 |
30 | 2. Redistributions in binary form must reproduce the above copyright notice,
31 | this list of conditions and the following disclaimer in the documentation
32 | and/or other materials provided with the distribution.
33 |
34 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
35 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
38 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
40 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
43 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 | */
45 |
46 | #include "PremultipliedAlpha.h"
47 | #include
48 |
49 | float PremultiplyColor(float color, float alpha, float maxValue)
50 | {
51 | return color * alpha / maxValue;
52 | }
53 |
54 | uint8_t PremultiplyColor(uint8_t color, uint8_t alpha)
55 | {
56 | constexpr float maxValueFloat = 255.0f;
57 |
58 | const float value = PremultiplyColor(static_cast(color), static_cast(alpha), maxValueFloat);
59 |
60 | return static_cast(std::min(roundf(value), maxValueFloat));
61 | }
62 |
63 | uint16_t PremultiplyColor(uint16_t color, uint16_t alpha, uint16_t maxValue)
64 | {
65 | const float maxValueFloat = static_cast(maxValue);
66 |
67 | const float value = PremultiplyColor(static_cast(color), static_cast(alpha), maxValueFloat);
68 |
69 | return static_cast(std::min(roundf(value), maxValueFloat));
70 | }
71 |
72 | float UnpremultiplyColor(float color, float alpha, float maxValue)
73 | {
74 | return std::min(color * maxValue / alpha, maxValue);
75 | }
76 |
77 | uint8_t UnpremultiplyColor(uint8_t color, uint8_t alpha)
78 | {
79 | constexpr float maxValueFloat = 255.0f;
80 |
81 | const float value = UnpremultiplyColor(static_cast(color), static_cast(alpha), maxValueFloat);
82 |
83 | return static_cast(std::min(roundf(value), maxValueFloat));
84 | }
85 |
86 | uint16_t UnpremultiplyColor(uint16_t color, uint16_t alpha, uint16_t maxValue)
87 | {
88 | const float maxValueFloat = static_cast(maxValue);
89 |
90 | const float value = UnpremultiplyColor(static_cast(color), static_cast(alpha), maxValueFloat);
91 |
92 | return static_cast(std::min(roundf(value), maxValueFloat));
93 | }
94 |
--------------------------------------------------------------------------------
/src/common/ScopedBufferSuite.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef SCOPEDBUFFERSUITE_H
22 | #define SCOPEDBUFFERSUITE_H
23 |
24 | #include "Common.h"
25 | #include "OSErrException.h"
26 | #include
27 |
28 | class ScopedBufferSuiteBuffer
29 | {
30 | public:
31 | explicit ScopedBufferSuiteBuffer()
32 | : bufferID(), bufferProcs(nullptr), bufferIDValid(false),
33 | bufferDataPtr(nullptr), allocatedSize(0)
34 | {
35 | }
36 |
37 | explicit ScopedBufferSuiteBuffer(BufferProcs* bufferProcs, int32 bufferSize)
38 | : bufferID(), bufferProcs(bufferProcs), bufferIDValid(false),
39 | bufferDataPtr(nullptr), allocatedSize(bufferSize)
40 | {
41 | OSErrException::ThrowIfError(bufferProcs->allocateProc(bufferSize, &bufferID));
42 | bufferIDValid = true;
43 | }
44 |
45 | ScopedBufferSuiteBuffer(ScopedBufferSuiteBuffer&& other) noexcept
46 | : bufferID(other.bufferID), bufferProcs(other.bufferProcs), bufferIDValid(other.bufferIDValid),
47 | bufferDataPtr(other.bufferDataPtr), allocatedSize(other.allocatedSize)
48 | {
49 | other.bufferDataPtr = nullptr;
50 | other.bufferIDValid = false;
51 | }
52 |
53 | ScopedBufferSuiteBuffer& operator=(ScopedBufferSuiteBuffer&& other) noexcept
54 | {
55 | bufferID = other.bufferID;
56 | bufferProcs = other.bufferProcs;
57 | bufferIDValid = other.bufferIDValid;
58 | bufferDataPtr = other.bufferDataPtr;
59 | allocatedSize = other.allocatedSize;
60 |
61 | other.bufferDataPtr = nullptr;
62 | other.bufferIDValid = false;
63 |
64 | return *this;
65 | }
66 |
67 | ScopedBufferSuiteBuffer(const ScopedBufferSuiteBuffer&) = delete;
68 | ScopedBufferSuiteBuffer& operator=(const ScopedBufferSuiteBuffer&) = delete;
69 |
70 | ~ScopedBufferSuiteBuffer()
71 | {
72 | reset();
73 | }
74 |
75 | int32 size() const noexcept
76 | {
77 | return allocatedSize;
78 | }
79 |
80 | void* lock()
81 | {
82 | if (!bufferIDValid)
83 | {
84 | throw std::runtime_error("Cannot Lock an invalid buffer.");
85 | }
86 |
87 | if (bufferDataPtr == nullptr)
88 | {
89 | bufferDataPtr = bufferProcs->lockProc(bufferID, false);
90 |
91 | if (bufferDataPtr == nullptr)
92 | {
93 | throw std::runtime_error("Unable to lock the BufferSuite buffer.");
94 | }
95 | }
96 |
97 | return bufferDataPtr;
98 | }
99 |
100 | bool operator==(std::nullptr_t) const noexcept
101 | {
102 | return !bufferIDValid;
103 | }
104 |
105 | bool operator!=(std::nullptr_t) const noexcept
106 | {
107 | return bufferIDValid;
108 | }
109 |
110 | explicit operator bool() const noexcept
111 | {
112 | return bufferIDValid;
113 | }
114 |
115 | private:
116 |
117 | void reset() noexcept
118 | {
119 | if (bufferIDValid)
120 | {
121 | bufferIDValid = false;
122 | allocatedSize = 0;
123 | if (bufferDataPtr != nullptr)
124 | {
125 | bufferProcs->unlockProc(bufferID);
126 | bufferDataPtr = nullptr;
127 | }
128 | bufferProcs->freeProc(bufferID);
129 | }
130 | }
131 |
132 | const BufferProcs* bufferProcs;
133 | BufferID bufferID;
134 | void* bufferDataPtr;
135 | int32 allocatedSize;
136 | bool bufferIDValid;
137 | };
138 |
139 | #endif
140 |
--------------------------------------------------------------------------------
/src/common/YUVDecode.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef YUVDECODE_H
22 | #define YUVDECODE_H
23 |
24 | #include "AvifFormat.h"
25 | #include "ColorTransfer.h"
26 | #include "YUVCoefficiants.h"
27 | #include "YUVLookupTables.h"
28 |
29 | void DecodeY8RowToGray8(
30 | const uint8_t* yPlane,
31 | uint8_t* grayRow,
32 | int32 rowWidth,
33 | const YUVLookupTables& tables);
34 |
35 | void DecodeY8RowToGrayAlpha8(
36 | const uint8_t* yPlane,
37 | const uint8_t* alphaPlane,
38 | bool alphaPremultiplied,
39 | uint8_t* grayaRow,
40 | int32 rowWidth,
41 | const YUVLookupTables& tables);
42 |
43 | void DecodeY16RowToGray16(
44 | const uint16_t* yPlane,
45 | uint16_t* grayRow,
46 | int32 rowWidth,
47 | const YUVLookupTables& tables);
48 |
49 | void DecodeY16RowToGrayAlpha16(
50 | const uint16_t* yPlane,
51 | const uint16_t* alphaPlane,
52 | bool alphaPremultiplied,
53 | uint16_t* grayaRow,
54 | int32 rowWidth,
55 | const YUVLookupTables& tables);
56 |
57 | void DecodeY16RowToGray32(
58 | const uint16_t* yPlane,
59 | float* grayRow,
60 | int32 rowWidth,
61 | const YUVLookupTables& tables,
62 | ColorTransferFunction transferFunction,
63 | const LoadUIOptions& loadOptions);
64 |
65 | void DecodeY16RowToGrayAlpha32(
66 | const uint16_t* yPlane,
67 | const uint16_t* alphaPlane,
68 | bool alphaPremultiplied,
69 | float* grayaRow,
70 | int32 rowWidth,
71 | const YUVLookupTables& tables,
72 | ColorTransferFunction transferFunction,
73 | const LoadUIOptions& loadOptions);
74 |
75 | void DecodeYUV8RowToRGB8(
76 | const uint8_t* yPlane,
77 | const uint8_t* uPlane,
78 | const uint8_t* vPlane,
79 | uint8_t* rgbRow,
80 | int32 rowWidth,
81 | int32 xChromaShift,
82 | const YUVCoefficiants& yuvCoefficiants,
83 | const YUVLookupTables& tables);
84 |
85 | void DecodeYUV8RowToRGBA8(
86 | const uint8_t* yPlane,
87 | const uint8_t* uPlane,
88 | const uint8_t* vPlane,
89 | const uint8_t* alphaPlane,
90 | bool alphaPremultiplied,
91 | uint8_t* rgbaRow,
92 | int32 rowWidth,
93 | int32 xChromaShift,
94 | const YUVCoefficiants& yuvCoefficiants,
95 | const YUVLookupTables& tables);
96 |
97 | void DecodeYUV16RowToRGB16(
98 | const uint16_t* yPlane,
99 | const uint16_t* uPlane,
100 | const uint16_t* vPlane,
101 | uint16_t* rgbRow,
102 | int32 rowWidth,
103 | int32 xChromaShift,
104 | const YUVCoefficiants& yuvCoefficiants,
105 | const YUVLookupTables& tables);
106 |
107 | void DecodeYUV16RowToRGBA16(
108 | const uint16_t* yPlane,
109 | const uint16_t* uPlane,
110 | const uint16_t* vPlane,
111 | const uint16_t* alphaRow,
112 | bool alphaPremultiplied,
113 | uint16_t* rgbaRow,
114 | int32 rowWidth,
115 | int32 xChromaShift,
116 | const YUVCoefficiants& yuvCoefficiants,
117 | const YUVLookupTables& tables);
118 |
119 | void DecodeYUV16RowToRGB32(
120 | const uint16_t* yPlane,
121 | const uint16_t* uPlane,
122 | const uint16_t* vPlane,
123 | float* rgbRow,
124 | int32 rowWidth,
125 | int32 xChromaShift,
126 | const YUVCoefficiants& yuvCoefficiants,
127 | const YUVLookupTables& tables,
128 | ColorTransferFunction transferFunction,
129 | const LoadUIOptions& loadOptions,
130 | const HLGLumaCoefficiants& hlgLumaCoefficiants);
131 |
132 | void DecodeYUV16RowToRGBA32(
133 | const uint16_t* yPlane,
134 | const uint16_t* uPlane,
135 | const uint16_t* vPlane,
136 | const uint16_t* alphaPlane,
137 | bool alphaPremultiplied,
138 | float* rgbaRow,
139 | int32 rowWidth,
140 | int32 xChromaShift,
141 | const YUVCoefficiants& yuvCoefficiants,
142 | const YUVLookupTables& tables,
143 | ColorTransferFunction transferFunction,
144 | const LoadUIOptions& loadOptions,
145 | const HLGLumaCoefficiants& hlgLumaCoefficiants);
146 |
147 | #endif // !YUVDECODE_H
148 |
--------------------------------------------------------------------------------
/src/common/ScopedHandleSuite.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef SCOPEDHANDLESUITE_H
22 | #define SCOPEDHANDLESUITE_H
23 |
24 | #include "AvifFormat.h"
25 | #include
26 |
27 | class ScopedHandleSuiteLock
28 | {
29 | public:
30 | ScopedHandleSuiteLock(const HandleProcs* handleProcs, Handle handle)
31 | : handleProcs(handleProcs), handle(handle),
32 | ptr(handleProcs->lockProc(handle, false))
33 | {
34 | }
35 |
36 | ScopedHandleSuiteLock(ScopedHandleSuiteLock&& other) noexcept
37 | : handleProcs(other.handleProcs), handle(other.handle), ptr(other.ptr)
38 | {
39 | other.ptr = nullptr;
40 | }
41 |
42 | ScopedHandleSuiteLock& operator=(ScopedHandleSuiteLock&& other) noexcept
43 | {
44 | handleProcs = other.handleProcs;
45 | handle = other.handle;
46 | ptr = other.ptr;
47 |
48 | other.ptr = nullptr;
49 |
50 | return *this;
51 | }
52 |
53 | ScopedHandleSuiteLock(const ScopedHandleSuiteLock&) = delete;
54 | ScopedHandleSuiteLock& operator=(const ScopedHandleSuiteLock&) = delete;
55 |
56 | ~ScopedHandleSuiteLock()
57 | {
58 | unlock();
59 | }
60 |
61 | Ptr data() const
62 | {
63 | if (ptr == nullptr)
64 | {
65 | throw std::runtime_error("The locked data pointer is invalid.");
66 | }
67 |
68 | return ptr;
69 | }
70 |
71 | void unlock()
72 | {
73 | if (ptr != nullptr)
74 | {
75 | handleProcs->unlockProc(handle);
76 | ptr = nullptr;
77 | }
78 | }
79 |
80 | private:
81 | const HandleProcs* handleProcs;
82 | Handle handle;
83 | Ptr ptr;
84 | };
85 |
86 | class ScopedHandleSuiteHandle
87 | {
88 | public:
89 | ScopedHandleSuiteHandle(const HandleProcs* handleProcs, Handle handle) noexcept
90 | : handleProcs(handleProcs), handle(handle)
91 | {
92 | }
93 |
94 | ScopedHandleSuiteHandle(const HandleProcs* handleProcs, int32 size)
95 | : handleProcs(handleProcs), handle(handleProcs->newProc(size))
96 | {
97 | if (handle == nullptr)
98 | {
99 | // Failed to allocate the handle, this is treated as an out of memory error.
100 | throw std::bad_alloc();
101 | }
102 | }
103 |
104 | ScopedHandleSuiteHandle(ScopedHandleSuiteHandle&& other) noexcept
105 | : handleProcs(other.handleProcs), handle(other.handle)
106 | {
107 | other.handle = nullptr;
108 | }
109 |
110 | ScopedHandleSuiteHandle& operator=(ScopedHandleSuiteHandle&& other) noexcept
111 | {
112 | handleProcs = other.handleProcs;
113 | handle = other.handle;
114 |
115 | other.handle = nullptr;
116 |
117 | return *this;
118 | }
119 |
120 | ScopedHandleSuiteHandle(const ScopedHandleSuiteHandle&) = delete;
121 | ScopedHandleSuiteHandle& operator=(const ScopedHandleSuiteHandle&) = delete;
122 |
123 | ~ScopedHandleSuiteHandle()
124 | {
125 | if (handle != nullptr)
126 | {
127 | handleProcs->disposeProc(handle);
128 | handle = nullptr;
129 | }
130 | }
131 |
132 | Handle get() const noexcept
133 | {
134 | return handle;
135 | }
136 |
137 | int32 size() const
138 | {
139 | int32 allocatedSize = 0;
140 |
141 | if (handle != nullptr)
142 | {
143 | allocatedSize = handleProcs->getSizeProc(handle);
144 | }
145 |
146 | return allocatedSize;
147 | }
148 |
149 | ScopedHandleSuiteLock lock() const
150 | {
151 | if (handle == nullptr)
152 | {
153 | throw std::runtime_error("Cannot Lock an invalid handle.");
154 | }
155 |
156 | return ScopedHandleSuiteLock(handleProcs, handle);
157 | }
158 |
159 | // Returns the underlying handle and releases the ownership.
160 | Handle release()
161 | {
162 | Handle existing = handle;
163 | handle = nullptr;
164 |
165 | return existing;
166 | }
167 |
168 | bool operator==(std::nullptr_t) const noexcept
169 | {
170 | return handle == nullptr;
171 | }
172 |
173 | bool operator!=(std::nullptr_t) const noexcept
174 | {
175 | return handle != nullptr;
176 | }
177 |
178 | explicit operator bool() const noexcept
179 | {
180 | return handle != nullptr;
181 | }
182 |
183 | private:
184 | const HandleProcs* handleProcs;
185 | Handle handle;
186 | };
187 |
188 | #endif // !SCOPEDHANDLESUITE_H
189 |
--------------------------------------------------------------------------------
/src/common/ScopedLcms.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef SCOPEDLCMS_H
22 | #define SCOPEDLCMS_H
23 |
24 | #include "lcms2.h"
25 | #include
26 |
27 | namespace detail
28 | {
29 | struct mlu_deleter { void operator()(cmsMLU* h) noexcept { if (h) cmsMLUfree(h); } };
30 |
31 | struct tonecurve_deleter { void operator()(cmsToneCurve* h) noexcept { if (h) cmsFreeToneCurve(h); } };
32 | }
33 |
34 | using ScopedLcmsMLU = std::unique_ptr;
35 |
36 | using ScopedLcmsToneCurve = std::unique_ptr;
37 |
38 | struct ScopedLcmsContext
39 | {
40 | ScopedLcmsContext(cmsContext context) : context(context)
41 | {
42 | }
43 |
44 | ~ScopedLcmsContext()
45 | {
46 | if (context != nullptr)
47 | {
48 | cmsDeleteContext(context);
49 | context = nullptr;
50 | }
51 | }
52 |
53 | ScopedLcmsContext(ScopedLcmsContext&& other) noexcept
54 | {
55 | context = other.context;
56 | other.context = nullptr;
57 | }
58 |
59 | ScopedLcmsContext& operator=(ScopedLcmsContext&& other) noexcept
60 | {
61 | context = other.context;
62 | other.context = nullptr;
63 |
64 | return *this;
65 | }
66 |
67 | ScopedLcmsContext(const ScopedLcmsContext&) = delete;
68 | ScopedLcmsContext& operator=(const ScopedLcmsContext&) = delete;
69 |
70 | cmsContext get() const noexcept
71 | {
72 | return context;
73 | }
74 |
75 | explicit operator bool() const noexcept
76 | {
77 | return context != nullptr;
78 | }
79 |
80 | private:
81 |
82 | cmsContext context;
83 | };
84 |
85 | struct ScopedLcmsProfile
86 | {
87 | ScopedLcmsProfile() : profile(nullptr)
88 | {
89 | }
90 |
91 | ScopedLcmsProfile(cmsHPROFILE profile) : profile(profile)
92 | {
93 | }
94 |
95 | ScopedLcmsProfile(ScopedLcmsProfile&& other) noexcept
96 | {
97 | profile = other.profile;
98 | other.profile = nullptr;
99 | }
100 |
101 | ScopedLcmsProfile& operator=(ScopedLcmsProfile&& other) noexcept
102 | {
103 | profile = other.profile;
104 | other.profile = nullptr;
105 |
106 | return *this;
107 | }
108 |
109 | ScopedLcmsProfile(const ScopedLcmsProfile&) = delete;
110 | ScopedLcmsProfile& operator=(const ScopedLcmsProfile&) = delete;
111 |
112 | ~ScopedLcmsProfile()
113 | {
114 | reset();
115 | }
116 |
117 | cmsHPROFILE get() const noexcept
118 | {
119 | return profile;
120 | }
121 |
122 | void reset()
123 | {
124 | if (profile != nullptr)
125 | {
126 | cmsCloseProfile(profile);
127 | profile = nullptr;
128 | }
129 | }
130 |
131 | void reset(cmsHPROFILE newProfile)
132 | {
133 | reset();
134 |
135 | profile = newProfile;
136 | }
137 |
138 | explicit operator bool() const noexcept
139 | {
140 | return profile != nullptr;
141 | }
142 |
143 | private:
144 |
145 | cmsHPROFILE profile;
146 | };
147 |
148 | struct ScopedLcmsTransform
149 | {
150 | ScopedLcmsTransform() : transform(nullptr)
151 | {
152 | }
153 |
154 | ScopedLcmsTransform(cmsHTRANSFORM transform) : transform(transform)
155 | {
156 | }
157 |
158 | ScopedLcmsTransform(ScopedLcmsTransform&& other) noexcept
159 | {
160 | transform = other.transform;
161 | other.transform = nullptr;
162 | }
163 |
164 | ScopedLcmsTransform& operator=(ScopedLcmsTransform&& other) noexcept
165 | {
166 | transform = other.transform;
167 | other.transform = nullptr;
168 |
169 | return *this;
170 | }
171 |
172 | ScopedLcmsTransform(const ScopedLcmsTransform&) = delete;
173 | ScopedLcmsTransform& operator=(const ScopedLcmsTransform&) = delete;
174 |
175 | ~ScopedLcmsTransform()
176 | {
177 | reset();
178 | }
179 |
180 | cmsHTRANSFORM get() const noexcept
181 | {
182 | return transform;
183 | }
184 |
185 | void reset()
186 | {
187 | if (transform != nullptr)
188 | {
189 | cmsDeleteTransform(transform);
190 | transform = nullptr;
191 | }
192 | }
193 |
194 | void reset(cmsHTRANSFORM newTransform)
195 | {
196 | reset();
197 |
198 | transform = newTransform;
199 | }
200 |
201 | explicit operator bool() const noexcept
202 | {
203 | return transform != nullptr;
204 | }
205 |
206 | private:
207 |
208 | cmsHTRANSFORM transform;
209 | };
210 |
211 | #endif // !SCOPEDLCMS_H
212 |
--------------------------------------------------------------------------------
/src/common/AvifFormat.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #ifndef AVIFFORMAT_H
22 | #define AVIFFORMAT_H
23 |
24 | #include "Common.h"
25 | #include "ColorTransfer.h"
26 | #include "Utilities.h"
27 |
28 | enum class ChromaSubsampling
29 | {
30 | Yuv420,
31 | Yuv422,
32 | Yuv444
33 | };
34 |
35 | enum class CompressionSpeed
36 | {
37 | Fastest,
38 | Default,
39 | Slowest
40 | };
41 |
42 | enum class ImageBitDepth
43 | {
44 | Eight,
45 | Ten,
46 | Twelve
47 | };
48 |
49 | constexpr float displayGammaMin = 1.0f;
50 | constexpr float displayGammaMax = 3.0f;
51 |
52 | constexpr int nominalPeakBrightnessMin = 1;
53 | constexpr int nominalPeakBrightnessMax = 10000;
54 |
55 | // The PQ default brightness is 80 nits for compatibility with older images and Krita.
56 | // 80 nits is the sRGB reference viewing environment maximum luminance level
57 | // See the 'Screen luminance level' value in the sRGB reference viewing environment table
58 | // https://en.wikipedia.org/wiki/SRGB#Viewing_environment
59 | constexpr int pqDefaultBrightness = 80;
60 |
61 | struct HLGOptions
62 | {
63 | bool applyOOTF;
64 | float displayGamma;
65 | int nominalPeakBrightness;
66 | };
67 |
68 | struct PQOptions
69 | {
70 | int nominalPeakBrightness;
71 | };
72 |
73 | enum class LoadOptionsHDRFormat : int
74 | {
75 | Unknown = 0,
76 | HLG,
77 | PQ
78 | };
79 |
80 | struct LoadUIOptions
81 | {
82 | LoadOptionsHDRFormat format;
83 | HLGOptions hlg;
84 | PQOptions pq;
85 | };
86 |
87 | struct SaveUIOptions
88 | {
89 | int quality;
90 | ChromaSubsampling chromaSubsampling;
91 | CompressionSpeed compressionSpeed;
92 | ImageBitDepth imageBitDepth;
93 | ColorTransferFunction hdrTransferFunction;
94 | PQOptions pq;
95 | bool lossless;
96 | bool losslessAlpha;
97 | bool keepColorProfile;
98 | bool keepExif;
99 | bool keepXmp;
100 | bool premultipliedAlpha;
101 | };
102 |
103 | struct RevertInfo
104 | {
105 | int version;
106 |
107 | // Version 0 fields:
108 |
109 | HLGOptions hlg;
110 |
111 | // Version 1 fields:
112 |
113 | PQOptions pq;
114 | LoadOptionsHDRFormat format;
115 | };
116 |
117 | struct Globals
118 | {
119 | heif_context* context;
120 | heif_image_handle* imageHandle;
121 | heif_color_profile_nclx* imageHandleNclxProfile;
122 | heif_image* image;
123 | heif_color_profile_type imageHandleProfileType;
124 |
125 | LoadUIOptions loadOptions;
126 | SaveUIOptions saveOptions;
127 | bool libheifInitialized;
128 | };
129 |
130 | DLLExport MACPASCAL void PluginMain(
131 | const short selector,
132 | FormatRecordPtr formatParamBlock,
133 | intptr_t* data,
134 | short* result);
135 |
136 |
137 | OSErr HandleErrorMessage(FormatRecordPtr formatRecord, const char* const message, OSErr fallbackErrorCode);
138 |
139 | OSErr NewPIHandle(const FormatRecordPtr formatRecord, int32 size, Handle* handle);
140 | void DisposePIHandle(const FormatRecordPtr formatRecord, Handle handle);
141 | Ptr LockPIHandle(const FormatRecordPtr formatRecord, Handle handle, Boolean moveHigh);
142 | void UnlockPIHandle(const FormatRecordPtr formatRecord, Handle handle);
143 |
144 | // Platform-specific UI methods
145 |
146 | void DoAbout(const AboutRecordPtr aboutRecord);
147 | bool DoHLGLoadUI(const FormatRecordPtr formatRecord, LoadUIOptions& options);
148 | bool DoPQLoadUI(const FormatRecordPtr formatRecord, LoadUIOptions& options);
149 | bool DoSaveUI(const FormatRecordPtr formatRecord, SaveUIOptions& options);
150 | OSErr ShowErrorDialog(const FormatRecordPtr formatRecord, const char* const message, OSErr fallbackErrorCode);
151 |
152 | // File Format API callbacks
153 |
154 | OSErr DoReadPrepare(FormatRecordPtr formatRecord);
155 | OSErr DoReadStart(FormatRecordPtr formatRecord, Globals* globals);
156 | OSErr DoReadContinue(FormatRecordPtr formatRecord, Globals* globals);
157 | OSErr DoReadFinish(FormatRecordPtr formatRecord, Globals* globals);
158 |
159 | OSErr DoOptionsPrepare(FormatRecordPtr formatRecord);
160 | OSErr DoOptionsStart(FormatRecordPtr formatRecord, Globals* globals);
161 | OSErr DoOptionsContinue();
162 | OSErr DoOptionsFinish();
163 |
164 | OSErr DoEstimatePrepare(FormatRecordPtr formatRecord);
165 | OSErr DoEstimateStart(FormatRecordPtr formatRecord);
166 | OSErr DoEstimateContinue();
167 | OSErr DoEstimateFinish();
168 |
169 | OSErr DoWritePrepare(FormatRecordPtr formatRecord);
170 | OSErr DoWriteStart(FormatRecordPtr formatRecord, SaveUIOptions& options);
171 | OSErr DoWriteContinue();
172 | OSErr DoWriteFinish(FormatRecordPtr formatRecord, const SaveUIOptions& options);
173 |
174 | // Scripting
175 |
176 | OSErr ReadScriptParamsOnRead(FormatRecordPtr formatRecord, LoadUIOptions& options, Boolean* showDialog);
177 | OSErr WriteScriptParamsOnRead(FormatRecordPtr formatRecord, const LoadUIOptions& options);
178 |
179 | OSErr ReadScriptParamsOnWrite(FormatRecordPtr formatRecord, SaveUIOptions& options, Boolean* showDialog);
180 | OSErr WriteScriptParamsOnWrite(FormatRecordPtr formatRecord, const SaveUIOptions& options);
181 |
182 | #endif // !AVIFFORMAT_H
183 |
--------------------------------------------------------------------------------
/src/common/ReadMetadata.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "ReadMetadata.h"
22 | #include "ExifParser.h"
23 | #include "LibHeifException.h"
24 | #include "OSErrException.h"
25 | #include "PIProperties.h"
26 | #include "ScopedBufferSuite.h"
27 | #include "ScopedHandleSuite.h"
28 | #include
29 | #include
30 |
31 | namespace
32 | {
33 | bool TryGetExifItemId(const heif_image_handle* handle, heif_item_id& exifId)
34 | {
35 | heif_item_id id;
36 |
37 | if (heif_image_handle_get_list_of_metadata_block_IDs(handle, "Exif", &id, 1) == 1)
38 | {
39 | exifId = id;
40 | return true;
41 | }
42 |
43 | return false;
44 | }
45 |
46 | bool TryGetXmpItemId(const heif_image_handle* handle, heif_item_id& xmpId)
47 | {
48 | int mimeBlockCount = heif_image_handle_get_number_of_metadata_blocks(handle, "mime");
49 |
50 | if (mimeBlockCount == 0)
51 | {
52 | return false;
53 | }
54 |
55 | std::vector ids(mimeBlockCount);
56 |
57 | if (heif_image_handle_get_list_of_metadata_block_IDs(handle, "mime", ids.data(), mimeBlockCount) == mimeBlockCount)
58 | {
59 | for (size_t i = 0; i < ids.size(); i++)
60 | {
61 | const heif_item_id id = ids[i];
62 | const char* contentType = heif_image_handle_get_metadata_content_type(handle, id);
63 |
64 | if (strcmp(contentType, "application/rdf+xml") == 0)
65 | {
66 | xmpId = id;
67 | return true;
68 | }
69 | }
70 | }
71 |
72 | return false;
73 | }
74 | }
75 |
76 | void ReadExifMetadata(const FormatRecordPtr formatRecord, const heif_image_handle* handle)
77 | {
78 | heif_item_id exifId;
79 |
80 | if (TryGetExifItemId(handle, exifId))
81 | {
82 | const size_t size = heif_image_handle_get_metadata_size(handle, exifId);
83 |
84 | // The EXIF data block has a header that indicates the number of bytes
85 | // that come before the start of the TIFF header.
86 | // See ISO/IEC 23008-12:2017 section A.2.1.
87 | constexpr size_t exifHeaderSize = sizeof(uint32_t);
88 |
89 | if (size > exifHeaderSize && size <= static_cast(std::numeric_limits::max()))
90 | {
91 | ScopedBufferSuiteBuffer exifBuffer(formatRecord->bufferProcs, static_cast(size));
92 | uint8* exifBlock = static_cast(exifBuffer.lock());
93 |
94 | LibHeifException::ThrowIfError(heif_image_handle_get_metadata(handle, exifId, exifBlock));
95 |
96 | uint32_t tiffHeaderOffset = (exifBlock[0] << 24) | (exifBlock[1] << 16) | (exifBlock[2] << 8) | exifBlock[3];
97 |
98 | size_t headerStartOffset = static_cast(4) + tiffHeaderOffset;
99 | size_t exifDataLength = size - headerStartOffset;
100 |
101 | if (exifDataLength > 0 &&
102 | exifDataLength <= static_cast(std::numeric_limits::max()) &&
103 | CheckTiffFileSignature(exifBlock + headerStartOffset, exifDataLength))
104 | {
105 | // Set the EXIF orientation value to top-left, this results in the host treating it as a no-op.
106 | // The HEIF specification requires that readers ignore the EXIF orientation tag.
107 | SetExifOrientationToTopLeft(exifBlock + headerStartOffset, exifDataLength);
108 |
109 | ScopedHandleSuiteHandle complexProperty(formatRecord->handleProcs, static_cast(exifDataLength));
110 |
111 | ScopedHandleSuiteLock lock = complexProperty.lock();
112 |
113 | memcpy(lock.data(), exifBlock + headerStartOffset, exifDataLength);
114 |
115 | lock.unlock();
116 |
117 | OSErrException::ThrowIfError(formatRecord->propertyProcs->setPropertyProc(
118 | kPhotoshopSignature,
119 | propEXIFData,
120 | 0,
121 | 0,
122 | complexProperty.get()));
123 | }
124 | }
125 | }
126 | }
127 |
128 | void ReadIccProfileMetadata(const FormatRecordPtr formatRecord, const heif_image_handle* handle)
129 | {
130 | const size_t iccProfileLength = heif_image_handle_get_raw_color_profile_size(handle);
131 |
132 | if (iccProfileLength > 0 && iccProfileLength <= static_cast(std::numeric_limits::max()))
133 | {
134 | ScopedHandleSuiteHandle iccProfile(formatRecord->handleProcs, static_cast(iccProfileLength));
135 |
136 | ScopedHandleSuiteLock lock = iccProfile.lock();
137 |
138 | LibHeifException::ThrowIfError(heif_image_handle_get_raw_color_profile(handle, lock.data()));
139 |
140 | lock.unlock();
141 |
142 | // Ownership of the handle is transfered to the host through the iCCprofileData field.
143 | formatRecord->iCCprofileData = iccProfile.release();
144 | formatRecord->iCCprofileSize = static_cast(iccProfileLength);
145 | }
146 | }
147 |
148 | void ReadXmpMetadata(const FormatRecordPtr formatRecord, const heif_image_handle* handle)
149 | {
150 | heif_item_id xmpId;
151 |
152 | if (TryGetXmpItemId(handle, xmpId))
153 | {
154 | const size_t xmpDataLength = heif_image_handle_get_metadata_size(handle, xmpId);
155 |
156 | if (xmpDataLength > 0 && xmpDataLength <= static_cast(std::numeric_limits::max()))
157 | {
158 | ScopedHandleSuiteHandle complexProperty(formatRecord->handleProcs, static_cast(xmpDataLength));
159 |
160 | ScopedHandleSuiteLock lock = complexProperty.lock();
161 |
162 | LibHeifException::ThrowIfError(heif_image_handle_get_metadata(handle, xmpId, lock.data()));
163 |
164 | lock.unlock();
165 |
166 | OSErrException::ThrowIfError(formatRecord->propertyProcs->setPropertyProc(
167 | kPhotoshopSignature,
168 | propXMP,
169 | 0,
170 | 0,
171 | complexProperty.get()));
172 | }
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/src/common/ExifParser.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "ExifParser.h"
22 | #include
23 | #include
24 |
25 | namespace
26 | {
27 | static const char bigEndianTiffSignature[] = "MM\0*";
28 | static const char littleEndianTiffSignature[] = "II*\0";
29 |
30 | uint32 ReadLong(const uint8* data, size_t startOffset, bool bigEndian)
31 | {
32 | uint32 result;
33 |
34 | if (bigEndian)
35 | {
36 | result = (data[startOffset] << 24) | (data[startOffset + 1] << 16) | (data[startOffset + 2] << 8) | data[startOffset + 3];
37 | }
38 | else
39 | {
40 | result = data[startOffset] | (data[startOffset + 1] << 8) | (data[startOffset + 2] << 16) | (data[startOffset + 3] << 24);
41 | }
42 |
43 | return result;
44 | }
45 |
46 | uint16 ReadShort(const uint8* data, size_t startOffset, bool bigEndian)
47 | {
48 | uint16 result;
49 |
50 | if (bigEndian)
51 | {
52 | result = (data[startOffset] << 8) | data[startOffset + 1];
53 | }
54 | else
55 | {
56 | result = data[startOffset] | (data[startOffset + 1] << 8);
57 | }
58 |
59 | return result;
60 | }
61 |
62 | bool TryReadLong(const uint8* data, size_t startOffset, size_t dataLength, bool bigEndian, uint32& result)
63 | {
64 | if ((startOffset + sizeof(uint32)) > dataLength)
65 | {
66 | result = 0;
67 | return false;
68 | }
69 |
70 | result = ReadLong(data, startOffset, bigEndian);
71 | return true;
72 | }
73 |
74 | bool TryReadShort(const uint8* data, size_t startOffset, size_t dataLength, bool bigEndian, uint16& result)
75 | {
76 | if ((startOffset + sizeof(uint16)) > dataLength)
77 | {
78 | result = 0;
79 | return false;
80 | }
81 |
82 | result = ReadShort(data, startOffset, bigEndian);
83 | return true;
84 | }
85 |
86 | void WriteShort(uint8* data, size_t startOffset, bool bigEndian, uint16 value)
87 | {
88 | if constexpr(std::endian::native == std::endian::little)
89 | {
90 | if (bigEndian)
91 | {
92 | data[startOffset] = static_cast((value >> 8) & 0xff);
93 | data[startOffset + 1] = static_cast(value & 0xff);
94 | }
95 | else
96 | {
97 | data[startOffset] = static_cast(value & 0xff);
98 | data[startOffset + 1] = static_cast((value >> 8) & 0xff);
99 | }
100 | }
101 | else
102 | {
103 | if (bigEndian)
104 | {
105 | data[startOffset] = static_cast(value & 0xff);
106 | data[startOffset + 1] = static_cast((value >> 8) & 0xff);
107 | }
108 | else
109 | {
110 | data[startOffset] = static_cast((value >> 8) & 0xff);
111 | data[startOffset + 1] = static_cast(value & 0xff);
112 | }
113 | }
114 | }
115 | }
116 |
117 | bool CheckTiffFileSignature(const uint8* data, size_t dataLength)
118 | {
119 | // We must have at least 4 bytes to check the TIFF file signature.
120 | if (dataLength < 4)
121 | {
122 | return false;
123 | }
124 |
125 | return memcmp(data, bigEndianTiffSignature, 4) == 0 || memcmp(data, littleEndianTiffSignature, 4) == 0;
126 | }
127 |
128 | void SetExifOrientationToTopLeft(uint8* data, size_t dataLength)
129 | {
130 | if (CheckTiffFileSignature(data, dataLength))
131 | {
132 | size_t offset = 4;
133 | const size_t length = dataLength;
134 |
135 | const bool bigEndian = memcmp(data, bigEndianTiffSignature, 4) == 0;
136 | uint32 ifdOffset;
137 |
138 | if (TryReadLong(data, offset, length, bigEndian, ifdOffset) &&
139 | ifdOffset < static_cast(std::numeric_limits::max()))
140 | {
141 | offset = ifdOffset;
142 |
143 | uint16 directoryEntryCount;
144 |
145 | if (offset < length &&
146 | TryReadShort(data, offset, length, bigEndian, directoryEntryCount))
147 | {
148 | offset += sizeof(uint16);
149 |
150 | constexpr size_t tiffIfdEntrySize = 12;
151 |
152 | const size_t directoryEntryLengthInBytes = static_cast(directoryEntryCount) * tiffIfdEntrySize;
153 |
154 | if ((offset + directoryEntryLengthInBytes) <= length)
155 | {
156 | constexpr uint16 orientationTag = 274;
157 | constexpr uint16 orientationType = 3; // SHORT - 16-bit unsigned integer
158 | constexpr uint16 orientationItemCount = 1;
159 |
160 | for (uint16 i = 0; i < directoryEntryCount; i++)
161 | {
162 | uint16 entryTag = ReadShort(data, offset, bigEndian);
163 | offset += sizeof(uint16);
164 |
165 | uint16 entryType = ReadShort(data, offset, bigEndian);;
166 | offset += sizeof(uint16);
167 |
168 | uint32 entryItemCount = ReadLong(data, offset, bigEndian);
169 | offset += sizeof(uint32);
170 |
171 | size_t entryOffsetFieldLocation = offset;
172 | offset += sizeof(uint32);
173 |
174 | if (entryTag == orientationTag &&
175 | entryType == orientationType &&
176 | entryItemCount == orientationItemCount)
177 | {
178 | constexpr uint16 orientationTopLeft = 1;
179 |
180 | // The value is packed into the IFD entry offset field.
181 | WriteShort(data, entryOffsetFieldLocation, bigEndian, orientationTopLeft);
182 |
183 | break;
184 | }
185 | }
186 | }
187 | }
188 | }
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/src/common/WriteMetadata.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "WriteMetadata.h"
22 | #include "ExifParser.h"
23 | #include "HostMetadata.h"
24 | #include "LibHeifException.h"
25 | #include "ScopedBufferSuite.h"
26 | #include "ScopedHeif.h"
27 |
28 | namespace
29 | {
30 | void SetNclxColorProfile(
31 | heif_image* image,
32 | heif_color_primaries primaries,
33 | heif_transfer_characteristics transferCharacteristics,
34 | heif_matrix_coefficients matrixCoefficients)
35 | {
36 | ScopedHeifNclxProfile nclxProfile(heif_nclx_color_profile_alloc());
37 |
38 | if (nclxProfile == nullptr)
39 | {
40 | throw std::bad_alloc();
41 | }
42 |
43 | nclxProfile->color_primaries = primaries;
44 | nclxProfile->transfer_characteristics = transferCharacteristics;
45 | nclxProfile->matrix_coefficients = matrixCoefficients;
46 | nclxProfile->full_range_flag = true;
47 |
48 | LibHeifException::ThrowIfError(heif_image_set_nclx_color_profile(image, nclxProfile.get()));
49 | }
50 |
51 | void SetIccColorProfile(const FormatRecordPtr formatRecord, heif_image* image)
52 | {
53 | const int32 dataSize = formatRecord->handleProcs->getSizeProc(formatRecord->iCCprofileData);
54 |
55 | if (dataSize > 0)
56 | {
57 | ScopedHandleSuiteLock lock(formatRecord->handleProcs, formatRecord->iCCprofileData);
58 |
59 | Ptr data = lock.data();
60 |
61 | LibHeifException::ThrowIfError(heif_image_set_raw_color_profile(
62 | image,
63 | "prof",
64 | data,
65 | static_cast(dataSize)));
66 | }
67 | }
68 |
69 | ScopedBufferSuiteBuffer GetExifDataWithHeader(const FormatRecordPtr formatRecord)
70 | {
71 | ScopedBufferSuiteBuffer buffer;
72 |
73 | ScopedHandleSuiteHandle exif = GetExifMetadata(formatRecord);
74 |
75 | if (exif != nullptr)
76 | {
77 | const int32 exifSize = exif.size();
78 |
79 | if (exifSize > 0)
80 | {
81 | // The EXIF data block has a header that indicates the number of bytes
82 | // that come before the start of the TIFF header.
83 | // See ISO/IEC 23008-12:2017 section A.2.1.
84 | const int64 exifSizeWithHeader = static_cast(exifSize) + 4;
85 |
86 | if (exifSizeWithHeader <= std::numeric_limits::max())
87 | {
88 | ScopedHandleSuiteLock lock = exif.lock();
89 | void* exifDataPtr = lock.data();
90 |
91 | buffer = ScopedBufferSuiteBuffer(formatRecord->bufferProcs, static_cast(exifSizeWithHeader));
92 |
93 | uint8* destinationBuffer = static_cast(buffer.lock());
94 |
95 | uint32_t* tiffHeaderOffset = reinterpret_cast(destinationBuffer);
96 | *tiffHeaderOffset = 0;
97 |
98 | memcpy(destinationBuffer + sizeof(uint32_t), exifDataPtr, static_cast(exifSize));
99 | }
100 | }
101 | }
102 |
103 | return buffer;
104 | }
105 | }
106 |
107 | void AddColorProfileToImage(const FormatRecordPtr formatRecord, heif_image* image, const SaveUIOptions& saveOptions)
108 | {
109 | heif_color_primaries primaries;
110 | heif_transfer_characteristics transferCharacteristics;
111 | heif_matrix_coefficients matrixCoefficients;
112 |
113 | if (formatRecord->depth == 32 && saveOptions.hdrTransferFunction != ColorTransferFunction::Clip)
114 | {
115 | primaries = heif_color_primaries_ITU_R_BT_2020_2_and_2100_0;
116 |
117 | switch (saveOptions.hdrTransferFunction)
118 | {
119 | case ColorTransferFunction::PQ:
120 | transferCharacteristics = heif_transfer_characteristic_ITU_R_BT_2100_0_PQ;
121 | matrixCoefficients = heif_matrix_coefficients_ITU_R_BT_2020_2_non_constant_luminance;
122 | break;
123 | case ColorTransferFunction::SMPTE428:
124 | transferCharacteristics = heif_transfer_characteristic_SMPTE_ST_428_1;
125 | matrixCoefficients = heif_matrix_coefficients_ITU_R_BT_2020_2_non_constant_luminance;
126 | break;
127 | default:
128 | throw std::runtime_error("Unsupported color transfer function.");
129 | }
130 | }
131 | else
132 | {
133 | if (saveOptions.keepColorProfile && HasColorProfileMetadata(formatRecord))
134 | {
135 | SetIccColorProfile(formatRecord, image);
136 | }
137 |
138 | primaries = heif_color_primaries_ITU_R_BT_709_5;
139 | transferCharacteristics = heif_transfer_characteristic_IEC_61966_2_1;
140 | matrixCoefficients = heif_matrix_coefficients_ITU_R_BT_601_6;
141 | }
142 |
143 | if (saveOptions.lossless && !IsMonochromeImage(formatRecord))
144 | {
145 | matrixCoefficients = heif_matrix_coefficients_RGB_GBR;
146 | }
147 |
148 | SetNclxColorProfile(image, primaries, transferCharacteristics, matrixCoefficients);
149 | }
150 |
151 | void AddExifMetadata(const FormatRecordPtr formatRecord, heif_context* context, heif_image_handle* imageHandle)
152 | {
153 | ScopedBufferSuiteBuffer exif = GetExifDataWithHeader(formatRecord);
154 |
155 | if (exif)
156 | {
157 | const int32 bufferSize = exif.size();
158 | void* ptr = exif.lock();
159 |
160 | LibHeifException::ThrowIfError(heif_context_add_exif_metadata(context, imageHandle, ptr, bufferSize));
161 | }
162 | }
163 |
164 | void AddXmpMetadata(const FormatRecordPtr formatRecord, heif_context* context, heif_image_handle* imageHandle)
165 | {
166 | ScopedHandleSuiteHandle xmp = GetXmpMetadata(formatRecord);
167 |
168 | if (xmp != nullptr)
169 | {
170 | const int32 xmpSize = xmp.size();
171 |
172 | if (xmpSize > 0)
173 | {
174 | ScopedHandleSuiteLock lock = xmp.lock();
175 | void* ptr = lock.data();
176 |
177 | LibHeifException::ThrowIfError(heif_context_add_XMP_metadata(context, imageHandle, ptr, xmpSize));
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/common/AvifFormat.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "AvifFormat.h"
22 | #include "FileIO.h"
23 | #include
24 |
25 | namespace
26 | {
27 | OSErr CreateGlobals(FormatRecordPtr formatRecord, intptr_t* data)
28 | {
29 | Handle handle;
30 |
31 | OSErr e = NewPIHandle(formatRecord, sizeof(Globals), &handle);
32 |
33 | if (e == noErr)
34 | {
35 | *data = reinterpret_cast(handle);
36 | }
37 |
38 | return e;
39 | }
40 |
41 | OSErr DoFilterFile(FormatRecordPtr formatRecord)
42 | {
43 | constexpr int bufferSize = 50;
44 | uint8_t buffer[bufferSize] = {};
45 |
46 | // Seek to the start of the file.
47 | OSErr err = SetFilePosition(formatRecord->dataFork, 0);
48 |
49 | if (err == noErr)
50 | {
51 | err = ReadData(formatRecord->dataFork, buffer, bufferSize);
52 |
53 | if (err == noErr)
54 | {
55 | try
56 | {
57 | if (!heif_has_compatible_brand(buffer, bufferSize, "avif"))
58 | {
59 | err = formatCannotRead;
60 | }
61 | }
62 | catch (const std::bad_alloc&)
63 | {
64 | err = memFullErr;
65 | }
66 | catch (...)
67 | {
68 | err = formatCannotRead;
69 | }
70 | }
71 | }
72 |
73 | return err;
74 | }
75 |
76 | void InitGlobals(Globals* globals)
77 | {
78 | globals->context = nullptr;
79 | globals->imageHandle = nullptr;
80 | globals->imageHandleNclxProfile = nullptr;
81 | globals->image = nullptr;
82 | globals->imageHandleProfileType = heif_color_profile_type_not_present;
83 | globals->loadOptions.format = LoadOptionsHDRFormat::Unknown;
84 | globals->loadOptions.hlg.applyOOTF = true;
85 | globals->loadOptions.hlg.displayGamma = 1.2f;
86 | globals->loadOptions.hlg.nominalPeakBrightness = 1000;
87 | globals->loadOptions.pq.nominalPeakBrightness = pqDefaultBrightness;
88 | globals->saveOptions.quality = 85;
89 | globals->saveOptions.chromaSubsampling = ChromaSubsampling::Yuv422;
90 | globals->saveOptions.compressionSpeed = CompressionSpeed::Default;
91 | globals->saveOptions.hdrTransferFunction = ColorTransferFunction::PQ;
92 | globals->saveOptions.pq.nominalPeakBrightness = pqDefaultBrightness;
93 | globals->saveOptions.lossless = false;
94 | globals->saveOptions.losslessAlpha = true;
95 | globals->saveOptions.imageBitDepth = ImageBitDepth::Twelve; // The save UI will default to 8-bit if the image is 8-bit.
96 | globals->saveOptions.keepColorProfile = false;
97 | globals->saveOptions.keepExif = false;
98 | globals->saveOptions.keepXmp = false;
99 | globals->saveOptions.premultipliedAlpha = false;
100 | globals->libheifInitialized = false;
101 | }
102 | }
103 |
104 | void PluginMain(const short selector, FormatRecordPtr formatRecord, intptr_t* data, short* result)
105 | {
106 | if (selector == formatSelectorAbout)
107 | {
108 | DoAbout(reinterpret_cast(formatRecord));
109 | *result = noErr;
110 | }
111 | else
112 | {
113 | if (formatRecord->HostSupports32BitCoordinates)
114 | {
115 | formatRecord->PluginUsing32BitCoordinates = true;
116 | }
117 |
118 | Globals* globals;
119 | if (*data == 0)
120 | {
121 | *result = CreateGlobals(formatRecord, data);
122 | if (*result != noErr)
123 | {
124 | return;
125 | }
126 |
127 | globals = reinterpret_cast(LockPIHandle(formatRecord, reinterpret_cast(*data), false));
128 | InitGlobals(globals);
129 | }
130 | else
131 | {
132 | globals = reinterpret_cast(LockPIHandle(formatRecord, reinterpret_cast(*data), false));
133 | }
134 |
135 | switch (selector)
136 | {
137 | case formatSelectorReadPrepare:
138 | *result = DoReadPrepare(formatRecord);
139 | break;
140 | case formatSelectorReadStart:
141 | *result = DoReadStart(formatRecord, globals);
142 | break;
143 | case formatSelectorReadContinue:
144 | *result = DoReadContinue(formatRecord, globals);
145 | break;
146 | case formatSelectorReadFinish:
147 | *result = DoReadFinish(formatRecord, globals);
148 | break;
149 |
150 | case formatSelectorOptionsPrepare:
151 | *result = DoOptionsPrepare(formatRecord);
152 | break;
153 | case formatSelectorOptionsStart:
154 | *result = DoOptionsStart(formatRecord, globals);
155 | break;
156 | case formatSelectorOptionsContinue:
157 | *result = DoOptionsContinue();
158 | break;
159 | case formatSelectorOptionsFinish:
160 | *result = DoOptionsFinish();
161 | break;
162 |
163 | case formatSelectorEstimatePrepare:
164 | *result = DoEstimatePrepare(formatRecord);
165 | break;
166 | case formatSelectorEstimateStart:
167 | *result = DoEstimateStart(formatRecord);
168 | break;
169 | case formatSelectorEstimateContinue:
170 | *result = DoEstimateContinue();
171 | break;
172 | case formatSelectorEstimateFinish:
173 | *result = DoEstimateFinish();
174 | break;
175 |
176 | case formatSelectorWritePrepare:
177 | *result = DoWritePrepare(formatRecord);
178 | break;
179 | case formatSelectorWriteStart:
180 | *result = DoWriteStart(formatRecord, globals->saveOptions);
181 | break;
182 | case formatSelectorWriteContinue:
183 | *result = DoWriteContinue();
184 | break;
185 | case formatSelectorWriteFinish:
186 | *result = DoWriteFinish(formatRecord, globals->saveOptions);
187 | break;
188 |
189 | case formatSelectorFilterFile:
190 | *result = DoFilterFile(formatRecord);
191 | break;
192 |
193 | default:
194 | *result = formatBadParameters;
195 | }
196 |
197 | UnlockPIHandle(formatRecord, reinterpret_cast(*data));
198 | }
199 | }
200 |
201 | OSErr HandleErrorMessage(FormatRecordPtr formatRecord, const char* const message, OSErr fallbackErrorCode)
202 | {
203 | return ShowErrorDialog(formatRecord, message, fallbackErrorCode);
204 | }
205 |
--------------------------------------------------------------------------------
/src/common/ColorTransfer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "ColorTransfer.h"
22 | #include
23 |
24 | namespace
25 | {
26 | // PQ (SMPTE ST 2084) has a maximum luminance level of 10000 nits
27 | // https://en.wikipedia.org/wiki/Perceptual_quantizer
28 | constexpr float pqMaxLuminanceLevel = 10000.0f;
29 | }
30 |
31 | HLGLumaCoefficiants GetHLGLumaCoefficients(heif_color_primaries primaries)
32 | {
33 | switch (primaries)
34 | {
35 | case heif_color_primaries_ITU_R_BT_709_5:
36 | return HLGLumaCoefficiants{ 0.2126f, 0.7152f, 0.0722f };
37 | case heif_color_primaries_ITU_R_BT_470_6_System_B_G:
38 | case heif_color_primaries_ITU_R_BT_601_6:
39 | return HLGLumaCoefficiants{ 0.299f, 0.587f, 0.114f };
40 | case heif_color_primaries_ITU_R_BT_2020_2_and_2100_0:
41 | return HLGLumaCoefficiants{ 0.2627f, 0.6780f, 0.0593f };
42 | default:
43 | throw std::runtime_error("Unsupported color primaries for the HLG Luma Coefficients ");
44 | }
45 | }
46 |
47 | ColorTransferFunction GetTransferFunctionFromNclx(heif_transfer_characteristics transferCharacteristics)
48 | {
49 | ColorTransferFunction transferFunction;
50 |
51 | switch (transferCharacteristics)
52 | {
53 | case heif_transfer_characteristic_ITU_R_BT_2100_0_PQ:
54 | transferFunction = ColorTransferFunction::PQ;
55 | break;
56 | case heif_transfer_characteristic_ITU_R_BT_2100_0_HLG:
57 | transferFunction = ColorTransferFunction::HLG;
58 | break;
59 | case heif_transfer_characteristic_SMPTE_ST_428_1:
60 | transferFunction = ColorTransferFunction::SMPTE428;
61 | break;
62 | default:
63 | throw std::runtime_error("Unsupported NCLX transfer characteristic.");
64 | }
65 |
66 | return transferFunction;
67 | }
68 |
69 | float LinearToPQ(float value, float imageMaxLuminanceLevel)
70 | {
71 | // These constant values are taken from the Perceptual quantizer article on Wikipedia
72 | // https://en.wikipedia.org/wiki/Perceptual_quantizer
73 | constexpr float m1 = 2610.0f / 16384.0f;
74 | constexpr float m2 = 2523.0f / 4096.0f * 128.0f;
75 | constexpr float c1 = 3424.0f / 4096.0f; // c3 - c2 + 1
76 | constexpr float c2 = 2413.0f / 4096.0f * 32.0f;
77 | constexpr float c3 = 2392.0f / 4096.0f * 32.0f;
78 |
79 | if (value < 0.0f)
80 | {
81 | return 0.0f;
82 | }
83 |
84 | // For the image to be displayed correctly, we have to adjust for the difference in the
85 | // maximum luminance level between the image and PQ.
86 | const float luminanceMultiplier = imageMaxLuminanceLevel / pqMaxLuminanceLevel;
87 |
88 | const float x = powf(value * luminanceMultiplier, m1);
89 | const float pq = powf((c1 + c2 * x) / (1.0f + c3 * x), m2);
90 |
91 | return pq;
92 | }
93 |
94 | float PQToLinear(float value, float imageMaxLuminanceLevel)
95 | {
96 | // These constant values are taken from the Perceptual quantizer article on Wikipedia
97 | // https://en.wikipedia.org/wiki/Perceptual_quantizer
98 | constexpr float m1 = 2610.0f / 16384.0f;
99 | constexpr float m2 = 2523.0f / 4096.0f * 128.0f;
100 | constexpr float c1 = 3424.0f / 4096.0f; // c3 - c2 + 1
101 | constexpr float c2 = 2413.0f / 4096.0f * 32.0f;
102 | constexpr float c3 = 2392.0f / 4096.0f * 32.0f;
103 |
104 | if (value < 0.0f)
105 | {
106 | return 0.0f;
107 | }
108 |
109 | const float x = powf(value, 1.0f / m2);
110 | const float normalizedLinear = powf(std::max(x - c1, 0.0f) / (c2 - c3 * x), 1.0f / m1);
111 |
112 | // For the image to be displayed correctly, we have to adjust for the difference in the
113 | // maximum luminance level between PQ and the image.
114 | const float luminanceMultiplier = pqMaxLuminanceLevel / imageMaxLuminanceLevel;
115 |
116 | return normalizedLinear * luminanceMultiplier;
117 | }
118 |
119 | float LinearToSMPTE428(float value)
120 | {
121 | if (value < 0.0f)
122 | {
123 | return 0.0f;
124 | }
125 |
126 | return powf(value * 48.0f / 52.37f, 1.0f / 2.6f);
127 | }
128 |
129 | float SMPTE428ToLinear(float value)
130 | {
131 | if (value < 0.0f)
132 | {
133 | return 0.0f;
134 | }
135 |
136 | // The following code is equivalent to (powf(value, 2.6f) * 52.37f) / 48.0f
137 | // but it removes the need to perform division at runtime.
138 | return powf(value, 2.6f) * (52.37f / 48.0f);
139 | }
140 |
141 | float LinearToHLG(float value)
142 | {
143 | if (value < 0.0f)
144 | {
145 | return 0.0f;
146 | }
147 |
148 | // These constants are from the ITU-R BT.2100 specification:
149 | // https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-2-201807-I!!PDF-E.pdf
150 | constexpr float a = 0.17883277f;
151 | constexpr float b = 0.28466892f;
152 | constexpr float c = 0.55991073f;
153 |
154 | if (value > (1.0f / 12.0f))
155 | {
156 | value = a * logf(value * 12.0f - b) + c;
157 | }
158 | else
159 | {
160 | value = sqrtf(value * 3.0f);
161 | }
162 |
163 | return value;
164 | }
165 |
166 | float HLGToLinear(float value)
167 | {
168 | if (value < 0.0f)
169 | {
170 | return 0.0f;
171 | }
172 |
173 | // These constants are from the ITU-R BT.2100 specification:
174 | // https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-2-201807-I!!PDF-E.pdf
175 | constexpr float a = 0.17883277f;
176 | constexpr float b = 0.28466892f;
177 | constexpr float c = 0.55991073f;
178 |
179 | if (value > 0.5f)
180 | {
181 | value = (expf((value - c) / a) + b) / 12.0f;
182 | }
183 | else
184 | {
185 | // Equivalent to powf(value, 2.0f) / 3.0f
186 | value = (value * value) * (1.0f / 3.0f);
187 | }
188 |
189 | return value;
190 | }
191 |
192 | void ApplyHLGOOTF(
193 | float* rgb,
194 | const HLGLumaCoefficiants& lumaCoefficiants,
195 | float displayGamma,
196 | float nominalPeakBrightness)
197 | {
198 | const float luma = (rgb[0] * lumaCoefficiants.red) + (rgb[1] * lumaCoefficiants.green) + (rgb[2] * lumaCoefficiants.blue);
199 |
200 | const float factor = nominalPeakBrightness * powf(luma, displayGamma - 1.0f);
201 |
202 | rgb[0] *= factor;
203 | rgb[1] *= factor;
204 | rgb[2] *= factor;
205 | }
206 |
207 | void ApplyInverseHLGOOTF(
208 | float* rgb,
209 | const HLGLumaCoefficiants& lumaCoefficiants,
210 | float displayGamma,
211 | float nominalPeakBrightness)
212 | {
213 | const float luma = (rgb[0] * lumaCoefficiants.red) + (rgb[1] * lumaCoefficiants.green) + (rgb[2] * lumaCoefficiants.blue);
214 |
215 | const float factor = powf(luma / nominalPeakBrightness, (displayGamma - 1.0f) / displayGamma) / nominalPeakBrightness;
216 |
217 | rgb[0] *= factor;
218 | rgb[1] *= factor;
219 | rgb[2] *= factor;
220 | }
221 |
--------------------------------------------------------------------------------
/Third Party Notices.txt:
--------------------------------------------------------------------------------
1 | This file lists the original copyright and license information for
2 | the third-party libraries or other resources included with this software.
3 |
4 | The attached notices are provided for information only.
5 |
6 | License notice for AOM
7 | --------------------------------------------------------------
8 | https://aomedia.googlesource.com/aom/
9 |
10 | Copyright (c) 2016, Alliance for Open Media. All rights reserved.
11 | Redistribution and use in source and binary forms, with or without
12 | modification, are permitted provided that the following conditions
13 | are met:
14 | 1. Redistributions of source code must retain the above copyright
15 | notice, this list of conditions and the following disclaimer.
16 | 2. Redistributions in binary form must reproduce the above copyright
17 | notice, this list of conditions and the following disclaimer in
18 | the documentation and/or other materials provided with the
19 | distribution.
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | POSSIBILITY OF SUCH DAMAGE.
32 |
33 | License notice for libheif
34 | --------------------------------------------------------------
35 | https://github.com/strukturag/libheif
36 |
37 | Copyright (c) 2017 struktur AG, Dirk Farin
38 |
39 | libheif is free software: you can redistribute it and/or modify
40 | it under the terms of the GNU Lesser General Public License as
41 | published by the Free Software Foundation, either version 3 of
42 | the License, or (at your option) any later version.
43 |
44 | libheif is distributed in the hope that it will be useful,
45 | but WITHOUT ANY WARRANTY; without even the implied warranty of
46 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47 | GNU Lesser General Public License for more details.
48 |
49 | You should have received a copy of the GNU Lesser General Public License
50 | along with libheif. If not, see .
51 |
52 | License notice for libavif
53 | --------------------------------------------------------------
54 | https://github.com/AOMediaCodec/libavif
55 |
56 | Copyright 2020 Joe Drago. All rights reserved.
57 |
58 | Redistribution and use in source and binary forms, with or without
59 | modification, are permitted provided that the following conditions are met:
60 |
61 | 1. Redistributions of source code must retain the above copyright notice, this
62 | list of conditions and the following disclaimer.
63 |
64 | 2. Redistributions in binary form must reproduce the above copyright notice,
65 | this list of conditions and the following disclaimer in the documentation
66 | and/or other materials provided with the distribution.
67 |
68 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
69 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
70 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
71 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
72 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
73 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
74 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
75 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
76 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
77 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
78 |
79 | License notice for Little CMS
80 | --------------------------------------------------------------
81 | https://github.com/mm2/Little-CMS
82 |
83 | Little CMS
84 | Copyright (c) 1998-2020 Marti Maria Saguer
85 |
86 | Permission is hereby granted, free of charge, to any person obtaining
87 | a copy of this software and associated documentation files (the
88 | "Software"), to deal in the Software without restriction, including
89 | without limitation the rights to use, copy, modify, merge, publish,
90 | distribute, sublicense, and/or sell copies of the Software, and to
91 | permit persons to whom the Software is furnished to do so, subject
92 | to the following conditions:
93 |
94 | The above copyright notice and this permission notice shall be
95 | included in all copies or substantial portions of the Software.
96 |
97 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
98 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
99 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
100 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
101 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
102 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
103 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
104 |
105 | License notice for FFMpeg
106 | --------------------------------------------------------------
107 | https://github.com/FFmpeg/FFmpeg
108 |
109 | FFmpeg is free software; you can redistribute it and/or
110 | modify it under the terms of the GNU Lesser General Public
111 | License as published by the Free Software Foundation; either
112 | version 2.1 of the License, or (at your option) any later version.
113 |
114 | FFmpeg is distributed in the hope that it will be useful,
115 | but WITHOUT ANY WARRANTY; without even the implied warranty of
116 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
117 | Lesser General Public License for more details.
118 |
119 | You should have received a copy of the GNU Lesser General Public
120 | License along with FFmpeg; if not, write to the Free Software
121 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
122 |
123 | License notice for openexrAE
124 | --------------------------------------------------------------
125 | https://gitlab.com/fnordware/openexrAE
126 |
127 | Copyright 2020 Brendan Bolles
128 |
129 | Redistribution and use in source and binary forms, with or without modification,
130 | are permitted provided that the following conditions are met:
131 |
132 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
133 |
134 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
135 | in the documentation and/or other materials provided with the distribution.
136 |
137 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
138 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
139 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
140 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
141 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.vspscc
94 | *.vssscc
95 | .builds
96 | *.pidb
97 | *.svclog
98 | *.scc
99 |
100 | # Chutzpah Test files
101 | _Chutzpah*
102 |
103 | # Visual C++ cache files
104 | ipch/
105 | *.aps
106 | *.ncb
107 | *.opendb
108 | *.opensdf
109 | *.sdf
110 | *.cachefile
111 | *.VC.db
112 | *.VC.VC.opendb
113 |
114 | # Visual Studio profiler
115 | *.psess
116 | *.vsp
117 | *.vspx
118 | *.sap
119 |
120 | # Visual Studio Trace Files
121 | *.e2e
122 |
123 | # TFS 2012 Local Workspace
124 | $tf/
125 |
126 | # Guidance Automation Toolkit
127 | *.gpState
128 |
129 | # ReSharper is a .NET coding add-in
130 | _ReSharper*/
131 | *.[Rr]e[Ss]harper
132 | *.DotSettings.user
133 |
134 | # TeamCity is a build add-in
135 | _TeamCity*
136 |
137 | # DotCover is a Code Coverage Tool
138 | *.dotCover
139 |
140 | # AxoCover is a Code Coverage Tool
141 | .axoCover/*
142 | !.axoCover/settings.json
143 |
144 | # Coverlet is a free, cross platform Code Coverage Tool
145 | coverage*.json
146 | coverage*.xml
147 | coverage*.info
148 |
149 | # Visual Studio code coverage results
150 | *.coverage
151 | *.coveragexml
152 |
153 | # NCrunch
154 | _NCrunch_*
155 | .*crunch*.local.xml
156 | nCrunchTemp_*
157 |
158 | # MightyMoose
159 | *.mm.*
160 | AutoTest.Net/
161 |
162 | # Web workbench (sass)
163 | .sass-cache/
164 |
165 | # Installshield output folder
166 | [Ee]xpress/
167 |
168 | # DocProject is a documentation generator add-in
169 | DocProject/buildhelp/
170 | DocProject/Help/*.HxT
171 | DocProject/Help/*.HxC
172 | DocProject/Help/*.hhc
173 | DocProject/Help/*.hhk
174 | DocProject/Help/*.hhp
175 | DocProject/Help/Html2
176 | DocProject/Help/html
177 |
178 | # Click-Once directory
179 | publish/
180 |
181 | # Publish Web Output
182 | *.[Pp]ublish.xml
183 | *.azurePubxml
184 | # Note: Comment the next line if you want to checkin your web deploy settings,
185 | # but database connection strings (with potential passwords) will be unencrypted
186 | *.pubxml
187 | *.publishproj
188 |
189 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
190 | # checkin your Azure Web App publish settings, but sensitive information contained
191 | # in these scripts will be unencrypted
192 | PublishScripts/
193 |
194 | # NuGet Packages
195 | *.nupkg
196 | # NuGet Symbol Packages
197 | *.snupkg
198 | # The packages folder can be ignored because of Package Restore
199 | **/[Pp]ackages/*
200 | # except build/, which is used as an MSBuild target.
201 | !**/[Pp]ackages/build/
202 | # Uncomment if necessary however generally it will be regenerated when needed
203 | #!**/[Pp]ackages/repositories.config
204 | # NuGet v3's project.json files produces more ignorable files
205 | *.nuget.props
206 | *.nuget.targets
207 |
208 | # Microsoft Azure Build Output
209 | csx/
210 | *.build.csdef
211 |
212 | # Microsoft Azure Emulator
213 | ecf/
214 | rcf/
215 |
216 | # Windows Store app package directories and files
217 | AppPackages/
218 | BundleArtifacts/
219 | Package.StoreAssociation.xml
220 | _pkginfo.txt
221 | *.appx
222 | *.appxbundle
223 | *.appxupload
224 |
225 | # Visual Studio cache files
226 | # files ending in .cache can be ignored
227 | *.[Cc]ache
228 | # but keep track of directories ending in .cache
229 | !?*.[Cc]ache/
230 |
231 | # Others
232 | ClientBin/
233 | ~$*
234 | *~
235 | *.dbmdl
236 | *.dbproj.schemaview
237 | *.jfm
238 | *.pfx
239 | *.publishsettings
240 | orleans.codegen.cs
241 |
242 | # Including strong name files can present a security risk
243 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
244 | #*.snk
245 |
246 | # Since there are multiple workflows, uncomment next line to ignore bower_components
247 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
248 | #bower_components/
249 |
250 | # RIA/Silverlight projects
251 | Generated_Code/
252 |
253 | # Backup & report files from converting an old project file
254 | # to a newer Visual Studio version. Backup files are not needed,
255 | # because we have git ;-)
256 | _UpgradeReport_Files/
257 | Backup*/
258 | UpgradeLog*.XML
259 | UpgradeLog*.htm
260 | ServiceFabricBackup/
261 | *.rptproj.bak
262 |
263 | # SQL Server files
264 | *.mdf
265 | *.ldf
266 | *.ndf
267 |
268 | # Business Intelligence projects
269 | *.rdl.data
270 | *.bim.layout
271 | *.bim_*.settings
272 | *.rptproj.rsuser
273 | *- [Bb]ackup.rdl
274 | *- [Bb]ackup ([0-9]).rdl
275 | *- [Bb]ackup ([0-9][0-9]).rdl
276 |
277 | # Microsoft Fakes
278 | FakesAssemblies/
279 |
280 | # GhostDoc plugin setting file
281 | *.GhostDoc.xml
282 |
283 | # Node.js Tools for Visual Studio
284 | .ntvs_analysis.dat
285 | node_modules/
286 |
287 | # Visual Studio 6 build log
288 | *.plg
289 |
290 | # Visual Studio 6 workspace options file
291 | *.opt
292 |
293 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
294 | *.vbw
295 |
296 | # Visual Studio LightSwitch build output
297 | **/*.HTMLClient/GeneratedArtifacts
298 | **/*.DesktopClient/GeneratedArtifacts
299 | **/*.DesktopClient/ModelManifest.xml
300 | **/*.Server/GeneratedArtifacts
301 | **/*.Server/ModelManifest.xml
302 | _Pvt_Extensions
303 |
304 | # Paket dependency manager
305 | .paket/paket.exe
306 | paket-files/
307 |
308 | # FAKE - F# Make
309 | .fake/
310 |
311 | # CodeRush personal settings
312 | .cr/personal
313 |
314 | # Python Tools for Visual Studio (PTVS)
315 | __pycache__/
316 | *.pyc
317 |
318 | # Cake - Uncomment if you are using it
319 | # tools/**
320 | # !tools/packages.config
321 |
322 | # Tabs Studio
323 | *.tss
324 |
325 | # Telerik's JustMock configuration file
326 | *.jmconfig
327 |
328 | # BizTalk build output
329 | *.btp.cs
330 | *.btm.cs
331 | *.odx.cs
332 | *.xsd.cs
333 |
334 | # OpenCover UI analysis results
335 | OpenCover/
336 |
337 | # Azure Stream Analytics local run output
338 | ASALocalRun/
339 |
340 | # MSBuild Binary and Structured Log
341 | *.binlog
342 |
343 | # NVidia Nsight GPU debugger configuration file
344 | *.nvuser
345 |
346 | # MFractors (Xamarin productivity tool) working folder
347 | .mfractor/
348 |
349 | # Local History for Visual Studio
350 | .localhistory/
351 |
352 | # BeatPulse healthcheck temp database
353 | healthchecksdb
354 |
355 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
356 | MigrationBackup/
357 |
358 | # Ionide (cross platform F# VS Code tools) working folder
359 | .ionide/
360 |
361 | # Fody - auto-generated XML schema
362 | FodyWeavers.xsd
363 |
364 | # vcpkg local install folder
365 | vcpkg_installed/
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
--------------------------------------------------------------------------------
/vs/AvifFormat.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 | Header Files
35 |
36 |
37 | Header Files
38 |
39 |
40 | Header Files
41 |
42 |
43 | Header Files
44 |
45 |
46 | Header Files
47 |
48 |
49 | Header Files
50 |
51 |
52 | Header Files
53 |
54 |
55 | Header Files
56 |
57 |
58 | Header Files
59 |
60 |
61 | Header Files
62 |
63 |
64 | Header Files
65 |
66 |
67 | Header Files
68 |
69 |
70 | Header Files
71 |
72 |
73 | Header Files
74 |
75 |
76 | Header Files
77 |
78 |
79 | Header Files
80 |
81 |
82 | Header Files
83 |
84 |
85 | Header Files
86 |
87 |
88 | Header Files
89 |
90 |
91 | Header Files
92 |
93 |
94 | Header Files
95 |
96 |
97 | Header Files
98 |
99 |
100 | Header Files
101 |
102 |
103 | Header Files
104 |
105 |
106 | Header Files
107 |
108 |
109 |
110 |
111 | Source Files
112 |
113 |
114 | Source Files
115 |
116 |
117 | Source Files
118 |
119 |
120 | Source Files
121 |
122 |
123 | Source Files
124 |
125 |
126 | Source Files
127 |
128 |
129 | Source Files
130 |
131 |
132 | Source Files
133 |
134 |
135 | Source Files
136 |
137 |
138 | Source Files
139 |
140 |
141 | Source Files
142 |
143 |
144 | Source Files
145 |
146 |
147 | Source Files
148 |
149 |
150 | Source Files
151 |
152 |
153 | Source Files
154 |
155 |
156 | Source Files
157 |
158 |
159 | Source Files
160 |
161 |
162 | Source Files
163 |
164 |
165 | Source Files
166 |
167 |
168 | Source Files
169 |
170 |
171 | Source Files
172 |
173 |
174 | Source Files
175 |
176 |
177 | Source Files
178 |
179 |
180 | Source Files
181 |
182 |
183 | Source Files
184 |
185 |
186 | Source Files
187 |
188 |
189 | Source Files
190 |
191 |
192 |
193 |
194 | Resource Files
195 |
196 |
197 | Resource Files
198 |
199 |
200 | Resource Files
201 |
202 |
203 |
204 |
205 | Resource Files
206 |
207 |
208 |
--------------------------------------------------------------------------------
/src/common/AvifFormat.r:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | //-------------------------------------------------------------------------------
22 | // Definitions -- Required by include files.
23 | //-------------------------------------------------------------------------------
24 |
25 | // The About box and resources are created in PIUtilities.r.
26 | // You can easily override them, if you like.
27 |
28 | #define plugInName "AV1 Image"
29 |
30 |
31 | //-------------------------------------------------------------------------------
32 | // Set up included files for Macintosh and Windows.
33 | //-------------------------------------------------------------------------------
34 |
35 | #include "PIDefines.h"
36 |
37 | #if __PIMac__
38 | #include "Types.r"
39 | #include "SysTypes.r"
40 | #include "PIGeneral.r"
41 | #include "PIUtilities.r"
42 | #elif defined(__PIWin__)
43 | #define Rez
44 | #include "PIGeneral.h"
45 | #include "PIUtilities.r"
46 | #endif
47 |
48 | #include "AvifFormatTerminology.h"
49 |
50 | //-------------------------------------------------------------------------------
51 | // PiPL resource
52 | //-------------------------------------------------------------------------------
53 |
54 | resource 'PiPL' (ResourceID, plugInName " PiPL", purgeable)
55 | {
56 | {
57 | Kind { ImageFormat },
58 | Name { plugInName },
59 | Version { (latestFormatVersion << 16) | latestFormatSubVersion },
60 |
61 | #ifdef __PIMac__
62 | #if defined(__arm64__)
63 | CodeMacARM64 { "PluginMain" },
64 | #elif defined(__x86_64__)
65 | CodeMacIntel64 { "PluginMain" },
66 | #elif defined(__i386__)
67 | CodeMacIntel32 { "PluginMain" },
68 | #endif
69 | #else
70 | #if defined(_M_ARM64)
71 | CodeWin64ARM { "PluginMain" },
72 | #elif defined(_M_AMD64)
73 | CodeWin64X86 { "PluginMain" },
74 | #else
75 | CodeWin32X86 { "PluginMain" },
76 | #endif
77 | #endif
78 |
79 | HasTerminology { plugInClassID,
80 | plugInEventID,
81 | ResourceID,
82 | vendorName " " plugInName },
83 |
84 | SupportedModes
85 | {
86 | noBitmap,
87 | doesSupportGrayScale,
88 | noIndexedColor,
89 | doesSupportRGBColor,
90 | noCMYKColor,
91 | noHSLColor,
92 | noHSBColor,
93 | noMultichannel,
94 | noDuotone,
95 | noLABColor
96 | },
97 |
98 | EnableInfo { "in (PSHOP_ImageMode, RGBMode, RGB48Mode, GrayScaleMode, Gray16Mode, RGB96Mode, Gray32Mode)" },
99 |
100 | PlugInMaxSize { 1073741824, 1073741824 },
101 |
102 | FormatMaxSize { { 32767, 32767 } },
103 |
104 | FormatMaxChannels { { 0, 2, 0, 4, 0, 0, 0, 0, 0, 0, 2, 4 } },
105 |
106 | FmtFileType { 'AV1F', '8BIM' },
107 | //ReadTypes { { '8B1F', ' ' } },
108 | //FilteredTypes { { '8B1F', ' ' } },
109 | ReadExtensions { { 'AVIF' } },
110 | WriteExtensions { { 'AVIF' } },
111 | //FilteredExtensions { { 'AVIF' } },
112 | FormatFlags { fmtDoesNotSaveImageResources,
113 | fmtCanRead,
114 | fmtCanWrite,
115 | fmtCanWriteIfRead,
116 | fmtCanWriteTransparency,
117 | fmtCannotCreateThumbnail }
118 | }
119 | };
120 | }
121 |
122 | resource 'aete' (ResourceID, plugInName " dictionary", purgeable)
123 | {
124 | 1, 0, english, roman, /* aete version and language specifiers */
125 | {
126 | vendorName, /* vendor suite name */
127 | "AVIF format plug-in", /* optional description */
128 | plugInSuiteID, /* suite ID */
129 | 1, /* suite code, must be 1 */
130 | 1, /* suite level, must be 1 */
131 | {}, /* structure for filters */
132 | { /* non-filter plug-in class here */
133 | vendorName " avifFormat", /* unique class name */
134 | plugInClassID, /* class ID, must be unique or Suite ID */
135 | plugInAETEComment, /* optional description */
136 | { /* define inheritance */
137 | "", /* must be exactly this */
138 | keyInherits, /* must be keyInherits */
139 | classFormat, /* parent: Format, Import, Export */
140 | "parent class format", /* optional description */
141 | flagsSingleProperty, /* if properties, list below */
142 |
143 | /* Common dialog parameters */
144 |
145 | "PQ nominal peak brightness", /* This value is shared between the load and save dialogs */
146 | keyPQNominalPeakBrightness,
147 | typeInteger,
148 | "The display brightness in nits (candela per square metre), range 1 to 10000 inclusive",
149 | flagsSingleProperty,
150 |
151 | /* Load dialog parameters */
152 |
153 | "apply HLG OOTF",
154 | keyApplyHLGOOTF,
155 | typeBoolean,
156 | "",
157 | flagsSingleProperty,
158 |
159 | "display gamma",
160 | keyHLGDisplayGamma,
161 | typeFloat, /* This should be a float32, but the PS scripting API only supports float64 */
162 | "The display gamma, range 1.0 to 3.0 inclusive",
163 | flagsSingleProperty,
164 |
165 | "HLG nominal peak brightness",
166 | keyHLGNominalPeakBrightness,
167 | typeInteger,
168 | "The display brightness in nits (candela per square metre), range 1 to 10000 inclusive",
169 | flagsSingleProperty,
170 |
171 | /* Save dialog parameters */
172 |
173 | "quality",
174 | keyQuality,
175 | typeInteger,
176 | "",
177 | flagsSingleProperty,
178 |
179 | "compression speed",
180 | keyCompressionSpeed,
181 | typeCompressionSpeed,
182 | "",
183 | flagsEnumeratedParameter,
184 |
185 | "lossless compression",
186 | keyLosslessCompression,
187 | typeBoolean,
188 | "",
189 | flagsSingleProperty,
190 |
191 | "chroma sub-sampling",
192 | keyChromaSubsampling,
193 | typeChromaSubsampling,
194 | "",
195 | flagsEnumeratedParameter,
196 |
197 | "color profile",
198 | keyKeepColorProfile,
199 | typeBoolean,
200 | "",
201 | flagsSingleProperty,
202 |
203 | "EXIF",
204 | keyKeepEXIF,
205 | typeBoolean,
206 | "",
207 | flagsSingleProperty,
208 |
209 | "XMP",
210 | keyKeepXMP,
211 | typeBoolean,
212 | "",
213 | flagsSingleProperty,
214 |
215 | "lossless alpha",
216 | keyLosslessAlpha,
217 | typeBoolean,
218 | "",
219 | flagsSingleProperty,
220 |
221 | "premultiplied alpha",
222 | keyPremultipliedAlpha,
223 | typeBoolean,
224 | "",
225 | flagsSingleProperty,
226 |
227 | "image depth",
228 | keyImageBitDepth,
229 | typeImageBitDepth,
230 | "",
231 | flagsEnumeratedParameter,
232 |
233 | "HDR transfer function",
234 | keyHDRTransferFunction,
235 | typeHDRTransferFunction,
236 | "",
237 | flagsEnumeratedParameter,
238 | },
239 | {}, /* elements (not supported) */
240 | /* class descriptions */
241 | },
242 | {}, /* comparison ops (not supported) */
243 | { /* enumerations */
244 |
245 | typeCompressionSpeed,
246 | {
247 | "fastest",
248 | compressionSpeedFastest,
249 | "",
250 |
251 | "default",
252 | compressionSpeedDefault,
253 | "",
254 |
255 | "slowest",
256 | compressionSpeedSlowest,
257 | ""
258 | },
259 | typeChromaSubsampling,
260 | {
261 | "4:2:0",
262 | chromaSubsampling420,
263 | "YUV 4:2:0 (best compression)",
264 |
265 | "4:2:2",
266 | chromaSubsampling422,
267 | "YUV 4:2:2",
268 |
269 | "4:4:4",
270 | chromaSubsampling444,
271 | "YUV 4:4:4 (best quality)"
272 | },
273 | typeImageBitDepth,
274 | {
275 | "8-bit",
276 | imageBitDepthEight,
277 | "",
278 |
279 | "10-bit",
280 | imageBitDepthTen,
281 | "",
282 |
283 | "12-bit",
284 | imageBitDepthTwelve,
285 | ""
286 | },
287 | typeHDRTransferFunction,
288 | {
289 | "PQ",
290 | hdrTransferFunctionPQ,
291 | "Rec. 2100 PQ",
292 | /* Reserved for future use
293 | "HLG",
294 | hdrTransferFunctionHLG,
295 | "Rec. 2100 HLG",
296 | */
297 | "SMPTE-428",
298 | hdrTransferFunctionSMPTE428,
299 | "SMPTE 428-1",
300 | "Clip",
301 | hdrTransferFunctionClip,
302 | "None, clip",
303 | }
304 | }
305 | }
306 | };
307 |
--------------------------------------------------------------------------------
/src/common/ColorProfileConversion.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "ColorProfileConversion.h"
22 | #include "ColorProfileDetection.h"
23 | #include "ColorProfileGeneration.h"
24 | #include "HostMetadata.h"
25 | #include "ScopedHandleSuite.h"
26 | #include "ScopedLcms.h"
27 |
28 | namespace
29 | {
30 | ScopedLcmsProfile ReadDocumentProfile(cmsContext context, const FormatRecordPtr formatRecord)
31 | {
32 | ScopedHandleSuiteLock lock(formatRecord->handleProcs, formatRecord->iCCprofileData);
33 |
34 | return ScopedLcmsProfile(cmsOpenProfileFromMemTHR(context, lock.data(), formatRecord->iCCprofileSize));
35 | }
36 |
37 | std::vector BuildHostToLcmsLookup()
38 | {
39 | std::vector lookupTable;
40 | lookupTable.reserve(32769);
41 |
42 | // Map the image data from Photoshop's 16-bit range [0, 32768] to [0, 65535].
43 | // Little CMS has a formatter plug-in that adds support for Photoshop's 16-bit range, but we
44 | // cannot use it because of the GPL license.
45 |
46 | constexpr int maxValue = 65535;
47 | constexpr float maxValueFloat = static_cast(maxValue);
48 |
49 | for (size_t i = 0; i < lookupTable.capacity(); i++)
50 | {
51 | int value = static_cast(((static_cast(i) / 32768.0f) * maxValueFloat) + 0.5f);
52 |
53 | if (value < 0)
54 | {
55 | value = 0;
56 | }
57 | else if (value > maxValue)
58 | {
59 | value = maxValue;
60 | }
61 |
62 | lookupTable.push_back(static_cast(value));
63 | }
64 |
65 | return lookupTable;
66 | }
67 |
68 | std::vector BuildLcmsToHostLookup()
69 | {
70 | std::vector lookupTable;
71 | lookupTable.reserve(65536);
72 |
73 | // Map the image data from [0, 65535] to Photoshop's 16-bit range [0, 32768].
74 |
75 | constexpr int maxValue = 32768;
76 | constexpr float maxValueFloat = static_cast(maxValue);
77 |
78 | for (size_t i = 0; i < lookupTable.capacity(); i++)
79 | {
80 | int value = static_cast(((static_cast(i) / 65535.0f) * maxValueFloat) + 0.5f);
81 |
82 | if (value < 0)
83 | {
84 | value = 0;
85 | }
86 | else if (value > maxValue)
87 | {
88 | value = maxValue;
89 | }
90 |
91 | lookupTable.push_back(static_cast(value));
92 | }
93 |
94 | return lookupTable;
95 | }
96 | }
97 |
98 | ColorProfileConversion::ColorProfileConversion(
99 | const FormatRecordPtr formatRecord,
100 | bool hasAlpha,
101 | ColorTransferFunction transferFunction,
102 | bool keepEmbeddedColorProfile)
103 | : context(cmsCreateContext(nullptr, nullptr)), documentProfile(), outputImageProfile(), transform(),
104 | numberOfChannels(hasAlpha ? 4 : 3), isSixteenBitMode(false), hostToLcmsLookupTable(),
105 | lcmsToHostLookupTable()
106 | {
107 | bool mayRequireConversion = transferFunction != ColorTransferFunction::Clip || !keepEmbeddedColorProfile;
108 |
109 | if (HasColorProfileMetadata(formatRecord) && mayRequireConversion)
110 | {
111 | documentProfile = ReadDocumentProfile(context.get(), formatRecord);
112 |
113 | if (!documentProfile)
114 | {
115 | throw ::std::runtime_error("Unable to load the document color profile.");
116 | }
117 |
118 | if (transferFunction == ColorTransferFunction::Clip)
119 | {
120 | // 32-bit documents always need to be converted to sRGB because the 32-bit mode
121 | // uses linear gamma.
122 | InitializeForSRGBConversion(hasAlpha, 32);
123 | }
124 | else
125 | {
126 | if (!IsRec2020ColorProfile(documentProfile.get()))
127 | {
128 | InitializeForRec2020Conversion(hasAlpha);
129 | }
130 | }
131 | }
132 | }
133 |
134 | ColorProfileConversion::ColorProfileConversion(
135 | const FormatRecordPtr formatRecord,
136 | bool hasAlpha,
137 | int hostBitsPerChannel,
138 | bool keepEmbeddedColorProfile)
139 | : context(cmsCreateContext(nullptr, nullptr)), documentProfile(), outputImageProfile(), transform(),
140 | numberOfChannels(hasAlpha ? 4 : 3), isSixteenBitMode(hostBitsPerChannel == 16), hostToLcmsLookupTable(),
141 | lcmsToHostLookupTable()
142 | {
143 | if (HasColorProfileMetadata(formatRecord) && !keepEmbeddedColorProfile)
144 | {
145 | documentProfile = ReadDocumentProfile(context.get(), formatRecord);
146 |
147 | if (!documentProfile)
148 | {
149 | throw ::std::runtime_error("Unable to load the document color profile.");
150 | }
151 |
152 | if (!IsSRGBColorProfile(documentProfile.get()))
153 | {
154 | InitializeForSRGBConversion(hasAlpha, hostBitsPerChannel);
155 | }
156 | }
157 | }
158 |
159 | void ColorProfileConversion::ConvertRow(void* row, cmsUInt32Number pixelsPerLine, cmsUInt32Number bytesPerLine)
160 | {
161 | if (transform)
162 | {
163 | constexpr cmsUInt32Number lineCount = 1;
164 | constexpr cmsUInt32Number bytesPerPlane = 0; // Unused for interleaved data
165 |
166 | if (isSixteenBitMode)
167 | {
168 | ConvertSixteenBitRowToLcms(static_cast(row), pixelsPerLine);
169 | }
170 |
171 | cmsDoTransformLineStride(
172 | transform.get(),
173 | row,
174 | row,
175 | pixelsPerLine,
176 | lineCount,
177 | bytesPerLine,
178 | bytesPerLine,
179 | bytesPerPlane,
180 | bytesPerPlane);
181 |
182 | if (isSixteenBitMode)
183 | {
184 | ConvertSixteenBitRowToHost(static_cast(row), pixelsPerLine);
185 | }
186 | }
187 | }
188 |
189 | void ColorProfileConversion::ConvertSixteenBitRowToLcms(uint16_t* row, cmsUInt32Number pixelsPerLine)
190 | {
191 | for (size_t i = 0; i < pixelsPerLine; i++)
192 | {
193 | const size_t index = i * numberOfChannels;
194 |
195 | uint16_t r = row[index];
196 | row[index] = hostToLcmsLookupTable[r];
197 |
198 | uint16_t g = row[index + 1];
199 | row[index + 1] = hostToLcmsLookupTable[g];
200 |
201 | uint16_t b = row[index + 2];
202 | row[index + 2] = hostToLcmsLookupTable[b];
203 |
204 | if (numberOfChannels == 4)
205 | {
206 | uint16_t a = row[index + 3];
207 | row[index + 3] = hostToLcmsLookupTable[a];
208 | }
209 | }
210 | }
211 |
212 | void ColorProfileConversion::ConvertSixteenBitRowToHost(uint16_t* row, cmsUInt32Number pixelsPerLine)
213 | {
214 | for (size_t i = 0; i < pixelsPerLine; i++)
215 | {
216 | const size_t index = i * numberOfChannels;
217 |
218 | uint16_t r = row[index];
219 | row[index] = lcmsToHostLookupTable[r];
220 |
221 | uint16_t g = row[index + 1];
222 | row[index + 1] = lcmsToHostLookupTable[g];
223 |
224 | uint16_t b = row[index + 2];
225 | row[index + 2] = lcmsToHostLookupTable[b];
226 |
227 | if (numberOfChannels == 4)
228 | {
229 | uint16_t a = row[index + 3];
230 | row[index + 3] = lcmsToHostLookupTable[a];
231 | }
232 | }
233 | }
234 |
235 | void ColorProfileConversion::InitializeForRec2020Conversion(bool hasAlpha)
236 | {
237 | outputImageProfile = CreateRec2020LinearRGBProfile(context.get());
238 |
239 | if (!outputImageProfile)
240 | {
241 | throw ::std::runtime_error("Unable to create a Rec. 2020 color profile for HDR conversion.");
242 | }
243 |
244 | cmsUInt32Number transformFormat = TYPE_RGB_FLT;
245 | cmsUInt32Number transformFlags = cmsFLAGS_BLACKPOINTCOMPENSATION;
246 |
247 | if (hasAlpha)
248 | {
249 | transformFormat = TYPE_RGBA_FLT;
250 | transformFlags |= cmsFLAGS_COPY_ALPHA;
251 | }
252 |
253 | transform.reset(cmsCreateTransformTHR(
254 | context.get(),
255 | documentProfile.get(),
256 | transformFormat,
257 | outputImageProfile.get(),
258 | transformFormat,
259 | INTENT_PERCEPTUAL,
260 | transformFlags));
261 |
262 | if (!transform)
263 | {
264 | throw ::std::runtime_error("Unable to create a color profile transform for HDR conversion.");
265 | }
266 | }
267 |
268 | void ColorProfileConversion::InitializeForSRGBConversion(bool hasAlpha, int hostBitsPerChannel)
269 | {
270 | outputImageProfile.reset(cmsCreate_sRGBProfileTHR(context.get()));
271 |
272 | if (!outputImageProfile)
273 | {
274 | throw ::std::runtime_error("Unable to create a sRGB color profile for the output image.");
275 | }
276 |
277 | cmsUInt32Number transformFormat;
278 | cmsUInt32Number transformFlags = cmsFLAGS_BLACKPOINTCOMPENSATION;
279 |
280 | if (hostBitsPerChannel == 8)
281 | {
282 | transformFormat = TYPE_RGB_8;
283 |
284 | if (hasAlpha)
285 | {
286 | transformFormat = TYPE_RGBA_8;
287 | transformFlags |= cmsFLAGS_COPY_ALPHA;
288 | }
289 | }
290 | else if (hostBitsPerChannel == 16)
291 | {
292 | transformFormat = TYPE_RGB_16;
293 |
294 | if (hasAlpha)
295 | {
296 | transformFormat = TYPE_RGBA_16;
297 | transformFlags |= cmsFLAGS_COPY_ALPHA;
298 | }
299 |
300 | hostToLcmsLookupTable = BuildHostToLcmsLookup();
301 | lcmsToHostLookupTable = BuildLcmsToHostLookup();
302 | }
303 | else if (hostBitsPerChannel == 32)
304 | {
305 | transformFormat = TYPE_RGB_FLT;
306 |
307 | if (hasAlpha)
308 | {
309 | transformFormat = TYPE_RGBA_FLT;
310 | transformFlags |= cmsFLAGS_COPY_ALPHA;
311 | }
312 | }
313 | else
314 | {
315 | throw ::std::runtime_error("Unsupported host bit depth, must be 8, 16 or 32.");
316 | }
317 |
318 | transform.reset(cmsCreateTransformTHR(
319 | context.get(),
320 | documentProfile.get(),
321 | transformFormat,
322 | outputImageProfile.get(),
323 | transformFormat,
324 | INTENT_PERCEPTUAL,
325 | transformFlags));
326 |
327 | if (!transform)
328 | {
329 | throw ::std::runtime_error("Unable to create a color profile transform for the output image conversion.");
330 | }
331 | }
332 |
--------------------------------------------------------------------------------
/src/common/ColorProfileDetection.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 | // Portions of this file has been adapted from openexrAE
21 | // These portions are licensed under the 2-Clause BSD License
22 |
23 | #include "ColorProfileDetection.h"
24 | #include "lcms2_plugin.h"
25 | #include "libheif/heif.h"
26 | #include
27 | #include
28 | #include
29 |
30 | namespace
31 | {
32 | bool ReadColorantTag(cmsHPROFILE profile, cmsTagSignature tag, cmsCIEXYZ& result)
33 | {
34 | const cmsCIEXYZ* const profileTag = static_cast(cmsReadTag(profile, tag));
35 |
36 | if (profileTag != nullptr)
37 | {
38 | result.X = profileTag->X;
39 | result.Y = profileTag->Y;
40 | result.Z = profileTag->Z;
41 |
42 | return true;
43 | }
44 |
45 | return false;
46 | }
47 |
48 | bool ReadMediaWhitePoint(cmsHPROFILE hProfile, cmsCIEXYZ& result)
49 | {
50 | cmsCIEXYZ* Tag;
51 |
52 | Tag = (cmsCIEXYZ*)cmsReadTag(hProfile, cmsSigMediaWhitePointTag);
53 |
54 | // If no wp, take D50
55 | if (Tag == nullptr)
56 | {
57 | result = *cmsD50_XYZ();
58 | return true;
59 | }
60 |
61 | // V2 display profiles should give D50
62 | if (cmsGetEncodedICCversion(hProfile) < 0x4000000)
63 | {
64 | if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass)
65 | {
66 | result = *cmsD50_XYZ();
67 | return true;
68 | }
69 | }
70 |
71 | // All seems ok
72 | result = *Tag;
73 | return true;
74 | }
75 |
76 | bool ComputeChromaticAdaptation(cmsMAT3* Conversion,
77 | const cmsCIEXYZ* SourceWhitePoint,
78 | const cmsCIEXYZ* DestWhitePoint,
79 | const cmsMAT3* Chad)
80 | {
81 |
82 | cmsMAT3 Chad_Inv{};
83 | cmsVEC3 ConeSourceXYZ{}, ConeSourceRGB{};
84 | cmsVEC3 ConeDestXYZ{}, ConeDestRGB{};
85 | cmsMAT3 Cone{}, Tmp{};
86 |
87 |
88 | Tmp = *Chad;
89 | if (!_cmsMAT3inverse(&Tmp, &Chad_Inv)) return FALSE;
90 |
91 | _cmsVEC3init(&ConeSourceXYZ, SourceWhitePoint->X,
92 | SourceWhitePoint->Y,
93 | SourceWhitePoint->Z);
94 |
95 | _cmsVEC3init(&ConeDestXYZ, DestWhitePoint->X,
96 | DestWhitePoint->Y,
97 | DestWhitePoint->Z);
98 |
99 | _cmsMAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ);
100 | _cmsMAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ);
101 |
102 | // Build matrix
103 | _cmsVEC3init(&Cone.v[0], ConeDestRGB.n[0] / ConeSourceRGB.n[0], 0.0, 0.0);
104 | _cmsVEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1] / ConeSourceRGB.n[1], 0.0);
105 | _cmsVEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2] / ConeSourceRGB.n[2]);
106 |
107 |
108 | // Normalize
109 | _cmsMAT3per(&Tmp, &Cone, Chad);
110 | _cmsMAT3per(Conversion, &Chad_Inv, &Tmp);
111 |
112 | return TRUE;
113 | }
114 |
115 | bool AdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll)
116 | {
117 | cmsMAT3 LamRigg = { { // Bradford matrix
118 | {{ 0.8951, 0.2664, -0.1614 }},
119 | {{ -0.7502, 1.7135, 0.0367 }},
120 | {{ 0.0389, -0.0685, 1.0296 }}
121 | } };
122 |
123 | if (ConeMatrix == nullptr)
124 | {
125 | ConeMatrix = &LamRigg;
126 | }
127 |
128 | return ComputeChromaticAdaptation(r, FromIll, ToIll, ConeMatrix);
129 | }
130 |
131 | bool AdaptMatrixFromD50(cmsMAT3* r, cmsCIExyY* DestWhitePt)
132 | {
133 | cmsCIEXYZ Dn;
134 | cmsMAT3 Bradford;
135 | cmsMAT3 Tmp;
136 |
137 | cmsxyY2XYZ(&Dn, DestWhitePt);
138 |
139 | AdaptationMatrix(&Bradford, NULL, cmsD50_XYZ(), &Dn);
140 |
141 | Tmp = *r;
142 | _cmsMAT3per(r, &Bradford, &Tmp);
143 |
144 | return TRUE;
145 | }
146 |
147 | bool CompareXYValues(const cmsCIExyY& a, const cmsCIExyY& b, cmsFloat64Number tolerance) noexcept
148 | {
149 | return fabs(a.x - b.x) < tolerance && fabs(a.y - b.y) < tolerance;
150 | }
151 |
152 | bool ProfileHasColorantsAndWhitepoint(
153 | cmsHPROFILE profile,
154 | const cmsCIExyY& requiredWhitepoint,
155 | const cmsCIExyYTRIPLE& requiredColorants,
156 | const cmsFloat64Number& tolerance)
157 | {
158 | bool result = false;
159 |
160 | if (cmsGetColorSpace(profile) == cmsSigRgbData)
161 | {
162 | cmsCIEXYZTRIPLE colorants{};
163 | cmsCIEXYZ whitepoint{};
164 |
165 | if (ReadColorantTag(profile, cmsSigRedColorantTag, colorants.Red) &&
166 | ReadColorantTag(profile, cmsSigGreenColorantTag, colorants.Green) &&
167 | ReadColorantTag(profile, cmsSigBlueColorantTag, colorants.Blue) &&
168 | ReadMediaWhitePoint(profile, whitepoint))
169 | {
170 | cmsCIExyYTRIPLE xyColorants{};
171 | cmsCIExyY xyWhitePoint{};
172 |
173 | // make a big matrix so we can run cmsAdaptMatrixFromD50() on it
174 | // before grabbing the chromaticities
175 | cmsMAT3 MColorants{};
176 |
177 | MColorants.v[0].n[0] = colorants.Red.X;
178 | MColorants.v[1].n[0] = colorants.Red.Y;
179 | MColorants.v[2].n[0] = colorants.Red.Z;
180 |
181 | MColorants.v[0].n[1] = colorants.Green.X;
182 | MColorants.v[1].n[1] = colorants.Green.Y;
183 | MColorants.v[2].n[1] = colorants.Green.Z;
184 |
185 | MColorants.v[0].n[2] = colorants.Blue.X;
186 | MColorants.v[1].n[2] = colorants.Blue.Y;
187 | MColorants.v[2].n[2] = colorants.Blue.Z;
188 |
189 |
190 | cmsXYZ2xyY(&xyWhitePoint, &whitepoint);
191 |
192 | // apparently I have to do this to get the right YXZ values
193 | // for my chromaticities - anyone know why?
194 | AdaptMatrixFromD50(&MColorants, &xyWhitePoint);
195 |
196 | // set the colorants back and convert to xyY
197 | colorants.Red.X = MColorants.v[0].n[0];
198 | colorants.Red.Y = MColorants.v[1].n[0];
199 | colorants.Red.Z = MColorants.v[2].n[0];
200 |
201 | colorants.Green.X = MColorants.v[0].n[1];
202 | colorants.Green.Y = MColorants.v[1].n[1];
203 | colorants.Green.Z = MColorants.v[2].n[1];
204 |
205 | colorants.Blue.X = MColorants.v[0].n[2];
206 | colorants.Blue.Y = MColorants.v[1].n[2];
207 | colorants.Blue.Z = MColorants.v[2].n[2];
208 |
209 | cmsXYZ2xyY(&xyColorants.Red, &colorants.Red);
210 | cmsXYZ2xyY(&xyColorants.Green, &colorants.Green);
211 | cmsXYZ2xyY(&xyColorants.Blue, &colorants.Blue);
212 |
213 | const bool whitepointMatches = CompareXYValues(xyWhitePoint, requiredWhitepoint, tolerance);
214 | const bool redMatches = CompareXYValues(xyColorants.Red, requiredColorants.Red, tolerance);
215 | const bool greenMatches = CompareXYValues(xyColorants.Green, requiredColorants.Green, tolerance);
216 | const bool blueMatches = CompareXYValues(xyColorants.Blue, requiredColorants.Blue, tolerance);
217 |
218 | if (whitepointMatches && redMatches && greenMatches && blueMatches)
219 | {
220 | result = true;
221 | }
222 | }
223 | }
224 |
225 | return result;
226 | }
227 |
228 | bool ProfileHasRec2020ColorantsAndWhitepoint(cmsHPROFILE profile)
229 | {
230 | const cmsCIExyY whitepointD65 = { 0.3127, 0.3290, 1.0f }; // D65
231 | const cmsCIExyYTRIPLE rec2020Primaries =
232 | {
233 | { 0.708, 0.292, 1.0 },
234 | { 0.170, 0.797, 1.0 },
235 | { 0.131, 0.046, 1.0 }
236 | };
237 |
238 | return ProfileHasColorantsAndWhitepoint(profile, whitepointD65, rec2020Primaries, 0.01);
239 | }
240 |
241 | bool ProfileHasSRGBColorantsAndWhitepoint(cmsHPROFILE profile)
242 | {
243 | const cmsCIExyY whitepointD65 = { 0.3127, 0.3290, 1.0f }; // D65
244 | const cmsCIExyYTRIPLE srgbPrimaries =
245 | {
246 | { 0.6400, 0.3300, 1.0 },
247 | { 0.3000, 0.6000, 1.0 },
248 | { 0.1500, 0.0600, 1.0 }
249 | };
250 |
251 | return ProfileHasColorantsAndWhitepoint(profile, whitepointD65, srgbPrimaries, 0.01);
252 | }
253 |
254 | constexpr std::pair MakeDescriptionEntry(const wchar_t* text)
255 | {
256 | return std::make_pair(text, std::char_traits::length(text));
257 | }
258 |
259 | bool ProfileHasRec2020Description(cmsHPROFILE profile)
260 | {
261 | const std::vector> entries =
262 | {
263 | // This name should cover all of Elle Stone's Rec. 2020 ICC profiles.
264 | // These profiles use the file name as the profile description, e.g. Rec2020-elle-V4-g10.icc.
265 | MakeDescriptionEntry(L"Rec2020-elle-V"),
266 | // The ICC profiles generated by colorist use this.
267 | MakeDescriptionEntry(L"Colorist BT. 2020"),
268 | // The beta Rec. 2020 profile from the International Color Consortium
269 | MakeDescriptionEntry(L"ITU-R BT. 2020 Reference Display")
270 | };
271 |
272 | constexpr cmsUInt32Number descriptionBufferSize = 256;
273 | wchar_t descriptionBuffer[descriptionBufferSize]{};
274 |
275 | const size_t charsWritten = cmsGetProfileInfo(
276 | profile,
277 | cmsInfoDescription,
278 | "en",
279 | "US",
280 | descriptionBuffer,
281 | descriptionBufferSize - 1) / sizeof(wchar_t);
282 |
283 | if (charsWritten > 0)
284 | {
285 | for (const auto& entry : entries)
286 | {
287 | if (charsWritten >= entry.second)
288 | {
289 | if (std::wcsncmp(descriptionBuffer, entry.first, entry.second) == 0)
290 | {
291 | return true;
292 | }
293 | }
294 | }
295 | }
296 |
297 | return false;
298 | }
299 |
300 | bool ProfileHasSRGBDescription(cmsHPROFILE profile)
301 | {
302 | constexpr cmsUInt32Number descriptionBufferSize = 256;
303 | wchar_t descriptionBuffer[descriptionBufferSize]{};
304 |
305 | const size_t charsWritten = cmsGetProfileInfo(
306 | profile,
307 | cmsInfoDescription,
308 | "en",
309 | "US",
310 | descriptionBuffer,
311 | descriptionBufferSize - 1) / sizeof(wchar_t);
312 |
313 | if (charsWritten > 0)
314 | {
315 | constexpr const wchar_t* const srgbProfileName = L"sRGB";
316 | constexpr size_t srgbProfileNameLength = std::char_traits::length(srgbProfileName);
317 |
318 | if (charsWritten >= srgbProfileNameLength)
319 | {
320 | if (std::wcsncmp(descriptionBuffer, srgbProfileName, srgbProfileNameLength) == 0)
321 | {
322 | return true;
323 | }
324 | }
325 | }
326 |
327 | return false;
328 | }
329 | }
330 |
331 | bool IsRec2020ColorProfile(cmsHPROFILE profile)
332 | {
333 | bool result = false;
334 |
335 | if (profile != nullptr)
336 | {
337 | // The CICP tag is checked first as it is the most accurate method.
338 | if (cmsIsTag(profile, cmsSigcicpTag))
339 | {
340 | cmsVideoSignalType* tag = static_cast(cmsReadTag(profile, cmsSigcicpTag));
341 |
342 | result = tag->ColourPrimaries == static_cast(heif_color_primaries_ITU_R_BT_2020_2_and_2100_0);
343 | }
344 | else
345 | {
346 | result = ProfileHasRec2020Description(profile) || ProfileHasRec2020ColorantsAndWhitepoint(profile);
347 | }
348 | }
349 |
350 | return result;
351 | }
352 |
353 | bool IsSRGBColorProfile(cmsHPROFILE profile)
354 | {
355 | bool result = false;
356 |
357 | if (profile != nullptr)
358 | {
359 | // The CICP tag is checked first as it is the most accurate method.
360 | if (cmsIsTag(profile, cmsSigcicpTag))
361 | {
362 | cmsVideoSignalType* tag = static_cast(cmsReadTag(profile, cmsSigcicpTag));
363 |
364 | result = tag->ColourPrimaries == static_cast(heif_color_primaries_ITU_R_BT_709_5)
365 | && tag->TransferCharacteristics == static_cast(heif_transfer_characteristic_IEC_61966_2_1);
366 | }
367 | else
368 | {
369 | result = ProfileHasSRGBDescription(profile) || ProfileHasSRGBColorantsAndWhitepoint(profile);
370 | }
371 | }
372 |
373 | return result;
374 | }
375 |
--------------------------------------------------------------------------------
/src/common/Write.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of avif-format, an AV1 Image (AVIF) file format
3 | * plug-in for Adobe Photoshop(R).
4 | *
5 | * Copyright (c) 2021, 2022, 2023 Nicholas Hayes
6 | *
7 | * avif-format is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * avif-format is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with avif-format. If not, see .
19 | */
20 |
21 | #include "AvifFormat.h"
22 | #include "FileIO.h"
23 | #include "LibHeifException.h"
24 | #include "OSErrException.h"
25 | #include "PremultipliedAlpha.h"
26 | #include "ScopedBufferSuite.h"
27 | #include "ScopedHeif.h"
28 | #include "WriteHeifImage.h"
29 | #include "WriteMetadata.h"
30 | #include
31 | #include
32 | #include
33 |
34 | namespace
35 | {
36 | ScopedHeifImageHandle EncodeImage(
37 | heif_context* context,
38 | heif_image* image,
39 | heif_encoder* encoder,
40 | const heif_encoding_options* options)
41 | {
42 | heif_image_handle* encodedImageHandle;
43 |
44 | LibHeifException::ThrowIfError(heif_context_encode_image(context, image, encoder, options, &encodedImageHandle));
45 |
46 | return ScopedHeifImageHandle(encodedImageHandle);
47 | }
48 |
49 | ScopedHeifEncoder GetAOMEncoder(heif_context* context)
50 | {
51 | heif_encoder* tempEncoder;
52 |
53 | const heif_encoder_descriptor* aomEncoderDescriptor;
54 |
55 | if (heif_context_get_encoder_descriptors(context, heif_compression_AV1, "aom", &aomEncoderDescriptor, 1) != 1)
56 | {
57 | throw std::runtime_error("Unable to get the AOM encoder descriptor.");
58 | }
59 |
60 | LibHeifException::ThrowIfError(heif_context_get_encoder(context, aomEncoderDescriptor, &tempEncoder));
61 |
62 | return ScopedHeifEncoder(tempEncoder);
63 | }
64 |
65 | heif_error heif_writer_write(
66 | heif_context* /*context*/,
67 | const void* data,
68 | size_t size,
69 | void* userdata)
70 | {
71 | static heif_error Success = { heif_error_Ok, heif_suberror_Unspecified, "Success" };
72 | static heif_error WriteError = { heif_error_Encoding_error, heif_suberror_Cannot_write_output_data, "Write error" };
73 |
74 | return WriteData(reinterpret_cast(userdata), data, size) == noErr ? Success : WriteError;
75 | }
76 |
77 | void WriteEncodedImage(const FormatRecordPtr formatRecord, heif_context* context)
78 | {
79 | static heif_writer writer = { 1, heif_writer_write };
80 |
81 | LibHeifException::ThrowIfError(heif_context_write(context, &writer, reinterpret_cast(formatRecord->dataFork)));
82 | }
83 |
84 | void EncodeAndSaveImage(
85 | const FormatRecordPtr formatRecord,
86 | heif_context* context,
87 | heif_image* image,
88 | const SaveUIOptions& saveOptions)
89 | {
90 | formatRecord->progressProc(50, 100);
91 |
92 | AddColorProfileToImage(formatRecord, image, saveOptions);
93 |
94 | ScopedHeifEncoder encoder = GetAOMEncoder(context);
95 |
96 | if (saveOptions.lossless)
97 | {
98 | heif_encoder_set_lossy_quality(encoder.get(), 100);
99 | heif_encoder_set_lossless(encoder.get(), true);
100 | heif_encoder_set_parameter(encoder.get(), "chroma", "444");
101 | }
102 | else
103 | {
104 | heif_encoder_set_lossy_quality(encoder.get(), saveOptions.quality);
105 | heif_encoder_set_lossless(encoder.get(), false);
106 |
107 | switch (saveOptions.chromaSubsampling)
108 | {
109 | case ChromaSubsampling::Yuv420:
110 | heif_encoder_set_parameter(encoder.get(), "chroma", "420");
111 | break;
112 | case ChromaSubsampling::Yuv422:
113 | heif_encoder_set_parameter(encoder.get(), "chroma", "422");
114 | break;
115 | case ChromaSubsampling::Yuv444:
116 | heif_encoder_set_parameter(encoder.get(), "chroma", "444");
117 | break;
118 | default:
119 | throw OSErrException(formatBadParameters);
120 | }
121 |
122 | if (HasAlphaChannel(formatRecord) && saveOptions.losslessAlpha)
123 | {
124 | heif_encoder_set_parameter_integer(encoder.get(), "alpha-quality", 100);
125 | heif_encoder_set_parameter_boolean(encoder.get(), "lossless-alpha", true);
126 | }
127 | }
128 |
129 | switch (saveOptions.compressionSpeed)
130 | {
131 | case CompressionSpeed::Fastest:
132 | heif_encoder_set_parameter_integer(encoder.get(), "speed", 6);
133 | heif_encoder_set_parameter_boolean(encoder.get(), "realtime", true);
134 | break;
135 | case CompressionSpeed::Slowest:
136 | heif_encoder_set_parameter_integer(encoder.get(), "speed", 1);
137 | break;
138 | case CompressionSpeed::Default:
139 | heif_encoder_set_parameter_integer(encoder.get(), "speed", 4);
140 | break;
141 | default:
142 | throw OSErrException(formatBadParameters);
143 | }
144 |
145 | const unsigned int threadCount = std::clamp(std::thread::hardware_concurrency(), 1U, 16U);
146 | heif_encoder_set_parameter_integer(encoder.get(), "threads", static_cast(threadCount));
147 |
148 | ScopedHeifEncodingOptions encodingOptions(heif_encoding_options_alloc());
149 |
150 | if (encodingOptions == nullptr)
151 | {
152 | throw std::bad_alloc();
153 | }
154 |
155 | encodingOptions->save_two_colr_boxes_when_ICC_and_nclx_available = true;
156 | encodingOptions->macOS_compatibility_workaround_no_nclx_profile = false;
157 |
158 | // Check if cancellation has been requested before staring the encode.
159 | // Unfortunately, most encoders do not provide a way to cancel an encode that is in progress.
160 | if (formatRecord->abortProc())
161 | {
162 | throw OSErrException(userCanceledErr);
163 | }
164 |
165 | ScopedHeifImageHandle encodedImageHandle = EncodeImage(
166 | context,
167 | image,
168 | encoder.get(),
169 | encodingOptions.get());
170 |
171 | formatRecord->progressProc(75, 100);
172 | if (formatRecord->abortProc())
173 | {
174 | throw OSErrException(userCanceledErr);
175 | }
176 |
177 | if (saveOptions.keepExif)
178 | {
179 | AddExifMetadata(formatRecord, context, encodedImageHandle.get());
180 | }
181 |
182 | if (saveOptions.keepXmp)
183 | {
184 | AddXmpMetadata(formatRecord, context, encodedImageHandle.get());
185 | }
186 |
187 | WriteEncodedImage(formatRecord, context);
188 |
189 | formatRecord->progressProc(100, 100);
190 | }
191 |
192 | AlphaState GetAlphaState(const FormatRecordPtr formatRecord, const SaveUIOptions& saveOptions)
193 | {
194 | AlphaState alphaState = AlphaState::None;
195 |
196 | if (HasAlphaChannel(formatRecord))
197 | {
198 | // The premultiplied alpha conversion can cause colors to drift, so it is
199 | // disabled for lossless compression.
200 | if (saveOptions.premultipliedAlpha && !saveOptions.lossless)
201 | {
202 | alphaState = AlphaState::Premultiplied;
203 | }
204 | else
205 | {
206 | alphaState = AlphaState::Straight;
207 | }
208 | }
209 |
210 | return alphaState;
211 | }
212 | }
213 |
214 | OSErr DoWritePrepare(FormatRecordPtr formatRecord)
215 | {
216 | PrintFunctionName();
217 |
218 | formatRecord->maxData /= 2;
219 |
220 | return noErr;
221 | }
222 |
223 | OSErr DoWriteStart(FormatRecordPtr formatRecord, SaveUIOptions& options)
224 | {
225 | PrintFunctionName();
226 |
227 | OSErr err = noErr;
228 |
229 | ReadScriptParamsOnWrite(formatRecord, options, nullptr);
230 |
231 | if (formatRecord->depth == 32)
232 | {
233 | if (IsMonochromeImage(formatRecord))
234 | {
235 | // Monochrome images are not currently supported for saving as HDR.
236 | // These images will be saved as 10-bit or 12-bit SDR.
237 | if (options.hdrTransferFunction != ColorTransferFunction::Clip)
238 | {
239 | options.hdrTransferFunction = ColorTransferFunction::Clip;
240 | }
241 | }
242 | else if (options.hdrTransferFunction == ColorTransferFunction::SMPTE428)
243 | {
244 | // SMPTE 428 requires 12-bit.
245 | if (options.imageBitDepth != ImageBitDepth::Twelve)
246 | {
247 | options.imageBitDepth = ImageBitDepth::Twelve;
248 | }
249 | }
250 |
251 | if (options.premultipliedAlpha && options.hdrTransferFunction != ColorTransferFunction::Clip)
252 | {
253 | // Disable premultiplied alpha for 32-bit HDR images.
254 | // There is currently no clear guidance on how this should be supported
255 | // between different applications.
256 | options.premultipliedAlpha = false;
257 | }
258 | }
259 |
260 | bool libheifInitialized = false;
261 |
262 | try
263 | {
264 | LibHeifException::ThrowIfError(heif_init(nullptr));
265 | libheifInitialized = true;
266 |
267 | formatRecord->progressProc(0, 100);
268 |
269 | ScopedHeifContext context(heif_context_alloc());
270 |
271 | if (context == nullptr)
272 | {
273 | throw std::bad_alloc();
274 | }
275 |
276 | const VPoint imageSize = GetImageSize(formatRecord);
277 | const AlphaState alphaState = GetAlphaState(formatRecord, options);
278 |
279 | formatRecord->planeBytes = (formatRecord->depth + 7) / 8;
280 | formatRecord->loPlane = 0;
281 | formatRecord->hiPlane = formatRecord->planes - 1;
282 | formatRecord->colBytes = static_cast(formatRecord->planes * formatRecord->planeBytes);
283 |
284 | formatRecord->progressProc(25, 100);
285 |
286 | const unsigned64 rowBytes = static_cast(imageSize.h) * static_cast(formatRecord->colBytes);
287 |
288 | if (rowBytes > std::numeric_limits::max())
289 | {
290 | throw std::bad_alloc();
291 | }
292 | else
293 | {
294 | formatRecord->rowBytes = static_cast(rowBytes);
295 | }
296 |
297 | ScopedBufferSuiteBuffer buffer(formatRecord->bufferProcs, formatRecord->rowBytes);
298 |
299 | formatRecord->data = buffer.lock();
300 |
301 | ScopedHeifImage image;
302 |
303 | if (IsMonochromeImage(formatRecord))
304 | {
305 | switch (formatRecord->depth)
306 | {
307 | case 8:
308 | image = CreateHeifImageGrayEightBit(formatRecord, alphaState, imageSize, options);
309 | break;
310 | case 16:
311 | image = CreateHeifImageGraySixteenBit(formatRecord, alphaState, imageSize, options);
312 | break;
313 | case 32:
314 | image = CreateHeifImageGrayThirtyTwoBit(formatRecord, alphaState, imageSize, options);
315 | break;
316 | default:
317 | throw OSErrException(formatBadParameters);
318 | }
319 | }
320 | else
321 | {
322 | switch (formatRecord->depth)
323 | {
324 | case 8:
325 | image = CreateHeifImageRGBEightBit(formatRecord, alphaState, imageSize, options);
326 | break;
327 | case 16:
328 | image = CreateHeifImageRGBSixteenBit(formatRecord, alphaState, imageSize, options);
329 | break;
330 | case 32:
331 | image = CreateHeifImageRGBThirtyTwoBit(formatRecord, alphaState, imageSize, options);
332 | break;
333 | default:
334 | throw OSErrException(formatBadParameters);
335 | }
336 | }
337 |
338 | if (alphaState == AlphaState::Premultiplied)
339 | {
340 | heif_image_set_premultiplied_alpha(image.get(), true);
341 | }
342 |
343 | EncodeAndSaveImage(formatRecord, context.get(), image.get(), options);
344 | }
345 | catch (const std::bad_alloc&)
346 | {
347 | err = memFullErr;
348 | }
349 | catch (const LibHeifException& e)
350 | {
351 | err = HandleErrorMessage(formatRecord, e.what(), writErr);
352 | }
353 | catch (const OSErrException& e)
354 | {
355 | err = e.GetErrorCode();
356 | }
357 | catch (const std::exception& e)
358 | {
359 | err = HandleErrorMessage(formatRecord, e.what(), writErr);
360 | }
361 | catch (...)
362 | {
363 | err = writErr;
364 | }
365 |
366 | if (libheifInitialized)
367 | {
368 | heif_deinit();
369 | }
370 |
371 | formatRecord->data = nullptr;
372 | SetRect(formatRecord, 0, 0, 0, 0);
373 |
374 | return err;
375 | }
376 |
377 | OSErr DoWriteContinue()
378 | {
379 | PrintFunctionName();
380 |
381 | return noErr;
382 | }
383 |
384 | OSErr DoWriteFinish(FormatRecordPtr formatRecord, const SaveUIOptions& options)
385 | {
386 | PrintFunctionName();
387 |
388 | WriteScriptParamsOnWrite(formatRecord, options);
389 | return noErr;
390 | }
391 |
--------------------------------------------------------------------------------