Exemple #1
0
        // use highest quality transforms and no cached bitmaps
        public static void FinalOutputOne(Item item, Stats stats, Dictionary <string, bool> createdFiles, List <string> messages, CancellationTokenSource cancel)
        {
            Profile profile = new Profile("FinalOutput {0}", item.RenamedFileName);

            profile.Push("Item.WaitInit");
            item.WaitInit();
            profile.Pop();

            DateTime originalCreationTime  = File.GetCreationTime(item.SourcePath);
            DateTime originalLastWriteTime = File.GetLastWriteTime(item.SourcePath);

            string renamedTargetPath = Path.Combine(Path.GetDirectoryName(item.TargetPath), item.RenamedFileName);

            if (item.Delete)
            {
                // actual deletion occurs after end of run, by file being omitted from createdFiles
                Interlocked.Increment(ref stats.deleted);
            }
            else if (item.Valid)
            {
                // load source

                string tempFile = Path.GetTempFileName();
                File.Copy(item.SourcePath, tempFile, true /*overwrite*/);


                SmartBitmap bitmap = null;

                bool jpegTranRotationRequired = true;


                // initial lossy transforms

                if (item.NormalizeGeometry || (item.FineRotateDegrees != 0))
                {
                    if (bitmap == null)
                    {
                        bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile));
                    }

                    jpegTranRotationRequired = false;
                    if (item.RightRotations != 0)
                    {
                        ManagedBitmap bitmap2 = bitmap.AsManaged().RotateFlip(Transforms.RotateFlipFromRightRotations(item.RightRotations));
                        bitmap.Dispose();
                        bitmap = new SmartBitmap(bitmap2);
                    }

                    Transforms.ApplyNormalizeGeometry(
                        profile,
                        item.SourceFileName,
                        bitmap.AsManaged(),
                        1,
                        new Transforms.NormalizeGeometryParameters(
                            item.CornerTL,
                            item.CornerTR,
                            item.CornerBL,
                            item.CornerBR,
                            item.NormalizeGeometryForcedAspectRatio,
                            item.FineRotateDegrees,
                            item.NormalizeGeometryFinalInterp),
                        delegate(string text) { },
                        cancel);
                }


                // lossless transform phase

                if (bitmap == null)
                {
                    List <string> jpegtranMessages = new List <string>();
                    string        error;

                    bool rotateOK = true;
                    if (jpegTranRotationRequired &&
                        ((item.RightRotations != 0) || (item.OriginalExifOrientation != RotateFlipType.RotateNoneFlipNone)))
                    {
                        rotateOK = false;
                        int combinedRotations = (item.RightRotations + Transforms.RightRotationsFromRotateFlipType(item.OriginalExifOrientation)) % 4;

                        // TODO: strip only Exif orientation after doing this - how? (currently strips all)
                        if (Transforms.LosslessRotateRightFinal(
                                tempFile,
                                tempFile,
                                combinedRotations,
                                out error))
                        {
                            Interlocked.Increment(ref stats.rotated);
                            rotateOK = true;
                        }
                        else
                        {
                            jpegtranMessages.Add(String.Format("Lossless rotate failed for \"{0}\" ({1}).", item.RenamedFileName, error));
                        }
                    }

                    bool cropOK = true;
                    if (!item.CropRect.IsEmpty)
                    {
                        cropOK = false;
                        if (Transforms.LosslessCropFinal(tempFile, tempFile, item.CropRect, out error))
                        {
                            Interlocked.Increment(ref stats.cropped);
                            cropOK = true;
                        }
                        else
                        {
                            jpegtranMessages.Add(String.Format("Lossless crop failed for \"{0}\" ({1}).", item.RenamedFileName, error));
                        }
                    }

                    if (!rotateOK || !cropOK)
                    {
                        // If jpegtran is unable to handle image (e.g. dimensions not integral multiples - as generated by
                        // some cameras), fall back to lossy rotation and log a message.

                        bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile));

                        if (!rotateOK)
                        {
                            ManagedBitmap bitmap2 = bitmap.AsManaged().RotateFlip(Transforms.RotateFlipFromRightRotations(item.RightRotations));
                            bitmap.Dispose();
                            bitmap = new SmartBitmap(bitmap2);
                        }

                        if (!cropOK)
                        {
                            ManagedBitmap bitmap2 = bitmap.AsManaged().Crop(item.CropRect);
                            bitmap.Dispose();
                            bitmap = new SmartBitmap(bitmap2);
                        }

                        jpegtranMessages.Add("Using lossy rotation/crop instead.");
                        lock (messages)
                        {
                            messages.Add(String.Join(" ", jpegtranMessages.ToArray()));
                        }
                    }
                }
                else
                {
                    // whoops- preceding transform prevents jpegtran from being used (recreating jpeg would be lossy)

                    if (!item.CropRect.IsEmpty)
                    {
                        ManagedBitmap bitmap2 = bitmap.AsManaged().Crop(item.CropRect);
                        bitmap.Dispose();
                        bitmap = new SmartBitmap(bitmap2);
                    }
                }


                // following lossy transforms phase

                if (item.Unbias)
                {
                    if (bitmap == null)
                    {
                        bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile));
                    }

                    Transforms.PolyUnbiasDiagnostics unused;
                    Transforms.ApplyPolyUnbias(
                        profile,
                        item.RenamedFileName,
                        bitmap.AsManaged(profile),
                        Rectangle.Empty /*already cropped*/,
                        new Transforms.PolyUnbiasParameters(
                            item.UnbiasMaxDegree,
                            item.UnbiasMaxChisq,
                            item.UnbiasMaxS,
                            item.UnbiasMinV),
                        null,
                        out unused,
                        cancel);

                    Interlocked.Increment(ref stats.polyUnbias);
                }

                if (item.BrightAdjust)
                {
                    if (bitmap == null)
                    {
                        bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile));
                    }

                    Transforms.ApplyBrightAdjust(
                        profile,
                        item.RenamedFileName,
                        bitmap.AsManaged(profile),
                        Rectangle.Empty /*already cropped*/,
                        new Transforms.BrightAdjustParameters(item.BrightAdjustMinClusterFrac, item.BrightAdjustWhiteCorrect),
                        null,
                        cancel);

                    Interlocked.Increment(ref stats.brightAdjust);
                }

                if (item.StaticSaturate)
                {
                    if (bitmap == null)
                    {
                        bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile));
                    }

                    Transforms.ApplyStaticSaturation(
                        profile,
                        item.RenamedFileName,
                        bitmap.AsManaged(profile),
                        Rectangle.Empty /*already cropped*/,
                        new Transforms.StaticSaturateParameters(item.StaticSaturateWhiteThreshhold, item.StaticSaturateBlackThreshhold, item.StaticSaturateExponent),
                        cancel);
                }

                if (item.Shrink)
                {
                    if (bitmap == null)
                    {
                        bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile));
                    }

                    //Bitmap shrunk = Transforms.Shrink(profile, bitmap.AsGDI(profile), item.ShrinkFactor);
                    int           newWidth  = (int)Math.Floor(bitmap.Width / item.ShrinkFactor);
                    int           newHeight = (int)Math.Floor(bitmap.Height / item.ShrinkFactor);
                    ManagedBitmap bitmap2   = ImageClient.ResizeGDI(profile, bitmap.AsManaged(profile), newWidth, newHeight);
                    bitmap.Dispose();
                    bitmap = new SmartBitmap(bitmap2);

                    Interlocked.Increment(ref stats.shrunk);
                }

                // TODO: eliminate shrink and OneBit's expand if both are configured

                if (item.OneBit)
                {
                    if (bitmap == null)
                    {
                        bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile));
                    }

                    SmartBitmap bitmap2 = new SmartBitmap(
                        Transforms.ApplyOneBit(
                            profile,
                            item.RenamedFileName,
                            bitmap,
                            new Transforms.OneBitParameters(item.OneBitChannel, item.OneBitThreshhold, item.OneBitScaleUp),
                            cancel));
                    bitmap.Dispose();
                    bitmap = bitmap2;

                    Interlocked.Increment(ref stats.oneBit);
                }

                if (bitmap != null)
                {
                    Transforms.SaveImage(profile, bitmap, tempFile, item.JpegQuality, item.JpegUseGdi, item.OutputFormat);
                    bitmap.Dispose();
                }


                // write target

                string targetPath;
                bool   extUpper = String.Equals(Path.GetExtension(renamedTargetPath), Path.GetExtension(renamedTargetPath).ToUpper());
                switch (item.OutputFormat)
                {
                default:
                    Debug.Assert(false);
                    throw new ArgumentException();

                case OutputFormat.Jpeg:
                    targetPath = Path.ChangeExtension(renamedTargetPath, extUpper ? ".JPG" : ".jpg");
                    break;

                case OutputFormat.Bmp:
                    targetPath = Path.ChangeExtension(renamedTargetPath, extUpper ? ".BMP" : ".bmp");
                    break;

                case OutputFormat.Png:
                    targetPath = Path.ChangeExtension(renamedTargetPath, extUpper ? ".PNG" : ".png");
                    break;
                }
                for (int i = 0; i <= RetryCount; i++)
                {
                    try
                    {
                        File.Copy(tempFile, targetPath, true /*overwrite*/);
                        File.SetCreationTime(targetPath, originalCreationTime);
                        File.SetLastWriteTime(targetPath, DateTime.Now);
                    }
                    catch (IOException) when(i < RetryCount)
                    {
                        // HACK: If folder is open, Explorer may have file locked to refresh thumbnail
                        Thread.Sleep(SleepRetry);
                    }
                }

                lock (createdFiles)
                {
                    createdFiles.Add(Path.GetFileName(targetPath).ToLowerInvariant(), false);
                }

                File.Delete(tempFile);
            }
            else
            {
                lock (createdFiles)
                {
                    createdFiles.Add(Path.GetFileName(renamedTargetPath).ToLowerInvariant(), false);
                }

                if (!String.Equals(item.SourcePath, renamedTargetPath, StringComparison.OrdinalIgnoreCase))
                {
                    File.Copy(item.SourcePath, renamedTargetPath, true /*overwrite*/);
                }
            }

            profile.End();
            Program.Log(LogCat.Perf, profile.Report());
        }