OSDN Git Service

camera2: Adding TIFF writing utilities.
authorRuben Brunk <rubenbrunk@google.com>
Mon, 28 Apr 2014 23:39:12 +0000 (16:39 -0700)
committerRuben Brunk <rubenbrunk@google.com>
Sat, 17 May 2014 07:15:51 +0000 (07:15 +0000)
Adds a native image utilities library with support for:
- Writing TIFF 6.0 and TIFF EP compliant file headers.
- Additional tags defined in EXIF 2.3 and DNG 1.4 specs.

Change-Id: I7a4fef74bd5254d92baf08a3cf61af5de1b7ca83

33 files changed:
media/img_utils/Android.mk [new file with mode: 0644]
media/img_utils/include/img_utils/ByteArrayOutput.h [new file with mode: 0644]
media/img_utils/include/img_utils/DngUtils.h [new file with mode: 0644]
media/img_utils/include/img_utils/EndianUtils.h [new file with mode: 0644]
media/img_utils/include/img_utils/FileInput.h [new file with mode: 0644]
media/img_utils/include/img_utils/FileOutput.h [new file with mode: 0644]
media/img_utils/include/img_utils/Input.h [new file with mode: 0644]
media/img_utils/include/img_utils/Orderable.h [new file with mode: 0644]
media/img_utils/include/img_utils/Output.h [new file with mode: 0644]
media/img_utils/include/img_utils/Pair.h [new file with mode: 0644]
media/img_utils/include/img_utils/SortedEntryVector.h [new file with mode: 0644]
media/img_utils/include/img_utils/TagDefinitions.h [new file with mode: 0644]
media/img_utils/include/img_utils/TiffEntry.h [new file with mode: 0644]
media/img_utils/include/img_utils/TiffEntryImpl.h [new file with mode: 0644]
media/img_utils/include/img_utils/TiffHelpers.h [new file with mode: 0644]
media/img_utils/include/img_utils/TiffIfd.h [new file with mode: 0644]
media/img_utils/include/img_utils/TiffWritable.h [new file with mode: 0644]
media/img_utils/include/img_utils/TiffWriter.h [new file with mode: 0644]
media/img_utils/src/Android.mk [new file with mode: 0644]
media/img_utils/src/ByteArrayOutput.cpp [new file with mode: 0644]
media/img_utils/src/DngUtils.cpp [new file with mode: 0644]
media/img_utils/src/EndianUtils.cpp [new file with mode: 0644]
media/img_utils/src/FileInput.cpp [new file with mode: 0644]
media/img_utils/src/FileOutput.cpp [new file with mode: 0644]
media/img_utils/src/Input.cpp [new file with mode: 0644]
media/img_utils/src/Orderable.cpp [new file with mode: 0644]
media/img_utils/src/Output.cpp [new file with mode: 0644]
media/img_utils/src/SortedEntryVector.cpp [new file with mode: 0644]
media/img_utils/src/TiffEntry.cpp [new file with mode: 0644]
media/img_utils/src/TiffEntryImpl.cpp [new file with mode: 0644]
media/img_utils/src/TiffIfd.cpp [new file with mode: 0644]
media/img_utils/src/TiffWritable.cpp [new file with mode: 0644]
media/img_utils/src/TiffWriter.cpp [new file with mode: 0644]

