From a2493bcc0ab6d9925ce7a104c29d98c5cbb8195c Mon Sep 17 00:00:00 2001 From: Essem Date: Sun, 11 Sep 2022 02:09:44 -0500 Subject: [PATCH] Port swirl to vips (based on jcupitt's implementation) --- natives/swirl.cc | 113 ++++++++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 40 deletions(-) diff --git a/natives/swirl.cc b/natives/swirl.cc index e1fc555..6471555 100644 --- a/natives/swirl.cc +++ b/natives/swirl.cc @@ -1,62 +1,95 @@ -#include #include -#include -#include +#include using namespace std; -using namespace Magick; +using namespace vips; Napi::Value Swirl(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); + Napi::Object result = Napi::Object::New(env); try { Napi::Object obj = info[0].As(); Napi::Buffer data = obj.Get("data").As>(); string type = obj.Get("type").As().Utf8Value(); - int delay = - obj.Has("delay") ? obj.Get("delay").As().Int32Value() : 0; - Blob blob; + VOption *options = VImage::option()->set("access", "sequential"); - list frames; - list coalesced; - list mid; - try { - readImages(&frames, Blob(data.Data(), data.Length())); - } catch (Magick::WarningCoder &warning) { - cerr << "Coder Warning: " << warning.what() << endl; - } catch (Magick::Warning &warning) { - cerr << "Warning: " << warning.what() << endl; + VImage in = + VImage::new_from_buffer(data.Data(), data.Length(), "", + type == "gif" ? options->set("n", -1) : options) + .colourspace(VIPS_INTERPRETATION_sRGB); + if (!in.has_alpha()) + in = in.bandjoin(255); + + int pageHeight = vips_image_get_page_height(in.get_image()); + int nPages = vips_image_get_n_pages(in.get_image()); + int width = in.width(); + double newWidth = width * 3; + double newHeight = pageHeight * 3; + vector divSize = {newWidth / 2, newHeight / 2}; + + VImage index = VImage::xyz(newWidth, newHeight); + VImage center = index - divSize; + VImage polar = center + .copy(VImage::option() + ->set("format", VIPS_FORMAT_COMPLEX) + ->set("bands", 1)) + .polar() + .copy(VImage::option() + ->set("format", VIPS_FORMAT_FLOAT) + ->set("bands", 2)); + + int size = min(width, pageHeight) / 2; + + VImage test = (1 - polar.extract_band(0) / size); + VImage degrees = test.cast(VIPS_FORMAT_FLOAT).pow(2); + + VImage angle = polar.extract_band(1) + degrees * 180; + + VImage distortion = polar.extract_band(0) + .bandjoin(angle) + .copy(VImage::option() + ->set("format", VIPS_FORMAT_COMPLEX) + ->set("bands", 1)) + .rect() + .copy(VImage::option() + ->set("format", VIPS_FORMAT_FLOAT) + ->set("bands", 2)) + + divSize; + + vector img; + for (int i = 0; i < nPages; i++) { + VImage img_frame = + type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in; + + VImage distort = + img_frame + .gravity(VIPS_COMPASS_DIRECTION_CENTRE, newWidth, newHeight, + VImage::option()->set("extend", VIPS_EXTEND_COPY)) + .mapim(distortion, VImage::option()->set( + "interpolate", + VInterpolate::new_from_name("bicubic"))); + VImage frame = distort.crop(width, pageHeight, width, pageHeight); + img.push_back(frame); } - coalesceImages(&coalesced, frames.begin(), frames.end()); + VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1)); + final.set(VIPS_META_PAGE_HEIGHT, pageHeight); - for (Image &image : coalesced) { - image.swirl(180); - image.magick(type); - mid.push_back(image); - } + void *buf; + size_t length; + final.write_to_buffer(".gif", &buf, &length); - optimizeTransparency(mid.begin(), mid.end()); - - if (type == "gif") { - for (Image &image : mid) { - image.quantizeDither(false); - image.quantize(); - if (delay != 0) image.animationDelay(delay); - } - } - - writeImages(mid.begin(), mid.end(), &blob); - - Napi::Object result = Napi::Object::New(env); - result.Set("data", Napi::Buffer::Copy(env, (char *)blob.data(), - blob.length())); + result.Set("data", Napi::Buffer::Copy(env, (char *)buf, length)); result.Set("type", type); - return result; } catch (std::exception const &err) { - throw Napi::Error::New(env, err.what()); + Napi::Error::New(env, err.what()).ThrowAsJavaScriptException(); } catch (...) { - throw Napi::Error::New(env, "Unknown error"); + Napi::Error::New(env, "Unknown error").ThrowAsJavaScriptException(); } + + vips_error_clear(); + vips_thread_shutdown(); + return result; } \ No newline at end of file