From 4510de26e5361f3a9f07057ec6f26483c888c1fa Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Wed, 28 May 2014 18:42:37 -0700 Subject: DNG: Update TiffWriter to handle thumbnails and SubIfds. - Fix SubIfd handling. - Add StripSources, convenience functions for writing image strips. - Update Input classes to use with JNI. - Add skip method. - Add tag definitions for GPS tags. - Add name string to tag definitions. Bug: 15112503 Change-Id: I9535b21261027f6c06a041c1621de8f865a0ad32 --- media/img_utils/include/img_utils/FileInput.h | 6 +- media/img_utils/include/img_utils/Input.h | 14 +- media/img_utils/include/img_utils/StripSource.h | 53 +++++ media/img_utils/include/img_utils/TagDefinitions.h | 229 +++++++++++++++++++-- media/img_utils/include/img_utils/TiffEntry.h | 13 +- media/img_utils/include/img_utils/TiffEntryImpl.h | 56 +++-- media/img_utils/include/img_utils/TiffHelpers.h | 2 +- media/img_utils/include/img_utils/TiffIfd.h | 46 ++++- media/img_utils/include/img_utils/TiffWriter.h | 145 +++++++++---- media/img_utils/src/Android.mk | 1 + media/img_utils/src/FileInput.cpp | 13 +- media/img_utils/src/Input.cpp | 28 +++ media/img_utils/src/StripSource.cpp | 25 +++ media/img_utils/src/TiffEntry.cpp | 10 - media/img_utils/src/TiffEntryImpl.cpp | 19 -- media/img_utils/src/TiffIfd.cpp | 208 ++++++++++++++++++- media/img_utils/src/TiffWriter.cpp | 219 +++++++++++++++++--- 17 files changed, 938 insertions(+), 149 deletions(-) create mode 100644 media/img_utils/include/img_utils/StripSource.h create mode 100644 media/img_utils/src/StripSource.cpp (limited to 'media/img_utils') diff --git a/media/img_utils/include/img_utils/FileInput.h b/media/img_utils/include/img_utils/FileInput.h index d3c5ec1..4d4f22b 100644 --- a/media/img_utils/include/img_utils/FileInput.h +++ b/media/img_utils/include/img_utils/FileInput.h @@ -52,10 +52,10 @@ class ANDROID_API FileInput : public Input { * of bytes given in the count argument will be read. Bytes will be written * into the given buffer starting at the index given in the offset argument. * - * Returns the number of bytes read. If an error has occurred, the value pointed - * to by the given status_t pointer will be set to a negative error code. + * Returns the number of bytes read, or NOT_ENOUGH_DATA if at the end of the file. If an + * error has occurred, this will return a negative error code other than NOT_ENOUGH_DATA. */ - virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err); + virtual ssize_t read(uint8_t* buf, size_t offset, size_t count); /** * Close the file descriptor to the path given in the constructor. diff --git a/media/img_utils/include/img_utils/Input.h b/media/img_utils/include/img_utils/Input.h index 2166601..6a03647 100644 --- a/media/img_utils/include/img_utils/Input.h +++ b/media/img_utils/include/img_utils/Input.h @@ -43,10 +43,18 @@ class ANDROID_API Input { * count argument will be read. Bytes will be written into the given buffer starting * at the index given in the offset argument. * - * Returns the number of bytes read. If an error has occurred, the value pointed - * to by the given status_t pointer will be set to a negative error code. + * Returns the number of bytes read, or NOT_ENOUGH_DATA if at the end of the file. If an + * error has occurred, this will return a negative error code other than NOT_ENOUGH_DATA. */ - virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err) = 0; + virtual ssize_t read(uint8_t* buf, size_t offset, size_t count) = 0; + + /** + * Skips bytes in the input. + * + * Returns the number of bytes skipped, or NOT_ENOUGH_DATA if at the end of the file. If an + * error has occurred, this will return a negative error code other than NOT_ENOUGH_DATA. + */ + virtual ssize_t skip(size_t count); /** * Close the Input. It is not valid to call open on a previously closed Input. diff --git a/media/img_utils/include/img_utils/StripSource.h b/media/img_utils/include/img_utils/StripSource.h new file mode 100644 index 0000000..b5c6b60 --- /dev/null +++ b/media/img_utils/include/img_utils/StripSource.h @@ -0,0 +1,53 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMG_UTILS_STRIP_SOURCE_H +#define IMG_UTILS_STRIP_SOURCE_H + +#include + +#include +#include + +#include + +namespace android { +namespace img_utils { + +/** + * This class acts as a data source for strips set in a TiffIfd. + */ +class ANDROID_API StripSource { + public: + virtual ~StripSource(); + + /** + * Write count bytes to the stream. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t writeToStream(Output& stream, uint32_t count) = 0; + + /** + * Return the source IFD. + */ + virtual uint32_t getIfd() const = 0; +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_STRIP_SOURCE_H*/ diff --git a/media/img_utils/include/img_utils/TagDefinitions.h b/media/img_utils/include/img_utils/TagDefinitions.h index 6cc42b2..e9a7480 100644 --- a/media/img_utils/include/img_utils/TagDefinitions.h +++ b/media/img_utils/include/img_utils/TagDefinitions.h @@ -29,16 +29,18 @@ namespace img_utils { * Tag definitions contain information about standard TIFF compatible tags. */ typedef struct TagDefinition { + // The tag name. + const char* tagName; // The specified tag ID. - uint16_t tagId; + const uint16_t tagId; // The default type for this tag. This must be a valid TIFF type. - TagType defaultType; + const TagType defaultType; // The default Image File Directory (IFD) for this tag. - uint32_t defaultIfd; + const uint32_t defaultIfd; // The valid count for this tag, or 0 if the count is not fixed. - uint32_t fixedCount; + const uint32_t fixedCount; // The endianness of the tag value, or UNDEFINED_ENDIAN if there is no fixed endian - Endianness fixedEndian; + const Endianness fixedEndian; } TagDefinition_t; /** @@ -180,6 +182,14 @@ enum { TAG_ISOSPEEDRATINGS = 0x8827u, TAG_FOCALLENGTH = 0x920Au, TAG_FNUMBER = 0x829Du, + TAG_GPSINFO = 0x8825u, + TAG_GPSVERSIONID = 0x0u, + TAG_GPSLATITUDEREF = 0x1u, + TAG_GPSLATITUDE = 0x2u, + TAG_GPSLONGITUDEREF = 0x3u, + TAG_GPSLONGITUDE = 0x4u, + TAG_GPSTIMESTAMP = 0x7u, + TAG_GPSDATESTAMP = 0x001Du, }; /** @@ -187,6 +197,7 @@ enum { */ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { { // PhotometricInterpretation + "PhotometricInterpretation", 0x0106u, SHORT, IFD_0, @@ -194,6 +205,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // SubIfds + "SubIfds", 0x014Au, LONG, IFD_0, @@ -201,6 +213,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CFAPattern + "CFAPattern", 0x828Eu, BYTE, IFD_0, @@ -208,6 +221,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CFARepeatPatternDim + "CFARepeatPatternDim", 0x828Du, SHORT, IFD_0, @@ -215,6 +229,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DateTimeOriginal + "DateTimeOriginal", 0x9003u, ASCII, IFD_0, @@ -222,6 +237,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Tiff/EPStandardID + "Tiff", 0x9216u, BYTE, IFD_0, @@ -229,6 +245,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ExposureTime + "ExposureTime", 0x829Au, RATIONAL, IFD_0, @@ -236,6 +253,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ISOSpeedRatings + "ISOSpeedRatings", 0x8827u, SHORT, IFD_0, @@ -243,6 +261,7 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // FocalLength + "FocalLength", 0x920Au, RATIONAL, IFD_0, @@ -250,12 +269,69 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // FNumber + "FNumber", 0x829Du, RATIONAL, IFD_0, 0, UNDEFINED_ENDIAN }, + { // GPSInfo + "GPSInfo", + 0x8825u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // GPSVersionID + "GPSVersionID", + 0x0u, + BYTE, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + { // GPSLatitudeRef + "GPSLatitudeRef", + 0x1u, + ASCII, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // GPSLatitude + "GPSLatitude", + 0x2u, + RATIONAL, + IFD_0, + 3, + UNDEFINED_ENDIAN + }, + { // GPSLongitudeRef + "GPSLongitudeRef", + 0x3u, + ASCII, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // GPSLongitude + "GPSLongitude", + 0x4u, + RATIONAL, + IFD_0, + 3, + UNDEFINED_ENDIAN + }, + { // GPSTimeStamp + "GPSTimeStamp", + 0x7u, + RATIONAL, + IFD_0, + 3, + UNDEFINED_ENDIAN + }, /*TODO: Remaining TIFF EP tags*/ }; @@ -264,12 +340,21 @@ const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { */ const TagDefinition_t EXIF_2_3_TAG_DEFINITIONS[] = { { // ExifVersion + "ExifVersion", 0x9000u, UNDEFINED, IFD_0, 4, UNDEFINED_ENDIAN }, + { // GPSDateStamp + "GPSDateStamp", + 0x001Du, + ASCII, + IFD_0, + 11, + UNDEFINED_ENDIAN + }, /*TODO: Remaining EXIF 2.3 tags*/ }; @@ -278,6 +363,7 @@ const TagDefinition_t EXIF_2_3_TAG_DEFINITIONS[] = { */ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { { // SubFileType + "SubFileType", 0x00FFu, SHORT, IFD_0, @@ -285,6 +371,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Artist + "Artist", 0x013Bu, ASCII, IFD_0, @@ -292,6 +379,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BitsPerSample + "BitsPerSample", 0x0102u, SHORT, IFD_0, @@ -299,6 +387,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CellLength + "CellLength", 0x0109u, SHORT, IFD_0, @@ -306,6 +395,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CellWidth + "CellWidth", 0x0108u, SHORT, IFD_0, @@ -313,6 +403,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ColorMap + "ColorMap", 0x0140u, SHORT, IFD_0, @@ -320,6 +411,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Compression + "Compression", 0x0103u, SHORT, IFD_0, @@ -327,6 +419,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Copyright + "Copyright", 0x8298u, ASCII, IFD_0, @@ -334,6 +427,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DateTime + "DateTime", 0x0132u, ASCII, IFD_0, @@ -341,6 +435,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ExtraSamples + "ExtraSamples", 0x0152u, SHORT, IFD_0, @@ -348,6 +443,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // FillOrder + "FillOrder", 0x010Au, SHORT, IFD_0, @@ -355,6 +451,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // FreeByteCounts + "FreeByteCounts", 0x0121u, LONG, IFD_0, @@ -362,6 +459,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // FreeOffsets + "FreeOffsets", 0x0120u, LONG, IFD_0, @@ -369,6 +467,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // GrayResponseCurve + "GrayResponseCurve", 0x0123u, SHORT, IFD_0, @@ -376,6 +475,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // GrayResponseUnit + "GrayResponseUnit", 0x0122u, SHORT, IFD_0, @@ -383,6 +483,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // HostComputer + "HostComputer", 0x013Cu, ASCII, IFD_0, @@ -390,6 +491,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ImageDescription + "ImageDescription", 0x010Eu, ASCII, IFD_0, @@ -397,6 +499,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ImageLength + "ImageLength", 0x0101u, LONG, IFD_0, @@ -404,6 +507,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ImageWidth + "ImageWidth", 0x0100u, LONG, IFD_0, @@ -411,6 +515,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Make + "Make", 0x010Fu, ASCII, IFD_0, @@ -418,6 +523,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // MaxSampleValue + "MaxSampleValue", 0x0119u, SHORT, IFD_0, @@ -425,6 +531,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // MinSampleValue + "MinSampleValue", 0x0118u, SHORT, IFD_0, @@ -432,6 +539,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Model + "Model", 0x0110u, ASCII, IFD_0, @@ -439,6 +547,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // NewSubfileType + "NewSubfileType", 0x00FEu, LONG, IFD_0, @@ -446,6 +555,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Orientation + "Orientation", 0x0112u, SHORT, IFD_0, @@ -453,6 +563,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PhotoMetricInterpretation + "PhotoMetricInterpretation", 0x0106u, SHORT, IFD_0, @@ -460,6 +571,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PlanarConfiguration + "PlanarConfiguration", 0x011Cu, SHORT, IFD_0, @@ -467,6 +579,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ResolutionUnit + "ResolutionUnit", 0x0128u, SHORT, IFD_0, @@ -474,6 +587,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // RowsPerStrip + "RowsPerStrip", 0x0116u, LONG, IFD_0, @@ -481,6 +595,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // SamplesPerPixel + "SamplesPerPixel", 0x0115u, SHORT, IFD_0, @@ -488,6 +603,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Software + "Software", 0x0131u, ASCII, IFD_0, @@ -495,6 +611,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // StripByteCounts + "StripByteCounts", 0x0117u, LONG, IFD_0, @@ -502,6 +619,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // StripOffsets + "StripOffsets", 0x0111u, LONG, IFD_0, @@ -509,6 +627,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // SubfileType + "SubfileType", 0x00FFu, SHORT, IFD_0, @@ -516,6 +635,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // Threshholding + "Threshholding", 0x0107u, SHORT, IFD_0, @@ -523,6 +643,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // XResolution + "XResolution", 0x011Au, RATIONAL, IFD_0, @@ -530,19 +651,13 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // YResolution + "YResolution", 0x011Bu, RATIONAL, IFD_0, 1, UNDEFINED_ENDIAN }, - { // YResolution - 0x011Bu, - RATIONAL, - IFD_0, - 1, - UNDEFINED_ENDIAN - } }; /** @@ -550,6 +665,7 @@ const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { */ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { { // DNGVersion + "DNGVersion", 0xC612u, BYTE, IFD_0, @@ -557,6 +673,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DNGBackwardVersion + "DNGBackwardVersion", 0xC613u, BYTE, IFD_0, @@ -564,6 +681,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // UniqueCameraModel + "UniqueCameraModel", 0xC614u, ASCII, IFD_0, @@ -571,6 +689,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // LocalizedCameraModel + "LocalizedCameraModel", 0xC615u, ASCII, IFD_0, @@ -578,6 +697,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CFAPlaneColor + "CFAPlaneColor", 0xC616u, BYTE, RAW_IFD, @@ -585,6 +705,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CFALayout + "CFALayout", 0xC617u, SHORT, RAW_IFD, @@ -592,6 +713,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // LinearizationTable + "LinearizationTable", 0xC618u, SHORT, RAW_IFD, @@ -599,6 +721,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BlackLevelRepeatDim + "BlackLevelRepeatDim", 0xC619u, SHORT, RAW_IFD, @@ -606,6 +729,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BlackLevel + "BlackLevel", 0xC61Au, LONG, RAW_IFD, @@ -613,6 +737,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BlackLevelDeltaH + "BlackLevelDeltaH", 0xC61Bu, SRATIONAL, RAW_IFD, @@ -620,6 +745,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BlackLevelDeltaV + "BlackLevelDeltaV", 0xC61Cu, SRATIONAL, RAW_IFD, @@ -627,6 +753,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // WhiteLevel + "WhiteLevel", 0xC61Du, LONG, RAW_IFD, @@ -634,6 +761,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DefaultScale + "DefaultScale", 0xC61Eu, RATIONAL, RAW_IFD, @@ -641,6 +769,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BestQualityScale + "BestQualityScale", 0xC65Cu, RATIONAL, RAW_IFD, @@ -648,6 +777,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DefaultCropOrigin + "DefaultCropOrigin", 0xC61Fu, LONG, RAW_IFD, @@ -655,6 +785,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DefaultCropSize + "DefaultCropSize", 0xC620u, LONG, RAW_IFD, @@ -662,6 +793,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CalibrationIlluminant1 + "CalibrationIlluminant1", 0xC65Au, SHORT, PROFILE_IFD, @@ -669,6 +801,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CalibrationIlluminant2 + "CalibrationIlluminant2", 0xC65Bu, SHORT, PROFILE_IFD, @@ -676,6 +809,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ColorMatrix1 + "ColorMatrix1", 0xC621u, SRATIONAL, PROFILE_IFD, @@ -683,6 +817,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ColorMatrix2 + "ColorMatrix2", 0xC622u, SRATIONAL, PROFILE_IFD, @@ -690,6 +825,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CameraCalibration1 + "CameraCalibration1", 0xC623u, SRATIONAL, IFD_0, @@ -697,6 +833,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CameraCalibration2 + "CameraCalibration2", 0xC624u, SRATIONAL, IFD_0, @@ -704,6 +841,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ReductionMatrix1 + "ReductionMatrix1", 0xC625u, SRATIONAL, PROFILE_IFD, @@ -711,6 +849,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ReductionMatrix2 + "ReductionMatrix2", 0xC626u, SRATIONAL, PROFILE_IFD, @@ -718,6 +857,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AnalogBalance + "AnalogBalance", 0xC627u, RATIONAL, IFD_0, @@ -725,6 +865,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AsShotNeutral + "AsShotNeutral", 0xC628u, RATIONAL, IFD_0, @@ -732,6 +873,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AsShotWhiteXY + "AsShotWhiteXY", 0xC629u, RATIONAL, IFD_0, @@ -739,6 +881,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BaselineExposure + "BaselineExposure", 0xC62Au, SRATIONAL, IFD_0, @@ -746,6 +889,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BaselineNoise + "BaselineNoise", 0xC62Bu, RATIONAL, IFD_0, @@ -753,6 +897,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BaselineSharpness + "BaselineSharpness", 0xC62Cu, RATIONAL, IFD_0, @@ -760,6 +905,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BayerGreenSplit + "BayerGreenSplit", 0xC62Du, LONG, RAW_IFD, @@ -767,6 +913,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // LinearResponseLimit + "LinearResponseLimit", 0xC62Eu, RATIONAL, IFD_0, @@ -774,6 +921,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CameraSerialNumber + "CameraSerialNumber", 0xC62Fu, ASCII, IFD_0, @@ -781,6 +929,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // LensInfo + "LensInfo", 0xC630u, RATIONAL, IFD_0, @@ -788,6 +937,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ChromaBlurRadius + "ChromaBlurRadius", 0xC631u, RATIONAL, RAW_IFD, @@ -795,6 +945,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AntiAliasStrength + "AntiAliasStrength", 0xC632u, RATIONAL, RAW_IFD, @@ -802,6 +953,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ShadowScale + "ShadowScale", 0xC633u, RATIONAL, IFD_0, @@ -809,6 +961,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DNGPrivateData + "DNGPrivateData", 0xC634u, BYTE, IFD_0, @@ -816,6 +969,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // MakerNoteSafety + "MakerNoteSafety", 0xC635u, SHORT, IFD_0, @@ -823,6 +977,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // RawDataUniqueID + "RawDataUniqueID", 0xC65Du, BYTE, IFD_0, @@ -830,6 +985,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalRawFileName + "OriginalRawFileName", 0xC68Bu, ASCII, IFD_0, @@ -837,6 +993,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalRawFileData + "OriginalRawFileData", 0xC68Cu, UNDEFINED, IFD_0, @@ -844,6 +1001,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { BIG }, { // ActiveArea + "ActiveArea", 0xC68Du, LONG, RAW_IFD, @@ -851,6 +1009,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // MaskedAreas + "MaskedAreas", 0xC68Eu, LONG, RAW_IFD, @@ -858,6 +1017,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AsShotICCProfile + "AsShotICCProfile", 0xC68Fu, UNDEFINED, IFD_0, @@ -865,6 +1025,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AsShotPreProfileMatrix + "AsShotPreProfileMatrix", 0xC690u, SRATIONAL, IFD_0, @@ -872,6 +1033,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CurrentICCProfile + "CurrentICCProfile", 0xC691u, UNDEFINED, IFD_0, @@ -879,6 +1041,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CurrentICCProfile + "CurrentICCProfile", 0xC691u, UNDEFINED, IFD_0, @@ -886,6 +1049,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CurrentPreProfileMatrix + "CurrentPreProfileMatrix", 0xC692u, SRATIONAL, IFD_0, @@ -893,6 +1057,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ColorimetricReference + "ColorimetricReference", 0xC6BFu, SHORT, IFD_0, @@ -900,6 +1065,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // CameraCalibrationSignature + "CameraCalibrationSignature", 0xC6F3u, ASCII, IFD_0, @@ -907,6 +1073,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileCalibrationSignature + "ProfileCalibrationSignature", 0xC6F4u, ASCII, PROFILE_IFD, @@ -914,6 +1081,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ExtraCameraProfiles + "ExtraCameraProfiles", 0xC6F5u, LONG, IFD_0, @@ -921,6 +1089,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // AsShotProfileName + "AsShotProfileName", 0xC6F6u, ASCII, IFD_0, @@ -928,6 +1097,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // NoiseReductionApplied + "NoiseReductionApplied", 0xC6F7u, RATIONAL, RAW_IFD, @@ -935,6 +1105,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileName + "ProfileName", 0xC6F8u, ASCII, PROFILE_IFD, @@ -942,6 +1113,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileHueSatMapDims + "ProfileHueSatMapDims", 0xC6F9u, LONG, PROFILE_IFD, @@ -949,6 +1121,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileHueSatMapData1 + "ProfileHueSatMapData1", 0xC6FAu, FLOAT, PROFILE_IFD, @@ -956,6 +1129,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileHueSatMapData2 + "ProfileHueSatMapData2", 0xC6FBu, FLOAT, PROFILE_IFD, @@ -963,6 +1137,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileToneCurve + "ProfileToneCurve", 0xC6FCu, FLOAT, PROFILE_IFD, @@ -970,6 +1145,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileEmbedPolicy + "ProfileEmbedPolicy", 0xC6FDu, LONG, PROFILE_IFD, @@ -977,6 +1153,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileCopyright + "ProfileCopyright", 0xC6FEu, ASCII, PROFILE_IFD, @@ -984,6 +1161,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ForwardMatrix1 + "ForwardMatrix1", 0xC714u, SRATIONAL, PROFILE_IFD, @@ -991,6 +1169,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ForwardMatrix2 + "ForwardMatrix2", 0xC715u, SRATIONAL, PROFILE_IFD, @@ -998,6 +1177,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewApplicationName + "PreviewApplicationName", 0xC716u, ASCII, PREVIEW_IFD, @@ -1005,6 +1185,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewApplicationVersion + "PreviewApplicationVersion", 0xC717u, ASCII, PREVIEW_IFD, @@ -1012,6 +1193,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewSettingsName + "PreviewSettingsName", 0xC718u, ASCII, PREVIEW_IFD, @@ -1019,6 +1201,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewSettingsDigest + "PreviewSettingsDigest", 0xC719u, BYTE, PREVIEW_IFD, @@ -1026,6 +1209,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewColorSpace + "PreviewColorSpace", 0xC71Au, LONG, PREVIEW_IFD, @@ -1033,6 +1217,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // PreviewDateTime + "PreviewDateTime", 0xC71Bu, ASCII, PREVIEW_IFD, @@ -1040,6 +1225,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // RawImageDigest + "RawImageDigest", 0xC71Cu, BYTE, IFD_0, @@ -1047,6 +1233,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalRawFileDigest + "OriginalRawFileDigest", 0xC71Du, BYTE, IFD_0, @@ -1054,6 +1241,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // SubTileBlockSize + "SubTileBlockSize", 0xC71Eu, LONG, RAW_IFD, @@ -1061,6 +1249,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // RowInterleaveFactor + "RowInterleaveFactor", 0xC71Fu, LONG, RAW_IFD, @@ -1068,6 +1257,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileLookTableDims + "ProfileLookTableDims", 0xC725u, LONG, PROFILE_IFD, @@ -1075,6 +1265,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileLookTableData + "ProfileLookTableData", 0xC726u, FLOAT, PROFILE_IFD, @@ -1082,6 +1273,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OpcodeList1 + "OpcodeList1", 0xC740u, UNDEFINED, RAW_IFD, @@ -1089,6 +1281,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { BIG }, { // OpcodeList2 + "OpcodeList2", 0xC741u, UNDEFINED, RAW_IFD, @@ -1096,6 +1289,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { BIG }, { // OpcodeList3 + "OpcodeList3", 0xC74Eu, UNDEFINED, RAW_IFD, @@ -1103,6 +1297,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { BIG }, { // NoiseProfile + "NoiseProfile", 0xC761u, DOUBLE, RAW_IFD, @@ -1110,6 +1305,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DefaultUserCrop + "DefaultUserCrop", 0xC7B5u, RATIONAL, RAW_IFD, @@ -1117,6 +1313,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // DefaultBlackRender + "DefaultBlackRender", 0xC7A6u, LONG, PROFILE_IFD, @@ -1124,6 +1321,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // BaselineExposureOffset + "BaselineExposureOffset", 0xC7A5u, RATIONAL, PROFILE_IFD, @@ -1131,6 +1329,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileLookTableEncoding + "ProfileLookTableEncoding", 0xC7A4u, LONG, PROFILE_IFD, @@ -1138,6 +1337,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // ProfileHueSatMapEncoding + "ProfileHueSatMapEncoding", 0xC7A3u, LONG, PROFILE_IFD, @@ -1145,6 +1345,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalDefaultFinalSize + "OriginalDefaultFinalSize", 0xC791u, LONG, IFD_0, @@ -1152,6 +1353,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalBestQualityFinalSize + "OriginalBestQualityFinalSize", 0xC792u, LONG, IFD_0, @@ -1159,6 +1361,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // OriginalDefaultCropSize + "OriginalDefaultCropSize", 0xC793u, LONG, IFD_0, @@ -1166,6 +1369,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // NewRawImageDigest + "NewRawImageDigest", 0xC7A7u, BYTE, IFD_0, @@ -1173,6 +1377,7 @@ const TagDefinition_t DNG_TAG_DEFINITIONS[] = { UNDEFINED_ENDIAN }, { // RawToPreviewGain + "RawToPreviewGain", 0xC7A8u, DOUBLE, PREVIEW_IFD, diff --git a/media/img_utils/include/img_utils/TiffEntry.h b/media/img_utils/include/img_utils/TiffEntry.h index cd01640..4d672b2 100644 --- a/media/img_utils/include/img_utils/TiffEntry.h +++ b/media/img_utils/include/img_utils/TiffEntry.h @@ -34,10 +34,11 @@ inline bool operator op (const TiffEntry& entry) const; /** * This class holds a single TIFF IFD entry. + * + * Subclasses are expected to support assignment and copying operations. */ class ANDROID_API TiffEntry : public TiffWritable { public: - // TODO: Copy constructor/equals here. virtual ~TiffEntry(); /** @@ -83,7 +84,7 @@ class ANDROID_API TiffEntry : public TiffWritable { template const T* getData() const; - String8 toString() const; + virtual String8 toString() const; /** * Force the type used here to be a valid TIFF type. @@ -99,10 +100,10 @@ class ANDROID_API TiffEntry : public TiffWritable { COMPARE_DEF(>) COMPARE_DEF(<) - protected: - enum { - MAX_PRINT_STRING_LENGTH = 256 - }; + protected: + enum { + MAX_PRINT_STRING_LENGTH = 256 + }; }; #define COMPARE(op) \ diff --git a/media/img_utils/include/img_utils/TiffEntryImpl.h b/media/img_utils/include/img_utils/TiffEntryImpl.h index cbe0e9a..f5ccb5e 100644 --- a/media/img_utils/include/img_utils/TiffEntryImpl.h +++ b/media/img_utils/include/img_utils/TiffEntryImpl.h @@ -17,6 +17,7 @@ #ifndef IMG_UTILS_TIFF_ENTRY_IMPL #define IMG_UTILS_TIFF_ENTRY_IMPL +#include #include #include #include @@ -24,6 +25,8 @@ #include #include +#include +#include #include namespace android { @@ -32,7 +35,6 @@ namespace img_utils { template class TiffEntryImpl : public TiffEntry { public: - // TODO: Copy constructor/equals here. TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end, const T* data); virtual ~TiffEntryImpl(); @@ -54,7 +56,7 @@ class TiffEntryImpl : public TiffEntry { uint16_t mType; uint32_t mCount; Endianness mEnd; - T* mData; + Vector mData; }; @@ -63,18 +65,12 @@ TiffEntryImpl::TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endi const T* data) : mTag(tag), mType(static_cast(type)), mCount(count), mEnd(end) { count = (type == RATIONAL || type == SRATIONAL) ? count * 2 : count; - mData = new T[count](); - for (uint32_t i = 0; i < count; ++i) { - mData[i] = data[i]; - } + ssize_t index = mData.appendArray(data, count); + LOG_ALWAYS_FATAL_IF(index < 0, "%s: Could not allocate vector for data.", __FUNCTION__); } template -TiffEntryImpl::~TiffEntryImpl() { - if (mData) { - delete[] mData; - } -} +TiffEntryImpl::~TiffEntryImpl() {} template uint32_t TiffEntryImpl::getCount() const { @@ -93,7 +89,7 @@ TagType TiffEntryImpl::getType() const { template const void* TiffEntryImpl::getDataHelper() const { - return reinterpret_cast(mData); + return reinterpret_cast(mData.array()); } template @@ -144,7 +140,7 @@ status_t TiffEntryImpl::writeTagInfo(uint32_t offset, /*out*/EndianOutput* ou */ count <<= 1; } - BAIL_ON_FAIL(out->write(mData, 0, count), ret); + BAIL_ON_FAIL(out->write(mData.array(), 0, count), ret); ZERO_TILL_WORD(out, dataSize, ret); } return ret; @@ -171,7 +167,7 @@ status_t TiffEntryImpl::writeData(uint32_t offset, EndianOutput* out) const { count <<= 1; } - BAIL_ON_FAIL(out->write(mData, 0, count), ret); + BAIL_ON_FAIL(out->write(mData.array(), 0, count), ret); if (mEnd != UNDEFINED_ENDIAN) { out->setEndianness(tmp); @@ -182,6 +178,38 @@ status_t TiffEntryImpl::writeData(uint32_t offset, EndianOutput* out) const { return ret; } +template<> +inline status_t TiffEntryImpl >::writeTagInfo(uint32_t offset, + /*out*/EndianOutput* out) const { + assert((offset % TIFF_WORD_SIZE) == 0); + status_t ret = OK; + BAIL_ON_FAIL(out->write(&mTag, 0, 1), ret); + BAIL_ON_FAIL(out->write(&mType, 0, 1), ret); + BAIL_ON_FAIL(out->write(&mCount, 0, 1), ret); + + BAIL_ON_FAIL(out->write(&offset, 0, 1), ret); + return ret; +} + +template<> +inline uint32_t TiffEntryImpl >::getActualSize() const { + uint32_t total = 0; + for (size_t i = 0; i < mData.size(); ++i) { + total += mData[i]->getSize(); + } + return total; +} + +template<> +inline status_t TiffEntryImpl >::writeData(uint32_t offset, EndianOutput* out) const { + status_t ret = OK; + for (uint32_t i = 0; i < mCount; ++i) { + BAIL_ON_FAIL(mData[i]->writeData(offset, out), ret); + offset += mData[i]->getSize(); + } + return ret; +} + } /*namespace img_utils*/ } /*namespace android*/ diff --git a/media/img_utils/include/img_utils/TiffHelpers.h b/media/img_utils/include/img_utils/TiffHelpers.h index fd0ea7a..0969e4d 100644 --- a/media/img_utils/include/img_utils/TiffHelpers.h +++ b/media/img_utils/include/img_utils/TiffHelpers.h @@ -37,7 +37,7 @@ const uint8_t ZERO_WORD[] = {0, 0, 0, 0}; { \ size_t remaining = BYTES_TILL_WORD(index); \ if (remaining > 0) { \ - BAIL_ON_FAIL(output->write(ZERO_WORD, 0, remaining), ret); \ + BAIL_ON_FAIL((output)->write(ZERO_WORD, 0, remaining), ret); \ } \ } diff --git a/media/img_utils/include/img_utils/TiffIfd.h b/media/img_utils/include/img_utils/TiffIfd.h index 9400456..51b5c9a 100644 --- a/media/img_utils/include/img_utils/TiffIfd.h +++ b/media/img_utils/include/img_utils/TiffIfd.h @@ -42,7 +42,6 @@ namespace img_utils { */ class ANDROID_API TiffIfd : public TiffWritable { public: - // TODO: Copy constructor/equals here - needed for SubIfds. TiffIfd(uint32_t ifdId); virtual ~TiffIfd(); @@ -98,9 +97,50 @@ class ANDROID_API TiffIfd : public TiffWritable { virtual sp getEntry(uint16_t tag) const; /** + * Remove the entry with the given tag ID if it exists. + */ + virtual void removeEntry(uint16_t tag); + + /** + * Convenience method to validate and set strip-related image tags. + * + * This sets all strip related tags, but leaves offset values unitialized. + * setStripOffsets must be called with the desired offset before writing. + * The strip tag values are calculated from the existing tags for image + * dimensions and pixel type set in the IFD. + * + * Does not handle planar image configurations (PlanarConfiguration != 1). + * + * Returns OK on success, or a negative error code. + */ + virtual status_t validateAndSetStripTags(); + + /** + * Returns true if validateAndSetStripTags has been called, but not setStripOffsets. + */ + virtual bool uninitializedOffsets() const; + + /** + * Convenience method to set beginning offset for strips. + * + * Call this to update the strip offsets before calling writeData. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t setStripOffset(uint32_t offset); + + /** + * Get the total size of the strips in bytes. + * + * This sums the byte count at each strip offset, and returns + * the total count of bytes stored in strips for this IFD. + */ + virtual uint32_t getStripSize() const; + + /** * Get a formatted string representing this IFD. */ - String8 toString() const; + virtual String8 toString() const; /** * Print a formatted string representing this IFD to logcat. @@ -111,11 +151,13 @@ class ANDROID_API TiffIfd : public TiffWritable { * Get value used to determine sort order. */ virtual uint32_t getComparableValue() const; + protected: virtual uint32_t checkAndGetOffset(uint32_t offset) const; SortedEntryVector mEntries; sp mNextIfd; uint32_t mIfdId; + bool mStripOffsetsInitialized; }; } /*namespace img_utils*/ diff --git a/media/img_utils/include/img_utils/TiffWriter.h b/media/img_utils/include/img_utils/TiffWriter.h index ec27fc3..b7af239 100644 --- a/media/img_utils/include/img_utils/TiffWriter.h +++ b/media/img_utils/include/img_utils/TiffWriter.h @@ -18,8 +18,10 @@ #define IMG_UTILS_TIFF_WRITER_H #include +#include #include #include +#include #include #include @@ -48,6 +50,10 @@ class Output; */ class ANDROID_API TiffWriter : public LightRefBase { public: + enum SubIfdType { + SUBIFD = 0, + GPSINFO + }; /** * Constructs a TiffWriter with the default tag mappings. This enables @@ -77,6 +83,25 @@ class ANDROID_API TiffWriter : public LightRefBase { * Write a TIFF header containing each IFD set. This will recursively * write all SubIFDs and tags. * + * Any StripSources passed in will be written to the output as image strips + * at the appropriate offests. The StripByteCounts, RowsPerStrip, and + * StripOffsets tags must be set to use this. To set these tags in a + * given IFD, use the addStrip method. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t write(Output* out, StripSource** sources, size_t sourcesCount, + Endianness end = LITTLE); + + /** + * Write a TIFF header containing each IFD set. This will recursively + * write all SubIFDs and tags. + * + * Image data for strips or tiles must be written separately at the + * appropriate offsets. These offsets must not fall within the file + * header written this way. The size of the header written is given + * by the getTotalSize() method. + * * Returns OK on success, or a negative error code on failure. */ virtual status_t write(Output* out, Endianness end = LITTLE); @@ -88,16 +113,7 @@ class ANDROID_API TiffWriter : public LightRefBase { virtual uint32_t getTotalSize() const; /** - * Add the given entry to its default IFD. If that IFD does not - * exist, it will be created. - */ - virtual status_t addEntry(const sp& entry); - - /** - * Build an entry for a known tag. This tag must be one of the tags - * defined in one of the definition vectors this TIFF writer was constructed - * with. The count and type are validated. If this succeeds, the resulting - * entry will be placed in the outEntry pointer. + * Add an entry to the IFD with the given ID. * * Returns OK on success, or a negative error code on failure. Valid * error codes for this method are: @@ -106,16 +122,14 @@ class ANDROID_API TiffWriter : public LightRefBase { * this tag. * - BAD_TYPE - The type of the given data isn't compatible with the * type required for this tag. + * - NAME_NOT_FOUND - No ifd exists with the given ID. */ - template - status_t buildEntry(uint16_t tag, uint32_t count, const T* data, - /*out*/sp* outEntry) const; + virtual status_t addEntry(const sp& entry, uint32_t ifd); - /** + /** * Build an entry for a known tag and add it to the IFD with the given ID. * This tag must be defined in one of the definition vectors this TIFF writer - * was constructed with. The count and type are validated. If this succeeds, - * the resulting entry will be placed in the outEntry pointer. + * was constructed with. The count and type are validated. * * Returns OK on success, or a negative error code on failure. Valid * error codes for this method are: @@ -130,18 +144,47 @@ class ANDROID_API TiffWriter : public LightRefBase { status_t addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd); /** + * Build an entry for a known tag. This tag must be one of the tags + * defined in one of the definition vectors this TIFF writer was constructed + * with. The count and type are validated. If this succeeds, the resulting + * entry will be placed in the outEntry pointer. + * + * Returns OK on success, or a negative error code on failure. Valid + * error codes for this method are: + * - BAD_INDEX - The given tag doesn't exist. + * - BAD_VALUE - The given count doesn't match the required count for + * this tag. + * - BAD_TYPE - The type of the given data isn't compatible with the + * type required for this tag. + */ + template + status_t buildEntry(uint16_t tag, uint32_t count, const T* data, + /*out*/sp* outEntry) const; + + /** + * Convenience function to set the strip related tags for a given IFD. + * + * Call this before using a StripSource as an input to write. + * The following tags must be set before calling this method: + * - ImageWidth + * - ImageLength + * - SamplesPerPixel + * - BitsPerSample + * + * Returns OK on success, or a negative error code. + */ + virtual status_t addStrip(uint32_t ifd); + + /** * Return the TIFF entry with the given tag ID in the IFD with the given ID, * or an empty pointer if none exists. */ virtual sp getEntry(uint16_t tag, uint32_t ifd) const; /** - * Add the given IFD to the end of the top-level IFD chain. No - * validation is done. - * - * Returns OK on success, or a negative error code on failure. + * Remove the TIFF entry with the given tag ID in the given IFD if it exists. */ - virtual status_t uncheckedAddIfd(const sp& ifd); + virtual void removeEntry(uint16_t tag, uint32_t ifd); /** * Create an empty IFD with the given ID and add it to the end of the @@ -150,24 +193,10 @@ class ANDROID_API TiffWriter : public LightRefBase { virtual status_t addIfd(uint32_t ifd); /** - * Build an entry. No validation is done. - * - * WARNING: Using this method can result in creating poorly formatted - * TIFF files. - * - * Returns a TiffEntry with the given tag, type, count, endianness, - * and data. + * Create an empty IFD with the given ID and add it as a SubIfd of the + * parent IFD. */ - template - static sp uncheckedBuildEntry(uint16_t tag, TagType type, - uint32_t count, Endianness end, const T* data); - - /** - * Utility function to build atag-to-definition mapping from a given - * array of tag definitions. - */ - static KeyedVector buildTagMap( - const TagDefinition_t* definitions, size_t length); + virtual status_t addSubIfd(uint32_t parentIfd, uint32_t ifd, SubIfdType type = SUBIFD); /** * Returns the default type for the given tag ID. @@ -181,15 +210,46 @@ class ANDROID_API TiffWriter : public LightRefBase { virtual uint32_t getDefaultCount(uint16_t tag) const; /** + * Returns true if an IFD with the given ID exists. + */ + virtual bool hasIfd(uint32_t ifd) const; + + /** * Returns true if a definition exist for the given tag ID. */ virtual bool checkIfDefined(uint16_t tag) const; /** + * Returns the name of the tag if a definition exists for the given tag + * ID, or null if no definition exists. + */ + virtual const char* getTagName(uint16_t tag) const; + + /** * Print the currently configured IFDs and entries to logcat. */ virtual void log() const; + /** + * Build an entry. No validation is done. + * + * WARNING: Using this method can result in creating poorly formatted + * TIFF files. + * + * Returns a TiffEntry with the given tag, type, count, endianness, + * and data. + */ + template + static sp uncheckedBuildEntry(uint16_t tag, TagType type, + uint32_t count, Endianness end, const T* data); + + /** + * Utility function to build atag-to-definition mapping from a given + * array of tag definitions. + */ + static KeyedVector buildTagMap( + const TagDefinition_t* definitions, size_t length); + protected: enum { DEFAULT_NUM_TAG_MAPS = 4, @@ -240,17 +300,14 @@ status_t TiffWriter::buildEntry(uint16_t tag, uint32_t count, const T* data, template status_t TiffWriter::addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd) { sp outEntry; + status_t ret = buildEntry(tag, count, data, &outEntry); if (ret != OK) { ALOGE("%s: Could not build entry for tag %x.", __FUNCTION__, tag); return ret; } - ssize_t index = mNamedIfds.indexOfKey(ifd); - if (index < 0) { - ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd); - return NAME_NOT_FOUND; - } - return mNamedIfds[index]->addEntry(outEntry); + + return addEntry(outEntry, ifd); } template diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk index 80893be..4074849 100644 --- a/media/img_utils/src/Android.mk +++ b/media/img_utils/src/Android.mk @@ -31,6 +31,7 @@ LOCAL_SRC_FILES := \ TiffEntryImpl.cpp \ ByteArrayOutput.cpp \ DngUtils.cpp \ + StripSource.cpp \ LOCAL_SHARED_LIBRARIES := \ libexpat \ diff --git a/media/img_utils/src/FileInput.cpp b/media/img_utils/src/FileInput.cpp index e43fd53..498e715 100644 --- a/media/img_utils/src/FileInput.cpp +++ b/media/img_utils/src/FileInput.cpp @@ -45,19 +45,24 @@ status_t FileInput::open() { return OK; } -size_t FileInput::read(uint8_t* buf, size_t offset, size_t count, status_t* err) { +ssize_t FileInput::read(uint8_t* buf, size_t offset, size_t count) { if (!mOpen) { ALOGE("%s: Could not read file %s, file not open.", __FUNCTION__, mPath.string()); - if (err != NULL) *err = BAD_VALUE; - return 0; + return BAD_VALUE; } size_t bytesRead = ::fread(buf + offset, sizeof(uint8_t), count, mFp); int error = ::ferror(mFp); if (error != 0) { ALOGE("%s: Error %d occurred while reading file %s.", __FUNCTION__, error, mPath.string()); - if (err != NULL) *err = BAD_VALUE; + return BAD_VALUE; } + + // End of file reached + if (::feof(mFp) != 0 && bytesRead == 0) { + return NOT_ENOUGH_DATA; + } + return bytesRead; } diff --git a/media/img_utils/src/Input.cpp b/media/img_utils/src/Input.cpp index 1e51e10..3782014 100644 --- a/media/img_utils/src/Input.cpp +++ b/media/img_utils/src/Input.cpp @@ -20,9 +20,37 @@ namespace android { namespace img_utils { Input::~Input() {} + status_t Input::open() { return OK; } + status_t Input::close() { return OK; } +ssize_t Input::skip(size_t count) { + const size_t SKIP_BUF_SIZE = 1024; + uint8_t skipBuf[SKIP_BUF_SIZE]; + + size_t remaining = count; + while (remaining > 0) { + size_t amt = (SKIP_BUF_SIZE > remaining) ? remaining : SKIP_BUF_SIZE; + ssize_t ret = read(skipBuf, 0, amt); + if (ret < 0) { + if(ret == NOT_ENOUGH_DATA) { + // End of file encountered + if (remaining == count) { + // Read no bytes, return EOF + return NOT_ENOUGH_DATA; + } else { + // Return num bytes read + return count - remaining; + } + } + // Return error code. + return ret; + } + remaining -= ret; + } + return count; +} } /*namespace img_utils*/ } /*namespace android*/ diff --git a/media/img_utils/src/StripSource.cpp b/media/img_utils/src/StripSource.cpp new file mode 100644 index 0000000..57b6082 --- /dev/null +++ b/media/img_utils/src/StripSource.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace android { +namespace img_utils { + +StripSource::~StripSource() {} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffEntry.cpp b/media/img_utils/src/TiffEntry.cpp index e028827..9cea721 100644 --- a/media/img_utils/src/TiffEntry.cpp +++ b/media/img_utils/src/TiffEntry.cpp @@ -32,16 +32,6 @@ TiffEntry::~TiffEntry() {} * * Values with types other than the ones given here should not compile. */ -template<> -const Vector >* TiffEntry::forceValidType > >(TagType type, - const Vector >* value) { - if (type == LONG) { - return value; - } - ALOGE("%s: Value of type 'ifd vector' is not valid for tag with TIFF type %d.", - __FUNCTION__, type); - return NULL; -} template<> const sp* TiffEntry::forceValidType >(TagType type, const sp* value) { diff --git a/media/img_utils/src/TiffEntryImpl.cpp b/media/img_utils/src/TiffEntryImpl.cpp index 6efa458..257c266 100644 --- a/media/img_utils/src/TiffEntryImpl.cpp +++ b/media/img_utils/src/TiffEntryImpl.cpp @@ -15,30 +15,11 @@ */ #include -#include #include namespace android { namespace img_utils { -template<> -size_t TiffEntryImpl::getSize() const { - uint32_t total = 0; - for (uint32_t i = 0; i < mCount; ++i) { - total += mData[i].getSize(); - } - return total; -} - -template<> -status_t TiffEntryImpl::writeData(uint32_t offset, EndianOutput* out) const { - status_t ret = OK; - for (uint32_t i = 0; i < mCount; ++i) { - BAIL_ON_FAIL(mData[i].writeData(offset, out), ret); - } - return ret; -} - } /*namespace img_utils*/ } /*namespace android*/ diff --git a/media/img_utils/src/TiffIfd.cpp b/media/img_utils/src/TiffIfd.cpp index 1b3b40d..3fb00cc 100644 --- a/media/img_utils/src/TiffIfd.cpp +++ b/media/img_utils/src/TiffIfd.cpp @@ -14,8 +14,12 @@ * limitations under the License. */ -#include +#define LOG_TAG "TiffIfd" + +#include #include +#include +#include #include @@ -23,7 +27,7 @@ namespace android { namespace img_utils { TiffIfd::TiffIfd(uint32_t ifdId) - : mNextIfd(), mIfdId(ifdId) {} + : mNextIfd(), mIfdId(ifdId), mStripOffsetsInitialized(false) {} TiffIfd::~TiffIfd() {} @@ -52,6 +56,14 @@ sp TiffIfd::getEntry(uint16_t tag) const { return mEntries[index]; } +void TiffIfd::removeEntry(uint16_t tag) { + ssize_t index = mEntries.indexOfTag(tag); + if (index >= 0) { + mEntries.removeAt(index); + } +} + + void TiffIfd::setNextIfd(const sp& ifd) { mNextIfd = ifd; } @@ -156,6 +168,198 @@ uint32_t TiffIfd::getComparableValue() const { return mIfdId; } +status_t TiffIfd::validateAndSetStripTags() { + sp widthEntry = getEntry(TAG_IMAGEWIDTH); + if (widthEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a ImageWidth tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp heightEntry = getEntry(TAG_IMAGELENGTH); + if (heightEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a ImageLength tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp samplesEntry = getEntry(TAG_SAMPLESPERPIXEL); + if (samplesEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a SamplesPerPixel tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp bitsEntry = getEntry(TAG_BITSPERSAMPLE); + if (bitsEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a BitsPerSample tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + uint32_t width = *(widthEntry->getData()); + uint32_t height = *(heightEntry->getData()); + uint16_t bitsPerSample = *(bitsEntry->getData()); + uint16_t samplesPerPixel = *(samplesEntry->getData()); + + if ((bitsPerSample % 8) != 0) { + ALOGE("%s: BitsPerSample %d in IFD %u is not byte-aligned.", __FUNCTION__, + bitsPerSample, mIfdId); + return BAD_VALUE; + } + + uint32_t bytesPerSample = bitsPerSample / 8; + + // Choose strip size as close to 8kb as possible without splitting rows. + // If the row length is >8kb, each strip will only contain a single row. + const uint32_t rowLengthBytes = bytesPerSample * samplesPerPixel * width; + const uint32_t idealChunkSize = (1 << 13); // 8kb + uint32_t rowsPerChunk = idealChunkSize / rowLengthBytes; + rowsPerChunk = (rowsPerChunk == 0) ? 1 : rowsPerChunk; + const uint32_t actualChunkSize = rowLengthBytes * rowsPerChunk; + + const uint32_t lastChunkRows = height % rowsPerChunk; + const uint32_t lastChunkSize = lastChunkRows * rowLengthBytes; + + if (actualChunkSize > /*max strip size for TIFF/EP*/65536) { + ALOGE("%s: Strip length too long.", __FUNCTION__); + return BAD_VALUE; + } + + size_t numStrips = height / rowsPerChunk; + + // Add another strip for the incomplete chunk. + if (lastChunkRows > 0) { + numStrips += 1; + } + + // Put each row in it's own strip + uint32_t rowsPerStripVal = rowsPerChunk; + sp rowsPerStrip = TiffWriter::uncheckedBuildEntry(TAG_ROWSPERSTRIP, LONG, 1, + UNDEFINED_ENDIAN, &rowsPerStripVal); + + if (rowsPerStrip == NULL) { + ALOGE("%s: Could not build entry for RowsPerStrip tag.", __FUNCTION__); + return BAD_VALUE; + } + + Vector byteCounts; + + for (size_t i = 0; i < numStrips; ++i) { + if (lastChunkRows > 0 && i == (numStrips - 1)) { + byteCounts.add(lastChunkSize); + } else { + byteCounts.add(actualChunkSize); + } + } + + // Set byte counts for each strip + sp stripByteCounts = TiffWriter::uncheckedBuildEntry(TAG_STRIPBYTECOUNTS, LONG, + static_cast(numStrips), UNDEFINED_ENDIAN, byteCounts.array()); + + if (stripByteCounts == NULL) { + ALOGE("%s: Could not build entry for StripByteCounts tag.", __FUNCTION__); + return BAD_VALUE; + } + + Vector stripOffsetsVector; + stripOffsetsVector.resize(numStrips); + + // Set uninitialized offsets + sp stripOffsets = TiffWriter::uncheckedBuildEntry(TAG_STRIPOFFSETS, LONG, + static_cast(numStrips), UNDEFINED_ENDIAN, stripOffsetsVector.array()); + + if (stripOffsets == NULL) { + ALOGE("%s: Could not build entry for StripOffsets tag.", __FUNCTION__); + return BAD_VALUE; + } + + if(addEntry(stripByteCounts) != OK) { + ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + if(addEntry(rowsPerStrip) != OK) { + ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + if(addEntry(stripOffsets) != OK) { + ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + mStripOffsetsInitialized = true; + return OK; +} + +bool TiffIfd::uninitializedOffsets() const { + return mStripOffsetsInitialized; +} + +status_t TiffIfd::setStripOffset(uint32_t offset) { + + // Get old offsets and bytecounts + sp oldOffsets = getEntry(TAG_STRIPOFFSETS); + if (oldOffsets == NULL) { + ALOGE("%s: IFD %u does not contain StripOffsets entry.", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp stripByteCounts = getEntry(TAG_STRIPBYTECOUNTS); + if (stripByteCounts == NULL) { + ALOGE("%s: IFD %u does not contain StripByteCounts entry.", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + uint32_t offsetsCount = oldOffsets->getCount(); + uint32_t byteCount = stripByteCounts->getCount(); + if (offsetsCount != byteCount) { + ALOGE("%s: StripOffsets count (%u) doesn't match StripByteCounts count (%u) in IFD %u", + __FUNCTION__, offsetsCount, byteCount, mIfdId); + return BAD_VALUE; + } + + const uint32_t* stripByteCountsArray = stripByteCounts->getData(); + + size_t numStrips = offsetsCount; + + Vector stripOffsets; + + // Calculate updated byte offsets + for (size_t i = 0; i < numStrips; ++i) { + stripOffsets.add(offset); + offset += stripByteCountsArray[i]; + } + + sp newOffsets = TiffWriter::uncheckedBuildEntry(TAG_STRIPOFFSETS, LONG, + static_cast(numStrips), UNDEFINED_ENDIAN, stripOffsets.array()); + + if (newOffsets == NULL) { + ALOGE("%s: Coult not build updated offsets entry in IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + if (addEntry(newOffsets) != OK) { + ALOGE("%s: Failed to add updated offsets entry in IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + return OK; +} + +uint32_t TiffIfd::getStripSize() const { + sp stripByteCounts = getEntry(TAG_STRIPBYTECOUNTS); + if (stripByteCounts == NULL) { + ALOGE("%s: IFD %u does not contain StripByteCounts entry.", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + uint32_t count = stripByteCounts->getCount(); + const uint32_t* byteCounts = stripByteCounts->getData(); + + uint32_t total = 0; + for (size_t i = 0; i < static_cast(count); ++i) { + total += byteCounts[i]; + } + return total; +} + String8 TiffIfd::toString() const { size_t s = mEntries.size(); String8 output; diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp index 2439033..d85289e 100644 --- a/media/img_utils/src/TiffWriter.cpp +++ b/media/img_utils/src/TiffWriter.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include +#define LOG_TAG "TiffWriter" + #include #include #include @@ -55,6 +56,82 @@ TiffWriter::TiffWriter(KeyedVector* enabledDef TiffWriter::~TiffWriter() {} +status_t TiffWriter::write(Output* out, StripSource** sources, size_t sourcesCount, + Endianness end) { + status_t ret = OK; + EndianOutput endOut(out, end); + + if (mIfd == NULL) { + ALOGE("%s: Tiff header is empty.", __FUNCTION__); + return BAD_VALUE; + } + + if (LOG_NDEBUG == 0) { + log(); + } + + uint32_t totalSize = getTotalSize(); + + KeyedVector offsetVector; + + for (size_t i = 0; i < mNamedIfds.size(); ++i) { + if (mNamedIfds[i]->uninitializedOffsets()) { + uint32_t stripSize = mNamedIfds[i]->getStripSize(); + if (mNamedIfds[i]->setStripOffset(totalSize) != OK) { + ALOGE("%s: Could not set strip offsets.", __FUNCTION__); + return BAD_VALUE; + } + totalSize += stripSize; + WORD_ALIGN(totalSize); + offsetVector.add(mNamedIfds.keyAt(i), totalSize); + } + } + + size_t offVecSize = offsetVector.size(); + if (offVecSize != sourcesCount) { + ALOGE("%s: Mismatch between number of IFDs with uninitialized strips (%zu) and" + " sources (%zu).", __FUNCTION__, offVecSize, sourcesCount); + return BAD_VALUE; + } + + BAIL_ON_FAIL(writeFileHeader(endOut), ret); + + uint32_t offset = FILE_HEADER_SIZE; + sp ifd = mIfd; + while(ifd != NULL) { + BAIL_ON_FAIL(ifd->writeData(offset, &endOut), ret); + offset += ifd->getSize(); + ifd = ifd->getNextIfd(); + } + + log(); + + for (size_t i = 0; i < offVecSize; ++i) { + uint32_t ifdKey = offsetVector.keyAt(i); + uint32_t nextOffset = offsetVector[i]; + uint32_t sizeToWrite = mNamedIfds[ifdKey]->getStripSize(); + bool found = false; + for (size_t j = 0; j < sourcesCount; ++j) { + if (sources[j]->getIfd() == ifdKey) { + if ((ret = sources[i]->writeToStream(endOut, sizeToWrite)) != OK) { + ALOGE("%s: Could not write to stream, received %d.", __FUNCTION__, ret); + return ret; + } + ZERO_TILL_WORD(&endOut, sizeToWrite, ret); + found = true; + break; + } + } + if (!found) { + ALOGE("%s: No stream for byte strips for IFD %u", __FUNCTION__, ifdKey); + return BAD_VALUE; + } + assert(nextOffset == endOut.getCurrentOffset()); + } + + return ret; +} + status_t TiffWriter::write(Output* out, Endianness end) { status_t ret = OK; EndianOutput endOut(out, end); @@ -101,48 +178,43 @@ sp TiffWriter::getEntry(uint16_t tag, uint32_t ifd) const { return mNamedIfds[index]->getEntry(tag); } +void TiffWriter::removeEntry(uint16_t tag, uint32_t ifd) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index >= 0) { + mNamedIfds[index]->removeEntry(tag); + } +} -// TODO: Fix this to handle IFD position in chain/sub-IFD tree -status_t TiffWriter::addEntry(const sp& entry) { +status_t TiffWriter::addEntry(const sp& entry, uint32_t ifd) { uint16_t tag = entry->getTag(); const TagDefinition_t* definition = lookupDefinition(tag); if (definition == NULL) { + ALOGE("%s: No definition exists for tag 0x%x.", __FUNCTION__, tag); return BAD_INDEX; } - uint32_t ifdId = 0; // TODO: all in IFD0 for now. - ssize_t index = mNamedIfds.indexOfKey(ifdId); + ssize_t index = mNamedIfds.indexOfKey(ifd); // Add a new IFD if necessary if (index < 0) { - sp ifdEntry = new TiffIfd(ifdId); - if (mIfd == NULL) { - mIfd = ifdEntry; - } - index = mNamedIfds.add(ifdId, ifdEntry); - assert(index >= 0); + ALOGE("%s: No IFD %u exists.", __FUNCTION__, ifd); + return NAME_NOT_FOUND; } sp selectedIfd = mNamedIfds[index]; return selectedIfd->addEntry(entry); } -status_t TiffWriter::uncheckedAddIfd(const sp& ifd) { - mNamedIfds.add(ifd->getId(), ifd); - sp last = findLastIfd(); - if (last == NULL) { - mIfd = ifd; - } else { - last->setNextIfd(ifd); - } - last = ifd->getNextIfd(); - while (last != NULL) { - mNamedIfds.add(last->getId(), last); - last = last->getNextIfd(); +status_t TiffWriter::addStrip(uint32_t ifd) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index < 0) { + ALOGE("%s: Ifd %u doesn't exist, cannot add strip entries.", __FUNCTION__, ifd); + return BAD_VALUE; } - return OK; + sp selected = mNamedIfds[index]; + return selected->validateAndSetStripTags(); } status_t TiffWriter::addIfd(uint32_t ifd) { @@ -151,6 +223,7 @@ status_t TiffWriter::addIfd(uint32_t ifd) { ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd); return BAD_VALUE; } + sp newIfd = new TiffIfd(ifd); if (mIfd == NULL) { mIfd = newIfd; @@ -158,7 +231,83 @@ status_t TiffWriter::addIfd(uint32_t ifd) { sp last = findLastIfd(); last->setNextIfd(newIfd); } - mNamedIfds.add(ifd, newIfd); + + if(mNamedIfds.add(ifd, newIfd) < 0) { + ALOGE("%s: Failed to add new IFD 0x%x.", __FUNCTION__, ifd); + return BAD_VALUE; + } + + return OK; +} + +status_t TiffWriter::addSubIfd(uint32_t parentIfd, uint32_t ifd, SubIfdType type) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index >= 0) { + ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd); + return BAD_VALUE; + } + + ssize_t parentIndex = mNamedIfds.indexOfKey(parentIfd); + if (parentIndex < 0) { + ALOGE("%s: Parent IFD with ID 0x%x does not exist.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + sp parent = mNamedIfds[parentIndex]; + sp newIfd = new TiffIfd(ifd); + + uint16_t subIfdTag; + if (type == SUBIFD) { + subIfdTag = TAG_SUBIFDS; + } else if (type == GPSINFO) { + subIfdTag = TAG_GPSINFO; + } else { + ALOGE("%s: Unknown SubIFD type %d.", __FUNCTION__, type); + return BAD_VALUE; + } + + sp subIfds = parent->getEntry(subIfdTag); + if (subIfds == NULL) { + if (buildEntry(subIfdTag, 1, &newIfd, &subIfds) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + } else { + if (type == GPSINFO) { + ALOGE("%s: Cannot add GPSInfo SubIFD to IFD %u, one already exists.", __FUNCTION__, + ifd); + return BAD_VALUE; + } + + Vector > subIfdList; + const sp* oldIfdArray = subIfds->getData >(); + if (subIfdList.appendArray(oldIfdArray, subIfds->getCount()) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + if (subIfdList.add(newIfd) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + uint32_t count = subIfdList.size(); + if (buildEntry(subIfdTag, count, subIfdList.array(), &subIfds) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + } + + if (parent->addEntry(subIfds) < 0) { + ALOGE("%s: Failed to add SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + if(mNamedIfds.add(ifd, newIfd) < 0) { + ALOGE("%s: Failed to add new IFD 0x%x.", __FUNCTION__, ifd); + return BAD_VALUE; + } + return OK; } @@ -180,10 +329,23 @@ uint32_t TiffWriter::getDefaultCount(uint16_t tag) const { return definition->fixedCount; } +bool TiffWriter::hasIfd(uint32_t ifd) const { + ssize_t index = mNamedIfds.indexOfKey(ifd); + return index >= 0; +} + bool TiffWriter::checkIfDefined(uint16_t tag) const { return lookupDefinition(tag) != NULL; } +const char* TiffWriter::getTagName(uint16_t tag) const { + const TagDefinition_t* definition = lookupDefinition(tag); + if (definition == NULL) { + return NULL; + } + return definition->tagName; +} + sp TiffWriter::findLastIfd() { sp ifd = mIfd; while(ifd != NULL) { @@ -221,10 +383,9 @@ uint32_t TiffWriter::getTotalSize() const { void TiffWriter::log() const { ALOGI("%s: TiffWriter:", __FUNCTION__); - sp ifd = mIfd; - while(ifd != NULL) { - ifd->log(); - ifd = ifd->getNextIfd(); + size_t length = mNamedIfds.size(); + for (size_t i = 0; i < length; ++i) { + mNamedIfds[i]->log(); } } -- cgit v1.1