Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
d1c5eb7
Create the image-shrinking progress dialog on the UI thread (BL-16646)
StephenMcConnel Aug 5, 2026
fa179c2
Document the UI-thread requirement on UpdateImagesWithProgressDialog …
StephenMcConnel Aug 5, 2026
462f977
Merge remote-tracking branch 'origin/master' into BL-16646-HugeImageHang
StephenMcConnel Aug 5, 2026
2efd625
Report image-shrinking progress through IProgress instead of a dialog…
StephenMcConnel Aug 5, 2026
c2b96d0
Merge remote-tracking branch 'origin/master' into BL-16646-HugeImageHang
StephenMcConnel Aug 5, 2026
bb09b0d
Correct comments that still described the deleted progress dialog (BL…
StephenMcConnel Aug 5, 2026
7b14a6d
Reinstate the progress dialog for callers with no browser progress (B…
StephenMcConnel Aug 5, 2026
47ab0d5
Show the image-shrinking dialog only on the UI thread (BL-16646)
StephenMcConnel Aug 5, 2026
2be1adc
Use the caller's progress whenever there is a real one (BL-16646)
StephenMcConnel Aug 6, 2026
e8ccafa
Merge remote-tracking branch 'origin/master' into BL-16646-HugeImageHang
StephenMcConnel Aug 6, 2026
7b68fe0
Record why a UI-thread caller needs a pumping progress (BL-16646)
StephenMcConnel Aug 6, 2026
b686e89
Merge remote-tracking branch 'origin/master' into BL-16646-HugeImageHang
StephenMcConnel Aug 6, 2026
cc9ecf3
Log a failed image shrink instead of throwing out of the dialog (BL-1…
StephenMcConnel Aug 6, 2026
89427d4
Merge remote-tracking branch 'origin/master' into BL-16646-HugeImageHang
StephenMcConnel Aug 6, 2026
f81e1b8
Do not repeat a failed image shrink within the same update pass (BL-1…
StephenMcConnel Aug 6, 2026
8fc9fe9
Tell the user when shrinking a book's images fails (BL-16646)
StephenMcConnel Aug 6, 2026
4e03242
Merge remote-tracking branch 'origin/master' into BL-16646-HugeImageHang
StephenMcConnel Aug 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/BloomExe/Book/Book.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1107,7 +1107,7 @@ public void EnsureUpToDate(IProgress progress = null, bool forCopyOfUpToDateBook
EnsureUpToDateMemory(progress);
UpdateSupportFiles();

Storage.MigrateToMediaLevel1ShrinkLargeImages();
Storage.MigrateToMediaLevel1ShrinkLargeImages(progress);
Comment thread
StephenMcConnel marked this conversation as resolved.

Storage.CleanupUnusedSupportFiles(forCopyOfUpToDateBook);

Expand Down Expand Up @@ -1895,7 +1895,7 @@ public void EnsureUpToDateMemory(IProgress progress)
// already been done, so they must be called in exactly this order.
Storage.RestoreStuffBeforeMigration();
Storage.MigrateMaintenanceLevels();
Storage.MigrateToMediaLevel1ShrinkLargeImages();
Storage.MigrateToMediaLevel1ShrinkLargeImages(progress);
Storage.MigrateToLevel2RemoveTransparentComicalSvgs();
Storage.MigrateToLevel3PutImgFirst();
Storage.MigrateToLevel4UseAppearanceSystem();
Expand Down
13 changes: 6 additions & 7 deletions src/BloomExe/Book/BookProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,12 @@ public static int ProcessBook(Book book, bool fitImageTextSplits = false)
// BookStorage.MigrateToMediaLevel1ShrinkLargeImages, won't help here: the bridge HTML
// already carries a modern maintenance level, so BringBookUpToDate below treats that
// migration as already done and skips it. So we do the shrink ourselves, unconditionally
// (not gated by mediaMaintenanceLevel), and it must come BEFORE BringBookUpToDate: (a) on
// a book old enough that the migration WOULD run, it normally finds nothing left to
// shrink, so its modal progress dialog is not created on this background thread (where a
// WinForms dialog is illegal, BL-16646) -- "normally" because a GraphicsMagick failure can
// leave an image oversized, in which case that narrow old-book case can still hit the
// dialog; (b) the off-screen per-page fix-up then measures and lays out against the
// final, already-shrunk images.
// (not gated by mediaMaintenanceLevel), and it must come BEFORE BringBookUpToDate so that
// the off-screen per-page fix-up measures and lays out against the final, already-shrunk
// images. (This used to have a second reason -- keeping the migration from creating its
// modal progress dialog on this background thread, which WinForms forbids. BL-16646
// removed that dialog in favor of reporting through the caller's IProgress, so only the
// layout reason remains.)
if (ImageUtils.NeedToShrinkImages(book.FolderPath))
{
Log("shrinking oversized images in the book folder");
Expand Down
32 changes: 22 additions & 10 deletions src/BloomExe/Book/BookStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void CleanupUnusedSupportFiles(
void CaptureInitialStateForMigration();
void RestoreStuffBeforeMigration();
void MigrateMaintenanceLevels();
void MigrateToMediaLevel1ShrinkLargeImages();
void MigrateToMediaLevel1ShrinkLargeImages(IProgress progress);
void MigrateToLevel2RemoveTransparentComicalSvgs();
void MigrateToLevel3PutImgFirst();

Expand Down Expand Up @@ -4047,7 +4047,11 @@ public void MigrateMaintenanceLevels()
/// memory. However, it is still helpful for performance and reducing published file sizes.
/// Does nothing if mediaMaintenanceLevel indicates it has already been done.
/// </summary>
public void MigrateToMediaLevel1ShrinkLargeImages()
/// <param name="progress">Where to report the (potentially very slow) shrinking, so the
/// user can see why we are busy. Callers pass whatever progress they already own; headless
/// callers such as the bulk-upload CLI pass a NullProgress and so report nothing. Must not
/// be null: ImageUtils.FixSizeAndTransparencyOfImagesInFolder dereferences it.</param>
public void MigrateToMediaLevel1ShrinkLargeImages(IProgress progress)
Comment thread
StephenMcConnel marked this conversation as resolved.
Outdated
{
var levelString = Dom.GetMetaValue("mediaMaintenanceLevel", "0");
if (!int.TryParse(levelString, out int level))
Expand All @@ -4058,10 +4062,11 @@ public void MigrateToMediaLevel1ShrinkLargeImages()
{
// If the book contains overlarge images, we want to fix those before editing because this can lead
// to thumbnails not being created properly and other bad behavior. This is a one-time fix that can
// permanently change the images in the original book folder. If any images must be shrunk, then a
// progress dialog pops up because that can be a very slow process. If nothing needs to be done,
// nothing will appear on the screen, and it usually takes a small fraction of a second to determine
// this.
// permanently change the images in the original book folder. Shrinking can be very slow, so we
Comment thread
StephenMcConnel marked this conversation as resolved.
// report it through the caller's progress rather than putting up our own dialog (BL-16646: this
// used to create a WinForms dialog, which is illegal on the background threads several of these
// callers run on). If nothing needs to be done, nothing is reported at all, and it usually takes
// a small fraction of a second to determine this.

// Bloom 4.9 and later limit images used by Bloom books to be no larger than 3500x2550 in
// order to avoid out of memory errors that can happen with really large images.
Expand All @@ -4073,13 +4078,21 @@ public void MigrateToMediaLevel1ShrinkLargeImages()
// This update can be very slow, so encourage the user that something is happening.
Comment thread
StephenMcConnel marked this conversation as resolved.
Comment thread
StephenMcConnel marked this conversation as resolved.
// NO images should have transparency removed. See https://issues.bloomlibrary.org/youtrack/issue/BL-8846.

if (Program.RunningUnitTests)
var shell = Shell.GetShellOrOtherOpenForm();
// shell is null when no window is open at all -- the headless CLI (bulk upload,
// hydrate). There is nothing to show a dialog on, and nothing to ask about thread
// affinity, so just do the work against whatever progress we were handed.
if (
Comment thread
StephenMcConnel marked this conversation as resolved.
Program.RunningUnitTests
|| progress is WebProgressAdapter
|| shell == null
|| !shell.InvokeRequired
)
{
// TeamCity enforces not showing modal dialogs during unit tests on Windows 10.
ImageUtils.FixSizeAndTransparencyOfImagesInFolder(
Comment thread
StephenMcConnel marked this conversation as resolved.
Outdated
FolderPath,
new List<string>(),
new NullProgress()
progress
);
}
else
Expand All @@ -4098,7 +4111,6 @@ public void MigrateToMediaLevel1ShrinkLargeImages()
}
}
}

Dom.UpdateMetaElement("mediaMaintenanceLevel", "1");
}

Expand Down
12 changes: 9 additions & 3 deletions src/BloomExe/CollectionTab/CollectionModel.BloomSourceImport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public void ImportBloomSourceFiles(
{
// The derivative path builds its Book in memory and adds it to the collection
// itself, so it needs no reload.
var book = MakeDerivativeFromBloomSourceFile(path);
var book = MakeDerivativeFromBloomSourceFile(path, progress);
if (book != null)
lastImported = book;
}
Expand Down Expand Up @@ -561,7 +561,10 @@ out string instanceId
/// creation was cancelled (e.g. a template configuration dialog). Because a derivative always
/// gets a fresh id, there is never a duplicate to resolve.
/// </summary>
internal Book.Book MakeDerivativeFromBloomSourceFile(string sourcePath)
internal Book.Book MakeDerivativeFromBloomSourceFile(
string sourcePath,
IWebSocketProgress progress
)
{
var tempFolder = ExtractAndPrepareBloomSourceToTemp(sourcePath, out _, out _);
try
Expand Down Expand Up @@ -589,7 +592,10 @@ internal Book.Book MakeDerivativeFromBloomSourceFile(string sourcePath)
newBook.BookData.Language1Tag
);

newBook.BringBookUpToDate(new NullProgress(), false);
newBook.BringBookUpToDate(
progress == null ? new NullProgress() : new WebProgressAdapter(progress),
false
);

TheOneEditableCollection.AddBookInfo(newBook.BookInfo);
newBook.RecordPendingCreatedHistoryEvent();
Expand Down
6 changes: 3 additions & 3 deletions src/BloomExe/web/WebProgressAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace Bloom.web
{
/// <summary>
/// Class that allows code expecting an SIL.Progress.IProgress object to use a WebSocketProgress instead.
/// Class that allows code expecting an SIL.Progress.IProgress object to use an IWebSocketProgress instead.
/// </summary>
public class WebProgressAdapter : IProgress
{
Expand All @@ -32,9 +32,9 @@ public void IndicateUnknownProgress() { }
public void Initialize() { }
}

private readonly WebSocketProgress _webProgress;
private readonly IWebSocketProgress _webProgress;

public WebProgressAdapter(WebSocketProgress progress)
public WebProgressAdapter(IWebSocketProgress progress)
{
_webProgress = progress;
}
Expand Down
10 changes: 5 additions & 5 deletions src/BloomTests/Book/BookStorageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1999,7 +1999,7 @@ public void PerformNecessaryMaintenanceOnBook_DeletesSVGIfOnlyNoneStyle()
);

//SUT
storage.MigrateToMediaLevel1ShrinkLargeImages(); // does nothing in this situation, but should still bump level
storage.MigrateToMediaLevel1ShrinkLargeImages(new NullProgress()); // does nothing in this situation, but should still bump level
var mediaLevel = storage.Dom.GetMetaValue("mediaMaintenanceLevel", "0");
Assert.That(mediaLevel, Is.EqualTo("1"));
storage.MigrateToLevel2RemoveTransparentComicalSvgs();
Expand Down Expand Up @@ -2129,7 +2129,7 @@ public void PerformNecessaryMaintenanceOnBook_EnsuresImgAtStartOfImageContainer(
);

//SUT
storage.MigrateToMediaLevel1ShrinkLargeImages();
storage.MigrateToMediaLevel1ShrinkLargeImages(new NullProgress());
storage.MigrateToLevel2RemoveTransparentComicalSvgs();
storage.MigrateToLevel3PutImgFirst();

Expand Down Expand Up @@ -2167,7 +2167,7 @@ public void PerformNecessaryMaintenanceOnBook_DoesNotDeleteSVGIfOtherStylePresen
);

//SUT
storage.MigrateToMediaLevel1ShrinkLargeImages();
storage.MigrateToMediaLevel1ShrinkLargeImages(new NullProgress());
storage.MigrateToLevel2RemoveTransparentComicalSvgs();
storage.MigrateToLevel3PutImgFirst();

Expand Down Expand Up @@ -2333,7 +2333,7 @@ public void PerformNecessaryMaintenanceOnBook_HandlesMultipleSVGs()
);

//SUT
storage.MigrateToMediaLevel1ShrinkLargeImages();
storage.MigrateToMediaLevel1ShrinkLargeImages(new NullProgress());
storage.MigrateToLevel2RemoveTransparentComicalSvgs();
storage.MigrateToLevel3PutImgFirst();

Expand Down Expand Up @@ -2615,7 +2615,7 @@ public void PerformNecessaryMaintenanceOnBook_DoesNothingIfAlreadyProcessed()
);

//SUT
storage.MigrateToMediaLevel1ShrinkLargeImages();
storage.MigrateToMediaLevel1ShrinkLargeImages(new NullProgress());
storage.MigrateToLevel2RemoveTransparentComicalSvgs();
storage.MigrateToLevel3PutImgFirst();

Expand Down