Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c87e7b6 authored by Fyodor Kyslov's avatar Fyodor Kyslov
Browse files

JPEGR Decoder: Add XMP data parsing

Parse XMP packet and get Range Scaling Factor

Test: build
Bug: b/252835416
Change-Id: Id05269286e0a32f789a26e2af2ce3ebc4c89b4a6
parent 327b9350
Loading
Loading
Loading
Loading
+128 −6
Original line number Diff line number Diff line
@@ -16,16 +16,138 @@

#include <jpegrecoverymap/recoverymaputils.h>
#include <jpegrecoverymap/recoverymap.h>
#include <image_io/xml/xml_reader.h>
#include <image_io/base/message_handler.h>
#include <image_io/xml/xml_element_rules.h>
#include <image_io/xml/xml_handler.h>
#include <image_io/xml/xml_rule.h>

#include <string>
#include <sstream>

using namespace photos_editing_formats::image_io;
using namespace std;

namespace android::recoverymap {

bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata) {
    // TODO: Parse XMP Data
    (void)xmp_data;
    (void)xmp_size;
    metadata->rangeScalingFactor = 0.0708864;
    metadata->transferFunction = JPEGR_TF_HLG;

// Extremely simple XML Handler - just searches for interesting elements
class XMPXmlHandler : public XmlHandler {
public:

    XMPXmlHandler() : XmlHandler() {
        rangeScalingFactorState = NotStrarted;
    }

    enum ParseState {
        NotStrarted,
        Started,
        Done
    };

    virtual DataMatchResult StartElement(const XmlTokenContext& context) {
        string val;
        if (context.BuildTokenValue(&val)) {
            if (!val.compare(rangeScalingFactorName)) {
                rangeScalingFactorState = Started;
            } else {
                if (rangeScalingFactorState != Done) {
                    rangeScalingFactorState = NotStrarted;
                }
            }
        }
        return context.GetResult();
    }

    virtual DataMatchResult FinishElement(const XmlTokenContext& context) {
        if (rangeScalingFactorState == Started) {
            rangeScalingFactorState = Done;
        }
        return context.GetResult();
    }

    virtual DataMatchResult ElementContent(const XmlTokenContext& context) {
        string val;
        if (rangeScalingFactorState == Started) {
            if (context.BuildTokenValue(&val)) {
                rangeScalingFactorStr.assign(val);
            }
        }
        return context.GetResult();
    }

    bool getRangeScalingFactor(float* scaling_factor) {
        if (rangeScalingFactorState == Done) {
            stringstream ss(rangeScalingFactorStr);
            float val;
            if (ss >> val) {
                *scaling_factor = val;
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    bool getTransferFunction(jpegr_transfer_function* transfer_function) {
        *transfer_function = JPEGR_TF_HLG;
        return true;
    }

private:
    static const string rangeScalingFactorName;
    string              rangeScalingFactorStr;
    ParseState          rangeScalingFactorState;
};

const string XMPXmlHandler::rangeScalingFactorName = "GContainer:rangeScalingFactor";


bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata) {
    string nameSpace = "http://ns.adobe.com/xap/1.0/\0";

    if (xmp_size < nameSpace.size()+2) {
        // Data too short
        return false;
    }

    if (strncmp(reinterpret_cast<char*>(xmp_data), nameSpace.c_str(), nameSpace.size())) {
        // Not correct namespace
        return false;
    }

    // Position the pointers to the start of XMP XML portion
    xmp_data += nameSpace.size()+1;
    xmp_size -= nameSpace.size()+1;
    XMPXmlHandler handler;

    // We need to remove tail data until the closing tag. Otherwise parser will throw an error.
    while(xmp_data[xmp_size-1]!='>' && xmp_size > 1) {
        xmp_size--;
    }

    string str(reinterpret_cast<const char*>(xmp_data), xmp_size);
    MessageHandler msg_handler;
    unique_ptr<XmlRule> rule(new XmlElementRule);
    XmlReader reader(&handler, &msg_handler);
    reader.StartParse(std::move(rule));
    reader.Parse(str);
    reader.FinishParse();
    if (reader.HasErrors()) {
        // Parse error
        return false;
    }

    if (!handler.getRangeScalingFactor(&metadata->rangeScalingFactor)) {
        return false;
    }

    if (!handler.getTransferFunction(&metadata->transferFunction)) {
        return false;
    }
    return true;
}

} // namespace android::recoverymap
 No newline at end of file