Commit fa5f3dd8 authored by Noel Gordon's avatar Noel Gordon Committed by Commit Bot

[piexwasm] Add Piex Wasm reader exposing an image() read API to JS

Wrap raw image data in a PiexStreamReader, and process it via Piex, to
extract the preview and thumbnail image properties.

Caller (JS on the same web page) owns the data. All this code needs to
do is provide the offset and length of the image preview or thumbnail,
as well its EXIF color space and orientation information, and callback
these results in a JS object. The result includes the camera maker and
model, and preview and thumbnail image format/width/height properties,
for testing purposes [1].

Add fake DEPS to node_modules/piex to silence bogus presubmit error on
uploading this patch. Update Wasm Makefile for new piex.cpp code.

Build products we care about are the a.out.{js,wasm}. Build sizes look
good running:

  % ls -sh a.out*
  36K a.out.js
  60K a.out.wasm

[1] Note the upstream Piex code is fuzzed, and has a large test suite.
Our test approach can be much simpler therefore, as we'll soon see.

Tbr: slangley
Bug: 935285
Change-Id: I406dc08c908027782390e793bf6c7765bf0afa39
Reviewed-on: https://chromium-review.googlesource.com/c/1488474
Commit-Queue: Noel Gordon <noel@chromium.org>
Reviewed-by: default avatarJochen Eisinger <jochen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#635788}
parent d86f770e
include_rules = [
"+node_modules/piex",
]
...@@ -12,7 +12,7 @@ PSRC = $(PIEX)/src/piex.cc \ ...@@ -12,7 +12,7 @@ PSRC = $(PIEX)/src/piex.cc \
WAPI = ["cwrap", "addFunction", "removeFunction"] WAPI = ["cwrap", "addFunction", "removeFunction"]
INCS = -I $(PIEX) -I . INCS = -I $(PIEX) -I .
WASM = -s WASM=1 -fno-exceptions -D NO_ENABLE_LOGGING WASM = -s WASM=1 -fno-exceptions -Wall
WOPT = -Os --llvm-opts 3 \ WOPT = -Os --llvm-opts 3 \
-s STRICT=1 \ -s STRICT=1 \
-s ALLOW_MEMORY_GROWTH=1 \ -s ALLOW_MEMORY_GROWTH=1 \
...@@ -24,7 +24,7 @@ all: a.out.js ...@@ -24,7 +24,7 @@ all: a.out.js
a.out.js: piex.cpp.bc piex.src.bc a.out.js: piex.cpp.bc piex.src.bc
em++ --bind --std=c++11 $(WASM) $(WOPT) $^ em++ --bind --std=c++11 $(WASM) $(WOPT) $^
piex.cpp.bc: piex.cpp log.h logfatal.h Makefile piex.cpp.bc: piex.cpp Makefile
em++ --bind --std=c++11 $(WASM) $(WOPT) $(INCS) piex.cpp -o $@ em++ --bind --std=c++11 $(WASM) $(WOPT) $(INCS) piex.cpp -o $@
piex.src.bc: $(PSRC) Makefile piex.src.bc: $(PSRC) Makefile
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "node_modules/piex/src/piex.h"
#include <assert.h>
#include <emscripten.h>
#include <emscripten/val.h>
#include <stdint.h>
#include <string.h>
class PiexStreamReader : public piex::StreamInterface {
public:
PiexStreamReader(const char* data, size_t size) : data_(data), size_(size) {}
piex::Error GetData(const size_t offset, const size_t length, uint8_t* out) {
if (!EnsureData(offset, length))
return piex::kFail;
memcpy(out, data_ + offset, length);
return piex::kOk;
}
private:
bool EnsureData(const size_t offset, const size_t length) const {
if (offset > size_ || (size_ - offset) < length)
return false;
return true;
}
private:
const char* data_;
const size_t size_;
};
class PiexReader {
public:
static void ReadImage(const char* data, size_t size, int callback) {
assert(callback);
auto result = emscripten::val::object();
if (!data || !size) {
result.set("error", emscripten::val("failed to fetch image source"));
CallbackResult(callback, result);
return;
}
PiexStreamReader reader(data, size);
piex::PreviewImageData image;
switch (piex::GetPreviewImageData(&reader, &image)) {
case piex::kFail:
result.set("error", emscripten::val("failed to extract preview"));
break;
case piex::kUnsupported:
result.set("error", emscripten::val("unsupported preview type"));
break;
case piex::kOk:
result = GetProperties(image);
break;
default:
result.set("error", emscripten::val("unknown error"));
break;
}
CallbackResult(callback, result);
}
private:
static void CallbackResult(int callback, const emscripten::val& result) {
const int index = callback - 1;
auto callbacks = emscripten::val::global("functionPointers");
assert(callbacks.as<bool>());
auto context = emscripten::val::undefined();
callbacks[index].call<emscripten::val>("call", context, result);
}
static emscripten::val GetProperties(const piex::PreviewImageData& image) {
auto result = emscripten::val::object();
result.set("maker", emscripten::val(image.maker));
result.set("model", emscripten::val(image.model));
result.set("preview", GetPreview(image));
result.set("thumbnail", GetThumbnail(image));
return result;
}
static emscripten::val GetPreview(const piex::PreviewImageData& image) {
auto undefined = emscripten::val::undefined();
const auto format = static_cast<uint32_t>(image.preview.format);
if (format != piex::Image::Format::kJpegCompressed)
return undefined;
if (!image.preview.offset || !image.preview.length)
return undefined;
auto object = emscripten::val::object();
object.set("colorSpace", GetColorSpace(image));
object.set("orientation", emscripten::val(image.exif_orientation));
object.set("format", emscripten::val(format));
object.set("offset", emscripten::val(image.preview.offset));
object.set("length", emscripten::val(image.preview.length));
object.set("width", emscripten::val(image.preview.width));
object.set("height", emscripten::val(image.preview.height));
return object;
}
static emscripten::val GetThumbnail(const piex::PreviewImageData& image) {
auto undefined = emscripten::val::undefined();
const auto format = static_cast<uint32_t>(image.thumbnail.format);
if (!image.thumbnail.offset || !image.thumbnail.length)
return undefined;
auto object = emscripten::val::object();
object.set("colorSpace", GetColorSpace(image));
object.set("orientation", emscripten::val(image.exif_orientation));
object.set("format", emscripten::val(format));
object.set("offset", emscripten::val(image.thumbnail.offset));
object.set("length", emscripten::val(image.thumbnail.length));
object.set("width", emscripten::val(image.thumbnail.width));
object.set("height", emscripten::val(image.thumbnail.height));
return object;
}
static emscripten::val GetColorSpace(const piex::PreviewImageData& image) {
const auto space = static_cast<uint32_t>(image.color_space);
if (space == ::piex::PreviewImageData::kSrgb)
return emscripten::val("sRgb");
if (space == ::piex::PreviewImageData::kAdobeRgb)
return emscripten::val("adobeRgb");
return emscripten::val::undefined();
}
};
extern "C" {
void EMSCRIPTEN_KEEPALIVE image(const char* data, size_t size, int callback) {
PiexReader::ReadImage(data, size, callback);
}
} // extern "C"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment