Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8c585c7
AI Image Editor: whole-book image enumeration + book-wide replacement
hatton May 30, 2026
3dd5687
Document AiImageEditorApi and remove the vestigial C# frame-message path
hatton May 31, 2026
ddf7be0
Merge remote-tracking branch 'origin/master' into AddAIImages
hatton Jun 19, 2026
da81d80
AI Image Editor: per-user OpenRouter key storage + serve editor from …
hatton Jun 19, 2026
3046752
go.sh --with: develop local library checkouts alongside Bloom
hatton Jun 19, 2026
1407bb6
go/dev: stage jQuery global in dev; make --with iframe-app startup wa…
hatton Jun 20, 2026
4be4735
AI Image Editor: document public RegisterWithApiHandler (preflight)
hatton Jul 3, 2026
87f4b36
Merge origin/master into AddAIImages (D5)
hatton Jul 9, 2026
c22c67f
AI Image Editor: apply preflight review decisions (D2-D4, F2-F5)
hatton Jul 9, 2026
118aa43
AI Image Editor: robustness, image-replacement matching, and dev-laun…
hatton Jul 10, 2026
3682c87
Merge remote-tracking branch 'origin/master' into AddAIImages
hatton Jul 10, 2026
87637f8
AI Image Editor: clean up orphaned ai-image files; localize menu item…
hatton Jul 10, 2026
5b5c881
AI Image Editor: fix CORS preflight, document OAuth reflection, test …
hatton Jul 10, 2026
0ad16c6
AI Image Editor: add host-side tests; extract testable helpers (BL-16…
hatton Jul 15, 2026
aa5fb65
AI Image Editor: restrict to editable image formats (BL-16523)
hatton Jul 15, 2026
3b59570
Merge remote-tracking branch 'origin/master' into AddAIImages
hatton Jul 15, 2026
a96190e
AI Image Editor: address review feedback (BL-16523)
hatton Jul 16, 2026
5e4e97b
AI Image Editor: remove the OpenRouter OAuth sign-in path (BL-16523)
hatton Jul 16, 2026
162ad6d
Merge remote-tracking branch 'origin/master' into AddAIImages
hatton Jul 17, 2026
dbecb8f
Correct two AI Image Editor code comments per review (BL-16523)
hatton Jul 17, 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
10 changes: 10 additions & 0 deletions DistFiles/localization/en/BloomMediumPriority.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@
<note>ID: CollectionSettingsDialog.AdvancedTab.Experimental.AppBuilder</note>
<note>This checkbox enables the experimental publish-to-apps workflow.</note>
</trans-unit>
<trans-unit id="CollectionSettingsDialog.AdvancedTab.Experimental.EditWithAI" translate="no">
<source xml:lang="en">Edit Images with AI</source>
<note>ID: CollectionSettingsDialog.AdvancedTab.Experimental.EditWithAI</note>
<note>This checkbox enables the experimental "Edit with AI" image editor.</note>
</trans-unit>
<trans-unit id="Feature.AiImageEditing" translate="no">
<source xml:lang="en">Edit Images with AI</source>
<note>ID: Feature.AiImageEditing</note>
<note>Name of the AI image editing feature, used in subscription messages.</note>
</trans-unit>
<!-- Drag Activity Tool -->
<trans-unit id="EditTab.Toolbox.DragActivity.ChooseSound">
<source xml:lang="en">Choose...</source>
Expand Down
45 changes: 37 additions & 8 deletions ReadMe.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
# Books for every child, in every language

Bloom is an [award winning](http://allchildrenreading.org/sil-international-wins-enabling-writers-prize-for-software-solution-to-childrens-book-shortage/) software solution to the children's book shortage among most of the world's languages. It is an application for Windows and [Linux](https://bloomlibrary.org/page/create/linux) that dramatically "lowers the bar" for creating, translating, and sharing books. With Bloom, communities can do the work for themselves instead of depending on outsiders. For more information, see https://bloomlibrary.org/about. For user documentation, see https://docs.bloomlibrary.org.
Bloom is an [award winning](http://allchildrenreading.org/sil-international-wins-enabling-writers-prize-for-software-solution-to-childrens-book-shortage/) software solution to the children's book shortage among most of the world's languages. It is an application for Windows and [Linux](https://bloomlibrary.org/page/create/linux) that dramatically "lowers the bar" for creating, translating, and sharing books. With Bloom, communities can do the work for themselves instead of depending on outsiders. For more information, see [https://bloomlibrary.org/about](https://bloomlibrary.org/about). For user documentation, see [https://docs.bloomlibrary.org](https://docs.bloomlibrary.org).

Internally, Bloom is a hybrid. It started as a C#/WinForms app with an embedded browser for editing documents and an embedded Adobe Acrobat for displaying PDF outputs. It is growing up to be a pure React-driven offline-capable web app, with a C# backend. In its current state, Bloom is hybrid of C#/web app in which the bits of the UI are gradually moving to html.

# Building

1. Install [volta](https://docs.volta.sh/guide/getting-started) globally on your computer. This will provide you with the correct node and yarn. You may need to restart your computer for the installation to take effect.

2. Install other dependencies:

```bash
./init.sh
```

3. Run a hot-reloading server for the front end and a "watch" run of the back end.
```bash
./go.sh
```

```bash
./go.sh
```

# Developing

Expand All @@ -29,11 +27,17 @@ We don't want developer and tester runs (and crashes) polluting our statistics.
### Set up formatting

In a terminal, run `dotnet tool restore`. This will install any tools we have put in .config/dotnet-tools.json along with the correct versions.

In Visual Studio, under Extensions, install "CSharpier". The extension's version will not be the same as the CSharpier installed by 'dotnet tool restore', but that's not a problem.

In Tools/Options, under CSharpier:General, set `Reformat with CSharpier on Save` to `true`. Note that you should set it for this solution, not globally.

You should also install the CSharpier extension in VSCode.

CSharpier should be using the version specified in `.config/dotnet-tools.json`.

When upgrading to a new version of CSharpier, to format everything, run `dotnet csharpier format src/BloomExe src/BloomTests src/WebView2PdfMaker`.

To hide reformatting-only commits from git blame, add the sha of the commit to `.git-blame-ignore-revs`.

For Typescript formatting, we use the Prettier extension in VSCode.
Expand All @@ -48,9 +52,32 @@ For fast hot-reloading, first do one yarn build, to get all the (so-far) static

It may be helpful before submitting a PR to turn off yarn dev and run yarn build, then do a quick smoke test of your work. Yarn build creates the transpiled files that will be used by Bloom in production.

### Developing a library alongside Bloom

Bloom uses several libraries that we maintain in their own repositories (they behave like a loose monorepo). By default, `./go.sh` uses each library exactly as installed in `node_modules` (i.e. as last `yarn install`ed / published) — you don't need their source.

When you're also working on one of those libraries, link your local checkout of it with the repeatable `--with` flag so your edits flow into the running Bloom:

```bash
./go.sh --with LIBRARY # auto-discover a sibling checkout
./go.sh --with LIBRARY=PATH # or point at an explicit checkout path
./go.sh --with bloom-player --with @sillsdev/config-r # link more than one
```

`LIBRARY` is one of the package names listed below; `PATH` is a checkout directory. With no path, the checkout is auto-discovered as a sibling of the Bloom repo (e.g. `../bloom-player`, or `../../bloom-player` from a git worktree). `go.sh` starts and stops the library's dev processes for you and tears them down on Ctrl-C; the library's own dependencies must already be installed in its checkout (`pnpm install` or `yarn install` there, as appropriate).

The linkable libraries (by package name) and what `--with` does for each:

- `bloom-ai-image-tools` — `--with` runs the library's own Vite dev server (`pnpm dev`) and points Bloom at it, giving full HMR inside the editor.
- `bloom-player` — `--with` aliases the package to your checkout and runs its watch-builds (both the imported library output and the standalone player assets), so your changes appear in Bloom's UI on reload.
- `@sillsdev/config-r` — `--with` aliases it to your checkout and runs its watch-build (`yarn build:dev`).

The list of linkable libraries lives in `src/BloomBrowserUI/scripts/devLibraries.mjs`; add an entry there to make another library linkable.

### Windows Defender exclusions

For performance reasons, you probably want to exclude at least the following in the Windows Defender settings:

- node.exe (process)
- Bloom source code folder (e.g. `C:/dev/BloomDesktop`)

Expand All @@ -77,6 +104,7 @@ Each time code is checked in, an automatic build begins on our [TeamCity build s
### Linux Development

5.4 is the last version for Linux until we get rid of WinForms.

See the `Version5.4` branch and ReadMe if you need to update it.

See [this page](https://bloomlibrary.org/page/create/linux) for how to run it.
Expand All @@ -87,9 +115,10 @@ UI localization happens on [Crowdin](https://crowdin.com/project/sil-bloom).

### Registry settings

One responsibility of Bloom desktop is to handle url's starting with "bloom://"", such as those used on bloomlibrary.org when the user clicks "Translate into _your_ language!" Making this work requires some registry settings. These are automatically created when you run Bloom. If you have multiple versions installed, just make sure that the one you ran most recently is the one you want to do the download.
One responsibility of Bloom desktop is to handle url's starting with "bloom://"", such as those used on bloomlibrary.org when the user clicks "Translate into *your* language!" Making this work requires some registry settings. These are automatically created when you run Bloom. If you have multiple versions installed, just make sure that the one you ran most recently is the one you want to do the download.

# License

Bloom is open source, using the [MIT License](http://sil.mit-license.org). It is Copyright SIL Global.
"Bloom" is a registered trademark of SIL Global.

"Bloom" is a registered trademark of SIL Global.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { getCanvasElementManager } from "../../toolbox/canvas/canvasElementPageB
import { kBackgroundImageClass } from "../../toolbox/canvas/canvasElementConstants";
import { BloomTooltip } from "../../../react_components/BloomToolTip";
import { useL10n } from "../../../react_components/l10nHooks";
import { useGetFeatureStatus } from "../../../react_components/featureStatus";
import { kBloomDisabledOpacity } from "../../../utils/colorUtils";
import { getAsync, useApiObject } from "../../../utils/bloomApi";
import AudioRecording from "../../toolbox/talkingBook/audioRecording";
Expand Down Expand Up @@ -88,6 +89,10 @@ const CanvasElementContextControls: React.FunctionComponent<{
};

const menuEl = useRef<HTMLElement | null>(null);
// The "Edit with AI" command is an experimental, subscription-gated feature.
// Its FeatureStatus.visible reflects whether the experimental feature is on;
// we feed that into the control context so the menu item is hidden when off.
const aiImageEditingStatus = useGetFeatureStatus("AiImageEditing");
const languageNameValues = useApiObject<ILanguageNameValues>(
"settings/languageNames",
{
Expand Down Expand Up @@ -454,6 +459,7 @@ const CanvasElementContextControls: React.FunctionComponent<{
textHasAudio,
hasClipboardText,
languageNameValues,
aiImageEditingAvailable: aiImageEditingStatus?.visible ?? false,
};

const definition =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,5 +226,8 @@ export const buildCanvasElementControlRegistryContext = (
language2Name: "",
language2Tag: "",
},
// Default off; CanvasElementContextControls overlays the real feature
// status (which is async) when it assembles the context.
aiImageEditingAvailable: false,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ export const imageAvailabilityRules: AvailabilityRulesMap = {
visible: (ctx) => ctx.hasImage,
enabled: (ctx) => ctx.isCropped,
},
editWithAi: {
// Only offered when the AI Image Editing experimental feature is turned on.
// The AI Image Editor needs a real raster image to work on, and the user
// must be allowed to modify it.
visible: (ctx) => ctx.aiImageEditingAvailable && ctx.hasImage,
enabled: (ctx) => ctx.hasRealImage && ctx.canModifyImage,
},
missingMetadata: {
surfacePolicy: {
toolbar: {
Expand Down
Loading