Add support for input array to join or animate #1580

This commit is contained in:
Lovell Fuller
2025-02-07 13:53:27 +00:00
parent 67ff930535
commit 5ab9168813
12 changed files with 377 additions and 20 deletions

View File

@@ -160,10 +160,30 @@ namespace sharp {
descriptor->textWrap = AttrAsEnum<VipsTextWrap>(input, "textWrap", VIPS_TYPE_TEXT_WRAP);
}
}
// Join images together
if (HasAttr(input, "joinAnimated")) {
descriptor->joinAnimated = AttrAsBool(input, "joinAnimated");
}
if (HasAttr(input, "joinAcross")) {
descriptor->joinAcross = AttrAsUint32(input, "joinAcross");
}
if (HasAttr(input, "joinShim")) {
descriptor->joinShim = AttrAsUint32(input, "joinShim");
}
if (HasAttr(input, "joinBackground")) {
descriptor->joinBackground = AttrAsVectorOfDouble(input, "joinBackground");
}
if (HasAttr(input, "joinHalign")) {
descriptor->joinHalign = AttrAsEnum<VipsAlign>(input, "joinHalign", VIPS_TYPE_ALIGN);
}
if (HasAttr(input, "joinValign")) {
descriptor->joinValign = AttrAsEnum<VipsAlign>(input, "joinValign", VIPS_TYPE_ALIGN);
}
// Limit input images to a given number of pixels, where pixels = width * height
descriptor->limitInputPixels = static_cast<uint64_t>(AttrAsInt64(input, "limitInputPixels"));
// Allow switch from random to sequential access
descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
if (HasAttr(input, "access")) {
descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
}
// Remove safety features and allow unlimited input
descriptor->unlimited = AttrAsBool(input, "unlimited");
// Use the EXIF orientation to auto orient the image

View File

@@ -71,6 +71,12 @@ namespace sharp {
int textSpacing;
VipsTextWrap textWrap;
int textAutofitDpi;
bool joinAnimated;
int joinAcross;
int joinShim;
std::vector<double> joinBackground;
VipsAlign joinHalign;
VipsAlign joinValign;
std::vector<double> pdfBackground;
InputDescriptor():
@@ -79,7 +85,7 @@ namespace sharp {
failOn(VIPS_FAIL_ON_WARNING),
limitInputPixels(0x3FFF * 0x3FFF),
unlimited(false),
access(VIPS_ACCESS_RANDOM),
access(VIPS_ACCESS_SEQUENTIAL),
bufferLength(0),
isBuffer(false),
density(72.0),
@@ -108,6 +114,12 @@ namespace sharp {
textSpacing(0),
textWrap(VIPS_TEXT_WRAP_WORD),
textAutofitDpi(0),
joinAnimated(false),
joinAcross(1),
joinShim(0),
joinBackground{ 0.0, 0.0, 0.0, 255.0 },
joinHalign(VIPS_ALIGN_LOW),
joinValign(VIPS_ALIGN_LOW),
pdfBackground{ 255.0, 255.0, 255.0, 255.0 } {}
};

View File

@@ -42,7 +42,39 @@ class PipelineWorker : public Napi::AsyncWorker {
// Open input
vips::VImage image;
sharp::ImageType inputImageType;
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
if (baton->join.empty()) {
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
} else {
std::vector<VImage> images;
bool hasAlpha = false;
for (auto &join : baton->join) {
std::tie(image, inputImageType) = sharp::OpenInput(join);
image = sharp::EnsureColourspace(image, baton->colourspacePipeline);
images.push_back(image);
hasAlpha |= sharp::HasAlpha(image);
}
if (hasAlpha) {
for (auto &image : images) {
if (!sharp::HasAlpha(image)) {
image = sharp::EnsureAlpha(image, 1);
}
}
} else {
baton->input->joinBackground.pop_back();
}
inputImageType = sharp::ImageType::PNG;
image = VImage::arrayjoin(images, VImage::option()
->set("across", baton->input->joinAcross)
->set("shim", baton->input->joinShim)
->set("background", baton->input->joinBackground)
->set("halign", baton->input->joinHalign)
->set("valign", baton->input->joinValign));
if (baton->input->joinAnimated) {
image = image.copy();
image.set(VIPS_META_N_PAGES, static_cast<int>(images.size()));
image.set(VIPS_META_PAGE_HEIGHT, static_cast<int>(image.height() / images.size()));
}
}
VipsAccess access = baton->input->access;
image = sharp::EnsureColourspace(image, baton->colourspacePipeline);
@@ -1069,6 +1101,7 @@ class PipelineWorker : public Napi::AsyncWorker {
// Unsupported output format
(baton->err).append("Unsupported output format ");
if (baton->formatOut == "input") {
(baton->err).append("when trying to match input format of ");
(baton->err).append(ImageTypeId(inputImageType));
} else {
(baton->err).append(baton->formatOut);
@@ -1495,6 +1528,14 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
// Input
baton->input = sharp::CreateInputDescriptor(options.Get("input").As<Napi::Object>());
// Join images together
if (sharp::HasAttr(options, "join")) {
Napi::Array join = options.Get("join").As<Napi::Array>();
for (unsigned int i = 0; i < join.Length(); i++) {
baton->join.push_back(
sharp::CreateInputDescriptor(join.Get(i).As<Napi::Object>()));
}
}
// Extract image options
baton->topOffsetPre = sharp::AttrAsInt32(options, "topOffsetPre");
baton->leftOffsetPre = sharp::AttrAsInt32(options, "leftOffsetPre");

View File

@@ -39,6 +39,7 @@ struct Composite {
struct PipelineBaton {
sharp::InputDescriptor *input;
std::vector<sharp::InputDescriptor *> join;
std::string formatOut;
std::string fileOut;
void *bufferOut;