jpegoptim が一時ファイルを書き込もうとする場所を理解できていないのではないかと思います。
IIS 7.5 で ASP.Net 4 AppDomain を実行しています。その中に、次のように jpegoptim で JPEG を最適化するプロセスがあります。
FileHelper.Copy(existingPath, optimizerPath);
var jpegOptimResult = await ImageHelper.JpegOptim(optimizerPath, 30);
ローカルで実行すると、最適化された画像が得られます。上記のサーバーで実行すると、次のようになります。
D:\www\hplusf.com\b\pc\test.jpg 4096x2990 24bit N Adobe [OK] jpegoptim: 一時ファイルを開くときにエラーが発生しました。
のコードを表示できますがFileHelper.Copy()
、基本的にFile.Copy()
は、ファイルが既に存在する場合に上書きするだけです。
ImageHelper.JpegOptim は次のとおりです。
public static async Task<string> JpegOptim(string path, int quality)
{
string jpegOptimPath = Path.GetDirectoryName(new Uri(Assembly
.GetExecutingAssembly().CodeBase).LocalPath)
+ @"\Lib\jpegoptim.exe";
var jpegOptimResult = await ProcessRunner.O.RunProcess(
jpegOptimPath,
"-m" + quality + " -o -p --strip-all --all-normal \"" + path + "\"",
false, true
);
return jpegOptimResult;
}
jpegOptimResult は、生成されているエラー メッセージとして表示されているものです。ProcessRunner.RunProcess は次のとおりです。
public async Task<string> RunProcess(string command, string args,
bool window, bool captureOutput)
{
var processInfo = new ProcessStartInfo(command, args);
if (!window)
makeWindowless(processInfo);
string output = null;
if (captureOutput)
output = await runAndCapture(processInfo);
else
runDontCapture(processInfo);
return output;
}
protected void makeWindowless(ProcessStartInfo processInfo)
{
processInfo.CreateNoWindow = true;
processInfo.WindowStyle = ProcessWindowStyle.Hidden;
}
protected async Task<string> runAndCapture(ProcessStartInfo processInfo)
{
processInfo.UseShellExecute = false;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardError = true;
var process = Process.Start(processInfo);
var output = process.StandardOutput;
var error = process.StandardError;
while (!process.HasExited)
{
await Task.Delay(100);
}
string s = output.ReadToEnd();
s += '\n' + error.ReadToEnd();
return s;
}
そう:
jpegOptim は私のローカル マシンで適切に動作し、ファイルを最適化するので、jpegOptim を呼び出す方法とは異なります。
コピー操作は例外なく成功するため、そのディレクトリからの ASP.Net ユーザーの読み取り/書き込みに関するアクセス許可の問題ではありません。
jpegOptim はファイルを最適化して上書きするだけなので、実際に同じ ASP.Net ユーザーの下で実行されている場合、このファイルの書き込みに問題はないはずですが...
jpegOptim がその一時ファイルをどこに書き込もうとしているかは不明であるため、おそらく根本的な問題は、この一時ファイルがどこに書き込まれているのかということです。
ただし、Windows ソースから判断すると、次のようになります。
http://sourceforge.net/p/jpegoptim/code/HEAD/tree/jpegoptim-1.3.0/trunk/jpegoptim.c
jpegOptim の「一時ファイル」は、上記のオプションを使用すると、目的のファイルのように見えます。関連する jpegOptim ソースの行:
int dest = 0;
int main(int argc, char **argv)
{
...
dest=1 を設定する -d 引数を探しているコードがいくつかあります。つまり、ここでは dest は 0 のままです。次に if 分岐にヒットし、dest == 0 の else 句がこれを行います。
if (!splitdir(argv[i],tmpdir,sizeof(tmpdir)))
fatal("splitdir() failed!");
strncpy(newname,argv[i],sizeof(newname));
これは、入力画像ファイル名のディレクトリ名部分を変数にコピーするtmpdir
ことです.C:\Blah\18.jpgが割り当てるようにtmpdir="C:\Blah\"
. 次に、入力画像ファイル名全体を にダンプしますnewname
。つまり、その場で上書きするだけです。
コードのこの時点で、使用している変数は次のようになります。
dest=0
argv[i]=D:\www\hplusf.com\b\pc\test.jpg
tmpdir=D:\www\hplusf.com\b\pc\
newname=D:\www\hplusf.com\b\pc\test.jpg
その後、実際にファイルを開きますが、そこにエラーが発生する可能性があり、jpegoptim がファイルを正常に開いていることを示唆しています。また、ファイルが正常に開かれていることをさらに確認して、ファイルを解凍します。
私が見ている特定のエラーメッセージは、これらの行で発生します-MKSTEMPSがデフォルトビルド(私が使用している)に設定されているかどうかわからないことを告白します:
snprintf(tmpfilename,sizeof(tmpfilename),
"%sjpegoptim-%d-%d.XXXXXX.tmp", tmpdir, (int)getuid(), (int)getpid());
#ifdef HAVE_MKSTEMPS
if ((tmpfd = mkstemps(tmpfilename,4)) < 0)
fatal("error creating temp file: mkstemps() failed");
if ((outfile=fdopen(tmpfd,"wb"))==NULL)
#else
tmpfd=0;
if ((outfile=fopen(tmpfilename,"wb"))==NULL)
#endif
fatal("error opening temporary file");
これsnprintf
は C#String.Format()
のようなもので、次のようなパスを生成する必要があります。
D:\www\hplusf.com\b\pc\jpegoptim-1-2.XXXXXX.tmp
私が見つけたものから判断すると、MKSTEMPS が定義されていない可能性がありますfopen
。つまり、「wb」で呼び出されているという意味であり、バイナリ ファイルを書き込んでおり、null を返しているという意味で、開くことができず、エラー メッセージが表示されます。
だから - 考えられる原因:
tmpdirのパスが正しくありません C++ の手順をよく踏襲していない可能性があります (おそらく) が、見た目からすると、イメージのソース パスと同じである必要があります。しかし、おそらくそれは tmpdir のために jpegoptim によって破壊されたのでしょうか? 入力パスは、jpegoptim が実際にエラー メッセージでクリーンに出力するため、明らかにクリーンです。
アクセス許可の問題かなりありそうにありません。これが実行されているASP.Netユーザーは、jpegoptimが起動する前にディレクトリにコピーされるため、明確に読み書きできます。このディレクトリへのアクセス許可を持つマシン上の唯一のユーザーはそのユーザーであるため、jpegoptimはこの時点より前に失敗するはずですパーミッションの場合。別のディレクトリにアクセスしようとしている可能性がありますが、それは実際には悪い tmpdir シナリオです。
私が考えていない他の何か。
アイデア?
注:この質問は似ています:
C# で jpegtran、jpegoptim、またはその他の jpeg 最適化/圧縮を使用する
ただし、その質問は GoDaddy の共有環境について尋ねているため、プロセスをスピンアップできない可能性について回答が渦巻いています。私たちはサーバーを完全に制御しており、上記から明らかなように、jpegoptim プロセスは間違いなく正常に開始されているため、別のシナリオです。