AppearsToBeJpeg() public static method

public static AppearsToBeJpeg ( SIL.Windows.Forms.ImageToolbox.PalasoImage imageInfo ) : bool
imageInfo SIL.Windows.Forms.ImageToolbox.PalasoImage
return bool
Example #1
0
        // Make a thumbnail of the input image. newWidth and newHeight are both limits; the image will not
        // be larger than original, but if necessary will be shrunk to fit within the indicated rectangle.
        // If parameter 'backColor' is not Empty, we fill the background of the thumbnail with that color.
        public static bool GenerateThumbnail(string originalPath, string pathToProcessedImage, int newWidth, Color backColor)
        {
            using (var originalImage = PalasoImage.FromFileRobustly(originalPath))
            {
                // check if it needs resized
                if (originalImage.Image.Width <= newWidth)
                {
                    return(false);
                }

                // calculate dimensions
                var newW = (originalImage.Image.Width > newWidth) ? newWidth : originalImage.Image.Width;
                // allow for proper rounding from the division
                var newH = (newW * originalImage.Image.Height + (originalImage.Image.Width / 2)) / originalImage.Image.Width;

                var thumbnail = new Bitmap(newW, newH);

                var g = Graphics.FromImage(thumbnail);
                if (backColor != Color.Empty)
                {
                    using (var brush = new SolidBrush(backColor))
                    {
                        g.FillRectangle(brush, new Rectangle(0, 0, newW, newH));
                    }
                }
                Image imageToDraw      = originalImage.Image;
                bool  useOriginalImage = ImageUtils.AppearsToBeJpeg(originalImage);
                if (!useOriginalImage)
                {
                    imageToDraw = MakePngBackgroundTransparent(originalImage);
                }
                var destRect = new Rectangle(0, 0, newW, newH);
                // Note the image size may change when the background is made transparent.
                // See https://silbloom.myjetbrains.com/youtrack/issue/BL-5632.
                g.DrawImage(imageToDraw, destRect, new Rectangle(0, 0, imageToDraw.Width, imageToDraw.Height), GraphicsUnit.Pixel);
                if (!useOriginalImage)
                {
                    imageToDraw.Dispose();
                }
                RobustImageIO.SaveImage(thumbnail, pathToProcessedImage);
            }

            return(true);
        }
Example #2
0
        public string GetPathToResizedImage(string originalPath)
        {
            //don't mess with Bloom UI images
            if (new[] { "/img/", "placeHolder", "Button" }.Any(s => originalPath.Contains(s)))
            {
                return(originalPath);
            }

            string resizedPath;

            if (_paths.TryGetValue(originalPath, out resizedPath))
            {
                if (File.Exists(resizedPath) && new FileInfo(originalPath).LastWriteTimeUtc <= new FileInfo(resizedPath).LastWriteTimeUtc)
                {
                    return(resizedPath);
                }
                else
                {
                    _paths.Remove(originalPath);
                }
            }
            using (var originalImage = PalasoImage.FromFile(originalPath))
            {
                if (!originalPath.Contains("Button") && !ImageUtils.AppearsToBeJpeg(originalImage))
                {
                    ((Bitmap)originalImage.Image).MakeTransparent(Color.White);                     //instead of white, show the background color
                }

                if (originalImage.Image.Width > TargetDimension || originalImage.Image.Height > TargetDimension)
                {
                    var    maxDimension = Math.Max(originalImage.Image.Width, originalImage.Image.Height);
                    double shrinkFactor = (TargetDimension / (double)maxDimension);

                    var destWidth  = (int)(shrinkFactor * originalImage.Image.Width);
                    var destHeight = (int)(shrinkFactor * originalImage.Image.Height);
                    using (var b = new Bitmap(destWidth, destHeight))
                    {
                        using (Graphics g = Graphics.FromImage((Image)b))
                        {
                            //in version 1.0, we used .NearestNeighbor. But if there is a border line down the right size (as is common for thumbnails that,
                            //are, for example, re-inserted into Teacher's Guides), then the line gets cut off. So I switched it to HighQualityBicubic
                            g.InterpolationMode = InterpolationMode.HighQualityBicubic;                             //.NearestNeighbor;//or smooth it: HighQualityBicubic
                            g.DrawImage(originalImage.Image, 0, 0, destWidth, destHeight);
                        }

                        var temp = Path.Combine(_cacheFolder, Path.GetRandomFileName() + Path.GetExtension(originalPath));


                        //Hatton July 2012:
                        //Once or twice I saw a GDI+ error on the Save below, when the app 1st launched.
                        //I verified that if there is an IO error, that's what it you get (a GDI+ error).
                        //I looked once, and the %temp%/Bloom directory wasn't there, so that's what I think caused the error.
                        //It's not clear why the temp/bloom directory isn't there... possibly it was there a moment ago
                        //but then some startup thread cleared and deleted it? (we are now running on a thread responding to the http request)

                        Exception error = null;
                        for (int i = 0; i < 5; i++)                         //try up to five times, a second apart
                        {
                            try
                            {
                                error = null;

                                if (!Directory.Exists(Path.GetDirectoryName(temp)))
                                {
                                    Directory.CreateDirectory(Path.GetDirectoryName(temp));
                                }
                                b.Save(temp, originalImage.Image.RawFormat);
                                break;
                            }
                            catch (Exception e)
                            {
                                Logger.WriteEvent("Error in LowResImage while trying to write image.");
                                Logger.WriteEvent(e.Message);
                                error = e;
                                Thread.Sleep(1000);                                 //wait a second before trying again
                            }
                        }
                        if (error != null)
                        {
                            //NB: this will be on a non-UI thread, so it probably won't work well!
                            ErrorReport.NotifyUserOfProblem(error,
                                                            "Bloom is having problem saving a low-res version to your temp directory, at " + temp +
                                                            "\r\n\r\nYou might want to quit and restart Bloom. In the meantime, Bloom will try to use the full-res images.");
                            return(originalPath);
                        }

                        try
                        {
                            _paths.Add(originalPath, temp);                             //remember it so we can reuse if they show it again, and later delete
                        }
                        catch (Exception)
                        {
                            // it happens sometimes that though it wasn't in the _paths when we entered, it is now
                            // I haven't tracked it down... possibly we get a new request for the image while we're busy compressing it?
                        }

                        return(temp);
                    }
                }
                else
                {
                    return(originalPath);
                }
            }
        }
