├── .github
└── workflows
│ ├── build-linux-27.yml
│ ├── build-linux-28.yml
│ ├── build-macos-27.yml
│ ├── build-macos-28.yml
│ ├── build-macos-arm-27.yml
│ ├── build-macos-arm-28.yml
│ ├── build-windows-27.yml
│ ├── build-windows-28.yml
│ └── test-interface.yml
├── .gitignore
├── .readthedocs.yaml
├── CHANGELOG.txt
├── INSTALL.rst
├── LICENSE
├── MANIFEST.in
├── README.rst
├── USAGE.rst
├── examples
├── README.rst
├── addmoddel.py
├── easyaccess.py
├── exifcomment.py
├── exifdata.py
├── exifprint.py
├── exifvalue.py
├── iptceasy.py
├── thumbnail.py
├── values.py
└── xmpsample.py
├── pyproject.toml
├── setup.py
├── src
├── doc
│ ├── _templates
│ │ └── module.rst
│ ├── conf.py
│ ├── index.rst
│ ├── misc
│ │ ├── api.rst
│ │ ├── changelog.rst
│ │ ├── install.rst
│ │ ├── readme.rst
│ │ └── usage.rst
│ └── requirements.txt
├── interface
│ ├── __main__.py
│ ├── basicio.i
│ ├── datasets.i
│ ├── easyaccess.i
│ ├── error.i
│ ├── exif.i
│ ├── image.i
│ ├── iptc.i
│ ├── metadatum.i
│ ├── preview.i
│ ├── properties.i
│ ├── shared
│ │ ├── buffers.i
│ │ ├── containers.i
│ │ ├── data_iterator.i
│ │ ├── enum.i
│ │ ├── exception.i
│ │ ├── exv_options.i
│ │ ├── keep_reference.i
│ │ ├── preamble.i
│ │ ├── static_list.i
│ │ ├── struct_dict.i
│ │ ├── unique_ptr.i
│ │ ├── windows_cp.i
│ │ └── windows_path.i
│ ├── tags.i
│ ├── types.i
│ ├── value.i
│ ├── version.i
│ └── xmp.i
├── swig-0_27_7
│ ├── __init__.py
│ ├── __main__.py
│ ├── basicio.py
│ ├── basicio_wrap.cxx
│ ├── datasets.py
│ ├── datasets_wrap.cxx
│ ├── easyaccess.py
│ ├── easyaccess_wrap.cxx
│ ├── error.py
│ ├── error_wrap.cxx
│ ├── exif.py
│ ├── exif_wrap.cxx
│ ├── image.py
│ ├── image_wrap.cxx
│ ├── iptc.py
│ ├── iptc_wrap.cxx
│ ├── metadatum.py
│ ├── metadatum_wrap.cxx
│ ├── preview.py
│ ├── preview_wrap.cxx
│ ├── properties.py
│ ├── properties_wrap.cxx
│ ├── tags.py
│ ├── tags_wrap.cxx
│ ├── types.py
│ ├── types_wrap.cxx
│ ├── value.py
│ ├── value_wrap.cxx
│ ├── version.py
│ ├── version_wrap.cxx
│ ├── xmp.py
│ └── xmp_wrap.cxx
└── swig-0_28_5
│ ├── __init__.py
│ ├── __main__.py
│ ├── basicio.py
│ ├── basicio_wrap.cxx
│ ├── datasets.py
│ ├── datasets_wrap.cxx
│ ├── easyaccess.py
│ ├── easyaccess_wrap.cxx
│ ├── error.py
│ ├── error_wrap.cxx
│ ├── exif.py
│ ├── exif_wrap.cxx
│ ├── image.py
│ ├── image_wrap.cxx
│ ├── iptc.py
│ ├── iptc_wrap.cxx
│ ├── metadatum.py
│ ├── metadatum_wrap.cxx
│ ├── preview.py
│ ├── preview_wrap.cxx
│ ├── properties.py
│ ├── properties_wrap.cxx
│ ├── tags.py
│ ├── tags_wrap.cxx
│ ├── types.py
│ ├── types_wrap.cxx
│ ├── value.py
│ ├── value_wrap.cxx
│ ├── version.py
│ ├── version_wrap.cxx
│ ├── xmp.py
│ └── xmp_wrap.cxx
├── tests
├── image_01.jpg
├── image_02.heic
├── image_02.jpg
├── test_basicio.py
├── test_datasets.py
├── test_easyaccess.py
├── test_error.py
├── test_exif.py
├── test_image.py
├── test_iptc.py
├── test_metadatum.py
├── test_preview.py
├── test_properties.py
├── test_tags.py
├── test_types.py
├── test_value.py
├── test_version.py
└── test_xmp.py
└── utils
├── build_docs.py
├── build_swig.py
└── tag_release.py
/.github/workflows/build-linux-27.yml:
--------------------------------------------------------------------------------
1 | name: Build Linux wheels exiv2 0.27
2 | on: workflow_dispatch
3 |
4 | jobs:
5 | build:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - name: Check out repository code
9 | uses: actions/checkout@v4
10 |
11 | - name: Fetch Exiv2 source
12 | run: >
13 | wget -nv
14 | https://github.com/Exiv2/exiv2/releases/download/v0.27.7/exiv2-0.27.7-Source.tar.gz
15 | -O exiv2.tar.gz
16 |
17 | - name: Extract Exiv2 source
18 | shell: bash
19 | run: |
20 | tar -xzf exiv2.tar.gz
21 | mv exiv2-0.27.7-Source libexiv2
22 |
23 | - name: Build wheels
24 | uses: pypa/cibuildwheel@v2.16.5
25 | env:
26 | CIBW_ARCHS: auto64
27 | CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
28 | CIBW_ENVIRONMENT: EXIV2_ROOT=libexiv2/build-linux/install
29 | CIBW_BUILD: cp*-manylinux_x86_64
30 | CIBW_TEST_COMMAND: >
31 | python3 -m exiv2 -v &&
32 | python3 -m unittest discover {project}/tests -v
33 | CIBW_BEFORE_ALL: >
34 | yum install -y zlib-devel expat-devel gettext-devel
35 | libcurl-devel &&
36 | localedef -c -i de_DE -f UTF-8 de_DE.UTF-8 &&
37 | cd libexiv2 &&
38 | cmake -B build-linux -D CMAKE_BUILD_TYPE=Release
39 | -D CMAKE_INSTALL_PREFIX=build-linux/install
40 | -D CMAKE_CXX_FLAGS="-Wno-deprecated-declarations"
41 | -D EXIV2_BUILD_SAMPLES=OFF
42 | -D EXIV2_BUILD_EXIV2_COMMAND=OFF
43 | -D EXIV2_ENABLE_BMFF=ON
44 | -D EXIV2_ENABLE_NLS=ON
45 | -D EXIV2_ENABLE_VIDEO=ON
46 | -D EXIV2_ENABLE_WEBREADY=ON
47 | -D EXIV2_ENABLE_CURL=ON
48 | -D EXIV2_ENABLE_SSH=OFF
49 | -D CMAKE_CXX_STANDARD=98 &&
50 | cmake --build build-linux &&
51 | cmake --install build-linux
52 |
53 | - name: Store results
54 | uses: actions/upload-artifact@v3
55 | with:
56 | name: linux-27-wheels
57 | path: wheelhouse/*.whl
58 |
--------------------------------------------------------------------------------
/.github/workflows/build-linux-28.yml:
--------------------------------------------------------------------------------
1 | name: Build Linux wheels exiv2 0.28
2 | on: workflow_dispatch
3 |
4 | jobs:
5 | build:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - name: Check out repository code
9 | uses: actions/checkout@v4
10 |
11 | - name: Fetch Exiv2 source
12 | run: >
13 | wget -nv
14 | https://github.com/Exiv2/exiv2/archive/refs/tags/v0.28.5.tar.gz
15 | -O exiv2.tar.gz
16 |
17 | - name: Extract Exiv2 source
18 | run: |
19 | tar -xzf exiv2.tar.gz
20 | mv exiv2-0.28.5 libexiv2
21 |
22 | - name: Download inih
23 | run: >
24 | wget -nv
25 | https://github.com/benhoyt/inih/archive/r58/inih-r58.tar.gz
26 | -O inih.tar.gz
27 |
28 | - name: Extract inih source
29 | run: |
30 | tar -xzf inih.tar.gz
31 | mv inih-r58 inih
32 |
33 | - name: Build wheels
34 | uses: pypa/cibuildwheel@v2.22.0
35 | env:
36 | CIBW_ARCHS: auto64
37 | CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
38 | CIBW_ENVIRONMENT: EXIV2_ROOT=libexiv2/build-linux-release/install
39 | CIBW_BUILD: cp*-manylinux_x86_64
40 | CIBW_TEST_COMMAND: >
41 | python3 -m exiv2 -v &&
42 | python3 -m unittest discover {project}/tests -v
43 | CIBW_BEFORE_ALL: >
44 | yum install -y --nogpgcheck zlib-devel expat-devel gettext-devel
45 | libcurl-devel brotli-devel meson &&
46 | localedef -c -i de_DE -f UTF-8 de_DE.UTF-8 &&
47 | pip install ninja &&
48 | cd inih && mkdir build && cd build &&
49 | meson setup --prefix=/usr --buildtype=release .. &&
50 | ninja && ninja install &&
51 | cd ../../libexiv2 &&
52 | cmake --preset linux-release
53 | -D CONAN_AUTO_INSTALL=OFF
54 | -D EXIV2_BUILD_SAMPLES=OFF
55 | -D EXIV2_BUILD_UNIT_TESTS=OFF
56 | -D EXIV2_ENABLE_NLS=ON
57 | -D EXIV2_ENABLE_FILESYSTEM_ACCESS=ON
58 | -D EXIV2_BUILD_EXIV2_COMMAND=OFF
59 | -D EXIV2_TEAM_WARNINGS_AS_ERRORS=OFF &&
60 | cmake --build build-linux-release --config Release &&
61 | cmake --install build-linux-release --config Release
62 |
63 | - name: Store results
64 | uses: actions/upload-artifact@v4
65 | with:
66 | name: linux-28-wheels
67 | path: wheelhouse/*.whl
68 |
--------------------------------------------------------------------------------
/.github/workflows/build-macos-27.yml:
--------------------------------------------------------------------------------
1 | name: Build MacOS wheels exiv2 0.27
2 | on: workflow_dispatch
3 |
4 | jobs:
5 | build:
6 | runs-on: macos-latest
7 | steps:
8 | - name: Check out repository code
9 | uses: actions/checkout@v4
10 |
11 | - name: Fetch Exiv2 source
12 | run: >
13 | wget -nv
14 | https://github.com/Exiv2/exiv2/releases/download/v0.27.7/exiv2-0.27.7-Source.tar.gz
15 | -O exiv2.tar.gz
16 |
17 | - name: Extract Exiv2 source
18 | shell: bash
19 | run: |
20 | tar -xzf exiv2.tar.gz
21 | mv exiv2-0.27.7-Source libexiv2
22 |
23 | - name: Build wheels
24 | uses: pypa/cibuildwheel@v2.16.5
25 | env:
26 | CIBW_ARCHS: x86_64
27 | CIBW_ENVIRONMENT: EXIV2_ROOT=libexiv2/build-macos/install
28 | CIBW_SKIP: pp3*
29 | CIBW_TEST_COMMAND: >
30 | python -m exiv2 -v &&
31 | python -m unittest discover {project}/tests -v
32 | CIBW_BEFORE_ALL: >
33 | brew install ninja gettext &&
34 | cd libexiv2 &&
35 | cmake . -B build-macos -DCMAKE_BUILD_TYPE=Release
36 | -D CMAKE_INSTALL_PREFIX=build-macos/install
37 | -D CMAKE_CXX_FLAGS="-Wno-deprecated-declarations"
38 | -D EXIV2_BUILD_SAMPLES=OFF
39 | -D EXIV2_BUILD_EXIV2_COMMAND=OFF
40 | -D EXIV2_ENABLE_BMFF=ON
41 | -D EXIV2_ENABLE_NLS=ON
42 | -D EXIV2_ENABLE_VIDEO=ON
43 | -D EXIV2_ENABLE_WEBREADY=ON
44 | -D EXIV2_ENABLE_CURL=ON
45 | -D EXIV2_ENABLE_SSH=OFF
46 | -D CMAKE_CXX_STANDARD=98
47 | -G Ninja &&
48 | cmake --build build-macos --config Release &&
49 | cmake --install build-macos --config Release
50 |
51 | - name: Store results
52 | uses: actions/upload-artifact@v3
53 | with:
54 | name: macos-27-wheels
55 | path: wheelhouse/*.whl
56 |
--------------------------------------------------------------------------------
/.github/workflows/build-macos-28.yml:
--------------------------------------------------------------------------------
1 | name: Build MacOS wheels exiv2 0.28
2 | on: workflow_dispatch
3 |
4 | jobs:
5 | build:
6 | runs-on: macos-13
7 | steps:
8 | - name: Check out repository code
9 | uses: actions/checkout@v4
10 |
11 | - name: Fetch Exiv2 source
12 | run: >
13 | wget -nv
14 | https://github.com/Exiv2/exiv2/archive/refs/tags/v0.28.5.tar.gz
15 | -O exiv2.tar.gz
16 |
17 | - name: Extract Exiv2 source
18 | shell: bash
19 | run: |
20 | tar -xzf exiv2.tar.gz
21 | mv exiv2-0.28.5 libexiv2
22 |
23 | - name: Build wheels
24 | uses: pypa/cibuildwheel@v2.22.0
25 | env:
26 | CIBW_ARCHS: x86_64
27 | CIBW_ENVIRONMENT: >
28 | EXIV2_ROOT=libexiv2/build-base_mac/install
29 | MACOSX_DEPLOYMENT_TARGET="13.0"
30 | SYSTEM_VERSION_COMPAT=0
31 | CIBW_SKIP: pp3*
32 | CIBW_TEST_COMMAND: >
33 | python -m exiv2 -v &&
34 | python -m unittest discover {project}/tests -v
35 | CIBW_BEFORE_ALL: >
36 | brew install ninja inih &&
37 | cd libexiv2 &&
38 | cmake --preset base_mac
39 | -D EXIV2_BUILD_SAMPLES=OFF
40 | -D EXIV2_BUILD_UNIT_TESTS=OFF
41 | -D EXIV2_ENABLE_NLS=ON
42 | -D EXIV2_ENABLE_FILESYSTEM_ACCESS=ON
43 | -D EXIV2_BUILD_EXIV2_COMMAND=OFF
44 | -D EXIV2_TEAM_WARNINGS_AS_ERRORS=OFF &&
45 | cmake --build build-base_mac --config Release &&
46 | cmake --install build-base_mac --config Release
47 |
48 | - name: Store results
49 | uses: actions/upload-artifact@v4
50 | with:
51 | name: macos-28-wheels
52 | path: wheelhouse/*.whl
53 |
--------------------------------------------------------------------------------
/.github/workflows/build-macos-arm-27.yml:
--------------------------------------------------------------------------------
1 | name: Build MacOS ARM wheels exiv2 0.27
2 | on: workflow_dispatch
3 |
4 | jobs:
5 | build:
6 | runs-on: flyci-macos-large-latest-m1
7 | steps:
8 | - name: Check out repository code
9 | uses: actions/checkout@v4
10 |
11 | - name: Fetch Exiv2 source
12 | run: >
13 | wget -nv
14 | https://github.com/Exiv2/exiv2/releases/download/v0.27.7/exiv2-0.27.7-Source.tar.gz
15 | -O exiv2.tar.gz
16 |
17 | - name: Extract Exiv2 source
18 | shell: bash
19 | run: |
20 | tar -xzf exiv2.tar.gz
21 | mv exiv2-0.27.7-Source libexiv2
22 |
23 | - name: Install pipx
24 | run: pip install pipx
25 |
26 | - name: Build wheels
27 | uses: pypa/cibuildwheel@v2.16.5
28 | env:
29 | CIBW_ARCHS: arm64
30 | CIBW_ENVIRONMENT: EXIV2_ROOT=libexiv2/build-macos/install
31 | CIBW_SKIP: pp3*
32 | CIBW_TEST_COMMAND: >
33 | python -m exiv2 -v &&
34 | python -m unittest discover {project}/tests -v
35 | CIBW_TEST_SKIP: cp38-*
36 | CIBW_BEFORE_ALL: >
37 | brew install ninja curl &&
38 | cd libexiv2 &&
39 | cmake . -B build-macos -DCMAKE_BUILD_TYPE=Release
40 | -D CMAKE_INSTALL_PREFIX=build-macos/install
41 | -D CMAKE_CXX_FLAGS="-Wno-deprecated-declarations"
42 | -D EXIV2_BUILD_SAMPLES=OFF
43 | -D EXIV2_BUILD_EXIV2_COMMAND=OFF
44 | -D EXIV2_ENABLE_BMFF=ON
45 | -D EXIV2_ENABLE_NLS=ON
46 | -D EXIV2_ENABLE_VIDEO=ON
47 | -D EXIV2_ENABLE_WEBREADY=ON
48 | -D EXIV2_ENABLE_CURL=ON
49 | -D EXIV2_ENABLE_SSH=OFF
50 | -D CMAKE_CXX_STANDARD=98
51 | -D CMAKE_OSX_ARCHITECTURES=arm64
52 | -G Ninja &&
53 | cmake --build build-macos --config Release &&
54 | cmake --install build-macos --config Release
55 |
56 | - name: Store results
57 | uses: actions/upload-artifact@v3
58 | with:
59 | name: macos-arm-27-wheels
60 | path: wheelhouse/*.whl
61 |
--------------------------------------------------------------------------------
/.github/workflows/build-macos-arm-28.yml:
--------------------------------------------------------------------------------
1 | name: Build MacOS ARM wheels exiv2 0.28
2 | on: workflow_dispatch
3 |
4 | jobs:
5 | build:
6 | runs-on: macos-latest
7 | steps:
8 | - name: Check out repository code
9 | uses: actions/checkout@v4
10 |
11 | - name: Fetch Exiv2 source
12 | run: >
13 | wget -nv
14 | https://github.com/Exiv2/exiv2/archive/refs/tags/v0.28.5.tar.gz
15 | -O exiv2.tar.gz
16 |
17 | - name: Extract Exiv2 source
18 | shell: bash
19 | run: |
20 | tar -xzf exiv2.tar.gz
21 | mv exiv2-0.28.5 libexiv2
22 |
23 | - name: Build wheels
24 | uses: pypa/cibuildwheel@v2.22.0
25 | env:
26 | CIBW_ARCHS: arm64
27 | CIBW_ENVIRONMENT: >
28 | EXIV2_ROOT=libexiv2/build-base_mac/install
29 | MACOSX_DEPLOYMENT_TARGET="14.0"
30 | SYSTEM_VERSION_COMPAT=0
31 | CIBW_SKIP: pp3*
32 | CIBW_TEST_COMMAND: >
33 | python -m exiv2 -v &&
34 | python -m unittest discover {project}/tests -v
35 | CIBW_TEST_SKIP: cp38-*
36 | CIBW_BEFORE_ALL: >
37 | brew install ninja inih &&
38 | cd libexiv2 &&
39 | cmake --preset base_mac
40 | -D CMAKE_OSX_ARCHITECTURES=arm64
41 | -D EXIV2_BUILD_SAMPLES=OFF
42 | -D EXIV2_BUILD_UNIT_TESTS=OFF
43 | -D EXIV2_ENABLE_NLS=ON
44 | -D EXIV2_ENABLE_FILESYSTEM_ACCESS=ON
45 | -D EXIV2_BUILD_EXIV2_COMMAND=OFF
46 | -D EXIV2_TEAM_WARNINGS_AS_ERRORS=OFF &&
47 | cmake --build build-base_mac --config Release &&
48 | cmake --install build-base_mac --config Release
49 |
50 | - name: Store results
51 | uses: actions/upload-artifact@v4
52 | with:
53 | name: macos-arm-28-wheels
54 | path: wheelhouse/*.whl
55 |
--------------------------------------------------------------------------------
/.github/workflows/build-windows-27.yml:
--------------------------------------------------------------------------------
1 | name: Build Windows wheels exiv2 0.27
2 | on: workflow_dispatch
3 |
4 | jobs:
5 | compile:
6 | runs-on: windows-2019
7 | steps:
8 | - name: Check out repository code
9 | uses: actions/checkout@v4
10 |
11 | - name: Fetch Gettext
12 | run: >
13 | c:\msys64\usr\bin\wget.exe -nv
14 | https://github.com/mlocati/gettext-iconv-windows/releases/download/v0.21-v1.16/gettext0.21-iconv1.16-shared-64.zip
15 | -O gettext.zip
16 |
17 | - name: Extract Gettext
18 | shell: bash
19 | run: |
20 | mkdir gettext
21 | cd gettext
22 | unzip ../gettext.zip
23 |
24 | - name: Fetch Exiv2 source
25 | run: >
26 | c:\msys64\usr\bin\wget.exe -nv
27 | https://github.com/Exiv2/exiv2/releases/download/v0.27.7/exiv2-0.27.7-Source.tar.gz
28 | -O exiv2.tar.gz
29 |
30 | - name: Extract Exiv2 source
31 | shell: bash
32 | run: |
33 | tar -xzf exiv2.tar.gz
34 | mv exiv2-0.27.7-Source libexiv2
35 | # tweaks to allow NLS
36 | rm libexiv2/cmake/FindIconv.cmake
37 | echo -e "24a25\n> self.requires('libgettext/0.21')" |
38 | c:/msys64/usr/bin/patch.exe libexiv2/conanfile.py
39 |
40 | - name: Build wheels
41 | uses: pypa/cibuildwheel@v2.16.5
42 | env:
43 | CIBW_ARCHS: auto64
44 | CIBW_SKIP: pp3*
45 | CIBW_ENVIRONMENT: |
46 | EXIV2_ROOT=libexiv2/build-msvc/install
47 | PATH="$PATH;$(pwd)\\gettext\\bin"
48 | CIBW_TEST_COMMAND: >
49 | python -m exiv2 -v &&
50 | python -m unittest discover {project}/tests -v
51 | CIBW_BEFORE_ALL: >
52 | pip install conan==1.59.0 &&
53 | cd libexiv2 &&
54 | conan install . -of build-msvc -if build-msvc -o unitTests=False
55 | -o iconv=True -o webready=True -b missing &&
56 | cmake -B build-msvc
57 | -D CMAKE_BUILD_TYPE=Release
58 | -D CMAKE_INSTALL_PREFIX=build-msvc/install
59 | -D EXIV2_ENABLE_WIN_UNICODE=OFF
60 | -D EXIV2_BUILD_SAMPLES=OFF
61 | -D EXIV2_BUILD_EXIV2_COMMAND=OFF
62 | -D EXIV2_ENABLE_BMFF=ON
63 | -D EXIV2_ENABLE_NLS=ON
64 | -D EXIV2_ENABLE_VIDEO=ON
65 | -D EXIV2_ENABLE_WEBREADY=ON
66 | -D CMAKE_CXX_STANDARD=98
67 | -G "Visual Studio 16 2019" -A x64 &&
68 | cmake --build build-msvc --config Release &&
69 | cmake --install build-msvc --config Release
70 |
71 | - name: Store results
72 | uses: actions/upload-artifact@v3
73 | with:
74 | name: windows-27-wheels
75 | path: wheelhouse/*.whl
76 |
--------------------------------------------------------------------------------
/.github/workflows/build-windows-28.yml:
--------------------------------------------------------------------------------
1 | name: Build Windows wheels exiv2 0.28
2 | on: workflow_dispatch
3 |
4 | jobs:
5 | compile:
6 | runs-on: windows-2019
7 | steps:
8 | - name: Check out repository code
9 | uses: actions/checkout@v4
10 |
11 | - name: Fetch Gettext
12 | run: >
13 | c:\msys64\usr\bin\wget.exe -nv
14 | https://github.com/mlocati/gettext-iconv-windows/releases/download/v0.21-v1.16/gettext0.21-iconv1.16-shared-64.zip
15 | -O gettext.zip
16 |
17 | - name: Extract Gettext
18 | shell: bash
19 | run: |
20 | mkdir gettext
21 | cd gettext
22 | unzip ../gettext.zip
23 |
24 | - name: Fetch Exiv2 source
25 | run: >
26 | c:\msys64\usr\bin\wget.exe -nv
27 | https://github.com/Exiv2/exiv2/archive/refs/tags/v0.28.5.tar.gz
28 | -O exiv2.tar.gz
29 |
30 | - name: Extract Exiv2 source
31 | shell: bash
32 | run: |
33 | tar -xzf exiv2.tar.gz
34 | mv exiv2-0.28.5 libexiv2
35 | # tweaks to allow NLS
36 | echo -e "24a25\n> self.requires('libgettext/0.21')" |
37 | c:/msys64/usr/bin/patch.exe libexiv2/conanfile.py
38 |
39 | - name: Install Python
40 | uses: actions/setup-python@v5
41 | with:
42 | python-version: 3.11
43 |
44 | - name: Install cmake
45 | uses: jwlawson/actions-setup-cmake@v2
46 |
47 | - name: Install ninja
48 | uses: seanmiddleditch/gha-setup-ninja@master
49 |
50 | - name: Compile Exiv2
51 | env:
52 | PATH: "${{ github.workspace }}\\gettext\\bin"
53 | run: >
54 | pip install conan==1.59.0 &&
55 | cd libexiv2 &&
56 | cmake --preset msvc
57 | -D CMAKE_BUILD_TYPE=Release
58 | -D EXIV2_BUILD_SAMPLES=OFF
59 | -D EXIV2_BUILD_EXIV2_COMMAND=OFF
60 | -D EXIV2_BUILD_UNIT_TESTS=OFF
61 | -D EXIV2_ENABLE_NLS=ON
62 | -D EXIV2_ENABLE_FILESYSTEM_ACCESS=ON
63 | -G "Visual Studio 16 2019" &&
64 | cmake --build build-msvc --config Release &&
65 | cmake --install build-msvc --config Release &&
66 | copy build-msvc\bin\libcurl.dll build-msvc\install\bin
67 |
68 | - name: Build wheels
69 | uses: pypa/cibuildwheel@v2.22.0
70 | env:
71 | CIBW_ARCHS: auto64
72 | CIBW_SKIP: pp3*
73 | CIBW_ENVIRONMENT: |
74 | EXIV2_ROOT=libexiv2/build-msvc/install
75 | CIBW_TEST_COMMAND: >
76 | python -m exiv2 -v &&
77 | python -m unittest discover {project}/tests -v
78 |
79 | - name: Store results
80 | uses: actions/upload-artifact@v4
81 | with:
82 | name: windows-28-wheels
83 | path: wheelhouse/*.whl
84 |
--------------------------------------------------------------------------------
/.github/workflows/test-interface.yml:
--------------------------------------------------------------------------------
1 | # python-exiv2 - Python interface to libexiv2
2 | # http://github.com/jim-easterbrook/python-exiv2
3 | # Copyright (C) 2022-25 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU General Public License as published by the Free Software
7 | # Foundation, either version 3 of the License, or (at your option) any later
8 | # version.
9 | #
10 | # This program is distributed in the hope that it will be useful, but WITHOUT
11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 | # details.
14 | #
15 | # You should have received a copy of the GNU General Public License along with
16 | # this program. If not, see .
17 |
18 |
19 | name: Run unit tests
20 | on:
21 | push:
22 | paths:
23 | - 'src/swig_0.27.0/**'
24 | - 'tests/**.py'
25 | workflow_dispatch:
26 |
27 | jobs:
28 | test:
29 | strategy:
30 | matrix:
31 | python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
32 | os: [ubuntu-latest]
33 | include:
34 | - python-version: '3.6'
35 | os: ubuntu-20.04
36 | - python-version: '3.7'
37 | os: ubuntu-22.04
38 | runs-on: ${{ matrix.os }}
39 | steps:
40 | - name: Check out repository code
41 | uses: actions/checkout@v3
42 |
43 | - name: Install libexiv2
44 | run: |
45 | sudo apt-get update
46 | sudo apt-get install libexiv2-dev
47 |
48 | - name: Setup Python
49 | uses: actions/setup-python@v4
50 | with:
51 | python-version: ${{ matrix.python-version }}
52 | architecture: 'x64'
53 |
54 | - name: Install python-exiv2
55 | run: pip3 install --disable-pip-version-check --user .
56 |
57 | - name: Get package details
58 | run: python3 -m exiv2 -v
59 |
60 | - name: Run unit tests
61 | run: python3 -m unittest discover tests -v
62 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /doc
3 | /dist
4 | /src/doc/api
5 | exiv2.egg-info
6 | __pycache__
7 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # Read the Docs configuration file
2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3 |
4 | # Required
5 | version: 2
6 |
7 | # Set the OS, Python version and other tools you might need
8 | build:
9 | os: ubuntu-22.04
10 | tools:
11 | python: "3.11"
12 | apt_packages:
13 | - graphviz
14 |
15 | # Build documentation in the "docs/" directory with Sphinx
16 | sphinx:
17 | configuration: src/doc/conf.py
18 |
19 | python:
20 | install:
21 | - requirements: src/doc/requirements.txt
22 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | recursive-include src *
2 | recursive-include utils *
3 | recursive-include examples *
4 | recursive-include tests *.py *.jpg
5 |
6 | recursive-exclude libexiv2* *
7 | recursive-exclude src/doc/api *
8 |
9 | include CHANGELOG.txt LICENSE *.rst
10 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | python-exiv2 v\ 0.17.3
2 | ======================
3 |
4 | python-exiv2 is a low level interface (or binding) to the exiv2_ C++ library.
5 | It is built using SWIG_ to automatically generate the interface code.
6 | The intention is to give direct access to all of the top-level classes in libexiv2_, but with additional "Pythonic" helpers where necessary.
7 | Not everything in libexiv2 is available in the Python interface.
8 | If you need something that's not there, please let me know.
9 |
10 | .. note::
11 | This project has taken over the PyPI exiv2 package created by Michael Vanslembrouck.
12 | If you need to use Michael's project, it is available at https://bitbucket.org/zmic/exiv2-python/src/master/ and can be installed with pip_::
13 |
14 | pip install exiv2==0.3.1
15 |
16 | .. contents::
17 | :backlinks: top
18 |
19 | Introduction
20 | ------------
21 |
22 | There are several other ways to access libexiv2_ from within Python.
23 | The first one I used was `pyexiv2 (old)`_.
24 | After its development ceased I moved on to using gexiv2_ and PyGObject_.
25 | This works well, providing a ``Metadata`` object with high level functions such as ``set_tag_string`` and ``set_tag_multiple`` to get and set metadata values.
26 |
27 | A more recent development is `pyexiv2 (new)`_.
28 | This new project is potentially very useful, providing a simple interface with functions to read and modify metadata using Python ``dict`` parameters.
29 |
30 | For more complicated metadata operations I think a lower level interface is required, which is where this project comes in.
31 | Here is an example of its use:
32 |
33 | .. code:: python
34 |
35 | Python 3.6.12 (default, Dec 02 2020, 09:44:23) [GCC] on linux
36 | Type "help", "copyright", "credits" or "license" for more information.
37 | >>> import exiv2
38 | >>> image = exiv2.ImageFactory.open('IMG_0211.JPG')
39 | >>> image.readMetadata()
40 | >>> data = image.exifData()
41 | >>> data['Exif.Image.Artist'].print()
42 | 'Jim Easterbrook'
43 | >>>
44 |
45 | Please see `USAGE.rst`_ for more help with using the Python interface to libexiv2.
46 |
47 | Transition to libexiv2 v0.28.x
48 | ------------------------------
49 |
50 | Before python-exiv2 v0.16 the "binary wheels" available from PyPI_ incorporated libexiv2 v0.27.7 or earlier.
51 | Binary wheels for python-exiv2 v0.16.3 incorporate libexiv2 v0.28.2, and those for python-exiv2 v0.16.2 incorporate libexiv2 v0.27.7.
52 | Binary wheels for python-exiv2 v0.17.0 incorporate libexiv2 v0.28.3.
53 | If your software is currently incompatible with libexiv2 v0.28.x you can use the older version of libexiv2 by explicitly installing python-exiv2 v0.16.2::
54 |
55 | $ pip install --user exiv2==0.16.2
56 |
57 | There are some changes in the libexiv2 API between v0.27.7 and v0.28.x.
58 | Future versions of python-exiv2 will all incorporate libexiv2 v0.28.x, so please update your software to use the changed API.
59 |
60 | Documentation
61 | -------------
62 |
63 | The libexiv2_ library is well documented for C++ users, in Doxygen_ format.
64 | Recent versions of SWIG_ can convert this documentation to pydoc_ format in the Python interface::
65 |
66 | $ pydoc3 exiv2.Image.readMetadata
67 | Help on method_descriptor in exiv2.Image:
68 |
69 | exiv2.Image.readMetadata = readMetadata(...)
70 | Read all metadata supported by a specific image format from the
71 | image. Before this method is called, the image metadata will be
72 | cleared.
73 |
74 | This method returns success even if no metadata is found in the
75 | image. Callers must therefore check the size of individual metadata
76 | types before accessing the data.
77 |
78 | :raises: Error if opening or reading of the file fails or the image
79 | data is not valid (does not look like data of the specific image
80 | type).
81 |
82 | This is then converted to web pages by Sphinx_ and hosted on ReadTheDocs_.
83 |
84 | Unfortunately some documentation gets lost in the manipulations needed to make a useful interface.
85 | The C++ documentation is still needed in these cases.
86 |
87 | Support for bmff files (e.g. CR3, HEIF, HEIC, AVIF, JPEG XL)
88 | ------------------------------------------------------------
89 |
90 | Python-exiv2 from version 0.17.0 has support for BMFF files enabled by default if libexiv2 was compiled with support for BMFF files enabled.
91 | In earlier versions you need to call the ``enableBMFF`` function before using BMFF files in your program.
92 | Use of BMFF files may infringe patents.
93 | Please read the Exiv2 `statement on BMFF`_ patents before doing so.
94 |
95 | Installation
96 | ------------
97 |
98 | Python "binary wheels" are available for Windows, Linux, and MacOS.
99 | These include the libexiv2 library and should not need any other software to be installed.
100 | They can be installed with Python's pip_ package.
101 | For example, on Windows::
102 |
103 | C:\Users\Jim>pip install exiv2
104 |
105 | or on Linux or MacOS::
106 |
107 | $ pip3 install --user exiv2
108 |
109 | If the available wheels are not compatible with your operating system or Python version then pip will download the python-exiv2 source and attempt to compile it.
110 | For more information, and details of how to compile python-exiv2 and libexiv2, see `INSTALL.rst`_.
111 |
112 | Problems?
113 | ---------
114 |
115 | Please email jim@jim-easterbrook.me.uk if you find any problems (or solutions!).
116 |
117 | .. _Doxygen: https://www.doxygen.nl/
118 | .. _exiv2: https://www.exiv2.org/getting-started.html
119 | .. _gexiv2: https://wiki.gnome.org/Projects/gexiv2
120 | .. _GitHub: https://github.com/jim-easterbrook/python-exiv2
121 | .. _libexiv2: https://www.exiv2.org/doc/index.html
122 | .. _pip: https://pip.pypa.io/
123 | .. _pyexiv2 (new): https://github.com/LeoHsiao1/pyexiv2
124 | .. _pyexiv2 (old): https://launchpad.net/pyexiv2
125 | .. _PyGObject: https://pygobject.readthedocs.io/en/latest/
126 | .. _PyPI: https://pypi.org/project/exiv2/
127 | .. _SWIG: http://swig.org/
128 | .. _pydoc: https://docs.python.org/3/library/pydoc.html
129 | .. _Python3: https://www.python.org/
130 | .. _ReadTheDocs: https://python-exiv2.readthedocs.io/
131 | .. _Sphinx: https://www.sphinx-doc.org/
132 | .. _statement on BMFF: https://github.com/exiv2/exiv2#BMFF
133 | .. _Visual C++: https://wiki.python.org/moin/WindowsCompilers
134 | .. _INSTALL.rst: INSTALL.rst
135 | .. _USAGE.rst: USAGE.rst
136 |
--------------------------------------------------------------------------------
/examples/README.rst:
--------------------------------------------------------------------------------
1 | Examples
2 | ========
3 |
4 | These example files show some typical (and not so typical) ways to use the Python exiv2 interface.
5 | Some of them are based on the `C++ examples`_ provided by the Exiv2 project.
6 | It might be instructive to compare the C++ and Python ways of doing the same thing.
7 |
8 | .. _C++ examples: https://www.exiv2.org/doc/examples.html
9 |
--------------------------------------------------------------------------------
/examples/addmoddel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # python-exiv2 - Python interface to libexiv2
4 | # http://github.com/jim-easterbrook/python-exiv2
5 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program 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 General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 | # Sample program showing how to add, modify and delete Exif metadata.
21 |
22 | import locale
23 | import sys
24 |
25 | import exiv2
26 |
27 | def main():
28 | locale.setlocale(locale.LC_ALL, '')
29 | try:
30 | exiv2.XmpParser.initialize()
31 | if len(sys.argv) != 2:
32 | print('Usage: {} file'.format(sys.argv[0]))
33 | return 1;
34 | file = sys.argv[1]
35 | # Container for exif metadata. This is an example of creating
36 | # exif metadata from scratch. If you want to add, modify, delete
37 | # metadata that exists in an image, start with
38 | # ImageFactory::open
39 | exifData = exiv2.ExifData()
40 |
41 | # **************************************************************
42 | # Add to the Exif data
43 |
44 | # This is the quickest way to add (simple) Exif data. If a
45 | # metadatum for a given key already exists, its value is
46 | # overwritten. Otherwise a new tag is added.
47 | exifData["Exif.Image.Model"] = "Test 1" # AsciiValue
48 | exifData["Exif.Image.SamplesPerPixel"] = exiv2.UShortValue(162) # UShortValue
49 | exifData["Exif.Image.XResolution"] = exiv2.LongValue(-2) # LongValue
50 | exifData["Exif.Image.YResolution"] = exiv2.RationalValue((-2, 3)) # Rational
51 | print("Added a few tags the quick way.")
52 |
53 | # Create a ASCII string value (note the use of create)
54 | v = exiv2.Value.create(exiv2.TypeId.asciiString)
55 | # Set the value to a string
56 | v.read("1999:12:31 23:59:59")
57 | # Add the value together with its key to the Exif data container
58 | key = exiv2.ExifKey("Exif.Photo.DateTimeOriginal")
59 | exifData.add(key, v)
60 | print('Added key "{}", value "{}"'.format(key, v))
61 |
62 | # Now create a more interesting value (without using the create method)
63 | rv = exiv2.URationalValue()
64 | # Set two rational components from a string
65 | rv.read("1/2 1/3")
66 | # Add more elements directly
67 | rv.append((2, 3))
68 | rv.append((3, 4))
69 | # Add the key and value pair to the Exif data
70 | key = exiv2.ExifKey("Exif.Image.PrimaryChromaticities")
71 | exifData.add(key, rv)
72 | print('Added key "{}", value "{}"'.format(key, rv))
73 |
74 | # **************************************************************
75 | # Modify Exif data
76 |
77 | # Since we know that the metadatum exists (or we don't mind
78 | # creating a new tag if it doesn't), we can simply do this:
79 | tag = exifData["Exif.Photo.DateTimeOriginal"]
80 | date = tag.toString()
81 | date = '2000' + date[4:]
82 | tag.setValue(date)
83 | print('Modified key "{}", new value "{}"'.format(
84 | tag.key(), tag.value()))
85 |
86 | # Alternatively, we can use findKey()
87 | key = exiv2.ExifKey("Exif.Image.PrimaryChromaticities")
88 | pos = exifData.findKey(key)
89 | if pos == exifData.end():
90 | raise exiv2.Exiv2Error("Key not found")
91 | # Get a copy of the value
92 | v = pos.getValue()
93 | # Downcast the Value pointer to its actual type
94 | rv = exiv2.URationalValue(v)
95 | # Modify the value directly
96 | rv[2] = 88, 77
97 |
98 | # **************************************************************
99 | # Delete metadata from the Exif data container
100 |
101 | # Delete the metadatum at iterator position pos
102 | key = exiv2.ExifKey("Exif.Image.PrimaryChromaticities")
103 | pos = exifData.findKey(key)
104 | if pos == exifData.end():
105 | raise exiv2.Exiv2Error("Key not found")
106 | exifData.erase(pos)
107 | print('Deleted key "{}"'.format(key))
108 |
109 | # **************************************************************
110 | # Finally, write the remaining Exif data to the image file
111 | image = exiv2.ImageFactory.open(file)
112 |
113 | image.setExifData(exifData)
114 | image.writeMetadata()
115 |
116 | return 0
117 | except exiv2.Exiv2Error as e:
118 | print('Caught Exiv2 exception "{}"'.format(str(e)))
119 | return -1;
120 | finally:
121 | exiv2.XmpParser.terminate()
122 | return 0
123 |
124 | if __name__ == "__main__":
125 | sys.exit(main())
126 |
--------------------------------------------------------------------------------
/examples/easyaccess.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # python-exiv2 - Python interface to libexiv2
4 | # http://github.com/jim-easterbrook/python-exiv2
5 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program 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 General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 | # Sample program to show use of "EasyAccess API".
21 | # See https://github.com/Exiv2/exiv2/wiki/EasyAccess-API
22 |
23 | import locale
24 | import sys
25 |
26 | import exiv2
27 |
28 |
29 | def main():
30 | locale.setlocale(locale.LC_ALL, '')
31 | exiv2.XmpParser.initialize()
32 |
33 | if len(sys.argv) != 2:
34 | print("Usage: {} file".format(sys.argv[0]))
35 | return 1
36 |
37 | file = sys.argv[1]
38 |
39 | image = exiv2.ImageFactory.open(file)
40 | image.readMetadata()
41 | exifData = image.exifData()
42 |
43 | for name in ('make', 'model', 'dateTimeOriginal', 'exposureTime',
44 | 'apertureValue', 'exposureBiasValue', 'exposureIndex', 'flash',
45 | 'flashBias', 'flashEnergy', 'focalLength', 'subjectDistance',
46 | 'isoSpeed', 'exposureMode', 'meteringMode', 'macroMode',
47 | 'imageQuality', 'whiteBalance', 'orientation', 'sceneMode',
48 | 'sceneCaptureType', 'lensName', 'saturation', 'sharpness',
49 | 'contrast', 'fNumber', 'serialNumber', 'afPoint',
50 | 'shutterSpeedValue', 'brightnessValue', 'maxApertureValue',
51 | 'lightSource', 'subjectArea', 'sensingMethod'):
52 | if hasattr(exiv2, name):
53 | datum = getattr(exiv2, name)(exifData)
54 | if datum:
55 | print('{:18s}: {:30s}: {:s}'.format(
56 | name, datum.key(), datum.print(exifData)))
57 | else:
58 | print(name)
59 |
60 | return 0
61 |
62 |
63 | if __name__ == "__main__":
64 | sys.exit(main())
65 |
--------------------------------------------------------------------------------
/examples/exifcomment.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # python-exiv2 - Python interface to libexiv2
4 | # http://github.com/jim-easterbrook/python-exiv2
5 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program 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 General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 | # Sample program showing how to set the Exif comment of an image.
21 |
22 | import locale
23 | import sys
24 |
25 | import exiv2
26 |
27 | def main():
28 | locale.setlocale(locale.LC_ALL, '')
29 | try:
30 | exiv2.XmpParser.initialize()
31 | if len(sys.argv) != 2:
32 | print('Usage: {} file'.format(sys.argv[0]))
33 | return 1;
34 | file = sys.argv[1]
35 |
36 | image = exiv2.ImageFactory.open(file)
37 | image.readMetadata()
38 | exifData = image.exifData()
39 |
40 | # Exiv2 uses a CommentValue for Exif user comments. The format
41 | # of the comment string includes an optional charset
42 | # specification at the beginning:
43 |
44 | # [charset=[Ascii|Jis|Unicode|Undefined]] comment
45 |
46 | # Undefined is used as a default if the comment doesn't start
47 | # with a charset definition.
48 |
49 | # Following are a few examples of valid comments. The last one
50 | # is written to the file.
51 |
52 | exifData["Exif.Photo.UserComment"] = (
53 | "charset=Unicode A Unicode Exif comment added with Exiv2")
54 | exifData["Exif.Photo.UserComment"] = (
55 | "charset=Undefined An undefined Exif comment added with Exiv2")
56 | exifData["Exif.Photo.UserComment"] = (
57 | "Another undefined Exif comment added with Exiv2")
58 | exifData["Exif.Photo.UserComment"] = (
59 | "charset=Ascii An ASCII Exif comment added with Exiv2")
60 |
61 | print("Writing user comment '{}' back to the image.".format(
62 | exifData["Exif.Photo.UserComment"]))
63 |
64 | image.writeMetadata()
65 |
66 | return 0
67 | except exiv2.Exiv2Error as e:
68 | print('Caught Exiv2 exception "{}"'.format(str(e)))
69 | return -1;
70 | finally:
71 | exiv2.XmpParser.terminate()
72 | return 0
73 |
74 | if __name__ == "__main__":
75 | sys.exit(main())
76 |
--------------------------------------------------------------------------------
/examples/exifdata.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # python-exiv2 - Python interface to libexiv2
4 | # http://github.com/jim-easterbrook/python-exiv2
5 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program 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 General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 | # Sample program to format exif data in various external formats.
21 |
22 | import locale
23 | import sys
24 |
25 | import exiv2
26 |
27 |
28 | def syntax(argv, formats):
29 | print("Usage: {} file format".format(argv[0]))
30 | print("formats: {}".format(' | '.join(formats)))
31 |
32 |
33 | def formatJSON(exifData):
34 | count = 0
35 | length = exifData.count()
36 | print('{')
37 | for datum in exifData:
38 | count += 1
39 | print(' "{}":"{}"{}'.format(
40 | datum.key(), datum.print(exifData).replace('"', r'\"'),
41 | ('',',')[count != length]))
42 | print('}')
43 |
44 |
45 | def formatXML(exifData):
46 | count = 0
47 | length = exifData.count()
48 | print('')
49 | for datum in exifData:
50 | count += 1
51 | print(' <{key}>{value}<{key}/>'.format(
52 | key=datum.key(),
53 | value=datum.print(exifData).replace(
54 | '<', '<').replace('>', '>')))
55 | print('')
56 |
57 |
58 | def main():
59 | locale.setlocale(locale.LC_ALL, '')
60 | try:
61 | exiv2.XmpParser.initialize()
62 |
63 | formats = {
64 | "json": formatJSON,
65 | "xml": formatXML,
66 | }
67 |
68 | if len(sys.argv) != 3:
69 | syntax(sys.argv, formats)
70 | return 1;
71 | file = sys.argv[1]
72 | format_ = sys.argv[2]
73 |
74 | if format_ not in formats:
75 | print("Unrecognised format {}".format(format_))
76 | syntax(sys.argv, formats)
77 | return 2;
78 |
79 | image = exiv2.ImageFactory.open(file)
80 | image.readMetadata()
81 | exifData = image.exifData()
82 |
83 | formats[format_](exifData)
84 |
85 | return 0
86 | except exiv2.Exiv2Error as e:
87 | print('*** error exiv2 exception "{}" ***'.format(str(e)))
88 | return 4;
89 | except Exception as e:
90 | print('*** error exception "{}" ***'.format(str(e)))
91 | return 5;
92 | finally:
93 | exiv2.XmpParser.terminate()
94 | return 0
95 |
96 | if __name__ == "__main__":
97 | sys.exit(main())
98 |
--------------------------------------------------------------------------------
/examples/exifprint.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # python-exiv2 - Python interface to libexiv2
4 | # http://github.com/jim-easterbrook/python-exiv2
5 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program 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 General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 | # Sample program to print Exif data from an image.
21 |
22 | import locale
23 | import sys
24 |
25 | import exiv2
26 |
27 |
28 | def main():
29 | locale.setlocale(locale.LC_ALL, '')
30 | try:
31 | exiv2.XmpParser.initialize()
32 |
33 | if len(sys.argv) != 2:
34 | print("Usage: {} [ path | --version | --version-test ]".format(
35 | sys.argv[0]))
36 | return 1;
37 | file = sys.argv[1]
38 |
39 | if file == '--version':
40 | # Python interface won't build dumpLibraryInfo
41 | ## Exiv2::dumpLibraryInfo(std::cout, keys)
42 | print(exiv2.versionString())
43 | return 0;
44 |
45 | if file == '--version-test':
46 | # verifies/test macro EXIV2_TEST_VERSION
47 | # described in include/exiv2/version.hpp
48 | # Python interface doesn't include C++ macros!
49 | ## print("EXV_PACKAGE_VERSION ", EXV_PACKAGE_VERSION)
50 | print("Exiv2::version() ", exiv2.version())
51 | print("strlen(Exiv2::version()) ", len(exiv2.version()))
52 | print("Exiv2::versionNumber() ", exiv2.versionNumber())
53 | print("Exiv2::versionString() ", exiv2.versionString())
54 | print("Exiv2::versionNumberHexString() ",
55 | exiv2.versionNumberHexString())
56 |
57 | # Test the Exiv2 version available at runtime but compile
58 | # the if-clause only if the compile-time version is at least
59 | # 0.15. Earlier versions didn't have a testVersion()
60 | # function:
61 | if hasattr(exiv2, 'testVersion'):
62 | if exiv2.testVersion(0,13,0):
63 | print("Available Exiv2 version is equal to or greater"
64 | " than 0.13")
65 | else:
66 | print("Installed Exiv2 version is less than 0.13")
67 | else:
68 | print("Compile-time Exiv2 version doesn't have"
69 | " exiv2.testVersion()")
70 | return 0
71 |
72 | image = exiv2.ImageFactory.open(file)
73 | image.readMetadata()
74 | exifData = image.exifData()
75 | if exifData.empty():
76 | raise exiv2.Exiv2Error("No Exif data found in file")
77 |
78 | end = exifData.end()
79 | i = exifData.begin()
80 | while i != end:
81 | print('{:44s} {:04x} {:9s} {:3d} {:s}'.format(
82 | i.key(), i.tag(), i.typeName(), i.count(), i.toString()))
83 | next(i)
84 |
85 | return 0
86 | except exiv2.Exiv2Error as e:
87 | print('*** error exiv2 exception "{}" ***'.format(str(e)))
88 | return 4;
89 | except Exception as e:
90 | print('*** error exception "{}" ***'.format(str(e)))
91 | return 5;
92 | finally:
93 | exiv2.XmpParser.terminate()
94 | return 0
95 |
96 | if __name__ == "__main__":
97 | sys.exit(main())
98 |
--------------------------------------------------------------------------------
/examples/exifvalue.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # python-exiv2 - Python interface to libexiv2
4 | # http://github.com/jim-easterbrook/python-exiv2
5 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program 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 General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 | # Sample program to print value of an exif key in an image.
21 |
22 | import locale
23 | import sys
24 |
25 | import exiv2
26 |
27 |
28 | def main():
29 | locale.setlocale(locale.LC_ALL, '')
30 | try:
31 | exiv2.XmpParser.initialize()
32 |
33 | if len(sys.argv) != 3:
34 | print("Usage: {} file key".format(sys.argv[0]))
35 | return 1
36 |
37 | file = sys.argv[1]
38 | key = sys.argv[2]
39 |
40 | image = exiv2.ImageFactory.open(file)
41 | image.readMetadata()
42 | exifData = image.exifData()
43 | if exifData.empty():
44 | print("No metadata found in file", file)
45 | return 2
46 |
47 | print(exifData[key])
48 |
49 | return 0
50 | except exiv2.Exiv2Error as e:
51 | print('*** error exiv2 exception "{}" ***'.format(str(e)))
52 | return 4;
53 | except Exception as e:
54 | print('*** error exception "{}" ***'.format(str(e)))
55 | return 5;
56 | finally:
57 | exiv2.XmpParser.terminate()
58 | return 0
59 |
60 | if __name__ == "__main__":
61 | sys.exit(main())
62 |
--------------------------------------------------------------------------------
/examples/iptceasy.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # python-exiv2 - Python interface to libexiv2
4 | # http://github.com/jim-easterbrook/python-exiv2
5 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program 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 General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 | # The quickest way to access, set or modify IPTC metadata.
21 |
22 | import locale
23 | import sys
24 |
25 | import exiv2
26 |
27 | def main():
28 | locale.setlocale(locale.LC_ALL, '')
29 | try:
30 | exiv2.XmpParser.initialize()
31 | if len(sys.argv) != 2:
32 | print('Usage: {} file'.format(sys.argv[0]))
33 | return 1;
34 | file = sys.argv[1]
35 |
36 | iptcData = exiv2.IptcData()
37 |
38 | iptcData["Iptc.Application2.Headline"] = "The headline I am"
39 | iptcData["Iptc.Application2.Keywords"] = "Yet another keyword"
40 | iptcData["Iptc.Application2.DateCreated"] = "2004-08-03"
41 | iptcData["Iptc.Application2.Urgency"] = exiv2.UShortValue(1)
42 | iptcData["Iptc.Envelope.ModelVersion"] = 42
43 | iptcData["Iptc.Envelope.TimeSent"] = "14:41:00-05:00"
44 | iptcData["Iptc.Application2.RasterizedCaption"] = "230 42 34 2 90 84 23 146"
45 | iptcData["Iptc.0x0009.0x0001"] = "Who am I?"
46 |
47 | value = exiv2.StringValue()
48 | value.read("very!")
49 | iptcData["Iptc.Application2.Urgency"] = value
50 |
51 | print("Time sent: {}".format(iptcData["Iptc.Envelope.TimeSent"]))
52 |
53 | # Open image file
54 | image = exiv2.ImageFactory.open(file)
55 |
56 | # Set IPTC data and write it to the file
57 | image.setIptcData(iptcData)
58 | image.writeMetadata()
59 |
60 | return 0
61 | except exiv2.Exiv2Error as e:
62 | print('Caught Exiv2 exception "{}"'.format(str(e)))
63 | return -1;
64 | finally:
65 | exiv2.XmpParser.terminate()
66 | return 0
67 |
68 | if __name__ == "__main__":
69 | sys.exit(main())
70 |
--------------------------------------------------------------------------------
/examples/thumbnail.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # python-exiv2 - Python interface to libexiv2
4 | # http://github.com/jim-easterbrook/python-exiv2
5 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program 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 General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 | # Sample program to display an image's Exif thumbnail.
21 |
22 | import io
23 | import locale
24 | import sys
25 |
26 | import PIL.Image as PIL
27 | from PIL import ImageShow
28 | import exiv2
29 |
30 |
31 | # Make sure we use ImageMagick viewer if it's available
32 | ImageShow.register(ImageShow.DisplayViewer(), -1)
33 |
34 |
35 | def main():
36 | locale.setlocale(locale.LC_ALL, '')
37 | try:
38 | exiv2.XmpParser.initialize()
39 |
40 | if len(sys.argv) != 2:
41 | print("Usage: {} file".format(sys.argv[0]))
42 | return 1
43 |
44 | file = sys.argv[1]
45 |
46 | image = exiv2.ImageFactory.open(file)
47 | image.readMetadata()
48 | exifData = image.exifData()
49 |
50 | thumb = exiv2.ExifThumb(exifData)
51 | print('Thumbnail type:', thumb.mimeType())
52 |
53 | data = thumb.copy()
54 | if not data:
55 | print("Image has no thumbnail data")
56 | return -1;
57 |
58 | print('Thumbnail data:', bytes(data.data())[:8],
59 | '...', bytes(data.data())[-8:])
60 |
61 | print("Displaying thumbnail image")
62 | thumb_image = PIL.open(io.BytesIO(data.data()))
63 | thumb_image.show()
64 |
65 | return 0
66 | except exiv2.Exiv2Error as e:
67 | print('*** error exiv2 exception "{}" ***'.format(str(e)))
68 | return 4;
69 | except Exception as e:
70 | print('*** error exception "{}" ***'.format(str(e)))
71 | return 5;
72 | finally:
73 | exiv2.XmpParser.terminate()
74 | return 0
75 |
76 | if __name__ == "__main__":
77 | sys.exit(main())
78 |
--------------------------------------------------------------------------------
/examples/values.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # python-exiv2 - Python interface to libexiv2
4 | # http://github.com/jim-easterbrook/python-exiv2
5 | # Copyright (C) 2021-22 Jim Easterbrook jim@jim-easterbrook.me.uk
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program 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 General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 |
21 | # Accessing some Exiv2::Value types directly, without going via string
22 | # representations. For most purposes, using string representations of
23 | # values is good enough, but for maximum speed and precision you can use
24 | # more appropriate Python types.
25 |
26 | import datetime
27 | from fractions import Fraction
28 | import locale
29 | import sys
30 |
31 | import exiv2
32 |
33 | def main():
34 | locale.setlocale(locale.LC_ALL, '')
35 | print('==== DateValue & TimeValue ====')
36 | # These are only used in Iptc - Exif & Xmp use string representations.
37 | tz = datetime.timezone(datetime.timedelta(hours=2, minutes=45))
38 | py_datetime = datetime.datetime.now(tz).replace(microsecond=0)
39 | print("Python datetime:", py_datetime)
40 | # Python -> Exiv2
41 | # can pass value to constructor or use setDate() afterwards
42 | date = exiv2.DateValue(py_datetime.year, py_datetime.month, py_datetime.day)
43 | print("Exiv2 date:", date)
44 | tz_minute = int(py_datetime.utcoffset().total_seconds()) // 60
45 | tz_hour = tz_minute // 60
46 | tz_minute -= tz_hour * 60
47 | time = exiv2.TimeValue(py_datetime.hour, py_datetime.minute,
48 | py_datetime.second, tz_hour, tz_minute)
49 | print("Exiv2 time:", time)
50 | # Exiv2 -> Python
51 | date_st = date.getDate()
52 | time_st = time.getTime()
53 | tz_info = datetime.timezone(datetime.timedelta(
54 | hours=time_st.tzHour, minutes=time_st.tzMinute))
55 | py_datetime = datetime.datetime(
56 | **date_st, hour=time_st.hour, minute=time_st.minute,
57 | second=time_st.second, tzinfo=tz_info);
58 | print("Python datetime:", py_datetime)
59 |
60 | print('==== ShortValue ====')
61 | # This stores 1 or more 16-bit ints.
62 | py_shorts = [34, 56, 78]
63 | print("Python short:", py_shorts)
64 | # Python -> Exiv2, the long way
65 | shorts = exiv2.ShortValue()
66 | # append values to initialise
67 | for x in py_shorts:
68 | shorts.append(x)
69 | print("Exiv2 short:", shorts)
70 | # Python -> Exiv2, the short way
71 | shorts = exiv2.ShortValue(py_shorts)
72 | print("Exiv2 short:", shorts)
73 | # modify a value by index
74 | shorts[1] = 12
75 | print("Exiv2 short:", shorts)
76 | # append a value
77 | shorts.append(90)
78 | print("Exiv2 short:", shorts)
79 | # Exiv2 -> Python
80 | py_shorts = list(shorts)
81 | print("Python short:", py_shorts)
82 |
83 | print('==== RationalValue ====')
84 | # This stores 1 or more pairs of ints. Typical usage is
85 | # Exif.GPSInfo.GPSLatitude, which stores degrees, minutes & seconds.
86 | py_latitude = [Fraction(51), Fraction(30),
87 | Fraction(4.6).limit_denominator(100000)]
88 | print("Python rational:", py_latitude)
89 | # Python -> Exiv2, the long way
90 | latitude = exiv2.RationalValue()
91 | # append values to initialise
92 | for x in py_latitude:
93 | latitude.append((x.numerator, x.denominator))
94 | print("Exiv2 rational:", latitude)
95 | # Python -> Exiv2, the short way
96 | latitude = exiv2.RationalValue(
97 | [(x.numerator, x.denominator) for x in py_latitude])
98 | print("Exiv2 rational:", latitude)
99 | # modify a value by index
100 | latitude[1] = -63, 11
101 | print("Exiv2 rational:", latitude)
102 | # append a value
103 | latitude.append((19, 3))
104 | print("Exiv2 rational:", latitude)
105 | # Exiv2 -> Python
106 | py_latitude = [Fraction(*x) for x in latitude]
107 | print("Python rational:", py_latitude)
108 |
109 | print('==== XmpArrayValue ====')
110 | # This is used for XmpSeq, XmpBag and XmpAlt values. It stores one
111 | # or more strings.
112 | py_seq = ['First string', 'Second', 'Third']
113 | print("Python seq:", py_seq)
114 | # Python -> Exiv2, the long way
115 | seq = exiv2.XmpArrayValue(exiv2.TypeId.xmpBag)
116 | # append values to initialise
117 | for x in py_seq:
118 | seq.append(x)
119 | print("Exiv2 seq:", seq)
120 | # Python -> Exiv2, the short way
121 | seq = exiv2.XmpArrayValue(py_seq, exiv2.TypeId.xmpBag)
122 | print("Exiv2 seq:", seq)
123 | # Exiv2 -> Python
124 | py_seq = list(seq)
125 | print("Python seq:", py_seq)
126 |
127 | print('==== LangAltValue ====')
128 | # Used to store text with default language and other language alternatives
129 | py_langalt = {'x-default': 'default', 'de': 'Deutsch', 'fr': 'French'}
130 | print("Python langalt:", py_langalt)
131 | # Python -> Exiv2, the long way
132 | langalt = exiv2.LangAltValue()
133 | for key in py_langalt:
134 | langalt[key] = py_langalt[key]
135 | print("Exiv2 langalt:", langalt)
136 | # Python -> Exiv2, the short way
137 | langalt = exiv2.LangAltValue(py_langalt)
138 | print("Exiv2 langalt:", langalt)
139 | print('keys', langalt.keys())
140 | print('values', langalt.values())
141 | print('items', langalt.items())
142 | # delete a value
143 | del langalt['fr']
144 | # add a value
145 | langalt['nl'] = 'Nederlands'
146 | # Exiv2 -> Python
147 | py_langalt = dict(langalt)
148 | print("Python langalt:", py_langalt)
149 |
150 | print('==== DataValue ====')
151 | py_data = b'0123456789'
152 | print("Python data:", py_data)
153 | # Python -> Exiv2
154 | data = exiv2.DataValue(py_data)
155 | print("Exiv2 data:", data)
156 | # Exiv2 -> Python
157 | py_data = bytearray(len(data))
158 | data.copy(py_data)
159 | print("Python data:", py_data)
160 |
161 | return 0
162 |
163 |
164 | if __name__ == "__main__":
165 | sys.exit(main())
166 |
--------------------------------------------------------------------------------
/examples/xmpsample.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # python-exiv2 - Python interface to libexiv2
4 | # http://github.com/jim-easterbrook/python-exiv2
5 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program 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 General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 | # Sample/test for high level XMP classes. See also addmoddel.py.
21 |
22 | import locale
23 | import sys
24 |
25 | import exiv2
26 |
27 | def main():
28 | locale.setlocale(locale.LC_ALL, '')
29 | try:
30 | exiv2.XmpParser.initialize()
31 |
32 | # The XMP property container
33 | xmpData = exiv2.XmpData()
34 |
35 | # --------------------------------------------------------------
36 | # Teaser: Setting XMP properties doesn't get much easier than
37 | # this:
38 |
39 | xmpData["Xmp.dc.source"] = "xmpsample.cpp" # a simple text value
40 | xmpData["Xmp.dc.subject"] = "Palmtree" # an array item
41 | xmpData["Xmp.dc.subject"] = "Rubbertree" # add a 2nd array item
42 | # a language alternative with two entries and without default
43 | xmpData["Xmp.dc.title"] = "lang=de-DE Sonnenuntergang am Strand"
44 | xmpData["Xmp.dc.title"] = "lang=en-US Sunset on the beach"
45 |
46 | # --------------------------------------------------------------
47 | # Any properties can be set provided the namespace is known.
48 | # Values of any type can be assigned to an Xmpdatum, if they
49 | # have an output operator. The default XMP value type for
50 | # unknown properties is a simple text value.
51 |
52 | xmpData["Xmp.dc.one"] = '-1'
53 | xmpData["Xmp.dc.two"] = '3.1415'
54 | xmpData["Xmp.dc.three"] = exiv2.RationalValue((5, 7))
55 | xmpData["Xmp.dc.four"] = exiv2.UShortValue(255)
56 | xmpData["Xmp.dc.five"] = '256'
57 | xmpData["Xmp.dc.six"] = 'False'
58 |
59 | except exiv2.Exiv2Error as e:
60 | print('Caught Exiv2 exception "{}"'.format(str(e)))
61 | return -1;
62 | finally:
63 | exiv2.XmpParser.terminate()
64 | return 0
65 |
66 | if __name__ == "__main__":
67 | sys.exit(main())
68 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools >= 59.6", "toml"]
3 | build-backend = "setuptools.build_meta"
4 |
5 | [project]
6 | name = "exiv2"
7 | description = "Python interface to libexiv2"
8 | readme = "README.rst"
9 | license = {text = "GNU GPL"}
10 | authors = [
11 | {name = "Jim Easterbrook", email = "jim@jim-easterbrook.me.uk"}
12 | ]
13 | classifiers = [
14 | "Development Status :: 4 - Beta",
15 | "Intended Audience :: Developers",
16 | "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
17 | "Operating System :: MacOS",
18 | "Operating System :: MacOS :: MacOS X",
19 | "Operating System :: POSIX",
20 | "Operating System :: POSIX :: Linux",
21 | "Operating System :: Microsoft",
22 | "Operating System :: Microsoft :: Windows",
23 | "Programming Language :: Python :: 3",
24 | "Topic :: Multimedia",
25 | "Topic :: Multimedia :: Graphics",
26 | ]
27 | dynamic = ["version"]
28 |
29 | [project.urls]
30 | Homepage = "https://github.com/jim-easterbrook/python-exiv2"
31 | Changelog = "https://github.com/jim-easterbrook/python-exiv2/blob/main/CHANGELOG.txt"
32 | Documentation = "https://python-exiv2.readthedocs.io/"
33 |
34 | [tool.setuptools]
35 | platforms = ["POSIX", "MacOS", "Windows"]
36 | zip-safe = false
37 |
38 | [tool.setuptools.dynamic]
39 | version = {attr = "exiv2.__version__"}
40 |
--------------------------------------------------------------------------------
/src/doc/_templates/module.rst:
--------------------------------------------------------------------------------
1 | {% if fullname == "exiv2._version" %}
2 | {% set attributes = ['__version__', '__version_tuple__'] %}
3 | {% endif %}
4 |
5 | {% extends "!autosummary/module.rst" %}
6 |
7 | {% block classes %}
8 | {% if classes %}
9 | .. rubric:: {{ _('Classes') }}
10 |
11 | {% if fullname == "exiv2._value" %}
12 | .. inheritance-diagram:: {{ classes |
13 | reject("in", ["Date", "Time"]) |
14 | join(" ") }}
15 | :top-classes: exiv2.value.Value
16 | {% endif %}
17 |
18 | {% if fullname in ["exiv2._datasets", "exiv2._metadatum", "exiv2._properties", "exiv2._tags"] %}
19 | .. inheritance-diagram:: exiv2.ExifKey exiv2.IptcKey exiv2.XmpKey
20 | :top-classes: exiv2.metadatum.Key
21 | {% endif %}
22 |
23 | {% if fullname in ["exiv2._exif", "exiv2._iptc", "exiv2._metadatum", "exiv2._xmp"] %}
24 | .. inheritance-diagram:: exiv2.Exifdatum exiv2.Iptcdatum exiv2.Xmpdatum
25 | :top-classes: exiv2.metadatum.Metadatum
26 | {% endif %}
27 |
28 | .. autosummary::
29 | {% for item in classes %}
30 | {{ item }}
31 | {%- endfor %}
32 | {% endif %}
33 | {% endblock %}
34 |
--------------------------------------------------------------------------------
/src/doc/index.rst:
--------------------------------------------------------------------------------
1 | .. This is part of the python-exiv2 documentation.
2 | Copyright (C) 2024 Jim Easterbrook.
3 |
4 | Python-exiv2 documentation
5 | ==========================
6 |
7 |
8 | .. toctree::
9 | :maxdepth: 2
10 |
11 | misc/readme
12 | misc/install
13 | misc/usage
14 | misc/changelog
15 | misc/api
16 |
17 |
--------------------------------------------------------------------------------
/src/doc/misc/api.rst:
--------------------------------------------------------------------------------
1 | .. This is part of the python-exiv2 documentation.
2 | Copyright (C) 2024 Jim Easterbrook.
3 |
4 | Detailed API
5 | ============
6 |
7 | This part of the documentation is auto-generated from the Doxygen_ format documentation in the libexiv2 "header" files.
8 | There are many ways in which the conversion process can fail, so you may need to consult the `Exiv2 C++ API`_ documentation as well.
9 |
10 | The documentation is split into several pages, one for each module in the Python interface.
11 | This makes it easier to use than having all the classes and functions in one document.
12 | Do not use the module names in your Python scripts: always use ``exiv2.name`` rather than ``exiv2.module.name`` or ``exiv2._module.name``.
13 |
14 | See :ref:`genindex` for a full index to all classes, attributes, functions and methods.
15 |
16 | .. autosummary::
17 | :toctree: ../api
18 | :recursive:
19 | :template: module.rst
20 |
21 | exiv2._image
22 | exiv2._exif
23 | exiv2._iptc
24 | exiv2._xmp
25 | exiv2._preview
26 | exiv2._value
27 | exiv2._types
28 | exiv2._tags
29 | exiv2._datasets
30 | exiv2._properties
31 | exiv2._version
32 | exiv2._error
33 | exiv2._easyaccess
34 | exiv2._basicio
35 | exiv2._metadatum
36 |
37 | .. _Doxygen: https://www.doxygen.nl/
38 | .. _Exiv2 C++ API: https://exiv2.org/doc/index.html
39 |
--------------------------------------------------------------------------------
/src/doc/misc/changelog.rst:
--------------------------------------------------------------------------------
1 | .. This is part of the python-exiv2 documentation.
2 | Copyright (C) 2024 Jim Easterbrook.
3 |
4 | Release history
5 | ===============
6 |
7 | .. literalinclude:: ../../../CHANGELOG.txt
8 | :language: none
9 | :start-after: licenses/>
10 | :end-before: Changes in v0.4.0
11 |
--------------------------------------------------------------------------------
/src/doc/misc/install.rst:
--------------------------------------------------------------------------------
1 | .. This is part of the python-exiv2 documentation.
2 | Copyright (C) 2024 Jim Easterbrook.
3 |
4 | .. include:: ../../../INSTALL.rst
5 | :end-before: .. _README
6 |
7 | .. _README.rst: readme.html
8 |
--------------------------------------------------------------------------------
/src/doc/misc/readme.rst:
--------------------------------------------------------------------------------
1 | .. This is part of the python-exiv2 documentation.
2 | Copyright (C) 2024 Jim Easterbrook.
3 |
4 | Project overview
5 | ================
6 |
7 | .. include:: ../../../README.rst
8 | :start-line: 2
9 | :end-before: .. _INSTALL
10 |
11 | .. _INSTALL.rst: install.html
12 | .. _USAGE.rst: usage.html
13 |
--------------------------------------------------------------------------------
/src/doc/misc/usage.rst:
--------------------------------------------------------------------------------
1 | .. This is part of the python-exiv2 documentation.
2 | Copyright (C) 2024 Jim Easterbrook.
3 |
4 | .. include:: ../../../USAGE.rst
5 |
--------------------------------------------------------------------------------
/src/doc/requirements.txt:
--------------------------------------------------------------------------------
1 | exiv2 <= 0.17.3
2 | sphinx == 7.2.6
3 | sphinx-rtd-theme == 2.0.0
4 |
--------------------------------------------------------------------------------
/src/interface/__main__.py:
--------------------------------------------------------------------------------
1 | # python-exiv2 - Python interface to exiv2
2 | # http://github.com/jim-easterbrook/python-exiv2
3 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import argparse
19 | import os
20 | import pprint
21 | import sys
22 |
23 | import exiv2
24 |
25 | def main():
26 | parser = argparse.ArgumentParser()
27 | parser.add_argument('-v', '--verbosity', help='increase output verbosity',
28 | action='store_true')
29 | args = parser.parse_args()
30 | print('libexiv2 version:', exiv2.version())
31 | print('python-exiv2 version:', exiv2.__version__)
32 | print('python-exiv2 examples:',
33 | os.path.join(os.path.dirname(__file__), 'examples'))
34 | if args.verbosity:
35 | print('libexiv2 build options:')
36 | pprint.pprint(exiv2.versionInfo())
37 |
38 | if __name__ == "__main__":
39 | sys.exit(main())
40 |
--------------------------------------------------------------------------------
/src/interface/datasets.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %module(package="exiv2") datasets
19 |
20 | #ifndef SWIGIMPORTED
21 | %constant char* __doc__ = "IPTC key class and data attributes.";
22 | #endif
23 |
24 | %include "shared/preamble.i"
25 | %include "shared/enum.i"
26 | %include "shared/exception.i"
27 | %include "shared/static_list.i"
28 | %include "shared/struct_dict.i"
29 | %include "shared/unique_ptr.i"
30 |
31 | %import "metadatum.i"
32 |
33 | IMPORT_ENUM(TypeId)
34 |
35 | // Catch some C++ exceptions
36 | %exception;
37 | EXCEPTION(Exiv2::IptcDataSets::dataSet)
38 | EXCEPTION(Exiv2::IptcDataSets::recordId)
39 | EXCEPTION(Exiv2::IptcKey::IptcKey(std::string))
40 | EXCEPTION(Exiv2::IptcKey::IptcKey(std::string const &))
41 |
42 | EXTEND_KEY(Exiv2::IptcKey);
43 |
44 | // IptcDataSets::application2RecordList and IptcDataSets::envelopeRecordList
45 | // return a static list as a pointer
46 | LIST_POINTER(const Exiv2::DataSet*, Exiv2::DataSet, number_ != 0xffff)
47 |
48 | // Give Exiv2::DataSet dict-like behaviour
49 | STRUCT_DICT(Exiv2::DataSet)
50 |
51 | // Structs are all static data
52 | %ignore Exiv2::IptcDataSets::IptcDataSets;
53 | %ignore Exiv2::IptcDataSets::~IptcDataSets;
54 | %ignore Exiv2::DataSet::DataSet;
55 | %ignore Exiv2::DataSet::~DataSet;
56 |
57 | // Ignore stuff that Python can't use or doesn't need
58 | %ignore Exiv2::Dictionary;
59 | %ignore Exiv2::Dictionary_i;
60 | %ignore Exiv2::IptcDataSets::dataSetList;
61 | %ignore Exiv2::RecordInfo;
62 | %ignore Exiv2::StringSet;
63 | %ignore Exiv2::StringSet_i;
64 | %ignore Exiv2::StringVector;
65 | %ignore Exiv2::StringVector_i;
66 | %ignore Exiv2::Uint32Vector;
67 | %ignore Exiv2::Uint32Vector_i;
68 |
69 | %immutable;
70 | %include "exiv2/datasets.hpp"
71 | %mutable;
72 |
--------------------------------------------------------------------------------
/src/interface/easyaccess.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %module(package="exiv2") easyaccess
19 |
20 | #ifndef SWIGIMPORTED
21 | %constant char* __doc__ = "Simplified reading of Exif metadata.";
22 | #endif
23 |
24 | %include "shared/preamble.i"
25 | %include "shared/exception.i"
26 | %include "shared/exv_options.i"
27 |
28 | // Catch all C++ exceptions
29 | EXCEPTION()
30 |
31 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::apertureValue)
32 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::brightnessValue)
33 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::dateTimeOriginal)
34 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::exposureBiasValue)
35 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::exposureIndex)
36 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::flash)
37 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::flashEnergy)
38 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::lightSource)
39 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::maxApertureValue)
40 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::sensingMethod)
41 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::shutterSpeedValue)
42 | EXV_ENABLE_EASYACCESS_FUNCTION(Exiv2::subjectArea)
43 |
44 | // Store data.end() after converting input
45 | %typemap(check) Exiv2::ExifData& (Exiv2::ExifData::const_iterator _global_end) %{
46 | _global_end = $1->end();
47 | %}
48 |
49 | // Convert result from iterator to datum or None
50 | %typemap(out) Exiv2::ExifData::const_iterator %{
51 | if ($1 == _global_end)
52 | $result = SWIG_Py_Void();
53 | else
54 | $result = SWIG_NewPointerObj(
55 | SWIG_as_voidptr(&(*$1)), $descriptor(Exiv2::Exifdatum*), 0);
56 | %}
57 |
58 | %include "exiv2/easyaccess.hpp"
59 |
--------------------------------------------------------------------------------
/src/interface/exif.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %module(package="exiv2") exif
19 |
20 | #ifndef SWIGIMPORTED
21 | %constant char* __doc__ = "Exif metadatum, container and iterators.";
22 | #endif
23 |
24 | #pragma SWIG nowarn=508 // Declaration of '__str__' shadows declaration accessible via operator->()
25 |
26 | %include "shared/preamble.i"
27 | %include "shared/buffers.i"
28 | %include "shared/containers.i"
29 | %include "shared/data_iterator.i"
30 | %include "shared/enum.i"
31 | %include "shared/exception.i"
32 | %include "shared/exv_options.i"
33 | %include "shared/keep_reference.i"
34 | %include "shared/windows_path.i"
35 |
36 | %include "stdint.i"
37 | %include "std_string.i"
38 |
39 | %import "tags.i"
40 |
41 | IMPORT_ENUM(ByteOrder)
42 | IMPORT_ENUM(TypeId)
43 |
44 | // Catch all C++ exceptions
45 | EXCEPTION()
46 |
47 | EXV_ENABLE_FILESYSTEM_FUNCTION(Exiv2::ExifThumb::setJpegThumbnail(
48 | const std::string&))
49 | EXV_ENABLE_FILESYSTEM_FUNCTION(Exiv2::ExifThumb::setJpegThumbnail(
50 | const std::string&, URational, URational, uint16_t))
51 | EXV_ENABLE_FILESYSTEM_FUNCTION(Exiv2::ExifThumbC::writeFile)
52 |
53 | // ExifThumb keeps a reference to the ExifData it uses
54 | KEEP_REFERENCE_EX(Exiv2::ExifThumb*, args)
55 |
56 | #if EXIV2_VERSION_HEX < 0x001c0000
57 | INPUT_BUFFER_RO(const Exiv2::byte* buf, long size)
58 | #else
59 | INPUT_BUFFER_RO(const Exiv2::byte* buf, size_t size)
60 | #endif
61 |
62 | EXTEND_METADATUM(Exiv2::Exifdatum)
63 |
64 | DATA_ITERATOR_TYPEMAPS(ExifData)
65 | #ifndef SWIGIMPORTED
66 | DATA_ITERATOR_CLASSES(ExifData, Exifdatum)
67 | #endif
68 |
69 | // Get the current (or default if not set) type id of a datum
70 | %fragment("get_type_id"{Exiv2::Exifdatum}, "header") {
71 | static Exiv2::TypeId get_type_id(Exiv2::Exifdatum* datum) {
72 | Exiv2::TypeId type_id = datum->typeId();
73 | if (type_id != Exiv2::invalidTypeId)
74 | return type_id;
75 | return Exiv2::ExifKey(datum->key()).defaultTypeId();
76 | };
77 | }
78 |
79 | DATA_CONTAINER(Exiv2::ExifData, Exiv2::Exifdatum, Exiv2::ExifKey)
80 |
81 | // Convert path encoding on Windows
82 | WINDOWS_PATH(const std::string& path)
83 |
84 | // Ignore const overloads of some methods
85 | %ignore Exiv2::ExifData::operator[];
86 | %ignore Exiv2::ExifData::begin() const;
87 | %ignore Exiv2::ExifData::end() const;
88 | %ignore Exiv2::ExifData::findKey(ExifKey const &) const;
89 | %ignore Exiv2::ExifParser;
90 |
91 | // Exifdatum::ifdId is documented as internal use only
92 | %ignore Exiv2::Exifdatum::ifdId;
93 |
94 | %include "exiv2/exif.hpp"
95 |
--------------------------------------------------------------------------------
/src/interface/iptc.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %module(package="exiv2") iptc
19 |
20 | #ifndef SWIGIMPORTED
21 | %constant char* __doc__ = "IPTC metadatum, container and iterators.";
22 | #endif
23 |
24 | #pragma SWIG nowarn=508 // Declaration of '__str__' shadows declaration accessible via operator->()
25 |
26 | %include "shared/preamble.i"
27 | %include "shared/containers.i"
28 | %include "shared/data_iterator.i"
29 | %include "shared/enum.i"
30 | %include "shared/exception.i"
31 |
32 | %include "stdint.i"
33 | %include "std_string.i"
34 |
35 | %import "datasets.i"
36 |
37 | IMPORT_ENUM(ByteOrder)
38 | IMPORT_ENUM(TypeId)
39 |
40 | // Catch all C++ exceptions
41 | EXCEPTION()
42 |
43 | EXTEND_METADATUM(Exiv2::Iptcdatum)
44 |
45 | DATA_ITERATOR_TYPEMAPS(IptcData)
46 | #ifndef SWIGIMPORTED
47 | DATA_ITERATOR_CLASSES(IptcData, Iptcdatum)
48 | #endif
49 |
50 | // Get the current (or default if not set) type id of a datum
51 | %fragment("get_type_id"{Exiv2::Iptcdatum}, "header") {
52 | static Exiv2::TypeId get_type_id(Exiv2::Iptcdatum* datum) {
53 | Exiv2::TypeId type_id = datum->typeId();
54 | if (type_id != Exiv2::invalidTypeId)
55 | return type_id;
56 | return Exiv2::IptcDataSets::dataSetType(datum->tag(), datum->record());
57 | };
58 | }
59 |
60 | DATA_CONTAINER(Exiv2::IptcData, Exiv2::Iptcdatum, Exiv2::IptcKey)
61 |
62 | // Ignore const overloads of some methods
63 | %ignore Exiv2::IptcData::operator[];
64 | %ignore Exiv2::IptcData::begin() const;
65 | %ignore Exiv2::IptcData::end() const;
66 | %ignore Exiv2::IptcData::findKey(IptcKey const &) const;
67 | %ignore Exiv2::IptcData::findId(uint16_t) const;
68 | %ignore Exiv2::IptcData::findId(uint16_t,uint16_t) const;
69 | %ignore Exiv2::IptcData::printStructure;
70 | %ignore Exiv2::IptcParser;
71 |
72 | %include "exiv2/iptc.hpp"
73 |
--------------------------------------------------------------------------------
/src/interface/metadatum.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %module(package="exiv2") metadatum
19 |
20 | #ifndef SWIGIMPORTED
21 | %constant char* __doc__ = "Exiv2 metadatum base class.";
22 | #endif
23 |
24 | %namewarn("") "print"; // don't rename print methods
25 |
26 | %include "shared/preamble.i"
27 | %include "shared/containers.i"
28 | %include "shared/exception.i"
29 | %include "shared/keep_reference.i"
30 | %include "shared/unique_ptr.i"
31 |
32 | %import "value.i"
33 |
34 | // Catch all C++ exceptions
35 | EXCEPTION()
36 |
37 | // Use default parameter for toFloat etc.
38 | %typemap(default) long n, size_t n {$1 = 0;}
39 | %ignore Exiv2::Metadatum::toFloat() const;
40 | %ignore Exiv2::Metadatum::toInt64() const;
41 | %ignore Exiv2::Metadatum::toLong() const;
42 | %ignore Exiv2::Metadatum::toRational() const;
43 | %ignore Exiv2::Metadatum::toUint32() const;
44 |
45 | // Use default parameter in print() and write()
46 | %typemap(default) const Exiv2::ExifData* pMetadata {$1 = NULL;}
47 | %ignore Exiv2::Metadatum::print() const;
48 | %ignore Exiv2::Metadatum::write(std::ostream &) const;
49 |
50 | %define EXTEND_KEY(key_type)
51 | UNIQUE_PTR(key_type);
52 | %feature("python:slot", "tp_str", functype="reprfunc") key_type::key;
53 | %enddef // EXTEND_KEY
54 |
55 | EXTEND_KEY(Exiv2::Key);
56 |
57 | // Macro for Metadatum subclasses
58 | %define EXTEND_METADATUM(datum_type)
59 | // Ignore overloaded default parameter version
60 | %ignore datum_type::write(std::ostream &) const;
61 | // Turn off exception checking for methods that are guaranteed not to throw
62 | %noexception datum_type::count;
63 | %noexception datum_type::size;
64 | // Keep a reference to Metadatum when calling value()
65 | KEEP_REFERENCE(const Exiv2::Value&)
66 | // Keep a reference to any object that returns a reference to a datum.
67 | KEEP_REFERENCE(datum_type&)
68 | // Set the datum's value from a Python object. The datum's current or default
69 | // type is used to create an Exiv2::Value object (via Python) from the Python
70 | // object.
71 | %fragment("set_value_from_py"{datum_type}, "header",
72 | fragment="get_type_object", fragment="get_type_id"{datum_type}) {
73 | static PyObject* set_value_from_py(datum_type* datum, PyObject* py_value) {
74 | swig_type_info* ty_info = get_type_object(get_type_id(datum));
75 | SwigPyClientData *cl_data = (SwigPyClientData*)ty_info->clientdata;
76 | // Call type object to invoke constructor
77 | PyObject* args = PyTuple_Pack(1, py_value);
78 | PyObject* swig_obj = PyObject_CallObject(
79 | (PyObject*)cl_data->pytype, args);
80 | Py_DECREF(args);
81 | if (!swig_obj)
82 | return NULL;
83 | // Convert constructed object to Exiv2::Value
84 | Exiv2::Value* value = 0;
85 | if (!SWIG_IsOK(SWIG_ConvertPtr(
86 | swig_obj, (void**)&value, $descriptor(Exiv2::Value*), 0))) {
87 | PyErr_SetString(
88 | PyExc_RuntimeError, "set_value_from_py: invalid conversion");
89 | Py_DECREF(swig_obj);
90 | return NULL;
91 | }
92 | // Set value
93 | datum->setValue(value);
94 | Py_DECREF(swig_obj);
95 | return SWIG_Py_Void();
96 | };
97 | }
98 | %extend datum_type {
99 | // Extend Metadatum to allow getting value as a specific type.
100 | Exiv2::Value::SMART_PTR getValue(Exiv2::TypeId as_type) {
101 | // deprecated since 2023-12-07
102 | PyErr_WarnEx(PyExc_DeprecationWarning, "Requested type ignored.", 1);
103 | return $self->getValue();
104 | }
105 | const Exiv2::Value& value(Exiv2::TypeId as_type) {
106 | // deprecated since 2023-12-07
107 | PyErr_WarnEx(PyExc_DeprecationWarning, "Requested type ignored.", 1);
108 | return $self->value();
109 | }
110 | // Set the value from a Python object. The datum's current or default
111 | // type is used to create an Exiv2::Value object (via Python) from the
112 | // Python object.
113 | %fragment("set_value_from_py"{datum_type});
114 | PyObject* setValue(PyObject* py_value) {
115 | return set_value_from_py($self, py_value);
116 | }
117 | // Old _print method for compatibility
118 | std::string _print(const Exiv2::ExifData* pMetadata) const {
119 | // deprecated since 2024-01-29
120 | PyErr_WarnEx(PyExc_DeprecationWarning,
121 | "'_print' has been replaced by 'print'", 1);
122 | return $self->print(pMetadata);
123 | }
124 | }
125 | %enddef // EXTEND_METADATUM
126 |
127 | // Extend base type
128 | %feature("python:slot", "tp_str", functype="reprfunc")
129 | Exiv2::Metadatum::__str__;
130 | %extend Exiv2::Metadatum {
131 | std::string __str__() {
132 | return $self->key() + ": " + $self->print();
133 | }
134 | }
135 |
136 | %ignore Exiv2::Key::~Key;
137 | %ignore Exiv2::Key::operator=;
138 | %ignore Exiv2::Metadatum::~Metadatum;
139 | %ignore Exiv2::Metadatum::operator=;
140 | %ignore Exiv2::cmpMetadataByKey;
141 | %ignore Exiv2::cmpMetadataByTag;
142 |
143 | %include "exiv2/metadatum.hpp"
144 |
--------------------------------------------------------------------------------
/src/interface/preview.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %module(package="exiv2") preview
19 |
20 | #ifndef SWIGIMPORTED
21 | %constant char* __doc__ = "Access to preview images.
22 |
23 | For Exif thumbnail images see the :py:class:`ExifThumb` class.";
24 | #endif
25 |
26 | // We don't need Python access to SwigPyIterator
27 | %ignore SwigPyIterator;
28 |
29 | %include "shared/preamble.i"
30 | %include "shared/buffers.i"
31 | %include "shared/exception.i"
32 | %include "shared/exv_options.i"
33 | %include "shared/keep_reference.i"
34 | %include "shared/struct_dict.i"
35 | %include "shared/windows_path.i"
36 |
37 | %include "std_string.i"
38 | %include "std_vector.i"
39 |
40 | %import "image.i";
41 |
42 | // Catch all C++ exceptions
43 | EXCEPTION()
44 |
45 | %fragment("EXV_USE_CURL");
46 | %fragment("EXV_USE_SSH");
47 | %fragment("EXV_ENABLE_FILESYSTEM");
48 | EXV_ENABLE_FILESYSTEM_FUNCTION(Exiv2::PreviewImage::writeFile)
49 |
50 | // Some calls don't raise exceptions
51 | %noexception Exiv2::PreviewImage::__len__;
52 | %noexception Exiv2::PreviewImage::extension;
53 | %noexception Exiv2::PreviewImage::height;
54 | %noexception Exiv2::PreviewImage::id;
55 | %noexception Exiv2::PreviewImage::mimeType;
56 | %noexception Exiv2::PreviewImage::pData;
57 | %noexception Exiv2::PreviewImage::size;
58 | %noexception Exiv2::PreviewImage::wextension;
59 | %noexception Exiv2::PreviewImage::width;
60 |
61 | // Convert path encoding on Windows
62 | WINDOWS_PATH(const std::string& path)
63 | WINDOWS_PATH_OUT(extension)
64 |
65 | // Convert getPreviewProperties result to a Python tuple
66 | %template() std::vector;
67 |
68 | // Make sure PreviewManager keeps a reference to the image it's using
69 | KEEP_REFERENCE_EX(Exiv2::PreviewManager*, args)
70 |
71 | // Enable len(PreviewImage)
72 | %feature("python:slot", "sq_length", functype="lenfunc")
73 | Exiv2::PreviewImage::__len__;
74 | %extend Exiv2::PreviewImage {
75 | size_t __len__() {
76 | return $self->size();
77 | }
78 | }
79 |
80 | // Expose Exiv2::PreviewImage contents as a Python buffer
81 | %fragment("get_ptr_size"{Exiv2::PreviewImage}, "header") {
82 | static bool get_ptr_size(Exiv2::PreviewImage* self, bool is_writeable,
83 | Exiv2::byte*& ptr, Py_ssize_t& size) {
84 | ptr = (Exiv2::byte*)self->pData();
85 | size = self->size();
86 | return true;
87 | };
88 | }
89 | EXPOSE_OBJECT_BUFFER(Exiv2::PreviewImage, false, false)
90 |
91 | // Convert pData result to a Python memoryview
92 | RETURN_VIEW(Exiv2::byte* pData, arg1->size(), PyBUF_READ,
93 | Exiv2::PreviewImage::pData)
94 |
95 | // Give Exiv2::PreviewProperties dict-like behaviour
96 | STRUCT_DICT(Exiv2::PreviewProperties)
97 |
98 | %immutable Exiv2::PreviewProperties::mimeType_;
99 | %immutable Exiv2::PreviewProperties::extension_;
100 | %immutable Exiv2::PreviewProperties::wextension_;
101 | %immutable Exiv2::PreviewProperties::size_;
102 | %immutable Exiv2::PreviewProperties::width_;
103 | %immutable Exiv2::PreviewProperties::height_;
104 | %immutable Exiv2::PreviewProperties::id_;
105 |
106 | %ignore Exiv2::PreviewImage::operator=;
107 | %ignore Exiv2::PreviewProperties::PreviewProperties;
108 |
109 | %include "exiv2/preview.hpp"
110 |
--------------------------------------------------------------------------------
/src/interface/properties.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %module(package="exiv2") properties
19 |
20 | #ifndef SWIGIMPORTED
21 | %constant char* __doc__ = "XMP key class and data attributes.";
22 | #endif
23 |
24 | %include "shared/preamble.i"
25 | %include "shared/exception.i"
26 | %include "shared/enum.i"
27 | %include "shared/static_list.i"
28 | %include "shared/struct_dict.i"
29 | %include "shared/unique_ptr.i"
30 |
31 | %import "metadatum.i"
32 |
33 | IMPORT_ENUM(TypeId)
34 |
35 | // Catch all C++ exceptions...
36 | EXCEPTION()
37 |
38 | // ...except these
39 | %noexception Exiv2::XmpKey::~XmpKey;
40 | %noexception Exiv2::XmpKey::familyName;
41 | %noexception Exiv2::XmpKey::groupName;
42 | %noexception Exiv2::XmpKey::key;
43 | %noexception Exiv2::XmpKey::tag;
44 | %noexception Exiv2::XmpKey::tagLabel;
45 | %noexception Exiv2::XmpKey::tagName;
46 | %noexception Exiv2::XmpProperties::prefix;
47 | %noexception Exiv2::XmpProperties::propertyDesc;
48 | %noexception Exiv2::XmpProperties::propertyInfo;
49 | %noexception Exiv2::XmpProperties::propertyTitle;
50 | %noexception Exiv2::XmpProperties::propertyType;
51 |
52 | EXTEND_KEY(Exiv2::XmpKey);
53 |
54 | // Make Xmp category more Pythonic
55 | DEFINE_ENUM(XmpCategory, "Category of an XMP property.",
56 | "xmpInternal", Exiv2::xmpInternal,
57 | "xmpExternal", Exiv2::xmpExternal,
58 | "Internal", Exiv2::xmpInternal,
59 | "External", Exiv2::xmpExternal);
60 |
61 | // Get registeredNamespaces to return a Python dict
62 | %typemap(in, numinputs=0) Exiv2::Dictionary &nsDict (Exiv2::Dictionary temp) %{
63 | $1 = &temp;
64 | %}
65 | %typemap(argout) Exiv2::Dictionary &nsDict {
66 | PyObject* value = NULL;
67 | PyObject* dict = PyDict_New();
68 | Exiv2::Dictionary::iterator e = $1->end();
69 | for (Exiv2::Dictionary::iterator i = $1->begin(); i != e; ++i) {
70 | value = PyUnicode_FromString(i->second.c_str());
71 | PyDict_SetItemString(dict, i->first.c_str(), value);
72 | Py_DECREF(value);
73 | }
74 | $result = SWIG_AppendOutput($result, dict);
75 | }
76 |
77 | // Convert XmpProperties.propertyList() result and XmpNsInfo.xmpPropertyInfo_
78 | // to a Python list of XmpPropertyInfo objects
79 | // XmpProperties.propertyInfo() returns a single XmpPropertyInfo object
80 | LIST_POINTER(const Exiv2::XmpPropertyInfo* propertyList,
81 | Exiv2::XmpPropertyInfo, name_)
82 | LIST_POINTER(const Exiv2::XmpPropertyInfo* xmpPropertyInfo_,
83 | Exiv2::XmpPropertyInfo, name_)
84 |
85 | // Give Exiv2::XmpPropertyInfo dict-like behaviour
86 | STRUCT_DICT(Exiv2::XmpPropertyInfo)
87 |
88 | // Give Exiv2::XmpNsInfo dict-like behaviour
89 | STRUCT_DICT(Exiv2::XmpNsInfo)
90 |
91 | // Structs are all static data
92 | %ignore Exiv2::XmpPropertyInfo::XmpPropertyInfo;
93 | %ignore Exiv2::XmpPropertyInfo::~XmpPropertyInfo;
94 | %ignore Exiv2::XmpProperties::XmpProperties;
95 | %ignore Exiv2::XmpProperties::~XmpProperties;
96 | %ignore Exiv2::XmpNsInfo::XmpNsInfo;
97 | %ignore Exiv2::XmpNsInfo::~XmpNsInfo;
98 |
99 | // Ignore "internal" stuff
100 | %ignore Exiv2::XmpProperties::rwLock_;
101 | %ignore Exiv2::XmpProperties::mutex_;
102 | %ignore Exiv2::XmpProperties::nsRegistry_;
103 | %ignore Exiv2::XmpPropertyInfo::operator==;
104 | %ignore Exiv2::XmpNsInfo::operator==;
105 | %ignore Exiv2::XmpNsInfo::Prefix;
106 | %ignore Exiv2::XmpNsInfo::Ns;
107 | %ignore NsRegistry;
108 |
109 | // Ignore stuff Python can't use
110 | %ignore Exiv2::XmpProperties::lookupNsRegistry;
111 | %ignore Exiv2::XmpProperties::printProperties;
112 | %ignore Exiv2::XmpProperties::printProperty;
113 |
114 | %immutable;
115 | %include "exiv2/properties.hpp"
116 | %mutable;
117 |
--------------------------------------------------------------------------------
/src/interface/shared/buffers.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 |
19 | // Macro for input read only byte buffer
20 | %define INPUT_BUFFER_RO(buf_type, len_type)
21 | %typemap(doctype) buf_type ":py:term:`bytes-like object`";
22 | %typemap(in) (buf_type, len_type) (PyObject* _global_view = NULL) {
23 | _global_view = PyMemoryView_GetContiguous($input, PyBUF_READ, 'A');
24 | if (!_global_view) {
25 | PyErr_Clear();
26 | %argument_fail(
27 | SWIG_TypeError, "bytes-like object", $symname, $argnum);
28 | }
29 | Py_buffer* buff = PyMemoryView_GET_BUFFER(_global_view);
30 | $1 = ($1_ltype) buff->buf;
31 | $2 = ($2_ltype) buff->len;
32 | }
33 | %typemap(freearg) (buf_type, len_type) %{
34 | Py_XDECREF(_global_view);
35 | %}
36 | %typemap(typecheck, precedence=SWIG_TYPECHECK_CHAR_PTR) buf_type %{
37 | $1 = PyObject_CheckBuffer($input) ? 1 : 0;
38 | %}
39 | %enddef // INPUT_BUFFER_RO
40 |
41 |
42 | // Macro for input read only byte buffer, result keeps reference to input
43 | %define INPUT_BUFFER_RO_EX(buf_type, len_type)
44 | INPUT_BUFFER_RO(buf_type, len_type)
45 | %typemap(argout) (buf_type, len_type) %{
46 | PyObject_SetAttrString(resultobj, "_refers_to", _global_view);
47 | %}
48 | %enddef // INPUT_BUFFER_RO_EX
49 |
50 |
51 | // Macro for output writeable byte buffer
52 | %define OUTPUT_BUFFER_RW(buf_type, count_type)
53 | %typemap(doctype) buf_type "writeable :py:term:`bytes-like object`";
54 | %typemap(in) (buf_type) (Py_buffer _global_view) {
55 | _global_view.obj = NULL;
56 | if (PyObject_GetBuffer(
57 | $input, &_global_view, PyBUF_CONTIG | PyBUF_WRITABLE) < 0) {
58 | PyErr_Clear();
59 | %argument_fail(SWIG_TypeError, "writable bytes-like object",
60 | $symname, $argnum);
61 | }
62 | $1 = ($1_ltype) _global_view.buf;
63 | }
64 | %typemap(check) (buf_type, count_type) {
65 | if ($2 > ($2_ltype) _global_view.len) {
66 | %argument_fail(SWIG_ValueError, "buffer too small",
67 | $symname, $argnum);
68 | }
69 | }
70 | %typemap(freearg) (buf_type) %{
71 | if (_global_view.obj) {
72 | PyBuffer_Release(&_global_view);
73 | }
74 | %}
75 | %typemap(typecheck, precedence=SWIG_TYPECHECK_CHAR_PTR) buf_type %{
76 | $1 = PyObject_CheckBuffer($input) ? 1 : 0;
77 | %}
78 | %enddef // OUTPUT_BUFFER_RW
79 |
80 | // Macro to convert byte* return value to memoryview
81 | // WARNING: return value does not keep a reference to the data it points to
82 | %define RETURN_VIEW(signature, size_func, flags, doc_method)
83 | %typemap(doctype) signature "memoryview";
84 | %typemap(out) (signature) %{
85 | $result = PyMemoryView_FromMemory((char*)$1, size_func, flags);
86 | %}
87 | #if #doc_method != ""
88 | %feature("docstring") doc_method
89 | "Returns a temporary Python memoryview of the object's data.
90 |
91 | WARNING: do not resize or delete the object while using the view.
92 |
93 | :rtype: memoryview"
94 | #endif
95 | %enddef // RETURN_VIEW
96 |
97 |
98 | // Macros to expose object data with a buffer interface
99 | %define _BF_GETBUFFER(object_type, writeable, get_func)
100 | %fragment("getbuffer"{object_type}, "header",
101 | fragment="get_ptr_size"{object_type}) {
102 | static int getbuffer_%mangle(object_type)(
103 | PyObject* exporter, Py_buffer* view, int flags) {
104 | object_type* self = 0;
105 | Exiv2::byte* ptr = 0;
106 | Py_ssize_t size = 0;
107 | bool is_writeable = writeable && (flags && PyBUF_WRITABLE);
108 | if (!SWIG_IsOK(SWIG_ConvertPtr(
109 | exporter, (void**)&self, $descriptor(object_type*), 0)))
110 | goto fail;
111 | if (!get_ptr_size(self, is_writeable, ptr, size))
112 | goto fail;
113 | return PyBuffer_FillInfo(view, exporter, ptr,
114 | ptr ? size : 0, is_writeable ? 0 : 1, flags);
115 | fail:
116 | PyErr_SetNone(PyExc_BufferError);
117 | view->obj = NULL;
118 | return -1;
119 | };
120 | }
121 | %fragment("getbuffer"{object_type});
122 | %feature("python:bf_getbuffer", functype="getbufferproc")
123 | object_type "get_func";
124 | %enddef // _BF_GETBUFFER
125 |
126 | %define _BF_RELEASEBUFFER(object_type, release_func)
127 | %fragment("releasebuffer"{object_type}, "header",
128 | fragment="release_ptr"{object_type}) {
129 | static void releasebuffer_%mangle(object_type)(
130 | PyObject* exporter, Py_buffer* view) {
131 | object_type* self = 0;
132 | if (!SWIG_IsOK(SWIG_ConvertPtr(
133 | exporter, (void**)&self, $descriptor(object_type*), 0)))
134 | return;
135 | release_ptr(self);
136 | };
137 | }
138 | %fragment("releasebuffer"{object_type});
139 | %feature("python:bf_releasebuffer", functype="releasebufferproc")
140 | object_type "release_func";
141 | %enddef // _BF_RELEASEBUFFER
142 |
143 | %define EXPOSE_OBJECT_BUFFER(object_type, writeable, with_release)
144 | // Add getbuffer slot to an object type
145 | _BF_GETBUFFER(object_type, writeable, getbuffer_%mangle(object_type))
146 | #if #with_release == "true"
147 | // Add releasebuffer slot to an object type (not often needed)
148 | _BF_RELEASEBUFFER(object_type, releasebuffer_%mangle(object_type))
149 | #endif
150 | %enddef // EXPOSE_OBJECT_BUFFER
151 |
--------------------------------------------------------------------------------
/src/interface/shared/containers.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 |
19 | // Macro to wrap data containers.
20 | %define DATA_CONTAINER(base_class, datum_type, key_type)
21 | // Turn off exception checking for methods that are guaranteed not to throw
22 | %noexception base_class::begin;
23 | %noexception base_class::end;
24 | %noexception base_class::clear;
25 | %noexception base_class::count;
26 | %noexception base_class::empty;
27 | // Add dict-like behaviour
28 | %feature("python:slot", "tp_iter", functype="getiterfunc")
29 | base_class::begin;
30 | %feature("python:slot", "mp_length", functype="lenfunc")
31 | base_class::count;
32 | %feature("python:slot", "mp_subscript", functype="binaryfunc")
33 | base_class::__getitem__;
34 | %feature("python:slot", "mp_ass_subscript", functype="objobjargproc")
35 | base_class::__setitem__;
36 | %feature("python:slot", "sq_contains", functype="objobjproc")
37 | base_class::__contains__;
38 | %extend base_class {
39 | %fragment("get_type_id"{datum_type});
40 | %fragment("set_value_from_py"{datum_type});
41 | datum_type& __getitem__(const std::string& key) {
42 | return (*$self)[key];
43 | }
44 | PyObject* __setitem__(const std::string& key, Exiv2::Value* value) {
45 | datum_type* datum = &(*$self)[key];
46 | datum->setValue(value);
47 | return SWIG_Py_Void();
48 | }
49 | PyObject* __setitem__(const std::string& key, const std::string& value) {
50 | datum_type* datum = &(*$self)[key];
51 | Exiv2::TypeId old_type = get_type_id(datum);
52 | if (datum->setValue(value) != 0)
53 | return PyErr_Format(PyExc_ValueError,
54 | "%s: cannot set type '%s' to value '%s'",
55 | datum->key().c_str(), Exiv2::TypeInfo::typeName(old_type),
56 | value.c_str());
57 | return SWIG_Py_Void();
58 | }
59 | PyObject* __setitem__(const std::string& key, PyObject* py_value) {
60 | datum_type* datum = &(*$self)[key];
61 | return set_value_from_py(datum, py_value);
62 | }
63 | PyObject* __setitem__(const std::string& key) {
64 | base_class::iterator pos = $self->findKey(key_type(key));
65 | if (pos == $self->end()) {
66 | PyErr_SetString(PyExc_KeyError, key.c_str());
67 | return NULL;
68 | }
69 | $self->erase(pos);
70 | return SWIG_Py_Void();
71 | }
72 | bool __contains__(const std::string& key) {
73 | return $self->findKey(key_type(key)) != $self->end();
74 | }
75 | }
76 | %enddef // DATA_CONTAINER
77 |
--------------------------------------------------------------------------------
/src/interface/shared/data_iterator.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 |
19 | %include "shared/keep_reference.i"
20 |
21 |
22 | // Macros to wrap data iterators
23 | %define DATA_ITERATOR_CLASSES(container_type, datum_type)
24 | %feature("python:slot", "tp_str", functype="reprfunc")
25 | container_type##_iterator_base::__str__;
26 | %feature("python:slot", "tp_iter", functype="getiterfunc")
27 | container_type##_iterator_base::__iter__;
28 | %feature("python:slot", "tp_iternext", functype="iternextfunc")
29 | container_type##_iterator_base::__next__;
30 | %noexception container_type##_iterator_base::__iter__;
31 | %noexception container_type##_iterator_base::operator==;
32 | %noexception container_type##_iterator_base::operator!=;
33 | %ignore container_type##_iterator_base::size;
34 | %ignore container_type##_iterator_base::##container_type##_iterator_base;
35 | %ignore container_type##_iterator_base::operator*;
36 | %ignore container_type##_iterator_base::valid;
37 | %feature("docstring") container_type##_iterator "
38 | Python wrapper for an :class:`" #container_type "` iterator. It has most of
39 | the methods of :class:`" #datum_type "` allowing easy access to the
40 | data it points to."
41 | %feature("docstring") container_type##_iterator_base "
42 | Python wrapper for an :class:`" #container_type "` iterator that points to
43 | the 'end' value and can not be dereferenced."
44 | // Creating a new iterator keeps a reference to the current one
45 | KEEP_REFERENCE(container_type##_iterator*)
46 | KEEP_REFERENCE(container_type##_iterator_base*)
47 | // Detect end of iteration
48 | %exception container_type##_iterator_base::__next__ %{
49 | $action
50 | if (!result) {
51 | PyErr_SetNone(PyExc_StopIteration);
52 | SWIG_fail;
53 | }
54 | %}
55 | %inline %{
56 | // Base class implements all methods except dereferencing
57 | class container_type##_iterator_base {
58 | protected:
59 | Exiv2::container_type::iterator ptr;
60 | Exiv2::container_type::iterator end;
61 | Exiv2::container_type::iterator safe_ptr;
62 | public:
63 | container_type##_iterator_base(Exiv2::container_type::iterator ptr,
64 | Exiv2::container_type::iterator end) {
65 | this->ptr = ptr;
66 | this->end = end;
67 | safe_ptr = ptr;
68 | }
69 | container_type##_iterator_base* __iter__() { return this; }
70 | Exiv2::datum_type* __next__() {
71 | if (!valid())
72 | return NULL;
73 | Exiv2::datum_type* result = &(*safe_ptr);
74 | ptr++;
75 | if (valid())
76 | safe_ptr = ptr;
77 | return result;
78 | }
79 | Exiv2::container_type::iterator operator*() const { return ptr; }
80 | bool operator==(const container_type##_iterator_base &other) const {
81 | return *other == ptr;
82 | }
83 | bool operator!=(const container_type##_iterator_base &other) const {
84 | return *other != ptr;
85 | }
86 | std::string __str__() {
87 | if (valid())
88 | return "iterator<" + ptr->key() + ": " + ptr->print() + ">";
89 | return "iterator";
90 | }
91 | bool valid() { return ptr != end; }
92 | // Provide size() C++ method for buffer size check
93 | size_t size() {
94 | if (valid())
95 | return safe_ptr->size();
96 | return 0;
97 | }
98 | };
99 | // Derived class can be dereferenced, giving Python access to all datum
100 | // methods.
101 | class container_type##_iterator : public container_type##_iterator_base {
102 | public:
103 | Exiv2::datum_type* operator->() const { return &(*safe_ptr); }
104 | };
105 | %}
106 | %enddef // DATA_ITERATOR_CLASSES
107 |
108 | // Declare typemaps for data iterators.
109 | %define DATA_ITERATOR_TYPEMAPS(container_type)
110 | %typemap(in) Exiv2::container_type::iterator {
111 | container_type##_iterator_base *argp = NULL;
112 | int res = SWIG_ConvertPtr($input, (void**)&argp,
113 | $descriptor(container_type##_iterator_base*), 0);
114 | if (!SWIG_IsOK(res)) {
115 | %argument_fail(res,
116 | container_type##_iterator_base, $symname, $argnum);
117 | }
118 | if (!argp) {
119 | %argument_nullref(container_type##_iterator_base, $symname, $argnum);
120 | }
121 | $1 = **argp;
122 | }
123 | // XmpData::eraseFamily takes an iterator reference (and invalidates it)
124 | %typemap(in) Exiv2::container_type::iterator&
125 | (Exiv2::container_type::iterator it) {
126 | container_type##_iterator_base* argp = NULL;
127 | int res = SWIG_ConvertPtr($input, (void**)&argp,
128 | $descriptor(container_type##_iterator_base*), 0);
129 | if (!SWIG_IsOK(res)) {
130 | %argument_fail(res,
131 | container_type##_iterator_base, $symname, $argnum);
132 | }
133 | if (!argp) {
134 | %argument_nullref(container_type##_iterator_base, $symname, $argnum);
135 | }
136 | it = **argp;
137 | $1 = ⁢
138 | }
139 | // Return types depend on validity of iterator
140 | %typemap(out) container_type##_iterator_base* {
141 | $result = SWIG_NewPointerObj((void*)$1,
142 | $1->valid() ? $descriptor(container_type##_iterator*) :
143 | $descriptor(container_type##_iterator_base*), 0);
144 | }
145 | // Assumes arg1 is the base class parent
146 | %typemap(out) Exiv2::container_type::iterator {
147 | container_type##_iterator_base* tmp = new container_type##_iterator_base($1, arg1->end());
148 | $result = SWIG_NewPointerObj((void*)tmp,
149 | tmp->valid() ? $descriptor(container_type##_iterator*) :
150 | $descriptor(container_type##_iterator_base*),
151 | SWIG_POINTER_OWN);
152 | }
153 | // Keep a reference to the data being iterated
154 | KEEP_REFERENCE(Exiv2::container_type::iterator)
155 | %enddef // DATA_ITERATOR_TYPEMAPS
156 |
--------------------------------------------------------------------------------
/src/interface/shared/exception.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2024 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %include "shared/enum.i"
19 | %include "shared/windows_cp.i"
20 |
21 | %include "exception.i"
22 |
23 | IMPORT_ENUM(ErrorCode)
24 |
25 | // Import PyExc_Exiv2Error exception
26 | %fragment("_import_exception_decl", "header") {
27 | static PyObject* PyExc_Exiv2Error = NULL;
28 | }
29 | %fragment("_import_exception", "init", fragment="_import_exception_decl",
30 | fragment="import_exiv2") {
31 | {
32 | PyExc_Exiv2Error = PyObject_GetAttrString(exiv2_module, "Exiv2Error");
33 | if (!PyExc_Exiv2Error)
34 | return NULL;
35 | }
36 | }
37 |
38 | // Function that re-raises an exception to handle different types
39 | %fragment("_set_python_exception", "header",
40 | fragment="_import_exception",
41 | fragment="py_from_enum"{Exiv2::ErrorCode},
42 | fragment="utf8_to_wcp") {
43 | static void _set_python_exception() {
44 | try {
45 | throw;
46 | }
47 | #if EXIV2_VERSION_HEX < 0x001c0000
48 | catch(Exiv2::AnyError const& e) {
49 | std::string msg = e.what();
50 | if (wcp_to_utf8(&msg))
51 | msg = e.what();
52 | PyObject* args = Py_BuildValue(
53 | "Ns", py_from_enum((Exiv2::ErrorCode)e.code()), msg.c_str());
54 | PyErr_SetObject(PyExc_Exiv2Error, args);
55 | Py_DECREF(args);
56 | }
57 | #else
58 | catch(Exiv2::Error const& e) {
59 | std::string msg = e.what();
60 | if (wcp_to_utf8(&msg))
61 | msg = e.what();
62 | PyObject* args = Py_BuildValue(
63 | "Ns", py_from_enum((Exiv2::ErrorCode)e.code()), msg.c_str());
64 | PyErr_SetObject(PyExc_Exiv2Error, args);
65 | Py_DECREF(args);
66 | }
67 | #endif
68 | SWIG_CATCH_STDEXCEPT
69 | fail:
70 | return;
71 | };
72 | }
73 |
74 | // Macro to define %exception directives
75 | %define EXCEPTION(method)
76 | %fragment("_set_python_exception");
77 | %exception method {
78 | try {
79 | $action
80 | }
81 | catch(std::exception const& e) {
82 | _set_python_exception();
83 | SWIG_fail;
84 | }
85 | }
86 | %enddef // EXCEPTION
87 |
--------------------------------------------------------------------------------
/src/interface/shared/exv_options.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2024 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This file is part of python-exiv2. python-exiv2 is free software: you can
6 | // redistribute it and/or modify it under the terms of the GNU General Public
7 | // License as published by the Free Software Foundation, either version 3 of
8 | // the License, or (at your option) any later version.
9 | //
10 | // python-exiv2 is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with python-exiv2. If not, see .
17 |
18 |
19 | // Fragment to define Exiv2::CurlIo if EXV_USE_CURL is OFF
20 | %fragment("EXV_USE_CURL", "header") %{
21 | #ifndef EXV_USE_CURL
22 | namespace Exiv2 {
23 | class CurlIo : public RemoteIo {};
24 | }
25 | #endif // EXV_USE_CURL
26 | %}
27 |
28 | // Fragment to define Exiv2::SshIo if EXV_USE_SSH is OFF
29 | %fragment("EXV_USE_SSH", "header") %{
30 | #ifndef EXV_USE_SSH
31 | namespace Exiv2 {
32 | class SshIo : public RemoteIo {};
33 | }
34 | #endif // EXV_USE_SSH
35 | %}
36 |
37 | // Fragment to set EXV_ENABLE_FILESYSTEM on old libexiv2 versions
38 | %fragment("set_EXV_ENABLE_FILESYSTEM", "header") %{
39 | #if !EXIV2_TEST_VERSION(0, 28, 3)
40 | #define EXV_ENABLE_FILESYSTEM
41 | #endif
42 | // Copy EXV_ENABLE_FILESYSTEM for use in macro
43 | #ifdef EXV_ENABLE_FILESYSTEM
44 | #define _EXV_ENABLE_FILESYSTEM
45 | #endif
46 | %}
47 |
48 | // Fragment to define FileIo and XPathIo if EXV_ENABLE_FILESYSTEM is OFF
49 | %fragment("EXV_ENABLE_FILESYSTEM", "header",
50 | fragment="set_EXV_ENABLE_FILESYSTEM") %{
51 | #ifndef EXV_ENABLE_FILESYSTEM
52 | namespace Exiv2 {
53 | class FileIo : public BasicIo {};
54 | class XPathIo : public MemIo {};
55 | }
56 | #endif // EXV_ENABLE_FILESYSTEM
57 | %}
58 |
59 | // Macro to not call a function if EXV_ENABLE_FILESYSTEM is OFF
60 | %define EXV_ENABLE_FILESYSTEM_FUNCTION(signature)
61 | %fragment("_set_python_exception");
62 | %fragment("set_EXV_ENABLE_FILESYSTEM");
63 | %exception signature {
64 | try {
65 | %#ifdef _EXV_ENABLE_FILESYSTEM
66 | $action
67 | %#else
68 | throw Exiv2::Error(Exiv2::ErrorCode::kerFunctionNotSupported);
69 | %#endif
70 | }
71 | catch(std::exception const& e) {
72 | _set_python_exception();
73 | SWIG_fail;
74 | }
75 | }
76 | %enddef // EXV_ENABLE_FILESYSTEM_FUNCTION
77 |
78 | // Macro to not call a function if libexiv2 version is <= 0.27.3
79 | %define EXV_ENABLE_EASYACCESS_FUNCTION(signature)
80 | %fragment("_set_python_exception");
81 | %exception signature {
82 | try {
83 | %#if EXIV2_TEST_VERSION(0, 27, 4)
84 | $action
85 | %#else
86 | throw Exiv2::Error(Exiv2::kerFunctionNotSupported);
87 | %#endif
88 | }
89 | catch(std::exception const& e) {
90 | _set_python_exception();
91 | SWIG_fail;
92 | }
93 | }
94 | %enddef // EXV_ENABLE_EASYACCESS_FUNCTION
95 |
--------------------------------------------------------------------------------
/src/interface/shared/keep_reference.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 |
19 | // Macro to keep a reference to any object when returning a particular type.
20 | %define KEEP_REFERENCE_EX(return_type, target)
21 | %typemap(ret) return_type %{
22 | if ($result != Py_None)
23 | if (PyObject_SetAttrString($result, "_refers_to", target)) {
24 | SWIG_fail;
25 | }
26 | %}
27 | %enddef // KEEP_REFERENCE_EX
28 |
29 | // Macro to keep a reference to "self" when returning a particular type.
30 | %define KEEP_REFERENCE(return_type)
31 | KEEP_REFERENCE_EX(return_type, self)
32 | %enddef // KEEP_REFERENCE
33 |
--------------------------------------------------------------------------------
/src/interface/shared/preamble.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %{
19 | #include "exiv2/exiv2.hpp"
20 | %}
21 |
22 | // EXIV2API prepends every function declaration
23 | #define EXIV2API
24 | // Some have this instead
25 | #define EXIV2LIB_DEPRECATED_EXPORT
26 | // Older versions of libexiv2 define these as well
27 | #define EXV_DLLLOCAL
28 | #define EXV_DLLPUBLIC
29 |
30 | %typemap(doctype) bool "bool"
31 | %typemap(doctype) Exiv2::byte "int"
32 | %typemap(doctype) std::string "str"
33 |
--------------------------------------------------------------------------------
/src/interface/shared/static_list.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 |
19 | // Macro to convert pointer to static list to a Python list of objects
20 | %define LIST_POINTER(pattern, item_type, valid_test)
21 | %fragment("pointer_to_list"{item_type}, "header") {
22 | static PyObject* pointer_to_list(item_type* ptr) {
23 | PyObject* list = PyList_New(0);
24 | if (!ptr)
25 | return list;
26 | PyObject* py_tmp = NULL;
27 | while (ptr->valid_test) {
28 | py_tmp = SWIG_Python_NewPointerObj(
29 | NULL, ptr, $descriptor(item_type*), 0);
30 | PyList_Append(list, py_tmp);
31 | Py_DECREF(py_tmp);
32 | ++ptr;
33 | }
34 | return list;
35 | };
36 | }
37 | %typemap(out, fragment="pointer_to_list"{item_type}) pattern {
38 | PyObject* list = pointer_to_list($1);
39 | if (!list)
40 | SWIG_fail;
41 | $result = SWIG_AppendOutput($result, list);
42 | }
43 | %enddef // LIST_POINTER
44 |
--------------------------------------------------------------------------------
/src/interface/shared/struct_dict.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2024 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 |
19 | // Add dict-like behaviour to an Exiv2 struct, e.g. PreviewProperties
20 |
21 | // Helper functions
22 | %fragment("getset_functions", "header") {
23 | static PyObject* list_getset(
24 | PyObject* obj, PyObject* (*conv)(PyObject*, PyGetSetDef*)) {
25 | PyGetSetDef* getset = obj->ob_type->tp_getset;
26 | PyObject* result = PyList_New(0);
27 | PyObject* item = NULL;
28 | while (getset->name) {
29 | if (getset->name[0] != '_') {
30 | item = (*conv)(obj, getset);
31 | PyList_Append(result, item);
32 | Py_DECREF(item);
33 | }
34 | getset++;
35 | }
36 | return result;
37 | };
38 | static PyGetSetDef* find_getset(PyObject* obj, const char* name) {
39 | size_t len = strlen(name);
40 | PyGetSetDef* getset = obj->ob_type->tp_getset;
41 | while (getset->name) {
42 | size_t cmp_len = strlen(getset->name);
43 | if (getset->name[cmp_len-1] == '_')
44 | cmp_len--;
45 | if ((cmp_len == len) && (strncmp(getset->name, name, len) == 0))
46 | return getset;
47 | getset++;
48 | }
49 | PyErr_Format(
50 | PyExc_KeyError, "'%s' not in '%s'", name, obj->ob_type->tp_name);
51 | return NULL;
52 | };
53 | static PyObject* getset_to_item(PyObject* obj, PyGetSetDef* getset) {
54 | size_t len = strlen(getset->name);
55 | if (getset->name[len-1] == '_')
56 | len--;
57 | return Py_BuildValue("(s#N)", getset->name, len,
58 | getset->get(obj, getset->closure));
59 | };
60 | static PyObject* getset_to_key(PyObject* obj, PyGetSetDef* getset) {
61 | size_t len = strlen(getset->name);
62 | if (getset->name[len-1] == '_')
63 | len--;
64 | return Py_BuildValue("s#", getset->name, len);
65 | };
66 | static PyObject* getset_to_value(PyObject* obj, PyGetSetDef* getset) {
67 | return Py_BuildValue("N", getset->get(obj, getset->closure));
68 | };
69 | }
70 |
71 | // Macro definition
72 | %define STRUCT_DICT(struct_type)
73 | // Type slots
74 | %feature("python:slot", "tp_iter", functype="getiterfunc")
75 | struct_type::__iter__;
76 | %feature("python:slot", "mp_subscript", functype="binaryfunc")
77 | struct_type::__getitem__;
78 | %feature("python:slot", "mp_ass_subscript", functype="objobjargproc")
79 | struct_type::__setitem__;
80 | // Typemaps for slot functions
81 | %typemap(in, numinputs=0) PyObject* py_self {$1 = self;}
82 | %typemap(default) PyObject* value {$1 = NULL;}
83 | // Document functions
84 | %feature("docstring") struct_type::items "Get structure members.
85 | :rtype: list of (str, value) tuple
86 | :return: structure member (name, value) pairs (with any trailing
87 | underscores removed from names)."
88 | %feature("docstring") struct_type::keys "Get structure member names.
89 | :rtype: list of str
90 | :return: structure member names (with any trailing underscores
91 | removed)."
92 | %feature("docstring") struct_type::values "Get structure member values.
93 | :rtype: list of value
94 | :return: structure member values."
95 | // Add functions
96 | %extend struct_type {
97 | %fragment("getset_functions");
98 | PyObject* items(PyObject* py_self) {
99 | return list_getset(py_self, getset_to_item);
100 | }
101 | PyObject* keys(PyObject* py_self) {
102 | return list_getset(py_self, getset_to_key);
103 | }
104 | PyObject* values(PyObject* py_self) {
105 | return list_getset(py_self, getset_to_value);
106 | }
107 | PyObject* __iter__(PyObject* py_self) {
108 | PyObject* seq =
109 | %mangle(struct_type::keys)($self, py_self);
110 | PyObject* result = PySeqIter_New(seq);
111 | Py_DECREF(seq);
112 | return result;
113 | }
114 | PyObject* __getitem__(PyObject* py_self, const std::string& key) {
115 | PyGetSetDef* getset = find_getset(py_self, key.c_str());
116 | if (!getset)
117 | return NULL;
118 | return getset->get(py_self, getset->closure);
119 | }
120 | PyObject* __setitem__(PyObject* py_self, const std::string& key,
121 | PyObject* value) {
122 | PyGetSetDef* getset = find_getset(py_self, key.c_str());
123 | if (!getset)
124 | return NULL;
125 | if (!value)
126 | return PyErr_Format(PyExc_TypeError,
127 | "%s['%s'] can not be deleted", py_self->ob_type->tp_name,
128 | key.c_str());
129 | if (!getset->set)
130 | return PyErr_Format(PyExc_TypeError, "%s['%s'] is read-only",
131 | py_self->ob_type->tp_name, key.c_str());
132 | if (getset->set(py_self, value, getset->closure) != 0)
133 | return NULL;
134 | return SWIG_Py_Void();
135 | }
136 | }
137 | %enddef // STRUCT_DICT
138 |
--------------------------------------------------------------------------------
/src/interface/shared/unique_ptr.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 |
19 | // Stuff to handle auto_ptr or unique_ptr
20 | #if EXIV2_VERSION_HEX < 0x001c0000
21 | #define SMART_PTR AutoPtr
22 | %ignore AutoPtr;
23 | %define UNIQUE_PTR(pointed_type)
24 | %include "std_auto_ptr.i"
25 | %typemap(doctype) pointed_type##::AutoPtr #pointed_type
26 | %auto_ptr(pointed_type)
27 | %enddef // UNIQUE_PTR
28 | #else
29 | #define SMART_PTR UniquePtr
30 | %ignore UniquePtr;
31 | #if SWIG_VERSION >= 0x040100
32 | %define UNIQUE_PTR(pointed_type)
33 | %include "std_unique_ptr.i"
34 | %typemap(doctype) pointed_type##::UniquePtr #pointed_type
35 | %unique_ptr(pointed_type)
36 | %enddef // UNIQUE_PTR
37 | #else
38 | template
39 | struct std::unique_ptr {};
40 | %define UNIQUE_PTR(pointed_type)
41 | %typemap(out) std::unique_ptr %{
42 | $result = SWIG_NewPointerObj(
43 | $1.release(), $descriptor(pointed_type *), SWIG_POINTER_OWN);
44 | %}
45 | %template() std::unique_ptr;
46 | %enddef // UNIQUE_PTR
47 | #endif
48 | #endif
49 |
--------------------------------------------------------------------------------
/src/interface/shared/windows_cp.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2024 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 |
19 | // Function to convert utf-8 string to/from current Windows code page
20 | %fragment("utf8_to_wcp", "header") %{
21 | #ifdef _WIN32
22 | #include
23 | #endif
24 |
25 | #ifdef _WIN32
26 | static int _transcode(std::string *str, UINT cp_in, UINT cp_out) {
27 | if (cp_out == cp_in)
28 | return 0;
29 | int size = MultiByteToWideChar(cp_in, 0, &(*str)[0], (int)str->size(),
30 | NULL, 0);
31 | if (!size)
32 | return GetLastError();
33 | std::wstring wide_str;
34 | wide_str.resize(size);
35 | if (!MultiByteToWideChar(cp_in, 0, &(*str)[0], (int)str->size(),
36 | &wide_str[0], size))
37 | return GetLastError();
38 | size = WideCharToMultiByte(cp_out, 0, &wide_str[0], (int)wide_str.size(),
39 | NULL, 0, NULL, NULL);
40 | if (!size)
41 | return GetLastError();
42 | str->resize(size);
43 | if (!WideCharToMultiByte(cp_out, 0, &wide_str[0], (int)wide_str.size(),
44 | &(*str)[0], size, NULL, NULL))
45 | return GetLastError();
46 | return 0;
47 | };
48 | #endif
49 |
50 | static int utf8_to_wcp(std::string *str) {
51 | #ifdef _WIN32
52 | return _transcode(str, CP_UTF8, GetACP());
53 | #else
54 | return 0;
55 | #endif
56 | };
57 |
58 | static int wcp_to_utf8(std::string *str) {
59 | #ifdef _WIN32
60 | return _transcode(str, GetACP(), CP_UTF8);
61 | #else
62 | return 0;
63 | #endif
64 | };
65 |
66 | %}
67 |
--------------------------------------------------------------------------------
/src/interface/shared/windows_path.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 |
19 | %include "shared/windows_cp.i"
20 |
21 | // Macro to convert Windows path inputs from utf-8 to current code page
22 | %define WINDOWS_PATH(signature)
23 | %typemap(check, fragment="utf8_to_wcp") signature {
24 | %#ifdef _WIN32
25 | int error = utf8_to_wcp($1);
26 | if (error) {
27 | PyErr_SetFromWindowsErr(error);
28 | SWIG_fail;
29 | }
30 | %#endif
31 | }
32 | %enddef // WINDOWS_PATH
33 |
34 | // Macro to convert Windows path outputs from current code page to utf-8
35 | %define WINDOWS_PATH_OUT(function)
36 | %typemap(out, fragment="utf8_to_wcp") std::string function {
37 | %#ifdef _WIN32
38 | int error = wcp_to_utf8(&$1);
39 | if (error) {
40 | PyErr_SetFromWindowsErr(error);
41 | SWIG_fail;
42 | }
43 | %#endif
44 | $result = SWIG_FromCharPtrAndSize($1.data(), $1.size());
45 | }
46 | %typemap(out, fragment="utf8_to_wcp") const std::string& function {
47 | std::string copy = *$1;
48 | %#ifdef _WIN32
49 | int error = wcp_to_utf8(©);
50 | if (error) {
51 | PyErr_SetFromWindowsErr(error);
52 | SWIG_fail;
53 | }
54 | %#endif
55 | $result = SWIG_FromCharPtrAndSize(copy.data(), copy.size());
56 | }
57 | %enddef // WINDOWS_PATH_OUT
58 |
--------------------------------------------------------------------------------
/src/interface/tags.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %module(package="exiv2") tags
19 |
20 | #ifndef SWIGIMPORTED
21 | %constant char* __doc__ = "Exif key class and data attributes.";
22 | #endif
23 |
24 | %include "shared/preamble.i"
25 | %include "shared/enum.i"
26 | %include "shared/exception.i"
27 | %include "shared/static_list.i"
28 | %include "shared/struct_dict.i"
29 | %include "shared/unique_ptr.i"
30 |
31 | %import "metadatum.i";
32 |
33 | IMPORT_ENUM(TypeId)
34 |
35 | // Catch some C++ exceptions
36 | %exception;
37 | EXCEPTION(Exiv2::ExifKey::ExifKey)
38 | EXCEPTION(Exiv2::ExifKey::clone)
39 |
40 | EXTEND_KEY(Exiv2::ExifKey);
41 |
42 | // Add Exif specific enums
43 | #if EXIV2_VERSION_HEX >= 0x001c0000
44 | DEFINE_ENUM(IfdId, "Type to specify the IFD to which a metadata belongs.\n"
45 | "\nMaker note IFDs have been omitted from this enum.",
46 | "ifdIdNotSet", Exiv2::IfdId::ifdIdNotSet,
47 | "ifd0Id", Exiv2::IfdId::ifd0Id,
48 | "ifd1Id", Exiv2::IfdId::ifd1Id,
49 | "ifd2Id", Exiv2::IfdId::ifd2Id,
50 | "ifd3Id", Exiv2::IfdId::ifd3Id,
51 | "exifId", Exiv2::IfdId::exifId,
52 | "gpsId", Exiv2::IfdId::gpsId,
53 | "iopId", Exiv2::IfdId::iopId,
54 | "mpfId", Exiv2::IfdId::mpfId,
55 | "subImage1Id", Exiv2::IfdId::subImage1Id,
56 | "subImage2Id", Exiv2::IfdId::subImage2Id,
57 | "subImage3Id", Exiv2::IfdId::subImage3Id,
58 | "subImage4Id", Exiv2::IfdId::subImage4Id,
59 | "subImage5Id", Exiv2::IfdId::subImage5Id,
60 | "subImage6Id", Exiv2::IfdId::subImage6Id,
61 | "subImage7Id", Exiv2::IfdId::subImage7Id,
62 | "subImage8Id", Exiv2::IfdId::subImage8Id,
63 | "subImage9Id", Exiv2::IfdId::subImage9Id,
64 | "subThumb1Id", Exiv2::IfdId::subThumb1Id,
65 | "lastId", Exiv2::IfdId::lastId,
66 | "ignoreId", Exiv2::IfdId::ignoreId);
67 |
68 | DEFINE_ENUM(SectionId, "Section identifiers to logically group tags.\n"
69 | "\nA section consists of nothing more than a name, based on the"
70 | "\nExif standard.",
71 | "sectionIfNotSet", Exiv2::SectionId::sectionIdNotSet,
72 | "imgStruct", Exiv2::SectionId::imgStruct,
73 | "recOffset", Exiv2::SectionId::recOffset,
74 | "imgCharacter", Exiv2::SectionId::imgCharacter,
75 | "otherTags", Exiv2::SectionId::otherTags,
76 | "exifFormat", Exiv2::SectionId::exifFormat,
77 | "exifVersion", Exiv2::SectionId::exifVersion,
78 | "imgConfig", Exiv2::SectionId::imgConfig,
79 | "userInfo", Exiv2::SectionId::userInfo,
80 | "relatedFile", Exiv2::SectionId::relatedFile,
81 | "dateTime", Exiv2::SectionId::dateTime,
82 | "captureCond", Exiv2::SectionId::captureCond,
83 | "gpsTags", Exiv2::SectionId::gpsTags,
84 | "iopTags", Exiv2::SectionId::iopTags,
85 | "mpfTags", Exiv2::SectionId::mpfTags,
86 | "makerTags", Exiv2::SectionId::makerTags,
87 | "dngTags", Exiv2::SectionId::dngTags,
88 | "panaRaw", Exiv2::SectionId::panaRaw,
89 | "tiffEp", Exiv2::SectionId::tiffEp,
90 | "tiffPm6", Exiv2::SectionId::tiffPm6,
91 | "adobeOpi", Exiv2::SectionId::adobeOpi,
92 | "lastSectionId", Exiv2::SectionId::lastSectionId);
93 | #endif // EXIV2_VERSION_HEX
94 |
95 | // Convert ExifTags::groupList() result to a Python list of GroupInfo objects
96 | LIST_POINTER(const Exiv2::GroupInfo*, Exiv2::GroupInfo, tagList_)
97 | // Convert ExifTags::tagList() result to a Python list of TagInfo objects
98 | LIST_POINTER(const Exiv2::TagInfo*, Exiv2::TagInfo, tag_ != 0xFFFF)
99 |
100 | // Give Exiv2::GroupInfo dict-like behaviour
101 | STRUCT_DICT(Exiv2::GroupInfo)
102 |
103 | // Give Exiv2::TagInfo dict-like behaviour
104 | STRUCT_DICT(Exiv2::TagInfo)
105 |
106 | // Wrapper class for TagListFct function pointer
107 | #ifndef SWIGIMPORTED
108 | %ignore _TagListFct::_TagListFct;
109 | %feature("python:slot", "tp_call", functype="ternarycallfunc")
110 | _TagListFct::__call__;
111 | %noexception _TagListFct::~_TagListFct;
112 | %noexception _TagListFct::__call__;
113 | %inline %{
114 | class _TagListFct {
115 | private:
116 | Exiv2::TagListFct func;
117 | public:
118 | _TagListFct(Exiv2::TagListFct func) : func(func) {}
119 | const Exiv2::TagInfo* __call__() {
120 | return (*func)();
121 | }
122 | };
123 | %}
124 | %fragment("new_TagListFct", "header") {
125 | static PyObject* new_TagListFct(Exiv2::TagListFct func) {
126 | return SWIG_Python_NewPointerObj(NULL, new _TagListFct(func),
127 | $descriptor(_TagListFct*), SWIG_POINTER_OWN);
128 | }
129 | }
130 | #endif // SWIGIMPORTED
131 |
132 | // Wrap TagListFct return values
133 | %typemap(out, fragment="new_TagListFct") Exiv2::TagListFct {
134 | $result = new_TagListFct($1);
135 | }
136 |
137 | // Structs are all static data
138 | %ignore Exiv2::GroupInfo::GroupInfo;
139 | %ignore Exiv2::GroupInfo::~GroupInfo;
140 | %ignore Exiv2::TagInfo::TagInfo;
141 | %ignore Exiv2::TagInfo::~TagInfo;
142 | %ignore Exiv2::ExifTags::~ExifTags;
143 |
144 | // Ignore stuff that Python can't use or doesn't need
145 | %ignore Exiv2::GroupInfo::operator==;
146 | %ignore Exiv2::GroupInfo::GroupName;
147 | %ignore Exiv2::ExifTags::taglist;
148 | %ignore Exiv2::TagInfo::printFct_;
149 |
150 | // Ignore unneeded key constructor
151 | %ignore Exiv2::ExifKey::ExifKey(const TagInfo&);
152 |
153 | // ExifKey::ifdId is documented as internal use only
154 | %ignore Exiv2::ExifKey::ifdId;
155 |
156 | %immutable;
157 | %include "exiv2/tags.hpp"
158 | %mutable;
159 |
--------------------------------------------------------------------------------
/src/interface/version.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %module(package="exiv2") version
19 |
20 | #ifndef SWIGIMPORTED
21 | %constant char* __doc__ = "Exiv2 library version information.";
22 | #endif
23 |
24 | %include "shared/preamble.i"
25 | %include "shared/exception.i"
26 | %include "shared/exv_options.i"
27 |
28 | %include "stdint.i"
29 | %include "std_string.i"
30 |
31 | // Catch all C++ exceptions
32 | EXCEPTION()
33 |
34 | // Import __version__ and __version_tuple__ from exiv2 module
35 | %fragment("import_exiv2");
36 | %constant PyObject* __version__ = PyObject_GetAttrString(
37 | exiv2_module, "__version__");
38 | %constant PyObject* __version_tuple__ = PyObject_GetAttrString(
39 | exiv2_module, "__version_tuple__");
40 |
41 | // Function to report build options used
42 | %feature("docstring") versionInfo "Return a dict of libexiv2 build options."
43 | %fragment("set_EXV_ENABLE_FILESYSTEM");
44 | %inline %{
45 | static PyObject* versionInfo() {
46 | bool nls = false;
47 | bool bmff = false;
48 | bool video = false;
49 | bool unicode = false;
50 | bool webready = false;
51 | bool curl = false;
52 | bool filesystem = false;
53 | #ifdef EXV_ENABLE_NLS
54 | nls = true;
55 | #endif
56 | #ifdef EXV_ENABLE_BMFF
57 | bmff = true;
58 | #endif
59 | #ifdef EXV_ENABLE_VIDEO
60 | video = true;
61 | #endif
62 | #ifdef EXV_ENABLE_WEBREADY
63 | webready = true;
64 | #endif
65 | #ifdef EXV_USE_CURL
66 | curl = true;
67 | #endif
68 | #ifdef EXV_ENABLE_FILESYSTEM
69 | filesystem = true;
70 | #endif
71 | return Py_BuildValue("{ss,sN,sN,sN,sN,sN,sN,sN}",
72 | "version", Exiv2::version(),
73 | "EXV_ENABLE_NLS", PyBool_FromLong(nls),
74 | "EXV_ENABLE_BMFF", PyBool_FromLong(bmff),
75 | "EXV_ENABLE_VIDEO", PyBool_FromLong(video),
76 | "EXV_UNICODE_PATH", PyBool_FromLong(unicode),
77 | "EXV_ENABLE_WEBREADY", PyBool_FromLong(webready),
78 | "EXV_USE_CURL", PyBool_FromLong(curl),
79 | "EXV_ENABLE_FILESYSTEM", PyBool_FromLong(filesystem));
80 | };
81 | %}
82 |
83 | %ignore exv_grep_keys_t;
84 | %ignore Exiv2_grep_key_t;
85 | %ignore Exiv2::dumpLibraryInfo;
86 | %ignore CPLUSPLUS11;
87 | %ignore EXIV2_VERSION;
88 |
89 | %include "exiv2/version.hpp"
90 |
--------------------------------------------------------------------------------
/src/interface/xmp.i:
--------------------------------------------------------------------------------
1 | // python-exiv2 - Python interface to libexiv2
2 | // http://github.com/jim-easterbrook/python-exiv2
3 | // Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | %module(package="exiv2") xmp
19 |
20 | #ifndef SWIGIMPORTED
21 | %constant char* __doc__ = "XMP metadatum, container and iterators.";
22 | #endif
23 |
24 | #pragma SWIG nowarn=508 // Declaration of '__str__' shadows declaration accessible via operator->()
25 |
26 | %include "shared/preamble.i"
27 | %include "shared/containers.i"
28 | %include "shared/data_iterator.i"
29 | %include "shared/enum.i"
30 | %include "shared/exception.i"
31 |
32 | %include "stdint.i"
33 | %include "std_string.i"
34 |
35 | %import "properties.i"
36 |
37 | IMPORT_ENUM(ByteOrder)
38 | IMPORT_ENUM(TypeId)
39 |
40 | // Catch all C++ exceptions
41 | EXCEPTION()
42 |
43 | EXTEND_METADATUM(Exiv2::Xmpdatum)
44 |
45 | DATA_ITERATOR_TYPEMAPS(XmpData)
46 | #ifndef SWIGIMPORTED
47 | DATA_ITERATOR_CLASSES(XmpData, Xmpdatum)
48 | #endif
49 |
50 | // Get the current (or default if not set) type id of a datum
51 | %fragment("get_type_id"{Exiv2::Xmpdatum}, "header") {
52 | static Exiv2::TypeId get_type_id(Exiv2::Xmpdatum* datum) {
53 | Exiv2::TypeId type_id = datum->typeId();
54 | if (type_id != Exiv2::invalidTypeId)
55 | return type_id;
56 | return Exiv2::XmpProperties::propertyType(Exiv2::XmpKey(datum->key()));
57 | };
58 | }
59 |
60 | DATA_CONTAINER(Exiv2::XmpData, Exiv2::Xmpdatum, Exiv2::XmpKey)
61 |
62 | // Ignore const overloads of some methods
63 | %ignore Exiv2::XmpData::operator[];
64 | %ignore Exiv2::XmpData::begin() const;
65 | %ignore Exiv2::XmpData::end() const;
66 | %ignore Exiv2::XmpData::findKey(XmpKey const &) const;
67 | %ignore Exiv2::XmpParser::decode;
68 | %ignore Exiv2::XmpParser::encode;
69 |
70 | %include "exiv2/xmp_exiv2.hpp"
71 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | import os
3 | import sys
4 |
5 | if sys.platform == 'win32':
6 | _dir = os.path.join(os.path.dirname(__file__), 'lib')
7 | if os.path.isdir(_dir):
8 | if hasattr(os, 'add_dll_directory'):
9 | os.add_dll_directory(_dir)
10 | os.environ['PATH'] = _dir + ';' + os.environ['PATH']
11 |
12 | class Exiv2Error(Exception):
13 | """Python exception raised by exiv2 library errors.
14 |
15 | :ivar ErrorCode code: The Exiv2 error code that caused the exception.
16 | :ivar str message: The message associated with the exception.
17 | """
18 | def __init__(self, code, message):
19 | self.code= code
20 | self.message = message
21 |
22 | #: python-exiv2 version as a string
23 | __version__ = "0.17.3"
24 | #: python-exiv2 version as a tuple of ints
25 | __version_tuple__ = tuple((0, 17, 3))
26 |
27 | __all__ = ["Exiv2Error"]
28 | from exiv2.basicio import *
29 | __all__ += exiv2._basicio.__all__
30 | from exiv2.datasets import *
31 | __all__ += exiv2._datasets.__all__
32 | from exiv2.easyaccess import *
33 | __all__ += exiv2._easyaccess.__all__
34 | from exiv2.error import *
35 | __all__ += exiv2._error.__all__
36 | from exiv2.exif import *
37 | __all__ += exiv2._exif.__all__
38 | from exiv2.image import *
39 | __all__ += exiv2._image.__all__
40 | from exiv2.iptc import *
41 | __all__ += exiv2._iptc.__all__
42 | from exiv2.metadatum import *
43 | __all__ += exiv2._metadatum.__all__
44 | from exiv2.preview import *
45 | __all__ += exiv2._preview.__all__
46 | from exiv2.properties import *
47 | __all__ += exiv2._properties.__all__
48 | from exiv2.tags import *
49 | __all__ += exiv2._tags.__all__
50 | from exiv2.types import *
51 | __all__ += exiv2._types.__all__
52 | from exiv2.value import *
53 | __all__ += exiv2._value.__all__
54 | from exiv2.version import *
55 | __all__ += exiv2._version.__all__
56 | from exiv2.xmp import *
57 | __all__ += exiv2._xmp.__all__
58 |
59 | __all__ = [x for x in __all__ if x[0] != '_']
60 | __all__.sort()
61 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/__main__.py:
--------------------------------------------------------------------------------
1 | # python-exiv2 - Python interface to exiv2
2 | # http://github.com/jim-easterbrook/python-exiv2
3 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import argparse
19 | import os
20 | import pprint
21 | import sys
22 |
23 | import exiv2
24 |
25 | def main():
26 | parser = argparse.ArgumentParser()
27 | parser.add_argument('-v', '--verbosity', help='increase output verbosity',
28 | action='store_true')
29 | args = parser.parse_args()
30 | print('libexiv2 version:', exiv2.version())
31 | print('python-exiv2 version:', exiv2.__version__)
32 | print('python-exiv2 examples:',
33 | os.path.join(os.path.dirname(__file__), 'examples'))
34 | if args.verbosity:
35 | print('libexiv2 build options:')
36 | pprint.pprint(exiv2.versionInfo())
37 |
38 | if __name__ == "__main__":
39 | sys.exit(main())
40 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/basicio.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.types
9 |
10 | # Pull in all the attributes from the low-level C/C++ module
11 | if __package__ or "." in __name__:
12 | from ._basicio import *
13 | else:
14 | from _basicio import *
15 |
16 |
17 | import enum
18 |
19 | class PositionMeta(enum.EnumMeta):
20 | def __getattribute__(cls, name):
21 | obj = super().__getattribute__(name)
22 | if isinstance(obj, enum.Enum):
23 | import warnings
24 | warnings.warn(
25 | "Use 'BasicIo.Position' instead of 'Position'",
26 | DeprecationWarning)
27 | return obj
28 |
29 | class DeprecatedPosition(enum.IntEnum, metaclass=PositionMeta):
30 | pass
31 |
32 | Position = DeprecatedPosition('Position', _enum_list_Position())
33 | Position.__doc__ = "Seek starting positions."
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/datasets.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.metadatum
9 | import exiv2.value
10 | import exiv2.types
11 |
12 | # Pull in all the attributes from the low-level C/C++ module
13 | if __package__ or "." in __name__:
14 | from ._datasets import *
15 | else:
16 | from _datasets import *
17 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/easyaccess.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | # Pull in all the attributes from the low-level C/C++ module
9 | if __package__ or "." in __name__:
10 | from ._easyaccess import *
11 | else:
12 | from _easyaccess import *
13 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/error.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | # Pull in all the attributes from the low-level C/C++ module
9 | if __package__ or "." in __name__:
10 | from ._error import *
11 | else:
12 | from _error import *
13 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/exif.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.tags
9 | import exiv2.metadatum
10 | import exiv2.value
11 | import exiv2.types
12 |
13 | # Pull in all the attributes from the low-level C/C++ module
14 | if __package__ or "." in __name__:
15 | from ._exif import *
16 | else:
17 | from _exif import *
18 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/image.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.basicio
9 | import exiv2.types
10 | import exiv2.exif
11 | import exiv2.tags
12 | import exiv2.metadatum
13 | import exiv2.value
14 | import exiv2.iptc
15 | import exiv2.datasets
16 | import exiv2.xmp
17 | import exiv2.properties
18 |
19 | # Pull in all the attributes from the low-level C/C++ module
20 | if __package__ or "." in __name__:
21 | from ._image import *
22 | else:
23 | from _image import *
24 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/iptc.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.datasets
9 | import exiv2.metadatum
10 | import exiv2.value
11 | import exiv2.types
12 |
13 | # Pull in all the attributes from the low-level C/C++ module
14 | if __package__ or "." in __name__:
15 | from ._iptc import *
16 | else:
17 | from _iptc import *
18 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/metadatum.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.value
9 | import exiv2.types
10 |
11 | # Pull in all the attributes from the low-level C/C++ module
12 | if __package__ or "." in __name__:
13 | from ._metadatum import *
14 | else:
15 | from _metadatum import *
16 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/preview.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.image
9 | import exiv2.basicio
10 | import exiv2.types
11 | import exiv2.exif
12 | import exiv2.tags
13 | import exiv2.metadatum
14 | import exiv2.value
15 | import exiv2.iptc
16 | import exiv2.datasets
17 | import exiv2.xmp
18 | import exiv2.properties
19 |
20 | # Pull in all the attributes from the low-level C/C++ module
21 | if __package__ or "." in __name__:
22 | from ._preview import *
23 | else:
24 | from _preview import *
25 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/properties.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.metadatum
9 | import exiv2.value
10 | import exiv2.types
11 |
12 | # Pull in all the attributes from the low-level C/C++ module
13 | if __package__ or "." in __name__:
14 | from ._properties import *
15 | else:
16 | from _properties import *
17 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/tags.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.metadatum
9 | import exiv2.value
10 | import exiv2.types
11 |
12 | # Pull in all the attributes from the low-level C/C++ module
13 | if __package__ or "." in __name__:
14 | from ._tags import *
15 | else:
16 | from _tags import *
17 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/types.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | # Pull in all the attributes from the low-level C/C++ module
9 | if __package__ or "." in __name__:
10 | from ._types import *
11 | else:
12 | from _types import *
13 |
14 |
15 | import os
16 | _dir = os.path.join(os.path.dirname(__file__), 'locale')
17 | if os.path.isdir(_dir):
18 | _set_locale_dir(_dir)
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/value.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.types
9 |
10 | # Pull in all the attributes from the low-level C/C++ module
11 | if __package__ or "." in __name__:
12 | from ._value import *
13 | else:
14 | from _value import *
15 |
16 |
17 | import enum
18 |
19 | class CharsetIdMeta(enum.EnumMeta):
20 | def __getattribute__(cls, name):
21 | obj = super().__getattribute__(name)
22 | if isinstance(obj, enum.Enum):
23 | import warnings
24 | warnings.warn(
25 | "Use 'CommentValue.CharsetId' instead of 'CharsetId'",
26 | DeprecationWarning)
27 | return obj
28 |
29 | class DeprecatedCharsetId(enum.IntEnum, metaclass=CharsetIdMeta):
30 | pass
31 |
32 | CharsetId = DeprecatedCharsetId('CharsetId', _enum_list_CharsetId())
33 | CharsetId.__doc__ = "Character set identifiers for the character sets defined by Exif."
34 |
35 |
36 | import enum
37 |
38 | class XmpArrayTypeMeta(enum.EnumMeta):
39 | def __getattribute__(cls, name):
40 | obj = super().__getattribute__(name)
41 | if isinstance(obj, enum.Enum):
42 | import warnings
43 | warnings.warn(
44 | "Use 'XmpValue.XmpArrayType' instead of 'XmpArrayType'",
45 | DeprecationWarning)
46 | return obj
47 |
48 | class DeprecatedXmpArrayType(enum.IntEnum, metaclass=XmpArrayTypeMeta):
49 | pass
50 |
51 | XmpArrayType = DeprecatedXmpArrayType('XmpArrayType', _enum_list_XmpArrayType())
52 | XmpArrayType.__doc__ = "XMP array types."
53 |
54 |
55 | import enum
56 |
57 | class XmpStructMeta(enum.EnumMeta):
58 | def __getattribute__(cls, name):
59 | obj = super().__getattribute__(name)
60 | if isinstance(obj, enum.Enum):
61 | import warnings
62 | warnings.warn(
63 | "Use 'XmpValue.XmpStruct' instead of 'XmpStruct'",
64 | DeprecationWarning)
65 | return obj
66 |
67 | class DeprecatedXmpStruct(enum.IntEnum, metaclass=XmpStructMeta):
68 | pass
69 |
70 | XmpStruct = DeprecatedXmpStruct('XmpStruct', _enum_list_XmpStruct())
71 | XmpStruct.__doc__ = "XMP structure indicator."
72 |
73 |
74 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/version.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | # Pull in all the attributes from the low-level C/C++ module
9 | if __package__ or "." in __name__:
10 | from ._version import *
11 | else:
12 | from _version import *
13 |
--------------------------------------------------------------------------------
/src/swig-0_27_7/xmp.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.properties
9 | import exiv2.metadatum
10 | import exiv2.value
11 | import exiv2.types
12 |
13 | # Pull in all the attributes from the low-level C/C++ module
14 | if __package__ or "." in __name__:
15 | from ._xmp import *
16 | else:
17 | from _xmp import *
18 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | import os
3 | import sys
4 |
5 | if sys.platform == 'win32':
6 | _dir = os.path.join(os.path.dirname(__file__), 'lib')
7 | if os.path.isdir(_dir):
8 | if hasattr(os, 'add_dll_directory'):
9 | os.add_dll_directory(_dir)
10 | os.environ['PATH'] = _dir + ';' + os.environ['PATH']
11 |
12 | class Exiv2Error(Exception):
13 | """Python exception raised by exiv2 library errors.
14 |
15 | :ivar ErrorCode code: The Exiv2 error code that caused the exception.
16 | :ivar str message: The message associated with the exception.
17 | """
18 | def __init__(self, code, message):
19 | self.code= code
20 | self.message = message
21 |
22 | #: python-exiv2 version as a string
23 | __version__ = "0.17.3"
24 | #: python-exiv2 version as a tuple of ints
25 | __version_tuple__ = tuple((0, 17, 3))
26 |
27 | __all__ = ["Exiv2Error"]
28 | from exiv2.basicio import *
29 | __all__ += exiv2._basicio.__all__
30 | from exiv2.datasets import *
31 | __all__ += exiv2._datasets.__all__
32 | from exiv2.easyaccess import *
33 | __all__ += exiv2._easyaccess.__all__
34 | from exiv2.error import *
35 | __all__ += exiv2._error.__all__
36 | from exiv2.exif import *
37 | __all__ += exiv2._exif.__all__
38 | from exiv2.image import *
39 | __all__ += exiv2._image.__all__
40 | from exiv2.iptc import *
41 | __all__ += exiv2._iptc.__all__
42 | from exiv2.metadatum import *
43 | __all__ += exiv2._metadatum.__all__
44 | from exiv2.preview import *
45 | __all__ += exiv2._preview.__all__
46 | from exiv2.properties import *
47 | __all__ += exiv2._properties.__all__
48 | from exiv2.tags import *
49 | __all__ += exiv2._tags.__all__
50 | from exiv2.types import *
51 | __all__ += exiv2._types.__all__
52 | from exiv2.value import *
53 | __all__ += exiv2._value.__all__
54 | from exiv2.version import *
55 | __all__ += exiv2._version.__all__
56 | from exiv2.xmp import *
57 | __all__ += exiv2._xmp.__all__
58 |
59 | __all__ = [x for x in __all__ if x[0] != '_']
60 | __all__.sort()
61 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/__main__.py:
--------------------------------------------------------------------------------
1 | # python-exiv2 - Python interface to exiv2
2 | # http://github.com/jim-easterbrook/python-exiv2
3 | # Copyright (C) 2021-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import argparse
19 | import os
20 | import pprint
21 | import sys
22 |
23 | import exiv2
24 |
25 | def main():
26 | parser = argparse.ArgumentParser()
27 | parser.add_argument('-v', '--verbosity', help='increase output verbosity',
28 | action='store_true')
29 | args = parser.parse_args()
30 | print('libexiv2 version:', exiv2.version())
31 | print('python-exiv2 version:', exiv2.__version__)
32 | print('python-exiv2 examples:',
33 | os.path.join(os.path.dirname(__file__), 'examples'))
34 | if args.verbosity:
35 | print('libexiv2 build options:')
36 | pprint.pprint(exiv2.versionInfo())
37 |
38 | if __name__ == "__main__":
39 | sys.exit(main())
40 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/basicio.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.types
9 |
10 | # Pull in all the attributes from the low-level C/C++ module
11 | if __package__ or "." in __name__:
12 | from ._basicio import *
13 | else:
14 | from _basicio import *
15 |
16 |
17 | import enum
18 |
19 | class PositionMeta(enum.EnumMeta):
20 | def __getattribute__(cls, name):
21 | obj = super().__getattribute__(name)
22 | if isinstance(obj, enum.Enum):
23 | import warnings
24 | warnings.warn(
25 | "Use 'BasicIo.Position' instead of 'Position'",
26 | DeprecationWarning)
27 | return obj
28 |
29 | class DeprecatedPosition(enum.IntEnum, metaclass=PositionMeta):
30 | pass
31 |
32 | Position = DeprecatedPosition('Position', _enum_list_Position())
33 | Position.__doc__ = "Seek starting positions."
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/datasets.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.metadatum
9 | import exiv2.value
10 | import exiv2.types
11 |
12 | # Pull in all the attributes from the low-level C/C++ module
13 | if __package__ or "." in __name__:
14 | from ._datasets import *
15 | else:
16 | from _datasets import *
17 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/easyaccess.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | # Pull in all the attributes from the low-level C/C++ module
9 | if __package__ or "." in __name__:
10 | from ._easyaccess import *
11 | else:
12 | from _easyaccess import *
13 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/error.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | # Pull in all the attributes from the low-level C/C++ module
9 | if __package__ or "." in __name__:
10 | from ._error import *
11 | else:
12 | from _error import *
13 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/exif.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.tags
9 | import exiv2.metadatum
10 | import exiv2.value
11 | import exiv2.types
12 |
13 | # Pull in all the attributes from the low-level C/C++ module
14 | if __package__ or "." in __name__:
15 | from ._exif import *
16 | else:
17 | from _exif import *
18 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/image.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.basicio
9 | import exiv2.types
10 | import exiv2.exif
11 | import exiv2.tags
12 | import exiv2.metadatum
13 | import exiv2.value
14 | import exiv2.iptc
15 | import exiv2.datasets
16 | import exiv2.xmp
17 | import exiv2.properties
18 |
19 | # Pull in all the attributes from the low-level C/C++ module
20 | if __package__ or "." in __name__:
21 | from ._image import *
22 | else:
23 | from _image import *
24 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/iptc.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.datasets
9 | import exiv2.metadatum
10 | import exiv2.value
11 | import exiv2.types
12 |
13 | # Pull in all the attributes from the low-level C/C++ module
14 | if __package__ or "." in __name__:
15 | from ._iptc import *
16 | else:
17 | from _iptc import *
18 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/metadatum.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.value
9 | import exiv2.types
10 |
11 | # Pull in all the attributes from the low-level C/C++ module
12 | if __package__ or "." in __name__:
13 | from ._metadatum import *
14 | else:
15 | from _metadatum import *
16 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/preview.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.image
9 | import exiv2.basicio
10 | import exiv2.types
11 | import exiv2.exif
12 | import exiv2.tags
13 | import exiv2.metadatum
14 | import exiv2.value
15 | import exiv2.iptc
16 | import exiv2.datasets
17 | import exiv2.xmp
18 | import exiv2.properties
19 |
20 | # Pull in all the attributes from the low-level C/C++ module
21 | if __package__ or "." in __name__:
22 | from ._preview import *
23 | else:
24 | from _preview import *
25 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/properties.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.metadatum
9 | import exiv2.value
10 | import exiv2.types
11 |
12 | # Pull in all the attributes from the low-level C/C++ module
13 | if __package__ or "." in __name__:
14 | from ._properties import *
15 | else:
16 | from _properties import *
17 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/tags.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.metadatum
9 | import exiv2.value
10 | import exiv2.types
11 |
12 | # Pull in all the attributes from the low-level C/C++ module
13 | if __package__ or "." in __name__:
14 | from ._tags import *
15 | else:
16 | from _tags import *
17 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/types.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | # Pull in all the attributes from the low-level C/C++ module
9 | if __package__ or "." in __name__:
10 | from ._types import *
11 | else:
12 | from _types import *
13 |
14 |
15 | import os
16 | _dir = os.path.join(os.path.dirname(__file__), 'locale')
17 | if os.path.isdir(_dir):
18 | _set_locale_dir(_dir)
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/value.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.types
9 |
10 | # Pull in all the attributes from the low-level C/C++ module
11 | if __package__ or "." in __name__:
12 | from ._value import *
13 | else:
14 | from _value import *
15 |
16 |
17 | import enum
18 |
19 | class CharsetIdMeta(enum.EnumMeta):
20 | def __getattribute__(cls, name):
21 | obj = super().__getattribute__(name)
22 | if isinstance(obj, enum.Enum):
23 | import warnings
24 | warnings.warn(
25 | "Use 'CommentValue.CharsetId' instead of 'CharsetId'",
26 | DeprecationWarning)
27 | return obj
28 |
29 | class DeprecatedCharsetId(enum.IntEnum, metaclass=CharsetIdMeta):
30 | pass
31 |
32 | CharsetId = DeprecatedCharsetId('CharsetId', _enum_list_CharsetId())
33 | CharsetId.__doc__ = "Character set identifiers for the character sets defined by Exif."
34 |
35 |
36 | import enum
37 |
38 | class XmpArrayTypeMeta(enum.EnumMeta):
39 | def __getattribute__(cls, name):
40 | obj = super().__getattribute__(name)
41 | if isinstance(obj, enum.Enum):
42 | import warnings
43 | warnings.warn(
44 | "Use 'XmpValue.XmpArrayType' instead of 'XmpArrayType'",
45 | DeprecationWarning)
46 | return obj
47 |
48 | class DeprecatedXmpArrayType(enum.IntEnum, metaclass=XmpArrayTypeMeta):
49 | pass
50 |
51 | XmpArrayType = DeprecatedXmpArrayType('XmpArrayType', _enum_list_XmpArrayType())
52 | XmpArrayType.__doc__ = "XMP array types."
53 |
54 |
55 | import enum
56 |
57 | class XmpStructMeta(enum.EnumMeta):
58 | def __getattribute__(cls, name):
59 | obj = super().__getattribute__(name)
60 | if isinstance(obj, enum.Enum):
61 | import warnings
62 | warnings.warn(
63 | "Use 'XmpValue.XmpStruct' instead of 'XmpStruct'",
64 | DeprecationWarning)
65 | return obj
66 |
67 | class DeprecatedXmpStruct(enum.IntEnum, metaclass=XmpStructMeta):
68 | pass
69 |
70 | XmpStruct = DeprecatedXmpStruct('XmpStruct', _enum_list_XmpStruct())
71 | XmpStruct.__doc__ = "XMP structure indicator."
72 |
73 |
74 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/version.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | # Pull in all the attributes from the low-level C/C++ module
9 | if __package__ or "." in __name__:
10 | from ._version import *
11 | else:
12 | from _version import *
13 |
--------------------------------------------------------------------------------
/src/swig-0_28_5/xmp.py:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by SWIG (https://www.swig.org).
2 | # Version 4.3.0
3 | #
4 | # Do not make changes to this file unless you know what you are doing - modify
5 | # the SWIG interface file instead.
6 |
7 | from sys import version_info as _swig_python_version_info
8 | import exiv2.properties
9 | import exiv2.metadatum
10 | import exiv2.value
11 | import exiv2.types
12 |
13 | # Pull in all the attributes from the low-level C/C++ module
14 | if __package__ or "." in __name__:
15 | from ._xmp import *
16 | else:
17 | from _xmp import *
18 |
--------------------------------------------------------------------------------
/tests/image_01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jim-easterbrook/python-exiv2/9790df5991bb613a5b5d8985233120d36bdf969a/tests/image_01.jpg
--------------------------------------------------------------------------------
/tests/image_02.heic:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jim-easterbrook/python-exiv2/9790df5991bb613a5b5d8985233120d36bdf969a/tests/image_02.heic
--------------------------------------------------------------------------------
/tests/image_02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jim-easterbrook/python-exiv2/9790df5991bb613a5b5d8985233120d36bdf969a/tests/image_02.jpg
--------------------------------------------------------------------------------
/tests/test_datasets.py:
--------------------------------------------------------------------------------
1 | ## python-exiv2 - Python interface to libexiv2
2 | ## http://github.com/jim-easterbrook/python-exiv2
3 | ## Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | ##
5 | ## This program is free software: you can redistribute it and/or
6 | ## modify it under the terms of the GNU General Public License as
7 | ## published by the Free Software Foundation, either version 3 of the
8 | ## License, or (at your option) any later version.
9 | ##
10 | ## This program is distributed in the hope that it will be useful,
11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | ## General Public License for more details.
14 | ##
15 | ## You should have received a copy of the GNU General Public License
16 | ## along with this program. If not, see
17 | ## .
18 |
19 | import io
20 | import os
21 | import sys
22 | import tempfile
23 | import unittest
24 |
25 | import exiv2
26 |
27 |
28 | class TestDatasetsModule(unittest.TestCase):
29 | def check_result(self, result, expected_type, expected_value):
30 | self.assertIsInstance(result, expected_type)
31 | self.assertEqual(result, expected_value)
32 |
33 | def test_DataSet(self):
34 | dataset = exiv2.IptcDataSets.application2RecordList()[0]
35 | self.assertIsInstance(dataset, exiv2.DataSet)
36 | self.assertEqual(dataset['desc'][:27], 'A binary number identifying')
37 | self.check_result(dataset['mandatory'], bool, True)
38 | self.check_result(dataset['maxbytes'], int, 2)
39 | self.check_result(dataset['minbytes'], int, 2)
40 | self.check_result(dataset['name'], str, 'RecordVersion')
41 | self.check_result(dataset['number'], int, 0)
42 | self.check_result(dataset['photoshop'], str, '')
43 | self.check_result(dataset['recordId'],
44 | int, exiv2.IptcDataSets.application2)
45 | self.check_result(dataset['repeatable'], bool, False)
46 | self.check_result(dataset['title'], str, 'Record Version')
47 | self.check_result(dataset['type'],
48 | exiv2.TypeId, exiv2.TypeId.unsignedShort)
49 |
50 | def test_IptcDataSets(self):
51 | # number and record id of Iptc.Application2.Caption
52 | number = exiv2.IptcDataSets.Caption
53 | record_id = exiv2.IptcDataSets.application2
54 | # static data lists
55 | datasets = exiv2.IptcDataSets.application2RecordList()
56 | self.assertIsInstance(datasets, list)
57 | self.assertIsInstance(datasets[0], exiv2.DataSet)
58 | datasets = exiv2.IptcDataSets.envelopeRecordList()
59 | self.assertIsInstance(datasets, list)
60 | self.assertIsInstance(datasets[0], exiv2.DataSet)
61 | # test other methods
62 | self.check_result(exiv2.IptcDataSets.dataSet('Caption', record_id),
63 | int, exiv2.IptcDataSets.Caption)
64 | self.check_result(exiv2.IptcDataSets.dataSetDesc(number, record_id),
65 | str, 'A textual description of the object data.')
66 | self.check_result(exiv2.IptcDataSets.dataSetName(number, record_id),
67 | str, 'Caption')
68 | self.check_result(exiv2.IptcDataSets.dataSetPsName(number, record_id),
69 | str, 'Description')
70 | self.check_result(exiv2.IptcDataSets.dataSetRepeatable(
71 | number, record_id), bool, False)
72 | self.check_result(exiv2.IptcDataSets.dataSetTitle(
73 | number, record_id), str, 'Caption')
74 | self.check_result(exiv2.IptcDataSets.dataSetType(
75 | number, record_id), exiv2.TypeId, exiv2.TypeId.string)
76 | self.check_result(exiv2.IptcDataSets.recordDesc(
77 | record_id), str, 'IIM application record 2')
78 | self.check_result(exiv2.IptcDataSets.recordId('Application2'),
79 | int, exiv2.IptcDataSets.application2)
80 | self.check_result(exiv2.IptcDataSets.recordName(
81 | exiv2.IptcDataSets.application2), str, 'Application2')
82 |
83 | def test_IptcKey(self):
84 | key_name = 'Iptc.Application2.Caption'
85 | # constructors
86 | key = exiv2.IptcKey(key_name)
87 | self.assertIsInstance(key, exiv2.IptcKey)
88 | key2 = exiv2.IptcKey(key.tag(), key.record())
89 | self.assertIsInstance(key2, exiv2.IptcKey)
90 | self.check_result(key2.key(), str, key_name)
91 | # copy
92 | key2 = key.clone()
93 | self.check_result(key2.key(), str, key_name)
94 | # other methods
95 | self.check_result(key.familyName(), str, key_name.split('.')[0])
96 | self.check_result(key.groupName(), str, key_name.split('.')[1])
97 | self.check_result(key.key(), str, key_name)
98 | self.check_result(key.record(), int, exiv2.IptcDataSets.application2)
99 | self.check_result(key.recordName(), str, key_name.split('.')[1])
100 | self.check_result(key.tag(), int, exiv2.IptcDataSets.Caption)
101 | self.check_result(key.tagLabel(), str, key_name.split('.')[2])
102 | self.check_result(key.tagName(), str, key_name.split('.')[2])
103 | buf = io.StringIO()
104 | buf = key.write(buf)
105 | self.assertEqual(buf.getvalue(), key_name)
106 |
107 |
108 | if __name__ == '__main__':
109 | unittest.main()
110 |
--------------------------------------------------------------------------------
/tests/test_easyaccess.py:
--------------------------------------------------------------------------------
1 | ## python-exiv2 - Python interface to libexiv2
2 | ## http://github.com/jim-easterbrook/python-exiv2
3 | ## Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | ##
5 | ## This program is free software: you can redistribute it and/or
6 | ## modify it under the terms of the GNU General Public License as
7 | ## published by the Free Software Foundation, either version 3 of the
8 | ## License, or (at your option) any later version.
9 | ##
10 | ## This program is distributed in the hope that it will be useful,
11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | ## General Public License for more details.
14 | ##
15 | ## You should have received a copy of the GNU General Public License
16 | ## along with this program. If not, see
17 | ## .
18 |
19 | import os
20 | import unittest
21 |
22 | import exiv2
23 |
24 |
25 | class TestEasyaccessModule(unittest.TestCase):
26 | @classmethod
27 | def setUpClass(cls):
28 | test_dir = os.path.dirname(__file__)
29 | with open(os.path.join(test_dir, 'image_02.jpg'), 'rb') as f:
30 | image = exiv2.ImageFactory.open(f.read())
31 | image.readMetadata()
32 | cls.exif_data = image.exifData()
33 |
34 | def check_result(self, datum, expected_type=None):
35 | # not all files have a value
36 | if datum is not None:
37 | self.assertIsInstance(datum, exiv2.Exifdatum)
38 | self.assertIsInstance(datum.getValue(), expected_type)
39 |
40 | def test_easyaccess(self):
41 | self.check_result(exiv2.afPoint(self.exif_data))
42 | self.check_result(exiv2.contrast(self.exif_data))
43 | self.check_result(exiv2.exposureMode(self.exif_data))
44 | self.check_result(exiv2.exposureTime(self.exif_data))
45 | self.check_result(exiv2.fNumber(self.exif_data), exiv2.URationalValue)
46 | self.check_result(exiv2.flashBias(self.exif_data))
47 | self.check_result(exiv2.focalLength(self.exif_data), exiv2.URationalValue)
48 | self.check_result(exiv2.imageQuality(self.exif_data))
49 | self.check_result(exiv2.isoSpeed(self.exif_data))
50 | self.check_result(exiv2.lensName(self.exif_data), exiv2.AsciiValue)
51 | self.check_result(exiv2.macroMode(self.exif_data))
52 | self.check_result(exiv2.make(self.exif_data))
53 | self.check_result(exiv2.meteringMode(self.exif_data))
54 | self.check_result(exiv2.model(self.exif_data))
55 | self.check_result(exiv2.orientation(self.exif_data), exiv2.UShortValue)
56 | self.check_result(exiv2.saturation(self.exif_data))
57 | self.check_result(exiv2.sceneCaptureType(self.exif_data))
58 | self.check_result(exiv2.sceneMode(self.exif_data))
59 | self.check_result(exiv2.serialNumber(self.exif_data))
60 | self.check_result(exiv2.sharpness(self.exif_data))
61 | self.check_result(exiv2.subjectDistance(self.exif_data))
62 | self.check_result(exiv2.whiteBalance(self.exif_data))
63 | if not exiv2.testVersion(0, 27, 4):
64 | self.skipTest('easyaccess funcs introduced in v0.27.4')
65 | self.check_result(exiv2.apertureValue(self.exif_data), exiv2.URationalValue)
66 | self.check_result(exiv2.brightnessValue(self.exif_data))
67 | self.check_result(exiv2.dateTimeOriginal(self.exif_data), exiv2.AsciiValue)
68 | self.check_result(exiv2.exposureBiasValue(self.exif_data))
69 | self.check_result(exiv2.exposureIndex(self.exif_data))
70 | self.check_result(exiv2.flash(self.exif_data))
71 | self.check_result(exiv2.flashEnergy(self.exif_data))
72 | self.check_result(exiv2.lightSource(self.exif_data))
73 | self.check_result(exiv2.maxApertureValue(self.exif_data))
74 | self.check_result(exiv2.sensingMethod(self.exif_data))
75 | self.check_result(exiv2.shutterSpeedValue(self.exif_data))
76 | self.check_result(exiv2.subjectArea(self.exif_data))
77 |
78 |
79 | if __name__ == '__main__':
80 | unittest.main()
81 |
--------------------------------------------------------------------------------
/tests/test_error.py:
--------------------------------------------------------------------------------
1 | ## python-exiv2 - Python interface to libexiv2
2 | ## http://github.com/jim-easterbrook/python-exiv2
3 | ## Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | ##
5 | ## This program is free software: you can redistribute it and/or
6 | ## modify it under the terms of the GNU General Public License as
7 | ## published by the Free Software Foundation, either version 3 of the
8 | ## License, or (at your option) any later version.
9 | ##
10 | ## This program is distributed in the hope that it will be useful,
11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | ## General Public License for more details.
14 | ##
15 | ## You should have received a copy of the GNU General Public License
16 | ## along with this program. If not, see
17 | ## .
18 |
19 | import enum
20 | import logging
21 | import os
22 | import unittest
23 |
24 | import exiv2
25 |
26 |
27 | class TestErrorModule(unittest.TestCase):
28 | @classmethod
29 | def setUpClass(cls):
30 | # clear locale
31 | name = 'en_US.UTF-8'
32 | os.environ['LC_ALL'] = name
33 | os.environ['LANG'] = name
34 | os.environ['LANGUAGE'] = name
35 |
36 | def check_result(self, result, expected_type, expected_value):
37 | self.assertIsInstance(result, expected_type)
38 | self.assertEqual(result, expected_value)
39 |
40 | def test_LogMsg(self):
41 | self.assertIsInstance(exiv2.LogMsg.Level, enum.EnumMeta)
42 | self.check_result(
43 | exiv2.LogMsg.level(), exiv2.LogMsg.Level, exiv2.LogMsg.Level.warn)
44 | exiv2.LogMsg.setLevel(exiv2.LogMsg.Level.debug)
45 | self.check_result(
46 | exiv2.LogMsg.level(), exiv2.LogMsg.Level, exiv2.LogMsg.Level.debug)
47 | # get exiv2 to log a message
48 | with self.assertLogs(level=logging.WARNING):
49 | comment = exiv2.CommentValue('charset=invalid Fred')
50 | # test setting and clearing handler
51 | self.assertEqual(exiv2.LogMsg.handler(), exiv2.LogMsg.pythonHandler)
52 | exiv2.LogMsg.setHandler(None)
53 | self.assertEqual(exiv2.LogMsg.handler(), None)
54 | exiv2.LogMsg.setHandler(exiv2.LogMsg.defaultHandler)
55 | self.assertEqual(exiv2.LogMsg.handler(), exiv2.LogMsg.defaultHandler)
56 | exiv2.LogMsg.setHandler(exiv2.LogMsg.pythonHandler)
57 | self.assertEqual(exiv2.LogMsg.handler(), exiv2.LogMsg.pythonHandler)
58 | # get exiv2 to raise an exception
59 | with self.assertRaises(exiv2.Exiv2Error) as cm:
60 | image = exiv2.ImageFactory.open(bytes())
61 | self.assertEqual(cm.exception.code,
62 | exiv2.ErrorCode.kerInputDataReadFailed)
63 |
64 |
65 | if __name__ == '__main__':
66 | unittest.main()
67 |
--------------------------------------------------------------------------------
/tests/test_metadatum.py:
--------------------------------------------------------------------------------
1 | ## python-exiv2 - Python interface to libexiv2
2 | ## http://github.com/jim-easterbrook/python-exiv2
3 | ## Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | ##
5 | ## This program is free software: you can redistribute it and/or
6 | ## modify it under the terms of the GNU General Public License as
7 | ## published by the Free Software Foundation, either version 3 of the
8 | ## License, or (at your option) any later version.
9 | ##
10 | ## This program is distributed in the hope that it will be useful,
11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | ## General Public License for more details.
14 | ##
15 | ## You should have received a copy of the GNU General Public License
16 | ## along with this program. If not, see
17 | ## .
18 |
19 | import unittest
20 |
21 | import exiv2
22 |
23 |
24 | class TestMetadatumModule(unittest.TestCase):
25 | def test_Key(self):
26 | # C++ class is abstract
27 | pass
28 |
29 | def test_Metadatum(self):
30 | # C++ class is abstract
31 | pass
32 |
33 |
34 | if __name__ == '__main__':
35 | unittest.main()
36 |
--------------------------------------------------------------------------------
/tests/test_preview.py:
--------------------------------------------------------------------------------
1 | ## python-exiv2 - Python interface to libexiv2
2 | ## http://github.com/jim-easterbrook/python-exiv2
3 | ## Copyright (C) 2022-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | ##
5 | ## This program is free software: you can redistribute it and/or
6 | ## modify it under the terms of the GNU General Public License as
7 | ## published by the Free Software Foundation, either version 3 of the
8 | ## License, or (at your option) any later version.
9 | ##
10 | ## This program is distributed in the hope that it will be useful,
11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | ## General Public License for more details.
14 | ##
15 | ## You should have received a copy of the GNU General Public License
16 | ## along with this program. If not, see
17 | ## .
18 |
19 | import os
20 | import sys
21 | import tempfile
22 | import unittest
23 |
24 | import exiv2
25 |
26 |
27 | class TestPreviewModule(unittest.TestCase):
28 | @classmethod
29 | def setUpClass(cls):
30 | test_dir = os.path.dirname(__file__)
31 | cls.image_path = os.path.join(test_dir, 'image_02.jpg')
32 | # read image file data into memory
33 | with open(cls.image_path, 'rb') as f:
34 | cls.image_data = f.read()
35 | cls.image = exiv2.ImageFactory.open(cls.image_data)
36 | cls.image.readMetadata()
37 |
38 | def check_result(self, result, expected_type, expected_value):
39 | self.assertIsInstance(result, expected_type)
40 | self.assertEqual(result, expected_value)
41 |
42 | def test_PreviewImage(self):
43 | manager = exiv2.PreviewManager(self.image)
44 | props = manager.getPreviewProperties()
45 | preview = manager.getPreviewImage(props[0])
46 | self.assertIsInstance(preview, exiv2.PreviewImage)
47 | preview2 = exiv2.PreviewImage(preview)
48 | self.assertIsInstance(preview2, exiv2.PreviewImage)
49 | self.assertEqual(len(preview), preview.size())
50 | copy = preview.copy()
51 | self.assertIsInstance(copy, exiv2.DataBuf)
52 | with preview.pData() as data:
53 | self.check_result(data, memoryview, copy)
54 | self.assertEqual(data[:10], b'\xff\xd8\xff\xe0\x00\x10JFIF')
55 | self.assertEqual(memoryview(preview), copy)
56 | self.check_result(preview.extension(), str, '.jpg')
57 | self.check_result(preview.height(), int, 120)
58 | self.check_result(preview.id(), int, 4)
59 | self.check_result(preview.mimeType(), str, 'image/jpeg')
60 | self.check_result(preview.size(), int, 2532)
61 | self.check_result(preview.width(), int, 160)
62 | if not exiv2.versionInfo()['EXV_ENABLE_FILESYSTEM']:
63 | self.skipTest('EXV_ENABLE_FILESYSTEM is off')
64 | with tempfile.TemporaryDirectory() as tmp_dir:
65 | temp_file = os.path.join(tmp_dir, 'image.jpg')
66 | self.assertEqual(preview.writeFile(temp_file), 2532)
67 |
68 | def test_PreviewManager(self):
69 | manager = exiv2.PreviewManager(self.image)
70 | self.assertIsInstance(manager, exiv2.PreviewManager)
71 | props = manager.getPreviewProperties()
72 | self.assertIsInstance(props, tuple)
73 | self.assertEqual(len(props), 1)
74 | prop = props[0]
75 | self.assertIsInstance(prop, exiv2.PreviewProperties)
76 | preview = manager.getPreviewImage(prop)
77 | self.assertIsInstance(preview, exiv2.PreviewImage)
78 |
79 | def test_PreviewProperties(self):
80 | properties = exiv2.PreviewManager(self.image).getPreviewProperties()[0]
81 | self.assertIsInstance(properties, exiv2.PreviewProperties)
82 | self.check_result(properties.extension_, str, '.jpg')
83 | self.check_result(properties.height_, int, 120)
84 | self.check_result(properties.id_, int, 4)
85 | self.check_result(properties.mimeType_, str, 'image/jpeg')
86 | self.check_result(properties.size_, int, 2532)
87 | self.check_result(properties.width_, int, 160)
88 | keys = properties.keys()
89 | self.assertIsInstance(keys, list)
90 | self.assertEqual(len(keys), 6)
91 | values = properties.values()
92 | self.assertIsInstance(values, list)
93 | self.assertEqual(len(values), 6)
94 | items = properties.items()
95 | self.assertIsInstance(items, list)
96 | self.assertEqual(len(items), 6)
97 | for k in properties:
98 | v = properties[k]
99 | self.assertIn(k, keys)
100 | self.assertIn(v, values)
101 | self.assertIn((k, v), items)
102 | with self.assertRaises(TypeError):
103 | properties[k] = 123
104 | with self.assertRaises(TypeError):
105 | del properties[k]
106 | with self.assertRaises(KeyError):
107 | a = properties['fred']
108 | with self.assertRaises(KeyError):
109 | properties['fred'] = 123
110 |
111 | def test_ref_counts(self):
112 | # manager keeps reference to image
113 | self.assertEqual(sys.getrefcount(self.image), 2)
114 | manager = exiv2.PreviewManager(self.image)
115 | self.assertEqual(sys.getrefcount(self.image), 3)
116 |
117 |
118 | if __name__ == '__main__':
119 | unittest.main()
120 |
--------------------------------------------------------------------------------
/tests/test_properties.py:
--------------------------------------------------------------------------------
1 | ## python-exiv2 - Python interface to libexiv2
2 | ## http://github.com/jim-easterbrook/python-exiv2
3 | ## Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | ##
5 | ## This program is free software: you can redistribute it and/or
6 | ## modify it under the terms of the GNU General Public License as
7 | ## published by the Free Software Foundation, either version 3 of the
8 | ## License, or (at your option) any later version.
9 | ##
10 | ## This program is distributed in the hope that it will be useful,
11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | ## General Public License for more details.
14 | ##
15 | ## You should have received a copy of the GNU General Public License
16 | ## along with this program. If not, see
17 | ## .
18 |
19 | import io
20 | import os
21 | import sys
22 | import tempfile
23 | import unittest
24 |
25 | import exiv2
26 |
27 |
28 | class TestPropertiesModule(unittest.TestCase):
29 | key_name = 'Xmp.dc.description'
30 | namespace = 'http://purl.org/dc/elements/1.1/'
31 | prefix_name = 'dc'
32 | property_name = 'description'
33 |
34 | @classmethod
35 | def setUpClass(cls):
36 | exiv2.XmpParser.initialize()
37 |
38 | @classmethod
39 | def tearDownClass(cls):
40 | exiv2.XmpParser.terminate()
41 |
42 | def check_result(self, result, expected_type, expected_value):
43 | self.assertIsInstance(result, expected_type)
44 | self.assertEqual(result, expected_value)
45 |
46 | def test_XmpNsInfo(self):
47 | ns_info = exiv2.XmpProperties.nsInfo(self.prefix_name)
48 | self.assertIsInstance(ns_info, exiv2.XmpNsInfo)
49 | self.check_result(ns_info['desc'], str, 'Dublin Core schema')
50 | self.check_result(ns_info['ns'], str, self.namespace)
51 | self.check_result(ns_info['prefix'], str, self.prefix_name)
52 | property_info = ns_info['xmpPropertyInfo']
53 | self.assertIsInstance(property_info, list)
54 | self.assertGreater(len(property_info), 0)
55 | self.assertIsInstance(property_info[0], exiv2.XmpPropertyInfo)
56 |
57 | def test_XmpProperties(self):
58 | properties = exiv2.XmpProperties
59 | self.check_result(properties.ns(self.prefix_name), str, self.namespace)
60 | self.check_result(properties.nsDesc(self.prefix_name),
61 | str, 'Dublin Core schema')
62 | self.assertIsInstance(properties.nsInfo(self.prefix_name),
63 | exiv2.XmpNsInfo)
64 | self.check_result(properties.prefix('http://purl.org/dc/elements/1.1/'),
65 | str, self.prefix_name)
66 | key = exiv2.XmpKey(self.key_name)
67 | key2 = exiv2.XmpKey('Xmp.dc.unknown')
68 | property_desc = properties.propertyDesc(key)
69 | self.assertIsInstance(property_desc, str)
70 | self.assertTrue(property_desc.startswith('A textual description of'))
71 | self.assertIsNone(properties.propertyDesc(key2))
72 | property_info = properties.propertyInfo(key)
73 | self.assertIsInstance(property_info, exiv2.XmpPropertyInfo)
74 | self.assertIsNone(properties.propertyInfo(key2))
75 | property_list = properties.propertyList(self.prefix_name)
76 | self.assertIsInstance(property_list, list)
77 | self.assertGreater(len(property_list), 0)
78 | self.assertIsInstance(property_list[0], exiv2.XmpPropertyInfo)
79 | self.check_result(properties.propertyTitle(key), str, 'Description')
80 | self.assertIsNone(properties.propertyTitle(key2))
81 | self.check_result(properties.propertyType(key),
82 | exiv2.TypeId, exiv2.TypeId.langAlt)
83 | self.check_result(properties.propertyType(key2),
84 | exiv2.TypeId, exiv2.TypeId.xmpText)
85 | namespaces = properties.registeredNamespaces()
86 | self.assertIsInstance(namespaces, dict)
87 | self.assertGreater(len(namespaces), 0)
88 | self.assertEqual(namespaces[self.prefix_name], self.namespace)
89 | # these don't seem to have any effect
90 | properties.registerNs('http://example.com/', 'exmpl')
91 | properties.unregisterNs('http://example.com/')
92 | properties.unregisterNs()
93 |
94 | def test_XmpPropertyInfo(self):
95 | key = exiv2.XmpKey(self.key_name)
96 | property_info = exiv2.XmpProperties.propertyInfo(key)
97 | self.assertIsInstance(property_info, exiv2.XmpPropertyInfo)
98 | desc = property_info['desc']
99 | self.assertIsInstance(desc, str)
100 | self.assertTrue(desc.startswith('A textual description of'))
101 | self.check_result(property_info['name'], str, 'description')
102 | self.check_result(property_info['title'], str, 'Description')
103 | self.check_result(property_info['typeId'],
104 | exiv2.TypeId, exiv2.TypeId.langAlt)
105 | self.check_result(property_info['xmpCategory'],
106 | exiv2.XmpCategory, exiv2.XmpCategory.External)
107 | self.check_result(property_info['xmpValueType'], str, 'Lang Alt')
108 |
109 | def test_XmpKey(self):
110 | # constructors
111 | key = exiv2.XmpKey(self.key_name)
112 | self.assertIsInstance(key, exiv2.XmpKey)
113 | key2 = exiv2.XmpKey(self.prefix_name, self.property_name)
114 | self.assertIsInstance(key2, exiv2.XmpKey)
115 | self.assertIsNot(key2, key)
116 | key2 = exiv2.XmpKey(key)
117 | self.assertIsInstance(key2, exiv2.XmpKey)
118 | self.assertIsNot(key2, key)
119 | # other methods
120 | self.assertEqual(str(key), self.key_name)
121 | key2 = key.clone()
122 | self.assertIsNot(key2, key)
123 | self.assertIsInstance(key2, exiv2.XmpKey)
124 | self.check_result(key.familyName(), str, self.key_name.split('.')[0])
125 | self.check_result(key.groupName(), str, self.key_name.split('.')[1])
126 | self.check_result(key.key(), str, self.key_name)
127 | self.check_result(key.ns(), str, self.namespace)
128 | self.check_result(key.tag(), int, 0)
129 | self.check_result(key.tagLabel(), str, 'Description')
130 | self.check_result(key.tagName(), str, self.key_name.split('.')[2])
131 | buf = io.StringIO()
132 | buf = key.write(buf)
133 | self.assertEqual(buf.getvalue(), self.key_name)
134 |
135 |
136 | if __name__ == '__main__':
137 | unittest.main()
138 |
--------------------------------------------------------------------------------
/tests/test_tags.py:
--------------------------------------------------------------------------------
1 | ## python-exiv2 - Python interface to libexiv2
2 | ## http://github.com/jim-easterbrook/python-exiv2
3 | ## Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | ##
5 | ## This program is free software: you can redistribute it and/or
6 | ## modify it under the terms of the GNU General Public License as
7 | ## published by the Free Software Foundation, either version 3 of the
8 | ## License, or (at your option) any later version.
9 | ##
10 | ## This program is distributed in the hope that it will be useful,
11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | ## General Public License for more details.
14 | ##
15 | ## You should have received a copy of the GNU General Public License
16 | ## along with this program. If not, see
17 | ## .
18 |
19 | import io
20 | import os
21 | import unittest
22 |
23 | import exiv2
24 |
25 |
26 | class TestTagsModule(unittest.TestCase):
27 | key_name = 'Exif.Image.ImageDescription'
28 | group_name = 'Image'
29 | tag = 270
30 |
31 | @classmethod
32 | def setUpClass(cls):
33 | # clear locale
34 | name = 'en_US.UTF-8'
35 | os.environ['LC_ALL'] = name
36 | os.environ['LANG'] = name
37 | os.environ['LANGUAGE'] = name
38 |
39 | def check_result(self, result, expected_type, expected_value):
40 | self.assertIsInstance(result, expected_type)
41 | self.assertEqual(result, expected_value)
42 |
43 | def test_ExifTags(self):
44 | tags = exiv2.ExifTags
45 | key = exiv2.ExifKey(self.key_name)
46 | self.check_result(tags.defaultCount(key), int, 0)
47 | group_list = tags.groupList()
48 | self.assertIsInstance(group_list, list)
49 | self.assertGreater(len(group_list), 0)
50 | self.assertIsInstance(group_list[0], exiv2.GroupInfo)
51 | self.check_result(tags.ifdName(self.group_name), str, 'IFD0')
52 | self.check_result(tags.isExifGroup(self.group_name), bool, True)
53 | self.check_result(tags.isMakerGroup(self.group_name), bool, False)
54 | self.check_result(tags.sectionName(key), str, 'OtherTags')
55 | tag_list = tags.tagList(self.group_name)
56 | self.assertIsInstance(tag_list, list)
57 | self.assertGreater(len(tag_list), 0)
58 | self.assertIsInstance(tag_list[0], exiv2.TagInfo)
59 |
60 | def test_GroupInfo(self):
61 | info = exiv2.ExifTags.groupList()[0]
62 | self.check_result(info['groupName'], str, 'Image')
63 | if exiv2.testVersion(0, 28, 0):
64 | self.check_result(info['ifdId'], int, exiv2.IfdId.ifd0Id)
65 | else:
66 | self.check_result(info['ifdId'], int, 1)
67 | self.check_result(info['ifdName'], str, 'IFD0')
68 | tag_list = info['tagList']()
69 | self.assertIsInstance(tag_list, list)
70 | self.assertGreater(len(tag_list), 0)
71 | self.assertIsInstance(tag_list[0], exiv2.TagInfo)
72 |
73 | def test_TagInfo(self):
74 | info = exiv2.ExifTags.tagList(self.group_name)[0]
75 | self.check_result(info['count'], int, 0)
76 | desc = info['desc']
77 | self.assertIsInstance(desc, str)
78 | self.assertTrue(desc.startswith('The name and version of the software'))
79 | if exiv2.testVersion(0, 28, 0):
80 | self.check_result(info['ifdId'], int, exiv2.IfdId.ifd0Id)
81 | else:
82 | self.check_result(info['ifdId'], int, 1)
83 | self.check_result(info['name'], str, 'ProcessingSoftware')
84 | if exiv2.testVersion(0, 28, 0):
85 | self.check_result(
86 | info['sectionId'], exiv2.SectionId, exiv2.SectionId.otherTags)
87 | else:
88 | self.check_result(info['sectionId'], int, 4)
89 | self.check_result(info['tag'], int, 11)
90 | self.check_result(info['title'], str, 'Processing Software')
91 | self.check_result(
92 | info['typeId'], exiv2.TypeId, exiv2.TypeId.asciiString)
93 |
94 | def test_ExifKey(self):
95 | # constructors
96 | key = exiv2.ExifKey(self.key_name)
97 | self.assertIsInstance(key, exiv2.ExifKey)
98 | key2 = exiv2.ExifKey(self.tag, self.group_name)
99 | self.assertIsInstance(key2, exiv2.ExifKey)
100 | self.assertIsNot(key2, key)
101 | key2 = exiv2.ExifKey(key)
102 | self.assertIsInstance(key2, exiv2.ExifKey)
103 | self.assertIsNot(key2, key)
104 | # other methods
105 | self.assertEqual(str(key), self.key_name)
106 | key2 = key.clone()
107 | self.assertIsNot(key2, key)
108 | self.assertIsInstance(key2, exiv2.ExifKey)
109 | self.check_result(
110 | key.defaultTypeId(), exiv2.TypeId, exiv2.TypeId.asciiString)
111 | self.check_result(key.familyName(), str, self.key_name.split('.')[0])
112 | self.check_result(key.groupName(), str, self.key_name.split('.')[1])
113 | self.check_result(key.idx(), int, 0)
114 | self.check_result(key.key(), str, self.key_name)
115 | key.setIdx(123)
116 | self.check_result(key.idx(), int, 123)
117 | self.check_result(key.tag(), int, self.tag)
118 | desc = key.tagDesc()
119 | self.assertIsInstance(desc, str)
120 | self.assertTrue(desc.startswith('A character string giving the title'))
121 | self.check_result(key.tagLabel(), str, 'Image Description')
122 | self.check_result(key.tagName(), str, self.key_name.split('.')[2])
123 | buf = io.StringIO()
124 | buf = key.write(buf)
125 | self.assertEqual(buf.getvalue(), self.key_name)
126 |
127 |
128 | if __name__ == '__main__':
129 | unittest.main()
130 |
--------------------------------------------------------------------------------
/tests/test_types.py:
--------------------------------------------------------------------------------
1 | ## python-exiv2 - Python interface to libexiv2
2 | ## http://github.com/jim-easterbrook/python-exiv2
3 | ## Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | ##
5 | ## This program is free software: you can redistribute it and/or
6 | ## modify it under the terms of the GNU General Public License as
7 | ## published by the Free Software Foundation, either version 3 of the
8 | ## License, or (at your option) any later version.
9 | ##
10 | ## This program is distributed in the hope that it will be useful,
11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | ## General Public License for more details.
14 | ##
15 | ## You should have received a copy of the GNU General Public License
16 | ## along with this program. If not, see
17 | ## .
18 |
19 | import locale
20 | import logging
21 | import os
22 | import random
23 | import sys
24 | import unittest
25 |
26 | import exiv2
27 |
28 |
29 | class TestTypesModule(unittest.TestCase):
30 | def check_result(self, result, expected_type, expected_value):
31 | self.assertIsInstance(result, expected_type)
32 | self.assertEqual(result, expected_value)
33 |
34 | def test_DataBuf(self):
35 | data = bytes(random.choices(range(256), k=128))
36 | # constructors
37 | buf = exiv2.DataBuf()
38 | self.assertIsInstance(buf, exiv2.DataBuf)
39 | self.assertEqual(len(buf), 0)
40 | buf = exiv2.DataBuf(4)
41 | self.assertEqual(len(buf), 4)
42 | buf = exiv2.DataBuf(data)
43 | self.assertEqual(len(buf), len(data))
44 | self.check_result(buf.data(), memoryview, data)
45 | # other methods
46 | self.check_result(buf.size(), int, len(data))
47 | with buf.data() as view:
48 | self.assertIsInstance(view, memoryview)
49 | self.check_result(view[23], int, data[23])
50 | view[49] = 99
51 | self.check_result(view[49], int, 99)
52 | buf = exiv2.DataBuf(data)
53 | self.assertEqual(buf, data)
54 | self.assertEqual(data, buf)
55 | self.assertNotEqual(buf, b'fred')
56 | self.assertNotEqual(b'fred', buf)
57 | if exiv2.testVersion(0, 28, 0):
58 | self.assertEqual(buf.cmpBytes(0, data), 0)
59 | self.assertEqual(buf.cmpBytes(5, data[5:]), 0)
60 | self.assertNotEqual(buf.cmpBytes(0, b'fred'), 0)
61 | buf.resize(6)
62 | self.assertEqual(len(buf), 6)
63 | self.assertEqual(buf.empty(), False)
64 | buf.resize(0)
65 | self.assertEqual(buf.empty(), True)
66 | else:
67 | with self.assertWarns(DeprecationWarning):
68 | result = buf[23]
69 | with self.assertWarns(DeprecationWarning):
70 | self.check_result(buf.pData_, memoryview, data)
71 | with self.assertWarns(DeprecationWarning):
72 | self.check_result(buf.size_, int, len(data))
73 | buf.free()
74 | self.assertEqual(len(buf), 0)
75 | buf = exiv2.DataBuf(data)
76 | buf.reset()
77 | self.assertEqual(len(buf), 0)
78 | buf = exiv2.DataBuf()
79 | buf.alloc(6)
80 | self.assertEqual(len(buf), 6)
81 |
82 | def test_Rational(self):
83 | for type_ in (exiv2.Rational, exiv2.URational):
84 | # constructors
85 | value = type_()
86 | self.assertIsInstance(value, type_)
87 | value = type_(13, 7)
88 | self.assertIsInstance(value, type_)
89 | # other methods
90 | self.assertEqual(len(value), 2)
91 | self.assertEqual(repr(value), '(13, 7)')
92 | self.check_result(value[0], int, 13)
93 | self.check_result(value[1], int, 7)
94 | self.check_result(value.first, int, value[0])
95 | self.check_result(value.second, int, value[1])
96 | value[0] = 23
97 | self.check_result(value[0], int, 23)
98 |
99 | def test_TypeInfo(self):
100 | info = exiv2.TypeInfo
101 | self.check_result(info.typeId('Rational'),
102 | exiv2.TypeId, exiv2.TypeId.unsignedRational)
103 | self.check_result(info.typeName(exiv2.TypeId.unsignedRational),
104 | str, 'Rational')
105 | self.check_result(info.typeSize(exiv2.TypeId.unsignedRational), int, 8)
106 |
107 | @unittest.skipUnless(exiv2.versionInfo()['EXV_ENABLE_NLS'],
108 | 'no localisation available')
109 | def test_localisation(self):
110 | str_en = 'Failed to read input data'
111 | str_de = 'Die Eingabedaten konnten nicht gelesen werden.'
112 | # clear current locale
113 | locale.setlocale(locale.LC_ALL, 'C')
114 | self.check_result(exiv2.exvGettext(str_en), str, str_en)
115 | # set German locale
116 | if sys.platform == 'win32':
117 | name = 'German'
118 | else:
119 | name = 'de_DE.UTF-8'
120 | try:
121 | locale.setlocale(locale.LC_ALL, name)
122 | except locale.Error:
123 | self.skipTest("failed to set locale")
124 | return
125 | name = 'de_DE.UTF-8'
126 | os.environ['LC_ALL'] = name
127 | os.environ['LANG'] = name
128 | os.environ['LANGUAGE'] = name
129 | locale.setlocale(locale.LC_ALL, '')
130 | name, encoding = locale.getlocale()
131 | if name != 'de_DE' and sys.platform != 'win32':
132 | self.skipTest("locale environment ignored")
133 | # test localisation
134 | self.check_result(exiv2.exvGettext(str_en), str, str_de)
135 | if exiv2.testVersion(0, 28, 3) or not exiv2.testVersion(0, 28, 0):
136 | with self.assertLogs(level=logging.WARNING) as cm:
137 | comment = exiv2.CommentValue('charset=invalid Fred')
138 | self.assertEqual(cm.output, [
139 | 'WARNING:exiv2:Ungültiger Zeichensatz: "invalid"'])
140 | with self.assertRaises(exiv2.Exiv2Error) as cm:
141 | key = exiv2.ExifKey('not.a.tag')
142 | self.assertEqual(cm.exception.message.replace('"', "'"),
143 | "Ungültiger Schlüssel 'not.a.tag'")
144 | # clear locale
145 | name = 'en_US.UTF-8'
146 | os.environ['LC_ALL'] = name
147 | os.environ['LANG'] = name
148 | os.environ['LANGUAGE'] = name
149 |
150 |
151 | if __name__ == '__main__':
152 | unittest.main()
153 |
--------------------------------------------------------------------------------
/tests/test_version.py:
--------------------------------------------------------------------------------
1 | ## python-exiv2 - Python interface to libexiv2
2 | ## http://github.com/jim-easterbrook/python-exiv2
3 | ## Copyright (C) 2023 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | ##
5 | ## This program is free software: you can redistribute it and/or
6 | ## modify it under the terms of the GNU General Public License as
7 | ## published by the Free Software Foundation, either version 3 of the
8 | ## License, or (at your option) any later version.
9 | ##
10 | ## This program is distributed in the hope that it will be useful,
11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | ## General Public License for more details.
14 | ##
15 | ## You should have received a copy of the GNU General Public License
16 | ## along with this program. If not, see
17 | ## .
18 |
19 | import unittest
20 |
21 | import exiv2
22 |
23 |
24 | class TestVersionModule(unittest.TestCase):
25 | def test_module(self):
26 | # earliest usable libexiv2 version
27 | result = exiv2.testVersion(0, 27, 0)
28 | self.assertIsInstance(result, bool)
29 | self.assertEqual(result, True)
30 | version = exiv2.version()
31 | self.assertIsInstance(version, str)
32 | self.assertGreaterEqual(version, '0.27.0')
33 | version_tuple = tuple(int(x) for x in version.split('.')[:3])
34 | version = exiv2.versionNumber()
35 | self.assertIsInstance(version, int)
36 | self.assertEqual(version, (version_tuple[0] << 16)
37 | + (version_tuple[1] << 8) + version_tuple[2])
38 | version = exiv2.versionNumberHexString()
39 | self.assertIsInstance(version, str)
40 | self.assertEqual(
41 | version, '{:02x}{:02x}{:02x}'.format(*version_tuple))
42 | version = exiv2.versionString()
43 | self.assertIsInstance(version, str)
44 | self.assertGreaterEqual(
45 | version, '.'.join(str(x) for x in version_tuple))
46 |
47 |
48 | if __name__ == '__main__':
49 | unittest.main()
50 |
--------------------------------------------------------------------------------
/utils/build_docs.py:
--------------------------------------------------------------------------------
1 | # python-exiv2 - Python interface to exiv2
2 | # http://github.com/jim-easterbrook/python-exiv2
3 | # Copyright (C) 2024 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import os
19 | import sys
20 |
21 | from sphinx.application import Sphinx
22 |
23 |
24 | def main(argv=None):
25 | root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
26 | src_dir = os.path.join(root, 'src', 'doc')
27 | dst_dir = os.path.join(root, 'doc', 'html')
28 | doctree_dir = os.path.join(root, 'doc', 'doctree')
29 | app = Sphinx(src_dir, src_dir, dst_dir, doctree_dir, 'html')
30 | app.build()
31 | return 0
32 |
33 |
34 | if __name__ == "__main__":
35 | sys.exit(main())
36 |
--------------------------------------------------------------------------------
/utils/tag_release.py:
--------------------------------------------------------------------------------
1 | # Photini - a simple photo metadata editor.
2 | # http://github.com/jim-easterbrook/Photini
3 | # Copyright (C) 2020 Jim Easterbrook jim@jim-easterbrook.me.uk
4 | #
5 | # This program is free software: you can redistribute it and/or
6 | # modify it under the terms of the GNU General Public License as
7 | # published by the Free Software Foundation, either version 3 of the
8 | # License, or (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | # .
18 |
19 | from datetime import date
20 | import re
21 | import sys
22 |
23 | # requires GitPython - 'sudo pip install gitpython'
24 | import git
25 |
26 |
27 | def main(argv=None):
28 | with open('README.rst') as rst:
29 | py_exiv2_version = rst.readline().split()[-1]
30 | message = 'python-exiv2-' + py_exiv2_version + '\n\n'
31 | with open('CHANGELOG.txt') as cl:
32 | while not cl.readline().startswith('Changes'):
33 | pass
34 | while True:
35 | line = cl.readline().strip()
36 | if not line:
37 | break
38 | message += line + '\n'
39 | repo = git.Repo()
40 | tag = repo.create_tag(py_exiv2_version, message=message)
41 | remote = repo.remotes.origin
42 | remote.push(tags=True)
43 | return 0
44 |
45 |
46 | if __name__ == "__main__":
47 | sys.exit(main())
48 |
--------------------------------------------------------------------------------