/// <summary>
        /// Usually we expect that a file at the same path but with extension .svg will
        /// be found and returned. Failing this we try for one ending in .png. If this still fails we
        /// start a process to generate an image from the template page content.
        /// </summary>
        /// <returns>Should always return a valid image path, unless we really can't come up with an image at all.</returns>
        private string FindOrGenerateThumbnail(string expectedPathOfThumbnailImage)
        {
            var localPath = AdjustPossibleLocalHostPathToFilePath(expectedPathOfThumbnailImage);

            var svgpath = Path.ChangeExtension(localPath, "svg");

            if (RobustFile.Exists(svgpath))
            {
                return(svgpath);
            }

            var  pngpath        = Path.ChangeExtension(localPath, "png");
            bool mustRegenerate = false;

            if (RobustFile.Exists(pngpath))
            {
                var f = new FileInfo(pngpath);
                if (f.IsReadOnly)
                {
                    return(pngpath);                    // it's locked, don't try and replace it
                }
                if (!IsPageTypeFromCurrentBook(localPath))
                {
                    return(pngpath);
                }

                mustRegenerate = true;                 // prevent thumbnailer using cached (obsolete) image
            }

            var altpath = GetAlternativeWritablePath(pngpath);

            if (RobustFile.Exists(altpath))
            {
                if (!IsPageTypeFromCurrentBook(localPath))
                {
                    return(altpath);
                }

                mustRegenerate = true;                 // prevent thumbnailer using cached (obsolete) image
            }

            // We don't have an image, or we want to make a fresh one
            var templatesDirectoryInTemplateBook = Path.GetDirectoryName(expectedPathOfThumbnailImage);
            var bookPath     = Path.GetDirectoryName(templatesDirectoryInTemplateBook);
            var templateBook = _bookFactory(new BookInfo(bookPath, false), _storageFactory(bookPath));

            //note: the caption is used here as a key to find the template page.
            var caption     = Path.GetFileNameWithoutExtension(expectedPathOfThumbnailImage).Trim();
            var isLandscape = caption.EndsWith("-landscape");             // matches string in page-chooser.ts

            if (isLandscape)
            {
                caption = caption.Substring(0, caption.Length - "-landscape".Length);
            }
            var isSquare = caption.EndsWith("-square");

            if (isSquare)
            {
                caption = caption.Substring(0, caption.Length - "-square".Length);
            }

            // The Replace of & with + corresponds to a replacement made in page-chooser.ts method loadPagesFromCollection.
            // The Trim is needed because template may now be created by users editing the pageLabel div, and those
            // labels typically include a trailing newline.
            IPage templatePage = templateBook.GetPages().FirstOrDefault(page => page.Caption.Replace("&", "+").Trim() == caption);

            if (templatePage == null)
            {
                templatePage = templateBook.GetPages().FirstOrDefault();                 // may get something useful?? or throw??
            }
            Image thumbnail = _thumbNailer.GetThumbnailForPage(templateBook, templatePage, isLandscape, isSquare, mustRegenerate);

            // lock to avoid BL-3781 where we got a "Object is currently in use elsewhere" while doing the Clone() below.
            // Note: it would appear that the clone isn't even needed, since it was added in the past to overcome this
            // same contention problem (but, in hindsight, only partially, see?). But for some reason if we just lock the image
            // until it is saved, we get all gray rectangles. So for now, we just quickly do the clone and unlock.
            var    resultPath = "";
            Bitmap clone;

            // Review: the coarse lock(SyncObj) in BloomServer.ProcessRequest() may have removed the need for this finer grained lock.
            lock (thumbnail)
            {
                clone = new Bitmap((Image)thumbnail.Clone());
            }
            using (clone)
            {
                try
                {
                    //if the directory doesn't exist in the template's directory, make it (i.e. "templates/").
                    Directory.CreateDirectory(templatesDirectoryInTemplateBook);
                    //save this thumbnail so that we don't have to generate it next time
                    clone.Save(pngpath);
                    resultPath = pngpath;
                }
                catch (Exception)
                {
                    var folder = Path.GetDirectoryName(altpath);
                    Directory.CreateDirectory(folder);
                    clone.Save(altpath);
                    resultPath = altpath;
                }
            }
            return(resultPath);
        }
        /// <summary>
        /// Usually we expect that a file at the same path but with extension .svg will
        /// be found and returned. Failing this we try for one ending in .png. If this still fails we
        /// start a process to generate an image from the template page content.
        /// </summary>
        /// <param name="expectedPathOfThumbnailImage"></param>
        /// <returns>Should always return true, unless we really can't come up with an image at all.</returns>
        private string FindOrGenerateThumbnail(string expectedPathOfThumbnailImage)
        {
            var localPath = AdjustPossibleLocalHostPathToFilePath(expectedPathOfThumbnailImage);

            var svgpath = Path.ChangeExtension(localPath, "svg");

            if (RobustFile.Exists(svgpath))
            {
                return(svgpath);
            }

            var  pngpath        = Path.ChangeExtension(localPath, "png");
            bool mustRegenerate = false;

            if (RobustFile.Exists(pngpath))
            {
                var f = new FileInfo(pngpath);
                if (f.IsReadOnly)
                {
                    return(pngpath);                    // it's locked, don't try and replace it
                }
                //If there is no svg, then we assume the we are using a generated image.
                //If the book we want a thumbnail from is the one is the one we are currently editing,
                //then the thumbnail we generated last time might not reflect how the page is laid out
                //now. So in that case we ignore the existing png thumbnail (and any cached version
                //of it we previously saved) and make a new one. Bloom saves the current page
                //before invoking AddPage, so the file contains the right content for making the new one.
                var testLocalPath  = localPath.Replace("/", "\\");
                var testFolderPath = _bookSelection.CurrentSelection.FolderPath.Replace("/", "\\");
                if (Platform.IsWindows)
                {
                    // Not a formality, since localPath comes from GetBookTemplatePaths and has been
                    // forced to LC on Windows, while the book's FolderPath has not.
                    testLocalPath  = testLocalPath.ToLowerInvariant();
                    testFolderPath = testFolderPath.ToLowerInvariant();
                }
                if (!testLocalPath.Contains(testFolderPath))
                {
                    return(pngpath);
                }
                mustRegenerate = true;                 // prevent thumbnailer using cached (obsolete) image
            }

            // We don't have an image, or we want to make a fresh one
            var templatesDirectoryInTemplateBook = Path.GetDirectoryName(expectedPathOfThumbnailImage);
            var bookPath     = Path.GetDirectoryName(templatesDirectoryInTemplateBook);
            var templateBook = _bookFactory(new BookInfo(bookPath, false), _storageFactory(bookPath));

            //note: the caption is used here as a key to find the template page.
            var caption     = Path.GetFileNameWithoutExtension(expectedPathOfThumbnailImage).Trim();
            var isLandscape = caption.EndsWith("-landscape");             // matches string in page-chooser.ts

            if (isLandscape)
            {
                caption = caption.Substring(0, caption.Length - "-landscape".Length);
            }

            // The Replace of & with + corresponds to a replacement made in page-chooser.ts method loadPagesFromCollection.
            // The Trim is needed because template may now be created by users editing the pageLabel div, and those
            // labels typically include a trailing newline.
            IPage templatePage = templateBook.GetPages().FirstOrDefault(page => page.Caption.Replace("&", "+").Trim() == caption);

            if (templatePage == null)
            {
                templatePage = templateBook.GetPages().FirstOrDefault();                 // may get something useful?? or throw??
            }
            Image thumbnail = _thumbNailer.GetThumbnailForPage(templateBook, templatePage, isLandscape, mustRegenerate);

            // lock to avoid BL-3781 where we got a "Object is currently in use elsewhere" while doing the Clone() below.
            // Note: it would appear that the clone isn't even needed, since it was added in the past to overcome this
            // same contention problem (but, in hindsight, only partially, see?). But for some reason if we just lock the image
            // until it is saved, we get all gray rectangles. So for now, we just quickly do the clone and unlock.
            var    resultPath = "";
            Bitmap clone;

            // Review: the coarse lock(SyncObj) in EnhancedImageServer.ProcessRequest() may have removed the need for this finer grained lock.
            lock (thumbnail)
            {
                clone = new Bitmap((Image)thumbnail.Clone());
            }
            using (clone)
            {
                try
                {
                    //if the directory doesn't exist in the template's directory, make it (i.e. "templates/").
                    Directory.CreateDirectory(templatesDirectoryInTemplateBook);
                    //save this thumbnail so that we don't have to generate it next time
                    clone.Save(pngpath);
                    resultPath = pngpath;
                }
                catch (Exception)
                {
                    using (var file = new TempFile())
                    {
                        clone.Save(file.Path);
                        resultPath = file.Path;
                    }
                }
            }
            return(resultPath);
        }