diff --git a/.github/workflows/test_package.yml b/.github/workflows/test_package.yml index 8664864..f0e52af 100644 --- a/.github/workflows/test_package.yml +++ b/.github/workflows/test_package.yml @@ -24,7 +24,7 @@ jobs: python-version: ${{ matrix.python_version }} - name: Install dependencies run: | - python -m pip install pyexiv2==2.14.0 + python -m pip install pyexiv2==2.15.0 python -m pip install pytest psutil - name: Test run: | @@ -50,7 +50,7 @@ jobs: python-version: ${{ matrix.python_version }} - name: Install dependencies run: | - python -m pip install pyexiv2==2.14.0 + python -m pip install pyexiv2==2.15.0 python -m pip install pytest psutil - name: Test run: | @@ -77,7 +77,7 @@ jobs: python-version: ${{ matrix.python_version }} - name: Install dependencies run: | - python -m pip install pyexiv2==2.14.0 + python -m pip install pyexiv2==2.15.0 python -m pip install pytest psutil - name: Test run: | diff --git a/docs/Tutorial-cn.md b/docs/Tutorial-cn.md index b74a134..e1e7cca 100644 --- a/docs/Tutorial-cn.md +++ b/docs/Tutorial-cn.md @@ -61,6 +61,9 @@ class Image: def __init__(self, filename, encoding='utf-8') def close(self) + + def get_pixel_width (self) -> int + def get_pixel_height(self) -> int def get_mime_type (self) -> str def get_access_mode (self) -> dict @@ -108,7 +111,7 @@ def convert_iptc_to_xmp(data: dict, encoding='utf-8') -> dict def convert_xmp_to_exif(data: dict, encoding='utf-8') -> dict def convert_xmp_to_iptc(data: dict, encoding='utf-8') -> dict -__version__ = '2.14.0' +__version__ = '2.15.0' __exiv2_version__ = '0.28.3' ``` diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 095d151..465da9d 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -61,6 +61,9 @@ Language: [English](./Tutorial.md) | [中文](./Tutorial-cn.md) class Image: def __init__(self, filename, encoding='utf-8') def close(self) + + def get_pixel_width (self) -> int + def get_pixel_height(self) -> int def get_mime_type (self) -> str def get_access_mode (self) -> dict @@ -108,7 +111,7 @@ def convert_iptc_to_xmp(data: dict, encoding='utf-8') -> dict def convert_xmp_to_exif(data: dict, encoding='utf-8') -> dict def convert_xmp_to_iptc(data: dict, encoding='utf-8') -> dict -__version__ = '2.14.0' +__version__ = '2.15.0' __exiv2_version__ = '0.28.3' ``` diff --git a/pyexiv2/__init__.py b/pyexiv2/__init__.py index fed78d8..5188064 100644 --- a/pyexiv2/__init__.py +++ b/pyexiv2/__init__.py @@ -6,7 +6,7 @@ from .core import * -__version__ = '2.14.0' +__version__ = '2.15.0' __exiv2_version__ = exiv2api.version() diff --git a/pyexiv2/core.py b/pyexiv2/core.py index e842e99..d014acc 100644 --- a/pyexiv2/core.py +++ b/pyexiv2/core.py @@ -33,6 +33,12 @@ def closed_warning(*args, **kwargs): else: setattr(self, attr, None) + def get_pixel_width(self) -> int: + return self._exiv2api_image.get_pixel_width() + + def get_pixel_height(self) -> int: + return self._exiv2api_image.get_pixel_height() + def get_mime_type(self) -> str: """ Get the MIME type of the image, such as 'image/jpeg'. """ return self._exiv2api_image.get_mime_type() diff --git a/pyexiv2/lib/exiv2api.cpp b/pyexiv2/lib/exiv2api.cpp index dca118e..ba91274 100644 --- a/pyexiv2/lib/exiv2api.cpp +++ b/pyexiv2/lib/exiv2api.cpp @@ -15,11 +15,14 @@ void logHandler(int level, const char *msg) switch (level) { case Exiv2::LogMsg::debug: + std::cout << "[debug] " << msg << std::endl; + break; case Exiv2::LogMsg::info: + std::cout << "[info] " << msg << std::endl; + break; case Exiv2::LogMsg::warn: - std::cout << msg << std::endl; + std::cout << "[warn] " << msg << std::endl; break; - case Exiv2::LogMsg::error: // For unknown reasons, the exception thrown here cannot be caught by pybind11, so temporarily save it to error_log. // throw std::exception(msg); @@ -140,6 +143,16 @@ class Image{ return py::bytes((char *)io.mmap(), io.size()); } + py::int_ get_pixel_width() + { + return img->pixelWidth(); + } + + py::int_ get_pixel_height() + { + return img->pixelHeight(); + } + std::string get_mime_type() { return img->mimeType(); @@ -165,7 +178,23 @@ class Image{ py::object read_exif() { Exiv2::ExifData &data = img->exifData(); - read_block; + py::list result; + for (const auto &datum : data) + { + py::list line; + line.append(py::bytes(datum.key())); + line.append(py::bytes(datum.value().toString())); + if (datum.typeSize() == 0) { + // Don't call py::str(datum.typeName()) on an unknown tag type. Otherwise, it raises a segmentation fault. + // https://github.com/LeoHsiao1/pyexiv2/issues/145 + line.append(py::str("unknown")); + } else { + line.append(py::str(datum.typeName())); + } + result.append(line); + } + check_error_log(); + return result; } py::object read_exif_detail() @@ -174,13 +203,20 @@ class Image{ py::list result; for (const auto &datum : data) { - py::dict tag_detail = py::dict(); - tag_detail["tag"] = py::bytes(datum.key()); - tag_detail["idx"] = py::int_(datum.idx()); - tag_detail["ifdName"] = py::str(datum.ifdName()); - tag_detail["tagDesc"] = py::str(datum.tagDesc()); - tag_detail["tagLabel"] = py::str(datum.tagLabel()); - tag_detail["typeName"] = py::str(datum.typeName()); + py::dict tag_detail = py::dict(); + tag_detail["idx"] = py::int_(datum.idx()); + tag_detail["ifdName"] = py::str(datum.ifdName()); + tag_detail["tag"] = py::bytes(datum.key()); + tag_detail["tagDesc"] = py::str(datum.tagDesc()); + tag_detail["tagLabel"] = py::str(datum.tagLabel()); + tag_detail["tagNumber"] = py::int_(datum.tag()); + if (datum.typeSize() == 0) { + // Don't call py::str(datum.typeName()) on an unknown tag type. Otherwise, it raises a segmentation fault. + // https://github.com/LeoHsiao1/pyexiv2/issues/145 + tag_detail["typeName"] = py::str("unknown"); + } else { + tag_detail["typeName"] = py::str(datum.typeName()); + } tag_detail["value"] = py::bytes(datum.value().toString()); result.append(tag_detail); } @@ -200,12 +236,13 @@ class Image{ py::list result; for (const auto &datum : data) { - py::dict tag_detail = py::dict(); - tag_detail["tag"] = py::bytes(datum.key()); - tag_detail["tagDesc"] = py::str(datum.tagDesc()); - tag_detail["tagLabel"] = py::str(datum.tagLabel()); - tag_detail["typeName"] = py::str(datum.typeName()); - tag_detail["value"] = py::bytes(datum.value().toString()); + py::dict tag_detail = py::dict(); + tag_detail["tag"] = py::bytes(datum.key()); + tag_detail["tagDesc"] = py::str(datum.tagDesc()); + tag_detail["tagLabel"] = py::str(datum.tagLabel()); + tag_detail["tagNumber"] = py::int_(datum.tag()); + tag_detail["typeName"] = py::str(datum.typeName()); + tag_detail["value"] = py::bytes(datum.value().toString()); result.append(tag_detail); } check_error_log(); @@ -656,6 +693,8 @@ PYBIND11_MODULE(exiv2api, m) .def(py::init()) .def("close_image" , &Image::close_image) .def("get_bytes" , &Image::get_bytes) + .def("get_pixel_width" , &Image::get_pixel_width) + .def("get_pixel_height" , &Image::get_pixel_height) .def("get_mime_type" , &Image::get_mime_type) .def("get_access_mode" , &Image::get_access_mode) .def("read_exif" , &Image::read_exif) diff --git a/pyexiv2/tests/data/data.py b/pyexiv2/tests/data/data.py index 139feaa..1986e86 100644 --- a/pyexiv2/tests/data/data.py +++ b/pyexiv2/tests/data/data.py @@ -12,6 +12,8 @@ with open(os.path.join(current_dir, '1-thumb.jpg'), 'rb') as f: EXIF_THUMB = f.read() +PIXEL_WIDTH = 200 +PIXEL_HEIGHT = 200 MIME_TYPE = 'image/jpeg' ACCESS_MODE = { @@ -25,268 +27,303 @@ EXIF_DETAIL = { 'Exif.Image.ImageDescription': { - 'value': 'test-中文-', - 'typeName': 'Ascii', 'idx': 1, 'ifdName': 'IFD0', 'tagDesc': 'A character string giving the title of the image. It may be a comment such as "1988 company picnic" or the like. Two-bytes character codes cannot be used. When a 2-bytes code is necessary, the Exif Private tag is to be used.', - 'tagLabel': 'Image Description' + 'tagLabel': 'Image Description', + 'tagNumber': 270, + 'typeName': 'Ascii', + 'value': 'test-中文-' }, 'Exif.Image.Make': { - 'value': 'test-中文-', - 'typeName': 'Ascii', 'idx': 2, 'ifdName': 'IFD0', 'tagDesc': 'The manufacturer of the recording equipment. This is the manufacturer of the DSC, scanner, video digitizer or other equipment that generated the image. When the field is left blank, it is treated as unknown.', - 'tagLabel': 'Manufacturer' + 'tagLabel': 'Manufacturer', + 'tagNumber': 271, + 'typeName': 'Ascii', + 'value': 'test-中文-' }, 'Exif.Image.Model': { - 'value': 'test-中文-', - 'typeName': 'Ascii', 'idx': 3, 'ifdName': 'IFD0', 'tagDesc': 'The model name or model number of the equipment. This is the model name or number of the DSC, scanner, video digitizer or other equipment that generated the image. When the field is left blank, it is treated as unknown.', - 'tagLabel': 'Model' + 'tagLabel': 'Model', + 'tagNumber': 272, + 'typeName': 'Ascii', + 'value': 'test-中文-' }, 'Exif.Image.Orientation': { - 'value': ['1', '2', '3'], - 'typeName': 'Ascii', 'idx': 4, 'ifdName': 'IFD0', 'tagDesc': 'The image orientation viewed in terms of rows and columns.', - 'tagLabel': 'Orientation' + 'tagLabel': 'Orientation', + 'tagNumber': 274, + 'typeName': 'Ascii', + 'value': ['1', + '2', + '3'] }, 'Exif.Image.DateTime': { - 'value': '2019:08:12 19:44:04', - 'typeName': 'Ascii', 'idx': 7, 'ifdName': 'IFD0', 'tagDesc': 'The date and time of image creation. In Exif standard, it is the date and time the file was changed.', - 'tagLabel': 'Date and Time' + 'tagLabel': 'Date and Time', + 'tagNumber': 306, + 'typeName': 'Ascii', + 'value': '2019:08:12 19:44:04' }, 'Exif.Image.Artist': { - 'value': 'test-中文-', - 'typeName': 'Ascii', 'idx': 8, 'ifdName': 'IFD0', 'tagDesc': 'This tag records the name of the camera owner, photographer or image creator. The detailed format is not specified, but it is recommended that the information be written as in the example below for ease of Interoperability. When the field is left blank, it is treated as unknown. Ex.) "Camera owner, John Smith; Photographer, Michael Brown; Image creator, Ken James"', - 'tagLabel': 'Artist' + 'tagLabel': 'Artist', + 'tagNumber': 315, + 'typeName': 'Ascii', + 'value': 'test-中文-' }, 'Exif.Image.Rating': { - 'value': '4', - 'typeName': 'Short', 'idx': 9, 'ifdName': 'IFD0', 'tagDesc': 'Rating tag used by Windows', - 'tagLabel': 'Windows Rating' + 'tagLabel': 'Windows Rating', + 'tagNumber': 18246, + 'typeName': 'Short', + 'value': '4' }, 'Exif.Image.RatingPercent': { - 'value': '75', - 'typeName': 'Short', 'idx': 10, 'ifdName': 'IFD0', 'tagDesc': 'Rating tag used by Windows, value in percent', - 'tagLabel': 'Windows Rating Percent' + 'tagLabel': 'Windows Rating Percent', + 'tagNumber': 18249, + 'typeName': 'Short', + 'value': '75' }, 'Exif.Image.Copyright': { - 'value': 'test-中文-', - 'typeName': 'Ascii', 'idx': 11, 'ifdName': 'IFD0', 'tagDesc': 'Copyright information. In this standard the tag is used to indicate both the photographer and editor copyrights. It is the copyright notice of the person or organization claiming rights to the image. The Interoperability copyright statement including date and rights should be written in this field; e.g., "Copyright, John Smith, 19xx. All rights reserved.". In this standard the field records both the photographer and editor copyrights, with each recorded in a separate part of the statement. When there is a clear distinction between the photographer and editor copyrights, these are to be written in the order of photographer followed by editor copyright, separated by NULL (in this case since the statement also ends with a NULL, there are two NULL codes). When only the photographer copyright is given, it is terminated by one NULL code. When only the editor copyright is given, the photographer copyright part consists of one space followed by a terminating NULL code, then the editor copyright is given. When the field is left blank, it is treated as unknown.', - 'tagLabel': 'Copyright' + 'tagLabel': 'Copyright', + 'tagNumber': 33432, + 'typeName': 'Ascii', + 'value': 'test-中文-' }, 'Exif.Image.ExifTag': { - 'value': '2470', - 'typeName': 'Long', 'idx': 12, 'ifdName': 'IFD0', 'tagDesc': 'A pointer to the Exif IFD. Interoperability, Exif IFD has the same structure as that of the IFD specified in TIFF. ordinarily, however, it does not contain image data as in the case of TIFF.', - 'tagLabel': 'Exif IFD Pointer' + 'tagLabel': 'Exif IFD Pointer', + 'tagNumber': 34665, + 'typeName': 'Long', + 'value': '2470' }, 'Exif.Photo.ExposureProgram': { - 'value': '1', - 'typeName': 'Short', 'idx': 1, 'ifdName': 'Exif', 'tagDesc': 'The class of the program used by the camera to set exposure when the picture is taken.', - 'tagLabel': 'Exposure Program' + 'tagLabel': 'Exposure Program', + 'tagNumber': 34850, + 'typeName': 'Short', + 'value': '1' }, 'Exif.Photo.ExifVersion': { - 'value': '48 50 50 49', - 'typeName': 'Undefined', 'idx': 2, 'ifdName': 'Exif', 'tagDesc': 'The version of this standard supported. Nonexistence of this field is taken to mean nonconformance to the standard.', - 'tagLabel': 'Exif Version' + 'tagLabel': 'Exif Version', + 'tagNumber': 36864, + 'typeName': 'Undefined', + 'value': '48 50 50 49' }, 'Exif.Photo.DateTimeOriginal': { - 'value': '2019:08:12 19:44:04', - 'typeName': 'Ascii', 'idx': 3, 'ifdName': 'Exif', 'tagDesc': 'The date and time when the original image data was generated. For a digital still camera the date and time the picture was taken are recorded.', - 'tagLabel': 'Date and Time (original)' + 'tagLabel': 'Date and Time (original)', + 'tagNumber': 36867, + 'typeName': 'Ascii', + 'value': '2019:08:12 19:44:04' }, 'Exif.Photo.DateTimeDigitized': { - 'value': '2019:08:12 19:44:04', - 'typeName': 'Ascii', 'idx': 4, 'ifdName': 'Exif', 'tagDesc': 'The date and time when the image was stored as digital data.', - 'tagLabel': 'Date and Time (digitized)' + 'tagLabel': 'Date and Time (digitized)', + 'tagNumber': 36868, + 'typeName': 'Ascii', + 'value': '2019:08:12 19:44:04' }, 'Exif.Photo.LightSource': { - 'value': '1', - 'typeName': 'Short', 'idx': 5, 'ifdName': 'Exif', 'tagDesc': 'The kind of light source.', - 'tagLabel': 'Light Source' + 'tagLabel': 'Light Source', + 'tagNumber': 37384, + 'typeName': 'Short', + 'value': '1' }, 'Exif.Photo.SubSecTime': { - 'value': '18', - 'typeName': 'Ascii', 'idx': 6, 'ifdName': 'Exif', 'tagDesc': 'A tag used to record fractions of seconds for the tag.', - 'tagLabel': 'Sub-seconds Time' + 'tagLabel': 'Sub-seconds Time', + 'tagNumber': 37520, + 'typeName': 'Ascii', + 'value': '18' }, 'Exif.Photo.SubSecTimeOriginal': { - 'value': '18', - 'typeName': 'Ascii', 'idx': 7, 'ifdName': 'Exif', 'tagDesc': 'A tag used to record fractions of seconds for the tag.', - 'tagLabel': 'Sub-seconds Time Original' + 'tagLabel': 'Sub-seconds Time Original', + 'tagNumber': 37521, + 'typeName': 'Ascii', + 'value': '18' }, 'Exif.Photo.SubSecTimeDigitized': { - 'value': '176', - 'typeName': 'Ascii', 'idx': 8, 'ifdName': 'Exif', 'tagDesc': 'A tag used to record fractions of seconds for the tag.', - 'tagLabel': 'Sub-seconds Time Digitized' + 'tagLabel': 'Sub-seconds Time Digitized', + 'tagNumber': 37522, + 'typeName': 'Ascii', + 'value': '176' }, 'Exif.Photo.ColorSpace': { - 'value': '65535', - 'typeName': 'Short', 'idx': 9, 'ifdName': 'Exif', 'tagDesc': 'The color space information tag is always recorded as the color space specifier. Normally sRGB is used to define the color space based on the PC monitor conditions and environment. If a color space other than sRGB is used, Uncalibrated is set. Image data recorded as Uncalibrated can be treated as sRGB when it is converted to FlashPix.', - 'tagLabel': 'Color Space' + 'tagLabel': 'Color Space', + 'tagNumber': 40961, + 'typeName': 'Short', + 'value': '65535' }, 'Exif.Photo.WhiteBalance': { - 'value': '0', - 'typeName': 'Short', 'idx': 10, 'ifdName': 'Exif', 'tagDesc': 'This tag indicates the white balance mode set when the image was shot.', - 'tagLabel': 'White Balance' + 'tagLabel': 'White Balance', + 'tagNumber': 41987, + 'typeName': 'Short', + 'value': '0' }, 'Exif.Photo.Contrast': { - 'value': '0', - 'typeName': 'Short', 'idx': 11, 'ifdName': 'Exif', 'tagDesc': 'This tag indicates the direction of contrast processing applied by the camera when the image was shot.', - 'tagLabel': 'Contrast' + 'tagLabel': 'Contrast', + 'tagNumber': 41992, + 'typeName': 'Short', + 'value': '0' }, 'Exif.Photo.Saturation': { - 'value': '0', - 'typeName': 'Short', 'idx': 12, 'ifdName': 'Exif', 'tagDesc': 'This tag indicates the direction of saturation processing applied by the camera when the image was shot.', - 'tagLabel': 'Saturation' + 'tagLabel': 'Saturation', + 'tagNumber': 41993, + 'typeName': 'Short', + 'value': '0' }, 'Exif.Photo.Sharpness': { - 'value': '0', - 'typeName': 'Short', 'idx': 13, 'ifdName': 'Exif', 'tagDesc': 'This tag indicates the direction of sharpness processing applied by the camera when the image was shot.', - 'tagLabel': 'Sharpness' + 'tagLabel': 'Sharpness', + 'tagNumber': 41994, + 'typeName': 'Short', + 'value': '0' }, 'Exif.Photo.0xea1c': { - 'value': '28 234 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0', - 'typeName': 'Undefined', 'idx': 14, 'ifdName': 'Exif', 'tagDesc': '', - 'tagLabel': '' + 'tagLabel': '', + 'tagNumber': 59932, + 'typeName': 'Undefined', + 'value': '28 234 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0' }, 'Exif.Image.XPTitle': { - 'value': 'test-中文-\x00', - 'typeName': 'Byte', 'idx': 13, 'ifdName': 'IFD0', 'tagDesc': 'Title tag used by Windows, encoded in UCS2', - 'tagLabel': 'Windows Title' + 'tagLabel': 'Windows Title', + 'tagNumber': 40091, + 'typeName': 'Byte', + 'value': 'test-中文-\x00' }, 'Exif.Image.XPComment': { - 'value': 'test-中文-\x00', - 'typeName': 'Byte', 'idx': 14, 'ifdName': 'IFD0', 'tagDesc': 'Comment tag used by Windows, encoded in UCS2', - 'tagLabel': 'Windows Comment' + 'tagLabel': 'Windows Comment', + 'tagNumber': 40092, + 'typeName': 'Byte', + 'value': 'test-中文-\x00' }, 'Exif.Image.XPAuthor': { - 'value': 'test-中文-\x00', - 'typeName': 'Byte', 'idx': 15, 'ifdName': 'IFD0', 'tagDesc': 'Author tag used by Windows, encoded in UCS2', - 'tagLabel': 'Windows Author' + 'tagLabel': 'Windows Author', + 'tagNumber': 40093, + 'typeName': 'Byte', + 'value': 'test-中文-\x00' }, 'Exif.Image.XPKeywords': { - 'value': 'test-中文-\x00', - 'typeName': 'Byte', 'idx': 16, 'ifdName': 'IFD0', 'tagDesc': 'Keywords tag used by Windows, encoded in UCS2', - 'tagLabel': 'Windows Keywords' + 'tagLabel': 'Windows Keywords', + 'tagNumber': 40094, + 'typeName': 'Byte', + 'value': 'test-中文-\x00' }, 'Exif.Image.XPSubject': { - 'value': 'test-中文-\x00', - 'typeName': 'Byte', 'idx': 17, 'ifdName': 'IFD0', 'tagDesc': 'Subject tag used by Windows, encoded in UCS2', - 'tagLabel': 'Windows Subject' + 'tagLabel': 'Windows Subject', + 'tagNumber': 40095, + 'typeName': 'Byte', + 'value': 'test-中文-\x00' }, 'Exif.Image.0xea1c': { - 'value': '28 234 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0', - 'typeName': 'Undefined', 'idx': 18, 'ifdName': 'IFD0', 'tagDesc': '', - 'tagLabel': '' + 'tagLabel': '', + 'tagNumber': 59932, + 'typeName': 'Undefined', + 'value': '28 234 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0' }, 'Exif.Thumbnail.Compression': { - 'value': '6', - 'typeName': 'Short', 'idx': 1, 'ifdName': 'IFD1', 'tagDesc': 'The compression scheme used for the image data. When a primary image is JPEG compressed, this designation is not necessary and is omitted. When thumbnails use JPEG compression, this tag value is set to 6.', - 'tagLabel': 'Compression' + 'tagLabel': 'Compression', + 'tagNumber': 259, + 'typeName': 'Short', + 'value': '6' }, 'Exif.Thumbnail.JPEGInterchangeFormat': { - 'value': '4786', - 'typeName': 'Long', 'idx': 2, 'ifdName': 'IFD1', 'tagDesc': 'The offset to the start byte (SOI) of JPEG compressed thumbnail data. This is not used for primary image JPEG data.', - 'tagLabel': 'JPEG Interchange Format' + 'tagLabel': 'JPEG Interchange Format', + 'tagNumber': 513, + 'typeName': 'Long', + 'value': '4786' }, 'Exif.Thumbnail.JPEGInterchangeFormatLength': { - 'value': '6969', - 'typeName': 'Long', 'idx': 3, 'ifdName': 'IFD1', 'tagDesc': 'The number of bytes of JPEG compressed thumbnail data. This is not used for primary image JPEG data. JPEG thumbnails are not divided but are recorded as a continuous JPEG bitstream from SOI to EOI. Appn and COM markers should not be recorded. Compressed thumbnails must be recorded in no more than 64 Kbytes, including all other data to be recorded in APP1.', - 'tagLabel': 'JPEG Interchange Format Length' + 'tagLabel': 'JPEG Interchange Format Length', + 'tagNumber': 514, + 'typeName': 'Long', + 'value': '6969' } } @@ -294,58 +331,69 @@ IPTC_DETAIL = { 'Iptc.Envelope.CharacterSet': { - 'value': '\x1b%G', - 'typeName': 'String', 'tagDesc': 'This tag consisting of one or more control functions used for the announcement, invocation or designation of coded character sets. The control functions follow the ISO 2022 standard and may consist of the escape control character and one or more graphic characters.', - 'tagLabel': 'Character Set' + 'tagLabel': 'Character Set', + 'tagNumber': 90, + 'typeName': 'String', + 'value': '\x1b%G' }, 'Iptc.Application2.RecordVersion': { - 'value': '4', - 'typeName': 'Short', 'tagDesc': 'A binary number identifying the version of the Information Interchange Model, Part II, utilised by the provider. Version numbers are assigned by IPTC and NAA organizations.', - 'tagLabel': 'Record Version' + 'tagLabel': 'Record Version', + 'tagNumber': 0, + 'typeName': 'Short', + 'value': '4' }, 'Iptc.Application2.ObjectName': { - 'value': 'test-中文-', - 'typeName': 'String', 'tagDesc': 'Used as a shorthand reference for the object. Changes to exist-ing data, such as updated stories or new crops on photos, should be identified in tag .', - 'tagLabel': 'Object Name' + 'tagLabel': 'Object Name', + 'tagNumber': 5, + 'typeName': 'String', + 'value': 'test-中文-' }, 'Iptc.Application2.Keywords': { - 'value': ['tag1', 'tag2', 'tag3'], - 'typeName': 'String', 'tagDesc': 'Used to indicate specific information retrieval words. It is expected that a provider of various types of data that are related in subject matter uses the same keyword, enabling the receiving system or subsystems to search across all types of data for related material.', - 'tagLabel': 'Keywords' + 'tagLabel': 'Keywords', + 'tagNumber': 25, + 'typeName': 'String', + 'value': ['tag1', + 'tag2', + 'tag3'] }, 'Iptc.Application2.DateCreated': { - 'value': '2019-08-12', - 'typeName': 'Date', 'tagDesc': 'Represented in the form CCYYMMDD to designate the date the intellectual content of the object data was created rather than the date of the creation of the physical representation. Follows ISO 8601 standard.', - 'tagLabel': 'Date Created' + 'tagLabel': 'Date Created', + 'tagNumber': 55, + 'typeName': 'Date', + 'value': '2019-08-12' }, 'Iptc.Application2.TimeCreated': { - 'value': '19:44:04+00:00', - 'typeName': 'Time', 'tagDesc': 'Represented in the form HHMMSS:HHMM to designate the time the intellectual content of the object data current source material was created rather than the creation of the physical representation. Follows ISO 8601 standard.', - 'tagLabel': 'Time Created' + 'tagLabel': 'Time Created', + 'tagNumber': 60, + 'typeName': 'Time', + 'value': '19:44:04+00:00' }, 'Iptc.Application2.Byline': { - 'value': ['test-中文-'], - 'typeName': 'String', 'tagDesc': 'Contains name of the creator of the object data, e.g. writer, photographer or graphic artist.', - 'tagLabel': 'By-line' + 'tagLabel': 'By-line', + 'tagNumber': 80, + 'typeName': 'String', + 'value': ['test-中文-'] }, 'Iptc.Application2.Copyright': { - 'value': 'test-中文-', - 'typeName': 'String', 'tagDesc': 'Contains any necessary copyright notice.', - 'tagLabel': 'Copyright' + 'tagLabel': 'Copyright', + 'tagNumber': 116, + 'typeName': 'String', + 'value': 'test-中文-' }, 'Iptc.Application2.Caption': { - 'value': 'test-中文-', - 'typeName': 'String', 'tagDesc': 'A textual description of the object data.', - 'tagLabel': 'Caption' + 'tagLabel': 'Caption', + 'tagNumber': 120, + 'typeName': 'String', + 'value': 'test-中文-' } } diff --git a/pyexiv2/tests/test_func.py b/pyexiv2/tests/test_func.py index 132e4c3..1dc49af 100644 --- a/pyexiv2/tests/test_func.py +++ b/pyexiv2/tests/test_func.py @@ -49,6 +49,16 @@ def _test_chinese_path(): os.remove(chinese_path) +def test_get_pixel_width(): + assert ENV.img.get_pixel_width() == data.PIXEL_WIDTH + check_img_md5() + + +def test_get_pixel_height(): + assert ENV.img.get_pixel_height() == data.PIXEL_HEIGHT + check_img_md5() + + def test_get_mime_type(): assert ENV.img.get_mime_type() == data.MIME_TYPE check_img_md5() diff --git a/setup.py b/setup.py index efe1ad3..ec07e77 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name='pyexiv2', - version='2.14.0', # need to set the variable in 'pyexiv2/__init__.py' + version='2.15.0', # need to set the variable in 'pyexiv2/__init__.py' author='LeoHsiao', author_email='leohsiao@foxmail.com', description='Read and write image metadata, including EXIF, IPTC, XMP, ICC Profile.',