Example #3
0
        private bool MakePngBackgroundTransparent(string originalPath, string pathToProcessedImage)
        {
            try
            {
                using (var originalImage = PalasoImage.FromFileRobustly(originalPath))
                {
                    //if it's a jpeg, we don't resize, we don't mess with transparency, nothing. These things
                    //are scary in .net. Just send the original back and wash our hands of it.
                    if (ImageUtils.AppearsToBeJpeg(originalImage))
                    {
                        return(false);
                    }

                    using (var processedBitmap = MakePngBackgroundTransparent(originalImage))
                    {
                        //Hatton July 2012:
                        //Once or twice I saw a GDI+ error on the Save below, when the app 1st launched.
                        //I verified that if there is an IO error, that's what you get (a GDI+ error).
                        //I looked once, and the %temp%/Bloom directory wasn't there, so that's what I think caused the error.
                        //It's not clear why the temp/bloom directory isn't there... possibly it was there a moment ago
                        //but then some startup thread cleared and deleted it? (we are now running on a thread responding to the http request)

                        Exception error = null;
                        for (var i = 0; i < 3; i++)                         //try three times
                        {
                            try
                            {
                                error = null;
                                RobustImageIO.SaveImage(processedBitmap, pathToProcessedImage, originalImage.Image.RawFormat);
                                break;
                            }
                            catch (Exception e)
                            {
                                Logger.WriteEvent("***Error in RuntimeImageProcessor while trying to write image.");
                                Logger.WriteEvent(e.Message);
                                error = e;
                                //in setting the sleep time, keep in mind that this may be one of 20 images
                                //so if the problem happens to all of them, then you're looking 20*retries*sleep-time,
                                //which will look like hung program.
                                //Meanwhile, this transparency thing is actually just a nice-to-have. If we give
                                //up, it's ok.
                                Thread.Sleep(100);                                 //wait a 1/5 second before trying again
                            }
                        }

                        if (error != null)
                        {
                            throw error;                            //will be caught below
                        }
                    }
                }

                return(true);
            }
            //we want to gracefully degrade if this fails (as it did once, see comment in bl-2871)
            catch (TagLib.CorruptFileException e)
            {
                NonFatalProblem.Report(ModalIf.Beta, PassiveIf.All, "Problem with image metadata", originalPath, e);
                return(false);
            }
            catch (Exception e)
            {
                //while beta might make sense, this is actually
                //a common failure at the moment, with the license.png
                //so I'm setting to alpha.
                NonFatalProblem.Report(ModalIf.Alpha, PassiveIf.All, "Problem making image transparent.", originalPath, e);
                return(false);
            }
        }
