Windows: Postscript Delegate: Concurrent PS/EPS read operations fail
Posted: 2018-08-02T08:38:49-07:00
ReadImage fails on Windows with ImageMagick 6.9.10 and GhostScript 9.06 if multiple threads execute these operation using dedicated ImageInfo instances.
The output (1 thread):
The output (2 threads):
The code:
This issues is independent from the actual PS/EPS input and does not occur on Linux. Please look into it.
Cheers,
Horst.
The output (1 thread):
Code: Select all
C:\>main 1 circle.eps test.jpg
Start READ
Start WRITE
END
Code: Select all
C:\>main 2 circle.eps test.jpg
Start READ
Start READ
Failed READ: PostscriptDelegateFailed `The system cannot find the file specified
.
' @ error/ps.c/ReadPSImage/888
Start WRITE
END
Code: Select all
#include <cstring>
#include <thread>
#include <list>
#include <string>
#include <iostream>
#include "magick/api.h"
class MagickException
{
ExceptionInfo exception_info;
public:
MagickException()
{
GetExceptionInfo(&exception_info);
}
~MagickException()
{
DestroyExceptionInfo(&exception_info);
}
operator ExceptionInfo * ()
{
return &exception_info;
}
ExceptionInfo * operator->()
{
return &exception_info;
}
};
class MagickImage
{
ImageInfo * imageinfo;
Image * image;
public:
MagickImage()
{
imageinfo = CloneImageInfo(nullptr);
image = nullptr;
}
~MagickImage()
{
DestroyImageList(image);
DestroyImageInfo(imageinfo);
}
std::string Read(char const * file)
{
MagickException magick_exception;
std::strcpy(imageinfo->filename, file);
image = ReadImage(imageinfo, magick_exception);
if (magick_exception->severity >= ErrorException) {
return magick_exception->reason;
}
return std::string();
}
std::string Write(char const * file)
{
std::strcpy(imageinfo->filename, file);
std::strcpy(image->filename, file);
WriteImage(imageinfo, image);
if (image->exception.severity >= ErrorException) {
return image->exception.reason;
}
return std::string();
}
};
static void Execute(char const * inputimage, char const * outputimage, std::string &errorstr)
{
MagickImage magick_image;
errorstr = magick_image.Read(inputimage);
if (!errorstr.empty()) {
return;
}
errorstr = magick_image.Write(outputimage);
if (!errorstr.empty()) {
return;
}
}
class MagickContext
{
public:
MagickContext()
{
MagickCoreGenesis(nullptr, MagickFalse);
}
~MagickContext()
{
MagickCoreTerminus();
}
};
int main(int argv, char **argc)
{
MagickContext magick_context;
unsigned threadcount = atoi(argc[1]);
char const * inputimage = argc[2];
char const * outputimage = argc[3];
std::list<std::thread> threads;
std::list<std::string> errorstrs;
for (unsigned i = 0; i < threadcount; ++i) {
errorstrs.emplace_back();
threads.emplace_back(Execute, inputimage, (std::to_string(i)+outputimage).c_str(), std::ref(errorstrs.back()));
}
{
decltype(threads)::iterator threadit = threads.begin();
decltype(errorstrs)::iterator errorstrit = errorstrs.begin();
for (unsigned i = 0; threadit != threads.end() && errorstrit != errorstrs.end(); ++i, ++threadit, ++errorstrit) {
threadit->join();
if (!errorstrit->empty()) {
std::cerr << i << " " << *errorstrit << std::endl;
}
}
}
std::cout << "END" << std::endl;
return 0;
}
Cheers,
Horst.