diff --git a/media/img_utils/Android.mk b/media/img_utils/Android.mk
new file mode 100644 (file)
index 0000000..1cd00bd
--- /dev/null
@@ -0,0 +1,15 @@
+# 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 $(call all-subdir-makefiles)
diff --git a/media/img_utils/include/img_utils/ByteArrayOutput.h b/media/img_utils/include/img_utils/ByteArrayOutput.h
new file mode 100644 (file)
index 0000000..ba73977
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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_BYTE_ARRAY_OUTPUT_H
+#define IMG_UTILS_BYTE_ARRAY_OUTPUT_H
+
+#include <img_utils/Output.h>
+
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+
+#include <cutils/compiler.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Utility class that accumulates written bytes into a buffer.
+ */
+class ANDROID_API ByteArrayOutput : public Output {
+    public:
+
+        ByteArrayOutput();
+
+        virtual ~ByteArrayOutput();
+
+        /**
+         * Open this ByteArrayOutput.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t open();
+
+        /**
+         * Write bytes from the given buffer.  The number of bytes given in the count
+         * argument will be written.  Bytes will be written from the given buffer starting
+         * at the index given in the offset argument.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t write(const uint8_t* buf, size_t offset, size_t count);
+
+        /**
+         * Close this ByteArrayOutput.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t close();
+
+        /**
+         * Get current size of the array of bytes written.
+         */
+        virtual size_t getSize() const;
+
+        /**
+         * Get pointer to array of bytes written.  It is not valid to use this pointer if
+         * open, write, or close is called after this method.
+         */
+        virtual const uint8_t* getArray() const;
+
+    protected:
+        Vector<uint8_t> mByteArray;
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_BYTE_ARRAY_OUTPUT_H*/
diff --git a/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h
new file mode 100644 (file)
index 0000000..4389b02
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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_DNG_UTILS_H
+#define IMG_UTILS_DNG_UTILS_H
+
+#include <img_utils/ByteArrayOutput.h>
+#include <img_utils/EndianUtils.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+#include <cutils/compiler.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+#define NELEMS(x) ((int) (sizeof(x) / sizeof((x)[0])))
+
+/**
+ * Utility class for building values for the OpcodeList tags specified
+ * in the Adobe DNG 1.4 spec.
+ */
+class ANDROID_API OpcodeListBuilder : public LightRefBase<OpcodeListBuilder> {
+    public:
+        enum CfaLayout {
+            CFA_RGGB = 0,
+            CFA_GRBG,
+            CFA_GBRG,
+            CFA_BGGR,
+        };
+
+        OpcodeListBuilder();
+        virtual ~OpcodeListBuilder();
+
+        /**
+         * Get the total size of this opcode list in bytes.
+         */
+        virtual size_t getSize() const;
+
+        /**
+         * Get the number of opcodes defined in this list.
+         */
+        virtual uint32_t getCount() const;
+
+        /**
+         * Write the opcode list into the given buffer.  This buffer
+         * must be able to hold at least as many elements as returned
+         * by calling the getSize() method.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t buildOpList(/*out*/ uint8_t* buf) const;
+
+        /**
+         * Add GainMap opcode(s) for the given metadata parameters.  The given
+         * CFA layout must match the layout of the shading map passed into the
+         * lensShadingMap parameter.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t addGainMapsForMetadata(uint32_t lsmWidth,
+                                                uint32_t lsmHeight,
+                                                uint32_t activeAreaTop,
+                                                uint32_t activeAreaLeft,
+                                                uint32_t activeAreaBottom,
+                                                uint32_t activeAreaRight,
+                                                CfaLayout cfa,
+                                                const float* lensShadingMap);
+
+
+        /**
+         * Add a GainMap opcode with the given fields.  The mapGains array
+         * must have mapPointsV * mapPointsH * mapPlanes elements.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t addGainMap(uint32_t top,
+                                    uint32_t left,
+                                    uint32_t bottom,
+                                    uint32_t right,
+                                    uint32_t plane,
+                                    uint32_t planes,
+                                    uint32_t rowPitch,
+                                    uint32_t colPitch,
+                                    uint32_t mapPointsV,
+                                    uint32_t mapPointsH,
+                                    double mapSpacingV,
+                                    double mapSpacingH,
+                                    double mapOriginV,
+                                    double mapOriginH,
+                                    uint32_t mapPlanes,
+                                    const float* mapGains);
+
+        // TODO: Add other Opcode methods
+    protected:
+        static const uint32_t FLAG_OPTIONAL = 0x1u;
+        static const uint32_t FLAG_OPTIONAL_FOR_PREVIEW = 0x2u;
+
+        enum {
+            GAIN_MAP_ID = 9,
+            LSM_R_IND = 0,
+            LSM_GE_IND = 1,
+            LSM_GO_IND = 2,
+            LSM_B_IND = 3,
+        };
+
+        uint32_t mCount;
+        ByteArrayOutput mOpList;
+        EndianOutput mEndianOut;
+
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_DNG_UTILS_H*/
diff --git a/media/img_utils/include/img_utils/EndianUtils.h b/media/img_utils/include/img_utils/EndianUtils.h
new file mode 100644 (file)
index 0000000..e99be1a
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * 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_ENDIAN_UTILS
+#define IMG_UTILS_ENDIAN_UTILS
+
+#include <img_utils/Output.h>
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <stdint.h>
+#include <endian.h>
+#include <assert.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Endianness types supported.
+ */
+enum ANDROID_API Endianness {
+    UNDEFINED_ENDIAN, // Default endianness will be used.
+    BIG,
+    LITTLE
+};
+
+/**
+ * Convert from the native device endianness to big endian.
+ */
+template<typename T>
+T convertToBigEndian(T in);
+
+/**
+ * Convert from the native device endianness to little endian.
+ */
+template<typename T>
+T convertToLittleEndian(T in);
+
+/**
+ * A utility class for writing to an Output with the given endianness.
+ */
+class ANDROID_API EndianOutput : public Output {
+    public:
+        /**
+         * Wrap the given Output.  Calling write methods will result in
+         * writes to this output.
+         */
+        EndianOutput(Output* out, Endianness end=LITTLE);
+
+        virtual ~EndianOutput();
+
+        /**
+         * Call open on the wrapped output.
+         */
+        virtual status_t open();
+
+        /**
+         * Call close on the wrapped output.
+         */
+        virtual status_t close();
+
+        /**
+         * Set the endianness to use when writing.
+         */
+        virtual void setEndianness(Endianness end);
+
+        /**
+         * Get the currently configured endianness.
+         */
+        virtual Endianness getEndianness() const;
+
+        /**
+         * Get the current number of bytes written by this EndianOutput.
+         */
+        virtual uint32_t getCurrentOffset() const;
+
+
+        // TODO: switch write methods to uint32_t instead of size_t,
+        // the max size of a TIFF files is bounded
+
+        /**
+         * The following methods will write elements from given input buffer to the output.
+         * Count elements in the buffer will be written with the endianness set for this
+         * EndianOutput.  If the given offset is greater than zero, that many elements will
+         * be skipped in the buffer before writing.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t write(const uint8_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const int8_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const uint16_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const int16_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const uint32_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const int32_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const uint64_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const int64_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const float* buf, size_t offset, size_t count);
+
+        virtual status_t write(const double* buf, size_t offset, size_t count);
+
+    protected:
+        template<typename T>
+        inline status_t writeHelper(const T* buf, size_t offset, size_t count);
+
+        uint32_t mOffset;
+        Output* mOutput;
+        Endianness mEndian;
+};
+
+template<typename T>
+inline status_t EndianOutput::writeHelper(const T* buf, size_t offset, size_t count) {
+    assert(offset <= count);
+    status_t res = OK;
+    size_t size = sizeof(T);
+    switch(mEndian) {
+        case BIG: {
+            for (size_t i = offset; i < count; ++i) {
+                T tmp = convertToBigEndian<T>(buf[offset + i]);
+                if ((res = mOutput->write(reinterpret_cast<uint8_t*>(&tmp), 0, size))
+                        != OK) {
+                    return res;
+                }
+                mOffset += size;
+            }
+            break;
+        }
+        case LITTLE: {
+            for (size_t i = offset; i < count; ++i) {
+                T tmp = convertToLittleEndian<T>(buf[offset + i]);
+                if ((res = mOutput->write(reinterpret_cast<uint8_t*>(&tmp), 0, size))
+                        != OK) {
+                    return res;
+                }
+                mOffset += size;
+            }
+            break;
+        }
+        default: {
+            return BAD_VALUE;
+        }
+    }
+    return res;
+}
+
+template<>
+inline uint8_t convertToBigEndian(uint8_t in) {
+    return in;
+}
+
+template<>
+inline int8_t convertToBigEndian(int8_t in) {
+    return in;
+}
+
+template<>
+inline uint16_t convertToBigEndian(uint16_t in) {
+    return htobe16(in);
+}
+
+template<>
+inline int16_t convertToBigEndian(int16_t in) {
+    return htobe16(in);
+}
+
+template<>
+inline uint32_t convertToBigEndian(uint32_t in) {
+    return htobe32(in);
+}
+
+template<>
+inline int32_t convertToBigEndian(int32_t in) {
+    return htobe32(in);
+}
+
+template<>
+inline uint64_t convertToBigEndian(uint64_t in) {
+    return htobe64(in);
+}
+
+template<>
+inline int64_t convertToBigEndian(int64_t in) {
+    return htobe64(in);
+}
+
+template<>
+inline uint8_t convertToLittleEndian(uint8_t in) {
+    return in;
+}
+
+template<>
+inline int8_t convertToLittleEndian(int8_t in) {
+    return in;
+}
+
+template<>
+inline uint16_t convertToLittleEndian(uint16_t in) {
+    return htole16(in);
+}
+
+template<>
+inline int16_t convertToLittleEndian(int16_t in) {
+    return htole16(in);
+}
+
+template<>
+inline uint32_t convertToLittleEndian(uint32_t in) {
+    return htole32(in);
+}
+
+template<>
+inline int32_t convertToLittleEndian(int32_t in) {
+    return htole32(in);
+}
+
+template<>
+inline uint64_t convertToLittleEndian(uint64_t in) {
+    return htole64(in);
+}
+
+template<>
+inline int64_t convertToLittleEndian(int64_t in) {
+    return htole64(in);
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_ENDIAN_UTILS*/
+
diff --git a/media/img_utils/include/img_utils/FileInput.h b/media/img_utils/include/img_utils/FileInput.h
new file mode 100644 (file)
index 0000000..d3c5ec1
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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_FILE_INPUT_H
+#define IMG_UTILS_FILE_INPUT_H
+
+#include <img_utils/Input.h>
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <stdio.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Utility class for reading from a file.
+ */
+class ANDROID_API FileInput : public Input {
+    public:
+        /**
+         * Create a file input for the given path.
+         */
+        FileInput(String8 path);
+
+        virtual ~FileInput();
+
+        /**
+         * Open a file descriptor to the path given in the constructor.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t open();
+
+        /**
+         * Read bytes from the file into the given buffer.  At most, the number
+         * 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.
+         */
+        virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err);
+
+        /**
+         * Close the file descriptor to the path given in the constructor.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t close();
+    private:
+        FILE *mFp;
+        String8 mPath;
+        bool mOpen;
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+
+#endif /*IMG_UTILS_INPUT_H*/
diff --git a/media/img_utils/include/img_utils/FileOutput.h b/media/img_utils/include/img_utils/FileOutput.h
new file mode 100644 (file)
index 0000000..fd5be27
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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_FILE_OUTPUT_H
+#define IMG_UTILS_FILE_OUTPUT_H
+
+#include <img_utils/Output.h>
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <stdio.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+class ANDROID_API FileOutput : public Output {
+    public:
+        FileOutput(String8 path);
+        virtual ~FileOutput();
+        virtual status_t open();
+        virtual status_t write(const uint8_t* buf, size_t offset, size_t count);
+        virtual status_t close();
+    private:
+        FILE *mFp;
+        String8 mPath;
+        bool mOpen;
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_FILE_OUTPUT_H*/
diff --git a/media/img_utils/include/img_utils/Input.h b/media/img_utils/include/img_utils/Input.h
new file mode 100644 (file)
index 0000000..2166601
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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_INPUT_H
+#define IMG_UTILS_INPUT_H
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Utility class used as a source of bytes.
+ */
+class ANDROID_API Input {
+    public:
+        virtual ~Input();
+
+        /**
+         * Open this Input.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t open();
+
+        /**
+         * Read bytes into the given buffer.  At most, the number 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.
+         */
+        virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err) = 0;
+
+        /**
+         * Close the Input.  It is not valid to call open on a previously closed Input.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t close();
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+
+#endif /*IMG_UTILS_INPUT_H*/
diff --git a/media/img_utils/include/img_utils/Orderable.h b/media/img_utils/include/img_utils/Orderable.h
new file mode 100644 (file)
index 0000000..87253a4
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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_ORDERABLE
+#define IMG_UTILS_ORDERABLE
+
+#include <cutils/compiler.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+#define COMPARE_DEF(op) \
+inline bool operator op (const Orderable& orderable) const;
+
+/**
+ * Subclasses of Orderable can be compared and sorted.  This is
+ * intended to be used to create sorted arrays of TIFF entries
+ * and IFDs.
+ */
+class ANDROID_API Orderable  {
+    public:
+        virtual ~Orderable();
+
+        /**
+         * Comparison operatotors are based on the value returned
+         * from this method.
+         */
+        virtual uint32_t getComparableValue() const = 0;
+
+        COMPARE_DEF(>)
+        COMPARE_DEF(<)
+        COMPARE_DEF(>=)
+        COMPARE_DEF(<=)
+        COMPARE_DEF(==)
+        COMPARE_DEF(!=)
+};
+
+#undef COMPARE_DEF
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_ORDERABLE*/
diff --git a/media/img_utils/include/img_utils/Output.h b/media/img_utils/include/img_utils/Output.h
new file mode 100644 (file)
index 0000000..35fae23
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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_OUTPUT_H
+#define IMG_UTILS_OUTPUT_H
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Utility class used to output bytes.
+ */
+class ANDROID_API Output {
+    public:
+        virtual ~Output();
+
+        /**
+         * Open this Output.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t open();
+
+        /**
+         * Write bytes from the given buffer.  The number of bytes given in the count
+         * argument will be written.  Bytes will be written from the given buffer starting
+         * at the index given in the offset argument.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t write(const uint8_t* buf, size_t offset, size_t count) = 0;
+
+        /**
+         * Close this Output.  It is not valid to call open on a previously closed Output.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t close();
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_OUTPUT_H*/
diff --git a/media/img_utils/include/img_utils/Pair.h b/media/img_utils/include/img_utils/Pair.h
new file mode 100644 (file)
index 0000000..d651cac
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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_PAIR_H
+#define IMG_UTILS_PAIR_H
+
+#include <cutils/compiler.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Generic pair utility class.  Nothing special here.
+ */
+template<typename F, typename S>
+class ANDROID_API Pair {
+    public:
+        F first;
+        S second;
+
+        Pair() {}
+
+        Pair(const Pair& o) : first(o.first), second(o.second) {}
+
+        Pair(const F& f, const S& s) : first(f), second(s) {}
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_PAIR_H*/
diff --git a/media/img_utils/include/img_utils/SortedEntryVector.h b/media/img_utils/include/img_utils/SortedEntryVector.h
new file mode 100644 (file)
index 0000000..f059a82
--- /dev/null
@@ -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_SORTED_ENTRY_VECTOR_H
+#define IMG_UTILS_SORTED_ENTRY_VECTOR_H
+
+#include <img_utils/TiffEntry.h>
+
+#include <utils/StrongPointer.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Subclass of SortedVector that has been extended to
+ * do comparisons/lookups based on the tag ID of the entries.
+ */
+class SortedEntryVector : public SortedVector<sp<TiffEntry> > {
+    public:
+        virtual ~SortedEntryVector();
+
+        /**
+         * Returns the index of the entry with the given tag ID, or
+         * -1 if none exists.
+         */
+        ssize_t indexOfTag(uint16_t tag) const;
+
+    protected:
+        /**
+         * Compare tag ID.
+         */
+        virtual int do_compare(const void* lhs, const void* rhs) const;
+};
+
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_SORTED_ENTRY_VECTOR_H*/
diff --git a/media/img_utils/include/img_utils/TagDefinitions.h b/media/img_utils/include/img_utils/TagDefinitions.h
new file mode 100644 (file)
index 0000000..9232e58
--- /dev/null
@@ -0,0 +1,1139 @@
+/*
+ * 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_TIFF_TAG_DEFINITION_H
+#define IMG_UTILS_TIFF_TAG_DEFINITION_H
+
+#include <img_utils/TiffEntry.h>
+#include <img_utils/Output.h>
+#include <img_utils/TiffHelpers.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Tag definitions contain information about standard TIFF compatible tags.
+ */
+typedef struct TagDefinition {
+    // The specified tag ID.
+    uint16_t tagId;
+    // The default type for this tag.  This must be a valid TIFF type.
+    TagType defaultType;
+    // The default Image File Directory (IFD) for this tag.
+    uint32_t defaultIfd;
+    // The valid count for this tag, or 0 if the count is not fixed.
+    uint32_t fixedCount;
+    // The endianness of the tag value, or UNDEFINED_ENDIAN if there is no fixed endian
+    Endianness fixedEndian;
+} TagDefinition_t;
+
+/**
+ * Convenience defines for tag ids.
+ */
+enum {
+    TAG_RAWTOPREVIEWGAIN = 0xC7A8u,
+    TAG_NEWRAWIMAGEDIGEST = 0xC7A7u,
+    TAG_ORIGINALDEFAULTCROPSIZE = 0xC793u,
+    TAG_ORIGINALBESTQUALITYFINALSIZE = 0xC792u,
+    TAG_ORIGINALDEFAULTFINALSIZE = 0xC791u,
+    TAG_PROFILEHUESATMAPENCODING = 0xC7A3u,
+    TAG_PROFILELOOKTABLEENCODING = 0xC7A4u,
+    TAG_BASELINEEXPOSUREOFFSET = 0xC7A5u,
+    TAG_DEFAULTBLACKRENDER = 0xC7A6u,
+    TAG_DEFAULTUSERCROP = 0xC7B5u,
+    TAG_NOISEPROFILE = 0xC761u,
+    TAG_OPCODELIST3 = 0xC74Eu,
+    TAG_OPCODELIST2 = 0xC741u,
+    TAG_OPCODELIST1 = 0xC740u,
+    TAG_PROFILELOOKTABLEDATA = 0xC726u,
+    TAG_PROFILELOOKTABLEDIMS = 0xC725u,
+    TAG_ROWINTERLEAVEFACTOR = 0xC71Fu,
+    TAG_SUBTILEBLOCKSIZE = 0xC71Eu,
+    TAG_ORIGINALRAWFILEDIGEST = 0xC71Du,
+    TAG_RAWIMAGEDIGEST = 0xC71Cu,
+    TAG_PREVIEWDATETIME = 0xC71Bu,
+    TAG_PREVIEWCOLORSPACE = 0xC71Au,
+    TAG_PREVIEWSETTINGSDIGEST = 0xC719u,
+    TAG_PREVIEWSETTINGSNAME = 0xC718u,
+    TAG_PREVIEWAPPLICATIONVERSION = 0xC717u,
+    TAG_PREVIEWAPPLICATIONNAME = 0xC716u,
+    TAG_FORWARDMATRIX2 = 0xC715u,
+    TAG_FORWARDMATRIX1 = 0xC714u,
+    TAG_PROFILECOPYRIGHT = 0xC6FEu,
+    TAG_PROFILEEMBEDPOLICY = 0xC6FDu,
+    TAG_PROFILETONECURVE = 0xC6FCu,
+    TAG_PROFILEHUESATMAPDATA2 = 0xC6FBu,
+    TAG_PROFILEHUESATMAPDATA1 = 0xC6FAu,
+    TAG_PROFILEHUESATMAPDIMS = 0xC6F9u,
+    TAG_PROFILENAME = 0xC6F8u,
+    TAG_NOISEREDUCTIONAPPLIED = 0xC6F7u,
+    TAG_ASSHOTPROFILENAME = 0xC6F6u,
+    TAG_EXTRACAMERAPROFILES = 0xC6F5u,
+    TAG_PROFILECALIBRATIONSIGNATURE = 0xC6F4u,
+    TAG_CAMERACALIBRATIONSIGNATURE = 0xC6F3u,
+    TAG_COLORIMETRICREFERENCE = 0xC6BFu,
+    TAG_CURRENTPREPROFILEMATRIX = 0xC692u,
+    TAG_CURRENTICCPROFILE = 0xC691u,
+    TAG_ASSHOTPREPROFILEMATRIX = 0xC690u,
+    TAG_ASSHOTICCPROFILE = 0xC68Fu,
+    TAG_MASKEDAREAS = 0xC68Eu,
+    TAG_ACTIVEAREA = 0xC68Du,
+    TAG_ORIGINALRAWFILEDATA = 0xC68Cu,
+    TAG_ORIGINALRAWFILENAME = 0xC68Bu,
+    TAG_RAWDATAUNIQUEID = 0xC65Du,
+    TAG_MAKERNOTESAFETY = 0xC635u,
+    TAG_DNGPRIVATEDATA = 0xC634u,
+    TAG_SHADOWSCALE = 0xC633u,
+    TAG_ANTIALIASSTRENGTH = 0xC632u,
+    TAG_CHROMABLURRADIUS = 0xC631u,
+    TAG_LENSINFO = 0xC630u,
+    TAG_CAMERASERIALNUMBER = 0xC62Fu,
+    TAG_LINEARRESPONSELIMIT = 0xC62Eu,
+    TAG_BAYERGREENSPLIT = 0xC62Du,
+    TAG_BASELINESHARPNESS = 0xC62Cu,
+    TAG_BASELINENOISE = 0xC62Bu,
+    TAG_BASELINEEXPOSURE = 0xC62Au,
+    TAG_ASSHOTWHITEXY = 0xC629u,
+    TAG_ASSHOTNEUTRAL = 0xC628u,
+    TAG_ANALOGBALANCE = 0xC627u,
+    TAG_REDUCTIONMATRIX2 = 0xC626u,
+    TAG_REDUCTIONMATRIX1 = 0xC625u,
+    TAG_CAMERACALIBRATION2 = 0xC624u,
+    TAG_CAMERACALIBRATION1 = 0xC623u,
+    TAG_COLORMATRIX2 = 0xC622u,
+    TAG_COLORMATRIX1 = 0xC621u,
+    TAG_CALIBRATIONILLUMINANT2 = 0xC65Bu,
+    TAG_CALIBRATIONILLUMINANT1 = 0xC65Au,
+    TAG_DEFAULTCROPSIZE = 0xC620u,
+    TAG_DEFAULTCROPORIGIN = 0xC61Fu,
+    TAG_BESTQUALITYSCALE = 0xC65Cu,
+    TAG_DEFAULTSCALE = 0xC61Eu,
+    TAG_WHITELEVEL = 0xC61Du,
+    TAG_BLACKLEVELDELTAV = 0xC61Cu,
+    TAG_BLACKLEVELDELTAH = 0xC61Bu,
+    TAG_BLACKLEVEL = 0xC61Au,
+    TAG_BLACKLEVELREPEATDIM = 0xC619u,
+    TAG_LINEARIZATIONTABLE = 0xC618u,
+    TAG_CFALAYOUT = 0xC617u,
+    TAG_CFAPLANECOLOR = 0xC616u,
+    TAG_LOCALIZEDCAMERAMODEL = 0xC615u,
+    TAG_UNIQUECAMERAMODEL = 0xC614u,
+    TAG_DNGBACKWARDVERSION = 0xC613u,
+    TAG_DNGVERSION = 0xC612u,
+    TAG_SUBFILETYPE = 0x00FFu,
+    TAG_YRESOLUTION = 0x011Bu,
+    TAG_XRESOLUTION = 0x011Au,
+    TAG_THRESHHOLDING = 0x0107u,
+    TAG_STRIPOFFSETS = 0x0111u,
+    TAG_STRIPBYTECOUNTS = 0x0117u,
+    TAG_SOFTWARE = 0x0131u,
+    TAG_SAMPLESPERPIXEL = 0x0115u,
+    TAG_ROWSPERSTRIP = 0x0116u,
+    TAG_RESOLUTIONUNIT = 0x0128u,
+    TAG_PLANARCONFIGURATION = 0x011Cu,
+    TAG_PHOTOMETRICINTERPRETATION = 0x0106u,
+    TAG_ORIENTATION = 0x0112u,
+    TAG_NEWSUBFILETYPE = 0x00FEu,
+    TAG_MODEL = 0x0110u,
+    TAG_MINSAMPLEVALUE = 0x0118u,
+    TAG_MAXSAMPLEVALUE = 0x0119u,
+    TAG_MAKE = 0x010Fu,
+    TAG_IMAGEWIDTH = 0x0100u,
+    TAG_IMAGELENGTH = 0x0101u,
+    TAG_IMAGEDESCRIPTION = 0x010Eu,
+    TAG_HOSTCOMPUTER = 0x013Cu,
+    TAG_GRAYRESPONSEUNIT = 0x0122u,
+    TAG_GRAYRESPONSECURVE = 0x0123u,
+    TAG_FREEOFFSETS = 0x0120u,
+    TAG_FREEBYTECOUNTS = 0x0121u,
+    TAG_FILLORDER = 0x010Au,
+    TAG_EXTRASAMPLES = 0x0152u,
+    TAG_DATETIME = 0x0132u,
+    TAG_COPYRIGHT = 0x8298u,
+    TAG_COMPRESSION = 0x0103u,
+    TAG_COLORMAP = 0x0140u,
+    TAG_CELLWIDTH = 0x0108u,
+    TAG_CELLLENGTH = 0x0109u,
+    TAG_BITSPERSAMPLE = 0x0102u,
+    TAG_ARTIST = 0x013Bu,
+    TAG_EXIFVERSION = 0x9000u,
+    TAG_CFAREPEATPATTERNDIM = 0x828Du,
+    TAG_CFAPATTERN = 0x828Eu,
+    TAG_SUBIFDS = 0x014Au,
+};
+
+/**
+ * TIFF_EP_TAG_DEFINITIONS contains tags defined in the TIFF EP spec
+ */
+const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] =  {
+    { // PhotometricInterpretation
+        0x0106u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // SubIfds
+        0x014Au,
+        LONG,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CFAPattern
+        0x828Eu,
+        BYTE,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CFARepeatPatternDim
+        0x828Du,
+        SHORT,
+        IFD_0,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    /*TODO: Remaining TIFF EP tags*/
+};
+
+/**
+ * EXIF_2_3_TAG_DEFINITIONS contains tags defined in the Jeita EXIF 2.3 spec
+ */
+const TagDefinition_t EXIF_2_3_TAG_DEFINITIONS[] = {
+    { // ExifVersion
+        0x9000u,
+        UNDEFINED,
+        IFD_0,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    /*TODO: Remaining EXIF 2.3 tags*/
+};
+
+/**
+ * TIFF_6_TAG_DEFINITIONS contains tags defined in the TIFF 6.0 spec
+ */
+const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = {
+    { // SubFileType
+        0x00FFu,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Artist
+        0x013Bu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // BitsPerSample
+        0x0102u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CellLength
+        0x0109u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // CellWidth
+        0x0108u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ColorMap
+        0x0140u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // Compression
+        0x0103u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Copyright
+        0x8298u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // DateTime
+        0x0132u,
+        ASCII,
+        IFD_0,
+        20,
+        UNDEFINED_ENDIAN
+    },
+    { // ExtraSamples
+        0x0152u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // FillOrder
+        0x010Au,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // FreeByteCounts
+        0x0121u,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // FreeOffsets
+        0x0120u,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // GrayResponseCurve
+        0x0123u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // GrayResponseUnit
+        0x0122u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // HostComputer
+        0x013Cu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ImageDescription
+        0x010Eu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ImageLength
+        0x0101u,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ImageWidth
+        0x0100u,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Make
+        0x010Fu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // MaxSampleValue
+        0x0119u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // MinSampleValue
+        0x0118u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // Model
+        0x0110u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // NewSubfileType
+        0x00FEu,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Orientation
+        0x0112u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // PhotoMetricInterpretation
+        0x0106u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // PlanarConfiguration
+        0x011Cu,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ResolutionUnit
+        0x0128u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // RowsPerStrip
+        0x0116u,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // SamplesPerPixel
+        0x0115u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Software
+        0x0131u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // StripByteCounts
+        0x0117u,
+        LONG,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // StripOffsets
+        0x0111u,
+        LONG,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // SubfileType
+        0x00FFu,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Threshholding
+        0x0107u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // XResolution
+        0x011Au,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // YResolution
+        0x011Bu,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // YResolution
+        0x011Bu,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    }
+};
+
+/**
+ * DNG_TAG_DEFINITIONS contains tags defined in the DNG 1.4 spec
+ */
+const TagDefinition_t DNG_TAG_DEFINITIONS[] = {
+    { // DNGVersion
+        0xC612u,
+        BYTE,
+        IFD_0,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    { // DNGBackwardVersion
+        0xC613u,
+        BYTE,
+        IFD_0,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    { // UniqueCameraModel
+        0xC614u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // LocalizedCameraModel
+        0xC615u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CFAPlaneColor
+        0xC616u,
+        BYTE,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CFALayout
+        0xC617u,
+        SHORT,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // LinearizationTable
+        0xC618u,
+        SHORT,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // BlackLevelRepeatDim
+        0xC619u,
+        SHORT,
+        RAW_IFD,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // BlackLevel
+        0xC61Au,
+        LONG,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // BlackLevelDeltaH
+        0xC61Bu,
+        SRATIONAL,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // BlackLevelDeltaV
+        0xC61Cu,
+        SRATIONAL,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // WhiteLevel
+        0xC61Du,
+        LONG,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // DefaultScale
+        0xC61Eu,
+        RATIONAL,
+        RAW_IFD,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // BestQualityScale
+        0xC65Cu,
+        RATIONAL,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // DefaultCropOrigin
+        0xC61Fu,
+        LONG,
+        RAW_IFD,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // DefaultCropSize
+        0xC620u,
+        LONG,
+        RAW_IFD,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // CalibrationIlluminant1
+        0xC65Au,
+        SHORT,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // CalibrationIlluminant2
+        0xC65Bu,
+        SHORT,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ColorMatrix1
+        0xC621u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ColorMatrix2
+        0xC622u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CameraCalibration1
+        0xC623u,
+        SRATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CameraCalibration2
+        0xC624u,
+        SRATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ReductionMatrix1
+        0xC625u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ReductionMatrix2
+        0xC626u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AnalogBalance
+        0xC627u,
+        RATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AsShotNeutral
+        0xC628u,
+        RATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AsShotWhiteXY
+        0xC629u,
+        RATIONAL,
+        IFD_0,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // BaselineExposure
+        0xC62Au,
+        SRATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // BaselineNoise
+        0xC62Bu,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // BaselineSharpness
+        0xC62Cu,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // BayerGreenSplit
+        0xC62Du,
+        LONG,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // LinearResponseLimit
+        0xC62Eu,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // CameraSerialNumber
+        0xC62Fu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // LensInfo
+        0xC630u,
+        RATIONAL,
+        IFD_0,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    { // ChromaBlurRadius
+        0xC631u,
+        RATIONAL,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // AntiAliasStrength
+        0xC632u,
+        RATIONAL,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ShadowScale
+        0xC633u,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // DNGPrivateData
+        0xC634u,
+        BYTE,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // MakerNoteSafety
+        0xC635u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // RawDataUniqueID
+        0xC65Du,
+        BYTE,
+        IFD_0,
+        16,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalRawFileName
+        0xC68Bu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalRawFileData
+        0xC68Cu,
+        UNDEFINED,
+        IFD_0,
+        0,
+        BIG
+    },
+    { // ActiveArea
+        0xC68Du,
+        LONG,
+        RAW_IFD,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    { // MaskedAreas
+        0xC68Eu,
+        LONG,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AsShotICCProfile
+        0xC68Fu,
+        UNDEFINED,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AsShotPreProfileMatrix
+        0xC690u,
+        SRATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CurrentICCProfile
+        0xC691u,
+        UNDEFINED,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CurrentICCProfile
+        0xC691u,
+        UNDEFINED,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CurrentPreProfileMatrix
+        0xC692u,
+        SRATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ColorimetricReference
+        0xC6BFu,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // CameraCalibrationSignature
+        0xC6F3u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileCalibrationSignature
+        0xC6F4u,
+        ASCII,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ExtraCameraProfiles
+        0xC6F5u,
+        LONG,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AsShotProfileName
+        0xC6F6u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // NoiseReductionApplied
+        0xC6F7u,
+        RATIONAL,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileName
+        0xC6F8u,
+        ASCII,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileHueSatMapDims
+        0xC6F9u,
+        LONG,
+        PROFILE_IFD,
+        3,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileHueSatMapData1
+        0xC6FAu,
+        FLOAT,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileHueSatMapData2
+        0xC6FBu,
+        FLOAT,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileToneCurve
+        0xC6FCu,
+        FLOAT,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileEmbedPolicy
+        0xC6FDu,
+        LONG,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileCopyright
+        0xC6FEu,
+        ASCII,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ForwardMatrix1
+        0xC714u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ForwardMatrix2
+        0xC715u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewApplicationName
+        0xC716u,
+        ASCII,
+        PREVIEW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewApplicationVersion
+        0xC717u,
+        ASCII,
+        PREVIEW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewSettingsName
+        0xC718u,
+        ASCII,
+        PREVIEW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewSettingsDigest
+        0xC719u,
+        BYTE,
+        PREVIEW_IFD,
+        16,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewColorSpace
+        0xC71Au,
+        LONG,
+        PREVIEW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewDateTime
+        0xC71Bu,
+        ASCII,
+        PREVIEW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // RawImageDigest
+        0xC71Cu,
+        BYTE,
+        IFD_0,
+        16,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalRawFileDigest
+        0xC71Du,
+        BYTE,
+        IFD_0,
+        16,
+        UNDEFINED_ENDIAN
+    },
+    { // SubTileBlockSize
+        0xC71Eu,
+        LONG,
+        RAW_IFD,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // RowInterleaveFactor
+        0xC71Fu,
+        LONG,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileLookTableDims
+        0xC725u,
+        LONG,
+        PROFILE_IFD,
+        3,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileLookTableData
+        0xC726u,
+        FLOAT,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // OpcodeList1
+        0xC740u,
+        UNDEFINED,
+        RAW_IFD,
+        0,
+        BIG
+    },
+    { // OpcodeList2
+        0xC741u,
+        UNDEFINED,
+        RAW_IFD,
+        0,
+        BIG
+    },
+    { // OpcodeList3
+        0xC74Eu,
+        UNDEFINED,
+        RAW_IFD,
+        0,
+        BIG
+    },
+    { // NoiseProfile
+        0xC761u,
+        DOUBLE,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // DefaultUserCrop
+        0xC7B5u,
+        RATIONAL,
+        RAW_IFD,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    { // DefaultBlackRender
+        0xC7A6u,
+        LONG,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // BaselineExposureOffset
+        0xC7A5u,
+        RATIONAL,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileLookTableEncoding
+        0xC7A4u,
+        LONG,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileHueSatMapEncoding
+        0xC7A3u,
+        LONG,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalDefaultFinalSize
+        0xC791u,
+        LONG,
+        IFD_0,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalBestQualityFinalSize
+        0xC792u,
+        LONG,
+        IFD_0,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalDefaultCropSize
+        0xC793u,
+        LONG,
+        IFD_0,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // NewRawImageDigest
+        0xC7A7u,
+        BYTE,
+        IFD_0,
+        16,
+        UNDEFINED_ENDIAN
+    },
+    { // RawToPreviewGain
+        0xC7A8u,
+        DOUBLE,
+        PREVIEW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_TAG_DEFINITION_H*/
diff --git a/media/img_utils/include/img_utils/TiffEntry.h b/media/img_utils/include/img_utils/TiffEntry.h
new file mode 100644 (file)
index 0000000..cd01640
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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_TIFF_ENTRY
+#define IMG_UTILS_TIFF_ENTRY
+
+#include <img_utils/TiffWritable.h>
+#include <img_utils/TiffHelpers.h>
+#include <img_utils/EndianUtils.h>
+
+#include <cutils/compiler.h>
+#include <utils/String8.h>
+#include <utils/Errors.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+#define COMPARE_DEF(op) \
+inline bool operator op (const TiffEntry& entry) const;
+
+/**
+ * This class holds a single TIFF IFD entry.
+ */
+class ANDROID_API TiffEntry : public TiffWritable {
+    public:
+        // TODO: Copy constructor/equals here.
+        virtual ~TiffEntry();
+
+        /**
+         * Write the 12-byte IFD entry to the output. The given offset will be
+         * set as the tag value if the size of the tag value exceeds the max
+         * size for the TIFF Value field (4 bytes), and should be word aligned.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const = 0;
+
+        /**
+         * Get the count set for this entry. This corresponds to the TIFF Count
+         * field.
+         */
+        virtual uint32_t getCount() const = 0;
+
+        /**
+         * Get the tag id set for this entry. This corresponds to the TIFF Tag
+         * field.
+         */
+        virtual uint16_t getTag() const = 0;
+
+        /**
+         * Get the type set for this entry.  This corresponds to the TIFF Type
+         * field.
+         */
+        virtual TagType getType() const = 0;
+
+        /**
+         * Get the defined endianness for this entry.  If this is defined,
+         * the tag value will be written with the given byte order.
+         */
+        virtual Endianness getEndianness() const = 0;
+
+        /**
+         * Get the value for this entry.  This corresponds to the TIFF Value
+         * field.
+         *
+         * Returns NULL if the value is NULL, or if the type used does not
+         * match the type of this tag.
+         */
+        template<typename T>
+        const T* getData() const;
+
+        String8 toString() const;
+
+        /**
+         * Force the type used here to be a valid TIFF type.
+         *
+         * Returns NULL if the given value is NULL, or if the type given does
+         * not match the type of the value given.
+         */
+        template<typename T>
+        static const T* forceValidType(TagType type, const T* value);
+
+        virtual const void* getDataHelper() const = 0;
+
+        COMPARE_DEF(>)
+        COMPARE_DEF(<)
+
+        protected:
+            enum {
+                MAX_PRINT_STRING_LENGTH = 256
+            };
+};
+
+#define COMPARE(op) \
+bool TiffEntry::operator op (const TiffEntry& entry) const { \
+    return getComparableValue() op entry.getComparableValue(); \
+}
+
+COMPARE(>)
+COMPARE(<)
+
+
+template<typename T>
+const T* TiffEntry::getData() const {
+    const T* value = reinterpret_cast<const T*>(getDataHelper());
+    return forceValidType<T>(getType(), value);
+}
+
+#undef COMPARE
+#undef COMPARE_DEF
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_ENTRY*/
diff --git a/media/img_utils/include/img_utils/TiffEntryImpl.h b/media/img_utils/include/img_utils/TiffEntryImpl.h
new file mode 100644 (file)
index 0000000..0e713dc
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * 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_TIFF_ENTRY_IMPL
+#define IMG_UTILS_TIFF_ENTRY_IMPL
+
+#include <img_utils/TiffEntry.h>
+#include <img_utils/TiffHelpers.h>
+#include <img_utils/Output.h>
+#include <img_utils/EndianUtils.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+template<typename T>
+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();
+
+        status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const;
+        status_t writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const;
+
+        uint32_t getCount() const;
+        uint16_t getTag() const;
+        TagType getType() const;
+        Endianness getEndianness() const;
+        uint32_t getSize() const;
+        uint32_t getComparableValue() const;
+
+    protected:
+        const void* getDataHelper() const;
+        uint32_t getActualSize() const;
+
+        uint16_t mTag;
+        uint16_t mType;
+        uint32_t mCount;
+        Endianness mEnd;
+        T* mData;
+
+};
+
+template<typename T>
+TiffEntryImpl<T>::TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end,
+        const T* data)
+        : mTag(tag), mType(static_cast<uint16_t>(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];
+    }
+}
+
+template<typename T>
+TiffEntryImpl<T>::~TiffEntryImpl() {
+    if (mData) {
+        delete[] mData;
+    }
+}
+
+template<typename T>
+uint32_t TiffEntryImpl<T>::getCount() const {
+    return mCount;
+}
+
+template<typename T>
+uint16_t TiffEntryImpl<T>::getTag() const {
+    return mTag;
+}
+
+template<typename T>
+TagType TiffEntryImpl<T>::getType() const {
+    return static_cast<TagType>(mType);
+}
+
+template<typename T>
+const void* TiffEntryImpl<T>::getDataHelper() const {
+    return reinterpret_cast<const void*>(mData);
+}
+
+template<typename T>
+uint32_t TiffEntryImpl<T>::getSize() const {
+    uint32_t total = getActualSize();
+    WORD_ALIGN(total)
+    return (total <= OFFSET_SIZE) ? 0 : total;
+}
+
+template<typename T>
+uint32_t TiffEntryImpl<T>::getActualSize() const {
+    uint32_t total = sizeof(T) * mCount;
+    if (getType() == RATIONAL || getType() == SRATIONAL) {
+        // 2 ints stored for each rational, multiply by 2
+        total <<= 1;
+    }
+    return total;
+}
+
+template<typename T>
+Endianness TiffEntryImpl<T>::getEndianness() const {
+    return mEnd;
+}
+
+template<typename T>
+uint32_t TiffEntryImpl<T>::getComparableValue() const {
+    return mTag;
+}
+
+template<typename T>
+status_t TiffEntryImpl<T>::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);
+
+    uint32_t dataSize = getActualSize();
+    if (dataSize > OFFSET_SIZE) {
+        BAIL_ON_FAIL(out->write(&offset, 0, 1), ret);
+    } else {
+        uint32_t count = mCount;
+        if (getType() == RATIONAL || getType() == SRATIONAL) {
+            /**
+             * Rationals are stored as an array of ints.  Each
+             * rational is represented by 2 ints.  To recover the
+             * size of the array here, multiply the count by 2.
+             */
+            count <<= 1;
+        }
+        BAIL_ON_FAIL(out->write(mData, 0, count), ret);
+        ZERO_TILL_WORD(out, dataSize, ret);
+    }
+    return ret;
+}
+
+template<typename T>
+status_t TiffEntryImpl<T>::writeData(uint32_t offset, EndianOutput* out) const {
+    status_t ret = OK;
+
+    // Some tags have fixed-endian value output
+    Endianness tmp = UNDEFINED_ENDIAN;
+    if (mEnd != UNDEFINED_ENDIAN) {
+        tmp = out->getEndianness();
+        out->setEndianness(mEnd);
+    }
+
+    uint32_t count = mCount;
+    if (getType() == RATIONAL || getType() == SRATIONAL) {
+        /**
+         * Rationals are stored as an array of ints.  Each
+         * rational is represented by 2 ints.  To recover the
+         * size of the array here, multiply the count by 2.
+         */
+        count <<= 1;
+    }
+
+    BAIL_ON_FAIL(out->write(mData, 0, count), ret);
+
+    if (mEnd != UNDEFINED_ENDIAN) {
+        out->setEndianness(tmp);
+    }
+
+    // Write to next word alignment
+    ZERO_TILL_WORD(out, sizeof(T) * count, ret);
+    return ret;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_ENTRY_IMPL*/
+
+
diff --git a/media/img_utils/include/img_utils/TiffHelpers.h b/media/img_utils/include/img_utils/TiffHelpers.h
new file mode 100644 (file)
index 0000000..fd0ea7a
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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_TIFF_HELPERS_H
+#define IMG_UTILS_TIFF_HELPERS_H
+
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+const uint8_t ZERO_WORD[] = {0, 0, 0, 0};
+
+#define BAIL_ON_FAIL(x, flag) \
+    if ((flag = (x)) != OK) return flag;
+
+#define BYTES_TILL_WORD(index) \
+    ((TIFF_WORD_SIZE - ((index) % TIFF_WORD_SIZE)) % TIFF_WORD_SIZE)
+
+#define WORD_ALIGN(count) \
+    count += BYTES_TILL_WORD(count);
+
+#define ZERO_TILL_WORD(output, index, ret) \
+    { \
+        size_t remaining = BYTES_TILL_WORD(index); \
+        if (remaining > 0) { \
+            BAIL_ON_FAIL(output->write(ZERO_WORD, 0, remaining), ret); \
+        } \
+    }
+
+/**
+ * Basic TIFF header constants.
+ */
+enum {
+    BAD_OFFSET = 0,
+    TIFF_WORD_SIZE = 4, // Size in bytes
+    IFD_HEADER_SIZE = 2, // Size in bytes
+    IFD_FOOTER_SIZE = 4, // Size in bytes
+    TIFF_ENTRY_SIZE = 12, // Size in bytes
+    MAX_IFD_ENTRIES = UINT16_MAX,
+    FILE_HEADER_SIZE = 8, // Size in bytes
+    ENDIAN_MARKER_SIZE = 2, // Size in bytes
+    TIFF_MARKER_SIZE = 2, // Size in bytes
+    OFFSET_MARKER_SIZE = 4, // Size in bytes
+    TIFF_FILE_MARKER = 42,
+    BIG_ENDIAN_MARKER = 0x4D4Du,
+    LITTLE_ENDIAN_MARKER = 0x4949u
+};
+
+/**
+ * Constants for the TIFF tag types.
+ */
+enum TagType {
+    UNKNOWN_TAGTYPE = 0,
+    BYTE=1,
+    ASCII,
+    SHORT,
+    LONG,
+    RATIONAL,
+    SBYTE,
+    UNDEFINED,
+    SSHORT,
+    SLONG,
+    SRATIONAL,
+    FLOAT,
+    DOUBLE
+};
+
+/**
+ * Sizes of the TIFF entry fields (in bytes).
+ */
+enum {
+    TAG_SIZE = 2,
+    TYPE_SIZE = 2,
+    COUNT_SIZE = 4,
+    OFFSET_SIZE = 4
+};
+
+/**
+ * Convenience IFD id constants.
+ */
+enum {
+    IFD_0 = 0,
+    RAW_IFD,
+    PROFILE_IFD,
+    PREVIEW_IFD
+};
+
+inline size_t getTypeSize(TagType type) {
+    switch(type) {
+        case UNDEFINED:
+        case ASCII:
+        case BYTE:
+        case SBYTE:
+            return 1;
+        case SHORT:
+        case SSHORT:
+            return 2;
+        case LONG:
+        case SLONG:
+        case FLOAT:
+            return 4;
+        case RATIONAL:
+        case SRATIONAL:
+        case DOUBLE:
+            return 8;
+        default:
+            return 0;
+    }
+}
+
+inline uint32_t calculateIfdSize(size_t numberOfEntries) {
+    return IFD_HEADER_SIZE + IFD_FOOTER_SIZE + TIFF_ENTRY_SIZE * numberOfEntries;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_HELPERS_H*/
diff --git a/media/img_utils/include/img_utils/TiffIfd.h b/media/img_utils/include/img_utils/TiffIfd.h
new file mode 100644 (file)
index 0000000..c35f858
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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_TIFF_IFD_H
+#define IMG_UTILS_TIFF_IFD_H
+
+#include <img_utils/TiffWritable.h>
+#include <img_utils/TiffEntry.h>
+#include <img_utils/Output.h>
+#include <img_utils/SortedEntryVector.h>
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/StrongPointer.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * This class holds a single TIFF Image File Directory (IFD) structure.
+ *
+ * This maps to the TIFF IFD structure that is logically composed of:
+ * - A 2-byte field listing the number of entries.
+ * - A list of 12-byte TIFF entries.
+ * - A 4-byte offset to the next IFD.
+ */
+class ANDROID_API TiffIfd : public TiffWritable {
+    public:
+        // TODO: Copy constructor/equals here - needed for SubIfds.
+        TiffIfd(uint32_t ifdId);
+        virtual ~TiffIfd();
+
+        /**
+         * Add a TiffEntry to this IFD or replace an existing entry with the
+         * same tag ID.  No validation is done.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t addEntry(const sp<TiffEntry>& entry);
+
+        /**
+         * Set the pointer to the next IFD.  This is used to create a linked
+         * list of IFDs as defined by the TIFF 6.0 spec., and is not included
+         * when calculating the size of IFD and entries for the getSize()
+         * method (unlike SubIFDs).
+         */
+        virtual void setNextIfd(const sp<TiffIfd>& ifd);
+
+        /**
+         * Get the pointer to the next IFD, or NULL if none exists.
+         */
+        virtual sp<TiffIfd> getNextIfd() const;
+
+        /**
+         * Write the IFD data.  This includes the IFD header, entries, footer,
+         * and the corresponding values for each entry (recursively including
+         * sub-IFDs).  The written amount should end on a word boundary, and
+         * the given offset should be word aligned.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const;
+
+        /**
+         * Get the size of the IFD. This includes the IFD header, entries, footer,
+         * and the corresponding values for each entry (recursively including
+         * any sub-IFDs).
+         */
+        virtual uint32_t getSize() const;
+
+        /**
+         * Get the id of this IFD.
+         */
+        virtual uint32_t getId() const;
+
+        /**
+         * Get an entry with the given tag ID.
+         *
+         * Returns a strong pointer to the entry if it exists, or an empty strong
+         * pointer.
+         */
+        virtual sp<TiffEntry> getEntry(uint16_t tag) const;
+
+        /**
+         * Get a formatted string representing this IFD.
+         */
+        String8 toString() const;
+
+        /**
+         * Print a formatted string representing this IFD to logcat.
+         */
+        void log() const;
+
+        /**
+         * Get value used to determine sort order.
+         */
+        virtual uint32_t getComparableValue() const;
+    protected:
+        virtual uint32_t checkAndGetOffset(uint32_t offset) const;
+        SortedEntryVector mEntries;
+        sp<TiffIfd> mNextIfd;
+        uint32_t mIfdId;
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_IFD_H*/
diff --git a/media/img_utils/include/img_utils/TiffWritable.h b/media/img_utils/include/img_utils/TiffWritable.h
new file mode 100644 (file)
index 0000000..a72cecc
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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_TIFF_WRITABLE
+#define IMG_UTILS_TIFF_WRITABLE
+
+#include <img_utils/Orderable.h>
+#include <img_utils/EndianUtils.h>
+#include <img_utils/Output.h>
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * TiffWritable subclasses represent TIFF metadata objects that can be written
+ * to an EndianOutput object.  This is used for TIFF entries and IFDs.
+ */
+class ANDROID_API TiffWritable : public Orderable, public LightRefBase<TiffWritable> {
+    public:
+        TiffWritable();
+        virtual ~TiffWritable();
+
+        /**
+         * Write the data to the output. The given offset is used to calculate
+         * the header offset for values written.  The offset is defined
+         * relative to the beginning of the TIFF header, and is word aligned.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const = 0;
+
+        /**
+         * Get the size of the data to write.
+         */
+        virtual size_t getSize() const = 0;
+
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_WRITABLE*/
diff --git a/media/img_utils/include/img_utils/TiffWriter.h b/media/img_utils/include/img_utils/TiffWriter.h
new file mode 100644 (file)
index 0000000..ec27fc3
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * 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_TIFF_WRITER_H
+#define IMG_UTILS_TIFF_WRITER_H
+
+#include <img_utils/EndianUtils.h>
+#include <img_utils/TiffEntryImpl.h>
+#include <img_utils/TagDefinitions.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+
+#include <cutils/compiler.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+class TiffEntry;
+class TiffIfd;
+class Output;
+
+/**
+ * This class holds a collection of TIFF IFDs that can be written as a
+ * complete DNG file header.
+ *
+ * This maps to the TIFF header structure that is logically composed of:
+ * - An 8-byte file header containing an endianness indicator, the TIFF
+ *   file marker, and the offset to the first IFD.
+ * - A list of TIFF IFD structures.
+ */
+class ANDROID_API TiffWriter : public LightRefBase<TiffWriter> {
+    public:
+
+        /**
+         * Constructs a TiffWriter with the default tag mappings. This enables
+         * all of the tags defined in TagDefinitions.h, and uses the following
+         * mapping precedence to resolve collisions:
+         * (highest precedence) TIFF/EP > DNG > EXIF 2.3 > TIFF 6.0
+         */
+        TiffWriter();
+
+        /**
+         * Constructs a TiffWriter with the given tag mappings.  The mapping
+         * precedence will be in the order that the definition maps are given,
+         * where the lower index map gets precedence.
+         *
+         * This can be used with user-defined definitions, or definitions form
+         * TagDefinitions.h
+         *
+         * The enabledDefinitions mapping object is owned by the caller, and must
+         * stay alive for the lifespan of the constructed TiffWriter object.
+         */
+        TiffWriter(KeyedVector<uint16_t, const TagDefinition_t*>* enabledDefinitions,
+                size_t length);
+
+        virtual ~TiffWriter();
+
+        /**
+         * Write a TIFF header containing each IFD set.  This will recursively
+         * write all SubIFDs and tags.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t write(Output* out, Endianness end = LITTLE);
+
+        /**
+         * Get the total size in bytes of the TIFF header.  This includes all
+         * IFDs, tags, and values set for this TiffWriter.
+         */
+        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<TiffEntry>& 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.
+         *
+         * 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<typename T>
+        status_t buildEntry(uint16_t tag, uint32_t count, const T* data,
+                  /*out*/sp<TiffEntry>* outEntry) const;
+
+         /**
+         * 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.
+         *
+         * 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.
+         * - NAME_NOT_FOUND - No ifd exists with the given ID.
+         */
+        template<typename T>
+        status_t addEntry(uint16_t tag, uint32_t count, const T* data, 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<TiffEntry> 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.
+         */
+        virtual status_t uncheckedAddIfd(const sp<TiffIfd>& ifd);
+
+        /**
+         * Create an empty IFD with the given ID and add it to the end of the
+         * list of IFDs.
+         */
+        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.
+         */
+        template<typename T>
+        static sp<TiffEntry> 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<uint16_t, const TagDefinition_t*> buildTagMap(
+                  const TagDefinition_t* definitions, size_t length);
+
+        /**
+         * Returns the default type for the given tag ID.
+         */
+        virtual TagType getDefaultType(uint16_t tag) const;
+
+        /**
+         * Returns the default count for a given tag ID, or 0 if this
+         * tag normally has a variable count.
+         */
+        virtual uint32_t getDefaultCount(uint16_t tag) const;
+
+        /**
+         * Returns true if a definition exist for the given tag ID.
+         */
+        virtual bool checkIfDefined(uint16_t tag) const;
+
+        /**
+         * Print the currently configured IFDs and entries to logcat.
+         */
+        virtual void log() const;
+
+    protected:
+        enum {
+            DEFAULT_NUM_TAG_MAPS = 4,
+        };
+
+        sp<TiffIfd> findLastIfd();
+        status_t writeFileHeader(EndianOutput& out);
+        const TagDefinition_t* lookupDefinition(uint16_t tag) const;
+        status_t calculateOffsets();
+
+        sp<TiffIfd> mIfd;
+        KeyedVector<uint32_t, sp<TiffIfd> > mNamedIfds;
+        KeyedVector<uint16_t, const TagDefinition_t*>* mTagMaps;
+        size_t mNumTagMaps;
+
+        static KeyedVector<uint16_t, const TagDefinition_t*> sTagMaps[];
+};
+
+template<typename T>
+status_t TiffWriter::buildEntry(uint16_t tag, uint32_t count, const T* data,
+                  /*out*/sp<TiffEntry>* outEntry) const {
+    const TagDefinition_t* definition = lookupDefinition(tag);
+
+    if (definition == NULL) {
+        ALOGE("%s: No such tag exists for id %x.", __FUNCTION__, tag);
+        return BAD_INDEX;
+    }
+
+    uint32_t fixedCount = definition->fixedCount;
+    if (fixedCount > 0 && fixedCount != count) {
+        ALOGE("%s: Invalid count %d for tag %x (expects %d).", __FUNCTION__, count, tag,
+                fixedCount);
+        return BAD_VALUE;
+    }
+
+    TagType fixedType = definition->defaultType;
+    if (TiffEntry::forceValidType(fixedType, data) == NULL) {
+        ALOGE("%s: Invalid type used for tag value for tag %x.", __FUNCTION__, tag);
+        return BAD_TYPE;
+    }
+
+    *outEntry = new TiffEntryImpl<T>(tag, fixedType, count,
+        definition->fixedEndian, data);
+
+    return OK;
+}
+
+template<typename T>
+status_t TiffWriter::addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd) {
+    sp<TiffEntry> outEntry;
+    status_t ret = buildEntry<T>(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);
+}
+
+template<typename T>
+sp<TiffEntry> TiffWriter::uncheckedBuildEntry(uint16_t tag, TagType type, uint32_t count,
+        Endianness end, const T* data) {
+    TiffEntryImpl<T>* entry = new TiffEntryImpl<T>(tag, type, count, end, data);
+    return sp<TiffEntry>(entry);
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+
+#endif /*IMG_UTILS_TIFF_WRITER_H*/
diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk
new file mode 100644 (file)
index 0000000..80893be
--- /dev/null
@@ -0,0 +1,61 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+  EndianUtils.cpp \
+  FileInput.cpp \
+  FileOutput.cpp \
+  SortedEntryVector.cpp \
+  Input.cpp \
+  Output.cpp \
+  Orderable.cpp \
+  TiffIfd.cpp \
+  TiffWritable.cpp \
+  TiffWriter.cpp \
+  TiffEntry.cpp \
+  TiffEntryImpl.cpp \
+  ByteArrayOutput.cpp \
+  DngUtils.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+  libexpat \
+  libutils \
+  libcutils \
+  libcamera_metadata \
+  libcamera_client
+
+LOCAL_C_INCLUDES += \
+  $(LOCAL_PATH)/../include \
+  system/media/camera/include
+
+LOCAL_CFLAGS += \
+  -Wall \
+  -Wextra \
+  -Werror \
+  -fvisibility=hidden
+
+ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
+    # Enable assert() in eng builds
+    LOCAL_CFLAGS += -UNDEBUG -DLOG_NDEBUG=1
+endif
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include
+
+LOCAL_MODULE := libimg_utils
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/img_utils/src/ByteArrayOutput.cpp b/media/img_utils/src/ByteArrayOutput.cpp
new file mode 100644 (file)
index 0000000..db2d248
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 <img_utils/ByteArrayOutput.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+ByteArrayOutput::ByteArrayOutput() {}
+
+ByteArrayOutput::~ByteArrayOutput() {}
+
+status_t ByteArrayOutput::open() {
+    return OK;
+}
+
+status_t ByteArrayOutput::write(const uint8_t* buf, size_t offset, size_t count) {
+    if (mByteArray.appendArray(buf + offset, count) < 0) {
+        ALOGE("%s: Failed to write to ByteArrayOutput.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+status_t ByteArrayOutput::close() {
+    mByteArray.clear();
+    return OK;
+}
+
+size_t ByteArrayOutput::getSize() const {
+    return mByteArray.size();
+}
+
+const uint8_t* ByteArrayOutput::getArray() const {
+    return mByteArray.array();
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
new file mode 100644 (file)
index 0000000..788dfc8
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * 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 <img_utils/DngUtils.h>
+
+namespace android {
+namespace img_utils {
+
+OpcodeListBuilder::OpcodeListBuilder() : mOpList(), mEndianOut(&mOpList, BIG) {
+    if(mEndianOut.open() != OK) {
+        ALOGE("%s: Open failed.", __FUNCTION__);
+    }
+}
+
+OpcodeListBuilder::~OpcodeListBuilder() {
+    if(mEndianOut.close() != OK) {
+        ALOGE("%s: Close failed.", __FUNCTION__);
+    }
+}
+
+size_t OpcodeListBuilder::getSize() const {
+    return mOpList.getSize() + sizeof(mCount);
+}
+
+uint32_t OpcodeListBuilder::getCount() const {
+    return mCount;
+}
+
+status_t OpcodeListBuilder::buildOpList(uint8_t* buf) const {
+    uint32_t count = convertToBigEndian(mCount);
+    memcpy(buf, &count, sizeof(count));
+    memcpy(buf + sizeof(count), mOpList.getArray(), mOpList.getSize());
+    return OK;
+}
+
+status_t OpcodeListBuilder::addGainMapsForMetadata(uint32_t lsmWidth,
+                                                   uint32_t lsmHeight,
+                                                   uint32_t activeAreaTop,
+                                                   uint32_t activeAreaLeft,
+                                                   uint32_t activeAreaBottom,
+                                                   uint32_t activeAreaRight,
+                                                   CfaLayout cfa,
+                                                   const float* lensShadingMap) {
+    uint32_t activeAreaWidth = activeAreaRight - activeAreaLeft;
+    uint32_t activeAreaHeight = activeAreaBottom - activeAreaTop;
+    double spacingV = 1.0 / lsmHeight;
+    double spacingH = 1.0 / lsmWidth;
+
+    float redMap[lsmWidth * lsmHeight];
+    float greenEvenMap[lsmWidth * lsmHeight];
+    float greenOddMap[lsmWidth * lsmHeight];
+    float blueMap[lsmWidth * lsmHeight];
+
+    size_t lsmMapSize = lsmWidth * lsmHeight * 4;
+
+    // Split lens shading map channels into separate arrays
+    size_t j = 0;
+    for (size_t i = 0; i < lsmMapSize; i += 4, ++j) {
+        redMap[j] = lensShadingMap[i + LSM_R_IND];
+        greenEvenMap[j] = lensShadingMap[i + LSM_GE_IND];
+        greenOddMap[j] = lensShadingMap[i + LSM_GO_IND];
+        blueMap[j] = lensShadingMap[i + LSM_B_IND];
+    }
+
+    uint32_t redTop = 0;
+    uint32_t redLeft = 0;
+    uint32_t greenEvenTop = 0;
+    uint32_t greenEvenLeft = 1;
+    uint32_t greenOddTop = 1;
+    uint32_t greenOddLeft = 0;
+    uint32_t blueTop = 1;
+    uint32_t blueLeft = 1;
+
+    switch(cfa) {
+        case CFA_RGGB:
+            redTop = 0;
+            redLeft = 0;
+            greenEvenTop = 0;
+            greenEvenLeft = 1;
+            greenOddTop = 1;
+            greenOddLeft = 0;
+            blueTop = 1;
+            blueLeft = 1;
+            break;
+        case CFA_GRBG:
+            redTop = 0;
+            redLeft = 1;
+            greenEvenTop = 0;
+            greenEvenLeft = 0;
+            greenOddTop = 1;
+            greenOddLeft = 1;
+            blueTop = 1;
+            blueLeft = 0;
+            break;
+        case CFA_GBRG:
+            redTop = 1;
+            redLeft = 0;
+            greenEvenTop = 0;
+            greenEvenLeft = 0;
+            greenOddTop = 1;
+            greenOddLeft = 1;
+            blueTop = 0;
+            blueLeft = 1;
+            break;
+        case CFA_BGGR:
+            redTop = 1;
+            redLeft = 1;
+            greenEvenTop = 0;
+            greenEvenLeft = 1;
+            greenOddTop = 1;
+            greenOddLeft = 0;
+            blueTop = 0;
+            blueLeft = 0;
+            break;
+        default:
+            ALOGE("%s: Unknown CFA layout %d", __FUNCTION__, cfa);
+            return BAD_VALUE;
+    }
+
+    status_t err = addGainMap(/*top*/redTop,
+                              /*left*/redLeft,
+                              /*bottom*/activeAreaHeight - 1,
+                              /*right*/activeAreaWidth - 1,
+                              /*plane*/0,
+                              /*planes*/1,
+                              /*rowPitch*/2,
+                              /*colPitch*/2,
+                              /*mapPointsV*/lsmHeight,
+                              /*mapPointsH*/lsmWidth,
+                              /*mapSpacingV*/spacingV,
+                              /*mapSpacingH*/spacingH,
+                              /*mapOriginV*/0,
+                              /*mapOriginH*/0,
+                              /*mapPlanes*/1,
+                              /*mapGains*/redMap);
+    if (err != OK) return err;
+
+    err = addGainMap(/*top*/greenEvenTop,
+                     /*left*/greenEvenLeft,
+                     /*bottom*/activeAreaHeight - 1,
+                     /*right*/activeAreaWidth - 1,
+                     /*plane*/0,
+                     /*planes*/1,
+                     /*rowPitch*/2,
+                     /*colPitch*/2,
+                     /*mapPointsV*/lsmHeight,
+                     /*mapPointsH*/lsmWidth,
+                     /*mapSpacingV*/spacingV,
+                     /*mapSpacingH*/spacingH,
+                     /*mapOriginV*/0,
+                     /*mapOriginH*/0,
+                     /*mapPlanes*/1,
+                     /*mapGains*/greenEvenMap);
+    if (err != OK) return err;
+
+    err = addGainMap(/*top*/greenOddTop,
+                     /*left*/greenOddLeft,
+                     /*bottom*/activeAreaHeight - 1,
+                     /*right*/activeAreaWidth - 1,
+                     /*plane*/0,
+                     /*planes*/1,
+                     /*rowPitch*/2,
+                     /*colPitch*/2,
+                     /*mapPointsV*/lsmHeight,
+                     /*mapPointsH*/lsmWidth,
+                     /*mapSpacingV*/spacingV,
+                     /*mapSpacingH*/spacingH,
+                     /*mapOriginV*/0,
+                     /*mapOriginH*/0,
+                     /*mapPlanes*/1,
+                     /*mapGains*/greenOddMap);
+    if (err != OK) return err;
+
+    err = addGainMap(/*top*/blueTop,
+                     /*left*/blueLeft,
+                     /*bottom*/activeAreaHeight - 1,
+                     /*right*/activeAreaWidth - 1,
+                     /*plane*/0,
+                     /*planes*/1,
+                     /*rowPitch*/2,
+                     /*colPitch*/2,
+                     /*mapPointsV*/lsmHeight,
+                     /*mapPointsH*/lsmWidth,
+                     /*mapSpacingV*/spacingV,
+                     /*mapSpacingH*/spacingH,
+                     /*mapOriginV*/0,
+                     /*mapOriginH*/0,
+                     /*mapPlanes*/1,
+                     /*mapGains*/blueMap);
+    return err;
+}
+
+status_t OpcodeListBuilder::addGainMap(uint32_t top,
+                                       uint32_t left,
+                                       uint32_t bottom,
+                                       uint32_t right,
+                                       uint32_t plane,
+                                       uint32_t planes,
+                                       uint32_t rowPitch,
+                                       uint32_t colPitch,
+                                       uint32_t mapPointsV,
+                                       uint32_t mapPointsH,
+                                       double mapSpacingV,
+                                       double mapSpacingH,
+                                       double mapOriginV,
+                                       double mapOriginH,
+                                       uint32_t mapPlanes,
+                                       const float* mapGains) {
+
+    uint32_t opcodeId = GAIN_MAP_ID;
+
+    status_t err = mEndianOut.write(&opcodeId, 0, 1);
+    if (err != OK) return err;
+
+    uint8_t version[] = {1, 3, 0, 0};
+    err = mEndianOut.write(version, 0, NELEMS(version));
+    if (err != OK) return err;
+
+    uint32_t flags = FLAG_OPTIONAL | FLAG_OPTIONAL_FOR_PREVIEW;
+    err = mEndianOut.write(&flags, 0, 1);
+    if (err != OK) return err;
+
+    const uint32_t NUMBER_INT_ARGS = 11;
+    const uint32_t NUMBER_DOUBLE_ARGS = 4;
+
+    uint32_t totalSize = NUMBER_INT_ARGS * sizeof(uint32_t) + NUMBER_DOUBLE_ARGS * sizeof(double) +
+            mapPointsV * mapPointsH * mapPlanes * sizeof(float);
+
+    err = mEndianOut.write(&totalSize, 0, 1);
+    if (err != OK) return err;
+
+    // Batch writes as much as possible
+    uint32_t settings1[] = { top,
+                            left,
+                            bottom,
+                            right,
+                            plane,
+                            planes,
+                            rowPitch,
+                            colPitch,
+                            mapPointsV,
+                            mapPointsH };
+
+    err = mEndianOut.write(settings1, 0, NELEMS(settings1));
+    if (err != OK) return err;
+
+    double settings2[] = { mapSpacingV,
+                          mapSpacingH,
+                          mapOriginV,
+                          mapOriginH };
+
+    err = mEndianOut.write(settings2, 0, NELEMS(settings2));
+    if (err != OK) return err;
+
+    err = mEndianOut.write(&mapPlanes, 0, 1);
+    if (err != OK) return err;
+
+    err = mEndianOut.write(mapGains, 0, mapPointsV * mapPointsH * mapPlanes);
+    if (err != OK) return err;
+
+    mCount++;
+
+    return OK;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/EndianUtils.cpp b/media/img_utils/src/EndianUtils.cpp
new file mode 100644 (file)
index 0000000..8681cbe
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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 <img_utils/EndianUtils.h>
+
+namespace android {
+namespace img_utils {
+
+EndianOutput::EndianOutput(Output* out, Endianness end)
+        : mOffset(0), mOutput(out), mEndian(end) {}
+
+EndianOutput::~EndianOutput() {}
+
+status_t EndianOutput::open() {
+    mOffset = 0;
+    return mOutput->open();
+}
+
+status_t EndianOutput::close() {
+    return mOutput->close();
+}
+
+void EndianOutput::setEndianness(Endianness end) {
+    mEndian = end;
+}
+
+uint32_t EndianOutput::getCurrentOffset() const {
+    return mOffset;
+}
+
+Endianness EndianOutput::getEndianness() const {
+    return mEndian;
+}
+
+status_t EndianOutput::write(const uint8_t* buf, size_t offset, size_t count) {
+    status_t res = OK;
+    if((res = mOutput->write(buf, offset, count)) == OK) {
+        mOffset += count;
+    }
+    return res;
+}
+
+status_t EndianOutput::write(const int8_t* buf, size_t offset, size_t count) {
+    return write(reinterpret_cast<const uint8_t*>(buf), offset, count);
+}
+
+#define DEFINE_WRITE(_type_) \
+status_t EndianOutput::write(const _type_* buf, size_t offset, size_t count) { \
+    return writeHelper<_type_>(buf, offset, count); \
+}
+
+DEFINE_WRITE(uint16_t)
+DEFINE_WRITE(int16_t)
+DEFINE_WRITE(uint32_t)
+DEFINE_WRITE(int32_t)
+DEFINE_WRITE(uint64_t)
+DEFINE_WRITE(int64_t)
+
+status_t EndianOutput::write(const float* buf, size_t offset, size_t count) {
+    assert(sizeof(float) == sizeof(uint32_t));
+    return writeHelper<uint32_t>(reinterpret_cast<const uint32_t*>(buf), offset, count);
+}
+
+status_t EndianOutput::write(const double* buf, size_t offset, size_t count) {
+    assert(sizeof(double) == sizeof(uint64_t));
+    return writeHelper<uint64_t>(reinterpret_cast<const uint64_t*>(buf), offset, count);
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/FileInput.cpp b/media/img_utils/src/FileInput.cpp
new file mode 100644 (file)
index 0000000..e43fd53
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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 <img_utils/FileInput.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+FileInput::FileInput(String8 path) : mFp(NULL), mPath(path), mOpen(false) {}
+
+FileInput::~FileInput() {
+    if (mOpen) {
+        ALOGE("%s: FileInput destroyed without calling close!", __FUNCTION__);
+        close();
+    }
+
+}
+
+status_t FileInput::open() {
+    if (mOpen) {
+        ALOGW("%s: Open called when file %s already open.", __FUNCTION__, mPath.string());
+        return OK;
+    }
+    mFp = ::fopen(mPath, "rb");
+    if (!mFp) {
+        ALOGE("%s: Could not open file %s", __FUNCTION__, mPath.string());
+        return BAD_VALUE;
+    }
+    mOpen = true;
+    return OK;
+}
+
+size_t FileInput::read(uint8_t* buf, size_t offset, size_t count, status_t* err) {
+    if (!mOpen) {
+        ALOGE("%s: Could not read file %s, file not open.", __FUNCTION__, mPath.string());
+        if (err != NULL) *err = BAD_VALUE;
+        return 0;
+    }
+
+    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 bytesRead;
+}
+
+status_t FileInput::close() {
+    if(!mOpen) {
+        ALOGW("%s: Close called when file %s already close.", __FUNCTION__, mPath.string());
+        return OK;
+    }
+
+    status_t ret = OK;
+    if(::fclose(mFp) != 0) {
+        ALOGE("%s: Failed to close file %s.", __FUNCTION__, mPath.string());
+        ret = BAD_VALUE;
+    }
+    mOpen = false;
+    return OK;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/FileOutput.cpp b/media/img_utils/src/FileOutput.cpp
new file mode 100644 (file)
index 0000000..ce763ff
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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 <img_utils/FileOutput.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+FileOutput::FileOutput(String8 path) : mFp(NULL), mPath(path), mOpen(false) {}
+
+FileOutput::~FileOutput() {
+    if (mOpen) {
+        ALOGW("%s: Destructor called with %s still open.", __FUNCTION__, mPath.string());
+        close();
+    }
+}
+
+status_t FileOutput::open() {
+    if (mOpen) {
+        ALOGW("%s: Open called when file %s already open.", __FUNCTION__, mPath.string());
+        return OK;
+    }
+    mFp = ::fopen(mPath, "wb");
+    if (!mFp) {
+        ALOGE("%s: Could not open file %s", __FUNCTION__, mPath.string());
+        return BAD_VALUE;
+    }
+    mOpen = true;
+    return OK;
+}
+
+status_t FileOutput::write(const uint8_t* buf, size_t offset, size_t count) {
+    if (!mOpen) {
+        ALOGE("%s: Could not write file %s, file not open.", __FUNCTION__, mPath.string());
+        return BAD_VALUE;
+    }
+
+    ::fwrite(buf + offset, sizeof(uint8_t), count, mFp);
+
+    int error = ::ferror(mFp);
+    if (error != 0) {
+        ALOGE("%s: Error %d occurred while writing file %s.", __FUNCTION__, error, mPath.string());
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+status_t FileOutput::close() {
+    if(!mOpen) {
+        ALOGW("%s: Close called when file %s already close.", __FUNCTION__, mPath.string());
+        return OK;
+    }
+
+    status_t ret = OK;
+    if(::fclose(mFp) != 0) {
+        ALOGE("%s: Failed to close file %s.", __FUNCTION__, mPath.string());
+        ret = BAD_VALUE;
+    }
+    mOpen = false;
+    return OK;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/Input.cpp b/media/img_utils/src/Input.cpp
new file mode 100644 (file)
index 0000000..1e51e10
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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 <img_utils/Input.h>
+
+namespace android {
+namespace img_utils {
+
+Input::~Input() {}
+status_t Input::open() { return OK; }
+status_t Input::close() { return OK; }
+
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
diff --git a/media/img_utils/src/Orderable.cpp b/media/img_utils/src/Orderable.cpp
new file mode 100644 (file)
index 0000000..300f122
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 <img_utils/Orderable.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+#define COMPARE(op) \
+bool Orderable::operator op (const Orderable& orderable) const { \
+    return getComparableValue() op orderable.getComparableValue(); \
+}
+
+COMPARE(>)
+COMPARE(<)
+COMPARE(>=)
+COMPARE(<=)
+COMPARE(==)
+COMPARE(!=)
+
+Orderable::~Orderable() {}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/Output.cpp b/media/img_utils/src/Output.cpp
new file mode 100644 (file)
index 0000000..0e395b9
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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 <img_utils/Output.h>
+
+namespace android {
+namespace img_utils {
+
+Output::~Output() {}
+status_t Output::open() { return OK; }
+status_t Output::close() { return OK; }
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/SortedEntryVector.cpp b/media/img_utils/src/SortedEntryVector.cpp
new file mode 100644 (file)
index 0000000..f0e1fa1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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 <img_utils/SortedEntryVector.h>
+
+#include <utils/TypeHelpers.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+SortedEntryVector::~SortedEntryVector() {}
+
+ssize_t SortedEntryVector::indexOfTag(uint16_t tag) const {
+    // TODO: Use binary search here.
+    for (size_t i = 0; i < size(); ++i) {
+        if (itemAt(i)->getTag() == tag) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int SortedEntryVector::do_compare(const void* lhs, const void* rhs) const {
+    const sp<TiffEntry>* lEntry = reinterpret_cast<const sp<TiffEntry>*>(lhs);
+    const sp<TiffEntry>* rEntry = reinterpret_cast<const sp<TiffEntry>*>(rhs);
+    return compare_type(**lEntry, **rEntry);
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/TiffEntry.cpp b/media/img_utils/src/TiffEntry.cpp
new file mode 100644 (file)
index 0000000..e028827
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * 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 <img_utils/TiffIfd.h>
+#include <img_utils/TiffHelpers.h>
+#include <img_utils/TiffEntry.h>
+
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace img_utils {
+
+TiffEntry::~TiffEntry() {}
+
+/**
+ * Specialize for each valid type, including sub-IFDs.
+ *
+ * Values with types other than the ones given here should not compile.
+ */
+template<>
+const Vector<sp<TiffIfd> >* TiffEntry::forceValidType<Vector<sp<TiffIfd> > >(TagType type,
+          const Vector<sp<TiffIfd> >* 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<TiffIfd>* TiffEntry::forceValidType<sp<TiffIfd> >(TagType type, const sp<TiffIfd>* value) {
+    if (type == LONG) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'ifd' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const uint8_t* TiffEntry::forceValidType<uint8_t>(TagType type, const uint8_t* value) {
+    if (type == BYTE || type == ASCII || type == UNDEFINED) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'uint8_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const int8_t* TiffEntry::forceValidType<int8_t>(TagType type, const int8_t* value) {
+    if (type == SBYTE || type == ASCII || type == UNDEFINED) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'int8_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const uint16_t* TiffEntry::forceValidType<uint16_t>(TagType type, const uint16_t* value) {
+    if (type == SHORT) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'uint16_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const int16_t* TiffEntry::forceValidType<int16_t>(TagType type, const int16_t* value) {
+    if (type == SSHORT) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'int16_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const uint32_t* TiffEntry::forceValidType<uint32_t>(TagType type, const uint32_t* value) {
+    if (type == LONG || type == RATIONAL) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'uint32_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const int32_t* TiffEntry::forceValidType<int32_t>(TagType type, const int32_t* value) {
+    if (type == SLONG || type == SRATIONAL) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'int32_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const double* TiffEntry::forceValidType<double>(TagType type, const double* value) {
+    if (type == DOUBLE) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'double' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const float* TiffEntry::forceValidType<float>(TagType type, const float* value) {
+    if (type == FLOAT) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'float' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+String8 TiffEntry::toString() const {
+    String8 output;
+    uint32_t count = getCount();
+    output.appendFormat("[id: %x, type: %d, count: %u, value: '", getTag(), getType(), count);
+
+    size_t cappedCount = count;
+    if (count > MAX_PRINT_STRING_LENGTH) {
+        cappedCount = MAX_PRINT_STRING_LENGTH;
+    }
+
+    TagType type = getType();
+    switch (type) {
+        case UNDEFINED:
+        case BYTE: {
+            const uint8_t* typed_data = getData<uint8_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%u ", typed_data[i]);
+            }
+            break;
+        }
+        case ASCII: {
+            const char* typed_data = reinterpret_cast<const char*>(getData<uint8_t>());
+            size_t len = count;
+            if (count > MAX_PRINT_STRING_LENGTH) {
+                 len = MAX_PRINT_STRING_LENGTH;
+            }
+            output.append(typed_data, len);
+            break;
+        }
+        case SHORT: {
+            const uint16_t* typed_data = getData<uint16_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%u ", typed_data[i]);
+            }
+            break;
+        }
+        case LONG: {
+            const uint32_t* typed_data = getData<uint32_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%u ", typed_data[i]);
+            }
+            break;
+        }
+        case RATIONAL: {
+            const uint32_t* typed_data = getData<uint32_t>();
+            cappedCount <<= 1;
+            for (size_t i = 0; i < cappedCount; i+=2) {
+                output.appendFormat("%u/%u ", typed_data[i], typed_data[i + 1]);
+            }
+            break;
+        }
+        case SBYTE: {
+            const int8_t* typed_data = getData<int8_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%d ", typed_data[i]);
+            }
+            break;
+        }
+        case SSHORT: {
+            const int16_t* typed_data = getData<int16_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%d ", typed_data[i]);
+            }
+            break;
+        }
+        case SLONG: {
+            const int32_t* typed_data = getData<int32_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%d ", typed_data[i]);
+            }
+            break;
+        }
+        case SRATIONAL: {
+            const int32_t* typed_data = getData<int32_t>();
+            cappedCount <<= 1;
+            for (size_t i = 0; i < cappedCount; i+=2) {
+                output.appendFormat("%d/%d ", typed_data[i], typed_data[i + 1]);
+            }
+            break;
+        }
+        case FLOAT:
+        case DOUBLE: {
+            const float* typed_data = getData<float>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%f ", typed_data[i]);
+            }
+            break;
+        }
+        default: {
+            output.append("unknown type ");
+            break;
+        }
+    }
+
+    if (count > MAX_PRINT_STRING_LENGTH) {
+        output.append("...");
+    }
+    output.append("']");
+    return output;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/TiffEntryImpl.cpp b/media/img_utils/src/TiffEntryImpl.cpp
new file mode 100644 (file)
index 0000000..2052ceb
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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 <img_utils/TiffEntryImpl.h>
+#include <img_utils/TiffIfd.h>
+
+#include <utils/Vector.h>
+
+namespace android {
+namespace img_utils {
+
+template<>
+uint32_t TiffEntryImpl<TiffIfd>::getSize() const {
+    uint32_t total = 0;
+    for (uint32_t i = 0; i < mCount; ++i) {
+        total += mData[i].getSize();
+    }
+    return total;
+}
+
+template<>
+status_t TiffEntryImpl<TiffIfd>::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
new file mode 100644 (file)
index 0000000..b75309b
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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 <img_utils/TiffIfd.h>
+#include <img_utils/TiffHelpers.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+TiffIfd::TiffIfd(uint32_t ifdId)
+        : mNextIfd(), mIfdId(ifdId) {}
+
+TiffIfd::~TiffIfd() {}
+
+status_t TiffIfd::addEntry(const sp<TiffEntry>& entry) {
+    size_t size = mEntries.size();
+    if (size >= MAX_IFD_ENTRIES) {
+        ALOGW("%s: Failed to add entry for tag 0x%x to IFD %d, too many entries in IFD!",
+                __FUNCTION__, entry->getTag(), mIfdId);
+        return BAD_INDEX;
+    }
+
+    if (mEntries.add(entry) < 0) {
+        ALOGW("%s: Failed to add entry for tag 0x%x to ifd %d.", __FUNCTION__, entry->getTag(),
+                mIfdId);
+        return BAD_INDEX;
+    }
+    return OK;
+}
+
+sp<TiffEntry> TiffIfd::getEntry(uint16_t tag) const {
+    ssize_t index = mEntries.indexOfTag(tag);
+    if (index < 0) {
+        ALOGW("%s: No entry for tag 0x%x in ifd %d.", __FUNCTION__, tag, mIfdId);
+        return NULL;
+    }
+    return mEntries[index];
+}
+
+void TiffIfd::setNextIfd(const sp<TiffIfd>& ifd) {
+    mNextIfd = ifd;
+}
+
+sp<TiffIfd> TiffIfd::getNextIfd() const {
+    return mNextIfd;
+}
+
+uint32_t TiffIfd::checkAndGetOffset(uint32_t offset) const {
+    size_t size = mEntries.size();
+
+    if (size > MAX_IFD_ENTRIES) {
+        ALOGW("%s: Could not calculate IFD offsets, IFD %d contains too many entries.",
+                __FUNCTION__, mIfdId);
+        return BAD_OFFSET;
+    }
+
+    if (size <= 0) {
+        ALOGW("%s: Could not calculate IFD offsets, IFD %d contains no entries.", __FUNCTION__,
+                mIfdId);
+        return BAD_OFFSET;
+    }
+
+    if (offset == BAD_OFFSET) {
+        ALOGW("%s: Could not calculate IFD offsets, IFD %d had a bad initial offset.",
+                __FUNCTION__, mIfdId);
+        return BAD_OFFSET;
+    }
+
+    uint32_t ifdSize = calculateIfdSize(size);
+    WORD_ALIGN(ifdSize);
+    return offset + ifdSize;
+}
+
+status_t TiffIfd::writeData(uint32_t offset, /*out*/EndianOutput* out) const {
+    assert((offset % TIFF_WORD_SIZE) == 0);
+    status_t ret = OK;
+
+    ALOGV("%s: IFD %u written to offset %u", __FUNCTION__, mIfdId, offset );
+    uint32_t valueOffset = checkAndGetOffset(offset);
+    if (valueOffset == 0) {
+        return BAD_VALUE;
+    }
+
+    size_t size = mEntries.size();
+
+    // Writer IFD header (2 bytes, number of entries).
+    uint16_t header = static_cast<uint16_t>(size);
+    BAIL_ON_FAIL(out->write(&header, 0, 1), ret);
+
+    // Write tag entries
+    for (size_t i = 0; i < size; ++i) {
+        BAIL_ON_FAIL(mEntries[i]->writeTagInfo(valueOffset, out), ret);
+        valueOffset += mEntries[i]->getSize();
+    }
+
+    // Writer IFD footer (4 bytes, offset to next IFD).
+    uint32_t footer = (mNextIfd != NULL) ? offset + getSize() : 0;
+    BAIL_ON_FAIL(out->write(&footer, 0, 1), ret);
+
+    assert(out->getCurrentOffset() == offset + calculateIfdSize(size));
+
+    // Write zeroes till word aligned
+    ZERO_TILL_WORD(out, calculateIfdSize(size), ret);
+
+    // Write values for each tag entry
+    for (size_t i = 0; i < size; ++i) {
+        size_t last = out->getCurrentOffset();
+        // Only write values that are too large to fit in the 12-byte TIFF entry
+        if (mEntries[i]->getSize() > OFFSET_SIZE) {
+            BAIL_ON_FAIL(mEntries[i]->writeData(out->getCurrentOffset(), out), ret);
+        }
+        size_t next = out->getCurrentOffset();
+        size_t diff = (next - last);
+        size_t actual = mEntries[i]->getSize();
+        if (diff != actual) {
+            ALOGW("Sizes do not match for tag %x. Expected %d, received %d",
+                    mEntries[i]->getTag(), actual, diff);
+        }
+    }
+
+    assert(out->getCurrentOffset() == offset + getSize());
+
+    return ret;
+}
+
+uint32_t TiffIfd::getSize() const {
+    size_t size = mEntries.size();
+    uint32_t total = calculateIfdSize(size);
+    WORD_ALIGN(total);
+    for (size_t i = 0; i < size; ++i) {
+        total += mEntries[i]->getSize();
+    }
+    return total;
+}
+
+uint32_t TiffIfd::getId() const {
+    return mIfdId;
+}
+
+uint32_t TiffIfd::getComparableValue() const {
+    return mIfdId;
+}
+
+String8 TiffIfd::toString() const {
+    size_t s = mEntries.size();
+    String8 output;
+    output.appendFormat("[ifd: %x, num_entries: %u, entries:\n", getId(), s);
+    for(size_t i = 0; i < mEntries.size(); ++i) {
+        output.append("\t");
+        output.append(mEntries[i]->toString());
+        output.append("\n");
+    }
+    output.append(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0));
+    return output;
+}
+
+void TiffIfd::log() const {
+    size_t s = mEntries.size();
+    ALOGI("[ifd: %x, num_entries: %u, entries:\n", getId(), s);
+    for(size_t i = 0; i < s; ++i) {
+        ALOGI("\t%s", mEntries[i]->toString().string());
+    }
+    ALOGI(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0));
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/TiffWritable.cpp b/media/img_utils/src/TiffWritable.cpp
new file mode 100644 (file)
index 0000000..f8d7de7
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 <img_utils/TiffWritable.h>
+#include <img_utils/TiffHelpers.h>
+
+#include <assert.h>
+
+namespace android {
+namespace img_utils {
+
+TiffWritable::TiffWritable() {}
+
+TiffWritable::~TiffWritable() {}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp
new file mode 100644 (file)
index 0000000..2439033
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * 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 <img_utils/TiffIfd.h>
+#include <img_utils/TiffHelpers.h>
+#include <img_utils/TiffWriter.h>
+#include <img_utils/TagDefinitions.h>
+
+#include <assert.h>
+
+namespace android {
+namespace img_utils {
+
+KeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::buildTagMap(
+            const TagDefinition_t* definitions, size_t length) {
+    KeyedVector<uint16_t, const TagDefinition_t*> map;
+    for(size_t i = 0; i < length; ++i) {
+        map.add(definitions[i].tagId, definitions + i);
+    }
+    return map;
+}
+
+#define COMPARE(op) \
+bool Orderable::operator op (const Orderable& orderable) const { \
+    return getComparableValue() op orderable.getComparableValue(); \
+}
+
+#define ARRAY_SIZE(array) \
+    (sizeof(array) / sizeof(array[0]))
+
+KeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::sTagMaps[] = {
+    buildTagMap(TIFF_EP_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_EP_TAG_DEFINITIONS)),
+    buildTagMap(DNG_TAG_DEFINITIONS, ARRAY_SIZE(DNG_TAG_DEFINITIONS)),
+    buildTagMap(EXIF_2_3_TAG_DEFINITIONS, ARRAY_SIZE(EXIF_2_3_TAG_DEFINITIONS)),
+    buildTagMap(TIFF_6_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_6_TAG_DEFINITIONS))
+};
+
+TiffWriter::TiffWriter() : mTagMaps(sTagMaps), mNumTagMaps(DEFAULT_NUM_TAG_MAPS) {}
+
+TiffWriter::TiffWriter(KeyedVector<uint16_t, const TagDefinition_t*>* enabledDefinitions,
+        size_t length) : mTagMaps(enabledDefinitions), mNumTagMaps(length) {}
+
+TiffWriter::~TiffWriter() {}
+
+status_t TiffWriter::write(Output* out, Endianness end) {
+    status_t ret = OK;
+    EndianOutput endOut(out, end);
+
+    if (mIfd == NULL) {
+        ALOGE("%s: Tiff header is empty.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    BAIL_ON_FAIL(writeFileHeader(endOut), ret);
+
+    uint32_t offset = FILE_HEADER_SIZE;
+    sp<TiffIfd> ifd = mIfd;
+    while(ifd != NULL) {
+        BAIL_ON_FAIL(ifd->writeData(offset, &endOut), ret);
+        offset += ifd->getSize();
+        ifd = ifd->getNextIfd();
+    }
+    return ret;
+}
+
+
+const TagDefinition_t* TiffWriter::lookupDefinition(uint16_t tag) const {
+    const TagDefinition_t* definition = NULL;
+    for (size_t i = 0; i < mNumTagMaps; ++i) {
+        ssize_t index = mTagMaps[i].indexOfKey(tag);
+        if (index >= 0) {
+            definition = mTagMaps[i][index];
+            break;
+        }
+    }
+
+    if (definition == NULL) {
+        ALOGE("%s: No definition exists for tag with id %x.", __FUNCTION__, tag);
+    }
+    return definition;
+}
+
+sp<TiffEntry> TiffWriter::getEntry(uint16_t tag, uint32_t ifd) const {
+    ssize_t index = mNamedIfds.indexOfKey(ifd);
+    if (index < 0) {
+        ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd);
+        return NULL;
+    }
+    return mNamedIfds[index]->getEntry(tag);
+}
+
+
+// TODO: Fix this to handle IFD position in chain/sub-IFD tree
+status_t TiffWriter::addEntry(const sp<TiffEntry>& entry) {
+    uint16_t tag = entry->getTag();
+
+    const TagDefinition_t* definition = lookupDefinition(tag);
+
+    if (definition == NULL) {
+        return BAD_INDEX;
+    }
+    uint32_t ifdId = 0;  // TODO: all in IFD0 for now.
+
+    ssize_t index = mNamedIfds.indexOfKey(ifdId);
+
+    // Add a new IFD if necessary
+    if (index < 0) {
+        sp<TiffIfd> ifdEntry = new TiffIfd(ifdId);
+        if (mIfd == NULL) {
+            mIfd = ifdEntry;
+        }
+        index = mNamedIfds.add(ifdId, ifdEntry);
+        assert(index >= 0);
+    }
+
+    sp<TiffIfd> selectedIfd  = mNamedIfds[index];
+    return selectedIfd->addEntry(entry);
+}
+
+status_t TiffWriter::uncheckedAddIfd(const sp<TiffIfd>& ifd) {
+    mNamedIfds.add(ifd->getId(), ifd);
+    sp<TiffIfd> 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();
+    }
+    return OK;
+}
+
+status_t TiffWriter::addIfd(uint32_t ifd) {
+    ssize_t index = mNamedIfds.indexOfKey(ifd);
+    if (index >= 0) {
+        ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd);
+        return BAD_VALUE;
+    }
+    sp<TiffIfd> newIfd = new TiffIfd(ifd);
+    if (mIfd == NULL) {
+        mIfd = newIfd;
+    } else {
+        sp<TiffIfd> last = findLastIfd();
+        last->setNextIfd(newIfd);
+    }
+    mNamedIfds.add(ifd, newIfd);
+    return OK;
+}
+
+TagType TiffWriter::getDefaultType(uint16_t tag) const {
+    const TagDefinition_t* definition = lookupDefinition(tag);
+    if (definition == NULL) {
+        ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag);
+        return UNKNOWN_TAGTYPE;
+    }
+    return definition->defaultType;
+}
+
+uint32_t TiffWriter::getDefaultCount(uint16_t tag) const {
+    const TagDefinition_t* definition = lookupDefinition(tag);
+    if (definition == NULL) {
+        ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag);
+        return 0;
+    }
+    return definition->fixedCount;
+}
+
+bool TiffWriter::checkIfDefined(uint16_t tag) const {
+    return lookupDefinition(tag) != NULL;
+}
+
+sp<TiffIfd> TiffWriter::findLastIfd() {
+    sp<TiffIfd> ifd = mIfd;
+    while(ifd != NULL) {
+        sp<TiffIfd> nextIfd = ifd->getNextIfd();
+        if (nextIfd == NULL) {
+            break;
+        }
+        ifd = nextIfd;
+    }
+    return ifd;
+}
+
+status_t TiffWriter::writeFileHeader(EndianOutput& out) {
+    status_t ret = OK;
+    uint16_t endMarker = (out.getEndianness() == BIG) ? BIG_ENDIAN_MARKER : LITTLE_ENDIAN_MARKER;
+    BAIL_ON_FAIL(out.write(&endMarker, 0, 1), ret);
+
+    uint16_t tiffMarker = TIFF_FILE_MARKER;
+    BAIL_ON_FAIL(out.write(&tiffMarker, 0, 1), ret);
+
+    uint32_t offsetMarker = FILE_HEADER_SIZE;
+    BAIL_ON_FAIL(out.write(&offsetMarker, 0, 1), ret);
+    return ret;
+}
+
+uint32_t TiffWriter::getTotalSize() const {
+    uint32_t totalSize = FILE_HEADER_SIZE;
+    sp<TiffIfd> ifd = mIfd;
+    while(ifd != NULL) {
+        totalSize += ifd->getSize();
+        ifd = ifd->getNextIfd();
+    }
+    return totalSize;
+}
+
+void TiffWriter::log() const {
+    ALOGI("%s: TiffWriter:", __FUNCTION__);
+    sp<TiffIfd> ifd = mIfd;
+    while(ifd != NULL) {
+        ifd->log();
+        ifd = ifd->getNextIfd();
+    }
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/