Example #4
0
        // Make a thumbnail of the input image. newWidth and newHeight are both limits; the image will not be larger than original,
        // but if necessary will be shrunk to fit within the indicated rectangle.
        public static bool GenerateEBookThumbnail(string coverImagePath, string pathToProcessedImage, int thumbnailWidth, int thumbnailHeight, Color backColor)
        {
            using (var coverImage = PalasoImage.FromFileRobustly(coverImagePath))
            {
                var coverImageWidth  = coverImage.Image.Width;
                var coverImageHeight = coverImage.Image.Height;


                // We want to see a small border of background color, even if the image is a photo.
                const int kborder = 1;
                var       availableThumbnailWidth  = thumbnailWidth - (2 * kborder);
                var       availableThumbnailHeight = thumbnailHeight - (2 * kborder);

                // Calculate how big the image can be while keeping its original proportions.
                // First assume the width is the limiting factor
                var targetImageWidth  = (coverImageWidth > availableThumbnailWidth) ? availableThumbnailWidth : coverImage.Image.Width;
                var targetImageHeight = targetImageWidth * coverImageHeight / coverImageWidth;

                // if actually the height is the limiting factor, maximize height and re-compute the width
                if (targetImageHeight > availableThumbnailHeight)
                {
                    targetImageHeight = availableThumbnailHeight;
                    targetImageWidth  = targetImageHeight * coverImageWidth / coverImageHeight;
                }

                // pad to center the cover image
                var horizontalPadding = (availableThumbnailWidth - targetImageWidth) / 2;
                var verticalPadding   = (availableThumbnailHeight - targetImageHeight) / 2;
                var destRect          = new Rectangle(kborder + horizontalPadding, kborder + verticalPadding, targetImageWidth, targetImageHeight);

                // the decision here is just a heuristic based on the observation that line-drawings seem to look better in nice square block of color,
                // while full-color (usually jpeg) books look better with a thin (or no) border. We could put this under user control eventually.

                Rectangle backgroundAndBorderRect;
                var       appearsToBeJpeg = ImageUtils.AppearsToBeJpeg(coverImage);
                if (appearsToBeJpeg)
                {
                    backgroundAndBorderRect = destRect;
                    backgroundAndBorderRect.Inflate(kborder * 2, kborder * 2);
                }
                else
                {
                    // or, if we decide to always deliver the full thing:
                    backgroundAndBorderRect = new Rectangle(0, 0, thumbnailWidth, thumbnailHeight);
                }

                using (var thumbnail = new Bitmap(thumbnailWidth, thumbnailHeight))
                    using (var g = Graphics.FromImage(thumbnail))
                        using (var brush = new SolidBrush(backColor))
                        {
                            g.FillRectangle(brush, backgroundAndBorderRect);

                            lock (ConvertWhiteToTransparent)
                            {
                                var imageAttributes = appearsToBeJpeg ? null : ConvertWhiteToTransparent;
                                g.DrawImage(
                                    coverImage.Image,                        // finally, draw the cover image
                                    destRect,                                // with a scaled and centered destination
                                    0, 0, coverImageWidth, coverImageHeight, // from the entire cover image,
                                    GraphicsUnit.Pixel,
                                    imageAttributes);                        // changing white to transparent if a png
                            }
                            RobustImageIO.SaveImage(thumbnail, pathToProcessedImage);
                            // PNG thumbnails created from jpeg files seem to often be way too big, so try to save them as jpeg
                            // files instead if it saves space.  See https://silbloom.myjetbrains.com/youtrack/issue/BL-5605.
                            if (appearsToBeJpeg && Path.GetFileName(pathToProcessedImage) == "thumbnail.png")
                            {
                                var jpgPath = Path.ChangeExtension(pathToProcessedImage, "jpg");
                                RobustImageIO.SaveImage(thumbnail, jpgPath, ImageFormat.Jpeg);
                                var infoPng = new FileInfo(pathToProcessedImage);
                                var infoJpg = new FileInfo(jpgPath);
                                //Debug.WriteLine(String.Format("thumbnail.png size={0}; thumbnail.jpg size={1} (using smaller)", infoPng.Length, infoJpg.Length));
                                if (infoJpg.Length < infoPng.Length)
                                {
                                    File.Delete(pathToProcessedImage);
                                }
                                else
                                {
                                    File.Delete(jpgPath);
                                }
                            }
                        }
            }

            return(true);
        }