├── 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 | --------------------------------------------------------------------------------