From 4a0a42c9f32d9195b11ceb2d4492d65e4c2e6d2a Mon Sep 17 00:00:00 2001 From: Robert Curtin Date: Tue, 24 Feb 2026 22:27:26 -0500 Subject: [PATCH 1/4] First pass at adding a target image menu option --- src/functions.js | 15 ++++++++------- src/menus.js | 10 ++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/functions.js b/src/functions.js index 1da3fb9f7..35ca50a8b 100644 --- a/src/functions.js +++ b/src/functions.js @@ -961,9 +961,9 @@ async function load_image_from_uri(uri) { * @param {() => void} [callback] * @param {() => void} [canceled] * @param {boolean} [into_existing_session] - * @param {boolean} [from_session_load] + * @param {boolean} [targetImage] */ -function open_from_image_info(info, callback, canceled, into_existing_session, from_session_load) { +function open_from_image_info(info, callback, canceled, into_existing_session, targetImage) { /*are_you_sure(({ canvas_modified_while_loading } = {}) => { deselect(); cancel(); @@ -978,7 +978,7 @@ function open_from_image_info(info, callback, canceled, into_existing_session, f reset_canvas_and_history(); // (with newly reset colors) set_magnification(default_magnification);*/ - if (from_session_load) { + if (targetImage) { createImageBitmap(info.image || info.image_data).then(function (e) { main_ctx.drawImage(e, 0, 0, e.width, e.height) current_history_node.name = localize("Open"); @@ -1031,7 +1031,7 @@ function open_from_image_info(info, callback, canceled, into_existing_session, f * @param {Blob} file * @param {UserFileHandle} source_file_handle */ -function open_from_file(file, source_file_handle) { +function open_from_file(file, source_file_handle, targetImage) { // The browser isn't very smart about MIME types. // It seems to look at the file extension, but not the actual file contents. // This is particularly problematic for files with no extension, where file.type gives an empty string. @@ -1063,7 +1063,7 @@ function open_from_file(file, source_file_handle) { return; } image_info.source_file_handle = source_file_handle; - open_from_image_info(image_info); + open_from_image_info(image_info, targetImage = targetImage); }); } @@ -1119,11 +1119,12 @@ function file_new() { set_magnification(default_magnification); } -async function file_open() { +async function file_open(targetImage = true) { const { file, fileHandle } = await systemHooks.showOpenFileDialog({ formats: image_formats }); - open_from_file(file, fileHandle); + open_from_file(file, fileHandle, targetImage); } + /** @type {OSGUI$Window} */ let $file_load_from_url_window; function file_load_from_url() { diff --git a/src/menus.js b/src/menus.js index 5803358e0..e801e1de9 100644 --- a/src/menus.js +++ b/src/menus.js @@ -39,6 +39,16 @@ const menus = { action: () => { file_open(); }, description: localize("Opens an existing document."), }, + { + label: localize("&Load Target Image From File"), + ...shortcut("Ctrl+Alt+O"), + speech_recognition: [ + "open target", + ], + enabled: true, + action: () => { file_open(false); }, + description: localize("Writes the provided file as your target image."), + }, { label: localize("&Save"), ...shortcut("Ctrl+S"), From 6b77f262c10e4922b746497d5f0035ddd9e0053a Mon Sep 17 00:00:00 2001 From: Robert Curtin Date: Tue, 24 Feb 2026 22:40:46 -0500 Subject: [PATCH 2/4] now with negative logic! --- src/functions.js | 6 +++--- src/menus.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/functions.js b/src/functions.js index 35ca50a8b..dc15e3dda 100644 --- a/src/functions.js +++ b/src/functions.js @@ -961,9 +961,9 @@ async function load_image_from_uri(uri) { * @param {() => void} [callback] * @param {() => void} [canceled] * @param {boolean} [into_existing_session] - * @param {boolean} [targetImage] + * @param {boolean} [target_image] */ -function open_from_image_info(info, callback, canceled, into_existing_session, targetImage) { +function open_from_image_info(info, callback, canceled, into_existing_session, target_image) { /*are_you_sure(({ canvas_modified_while_loading } = {}) => { deselect(); cancel(); @@ -978,7 +978,7 @@ function open_from_image_info(info, callback, canceled, into_existing_session, t reset_canvas_and_history(); // (with newly reset colors) set_magnification(default_magnification);*/ - if (targetImage) { + if (!target_image) { createImageBitmap(info.image || info.image_data).then(function (e) { main_ctx.drawImage(e, 0, 0, e.width, e.height) current_history_node.name = localize("Open"); diff --git a/src/menus.js b/src/menus.js index e801e1de9..323f43120 100644 --- a/src/menus.js +++ b/src/menus.js @@ -40,7 +40,7 @@ const menus = { description: localize("Opens an existing document."), }, { - label: localize("&Load Target Image From File"), + label: localize("&Load Your Image From File"), ...shortcut("Ctrl+Alt+O"), speech_recognition: [ "open target", From d9b41527dcd842d7947be307a2f69cde3090f8fa Mon Sep 17 00:00:00 2001 From: Robert Curtin Date: Sun, 1 Mar 2026 23:40:10 -0500 Subject: [PATCH 3/4] Tidying some things and adding documentation --- help/archipelago.html | 4 ++++ src/functions.js | 37 +++++++++++++++++++++++++++---------- src/menus.js | 10 +++++----- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/help/archipelago.html b/help/archipelago.html index c9a760db3..a17972dc2 100644 --- a/help/archipelago.html +++ b/help/archipelago.html @@ -29,6 +29,10 @@ appear the same neutral gray as the area around the canvases.
  • The Pick Color tool, once unlocked, can be used on the target image as well as on the main canvas.
  • +
  • Your progress is automatically saved within your browser, but you can also use + File->Save or Ctrl+S to save your image. You can then load the saved image + using Load Saved Drawing or Ctrl+Alt+O, +
  • diff --git a/src/functions.js b/src/functions.js index dc15e3dda..c8efd60f2 100644 --- a/src/functions.js +++ b/src/functions.js @@ -961,9 +961,9 @@ async function load_image_from_uri(uri) { * @param {() => void} [callback] * @param {() => void} [canceled] * @param {boolean} [into_existing_session] - * @param {boolean} [target_image] + * @param {boolean} [load_into_goal_image] */ -function open_from_image_info(info, callback, canceled, into_existing_session, target_image) { +function open_from_image_info(info, callback, canceled, into_existing_session, load_into_goal_image) { /*are_you_sure(({ canvas_modified_while_loading } = {}) => { deselect(); cancel(); @@ -978,18 +978,18 @@ function open_from_image_info(info, callback, canceled, into_existing_session, t reset_canvas_and_history(); // (with newly reset colors) set_magnification(default_magnification);*/ - if (!target_image) { + if (load_into_goal_image) { createImageBitmap(info.image || info.image_data).then(function (e) { - main_ctx.drawImage(e, 0, 0, e.width, e.height) - current_history_node.name = localize("Open"); - current_history_node.image_data = main_ctx.getImageData(0, 0, main_canvas.width, main_canvas.height); - current_history_node.icon = get_help_folder_icon("p_open.png"); + goal_ctx.drawImage(e, 0, 0, goal_canvas.width, goal_canvas.height); + $G.triggerHandler("save-goal"); }); } else { createImageBitmap(info.image || info.image_data).then(function (e) { - goal_ctx.drawImage(e, 0, 0, goal_canvas.width, goal_canvas.height); - $G.triggerHandler("save-goal"); + main_ctx.drawImage(e, 0, 0, e.width, e.height) + current_history_node.name = localize("Open"); + current_history_node.image_data = main_ctx.getImageData(0, 0, main_canvas.width, main_canvas.height); + current_history_node.icon = get_help_folder_icon("p_open.png"); }); } /*apply_file_format_and_palette_info(info); @@ -1124,6 +1124,23 @@ async function file_open(targetImage = true) { open_from_file(file, fileHandle, targetImage); } +async function load_saved_drawing() { + const { $window, promise } = showMessageBox({ + messageHTML: ` +

    WARNING

    +

    This will overwrite your current drawing progress with a saved image.

    +

    Are you sure you want to load a saved image as your drawing?

    + `, + buttons: [ + { label: localize("Yes"), value: "yes", default: true }, + { label: localize("Cancel"), value: "cancel" }, + ], + }); + const result = await promise; + if (result === "yes") { + await file_open(false) + } +} /** @type {OSGUI$Window} */ let $file_load_from_url_window; @@ -4306,7 +4323,7 @@ export { $this_version_news, apply_file_format_and_palette_info, are_you_sure, calculate_similarity, cancel, change_some_url_params, change_url_param, choose_file_to_paste, cleanup_bitmap_view, clear, confirm_overwrite_capability, delete_selection, deselect, detect_monochrome, edit_copy, edit_cut, edit_paste, exit_fullscreen_if_ios, file_load_from_url, file_new, file_open, file_print, file_save, - file_save_as, getSelectionText, get_all_url_params, get_history_ancestors, get_tool_by_id, get_uris, get_url_param, go_to_history_node, handle_keyshortcuts, has_any_transparency, image_attributes, image_flip_and_rotate, image_invert_colors, image_stretch_and_skew, load_image_from_uri, load_theme_from_text, make_history_node, make_monochrome_palette, make_monochrome_pattern, make_opaque, make_or_update_undoable, make_stripe_pattern, meld_selection_into_canvas, + file_save_as, getSelectionText, get_all_url_params, get_history_ancestors, get_tool_by_id, get_uris, get_url_param, go_to_history_node, handle_keyshortcuts, has_any_transparency, image_attributes, image_flip_and_rotate, image_invert_colors, image_stretch_and_skew, load_image_from_uri, load_saved_drawing, load_theme_from_text, make_history_node, make_monochrome_palette, make_monochrome_pattern, make_opaque, make_or_update_undoable, make_stripe_pattern, meld_selection_into_canvas, meld_textbox_into_canvas, open_from_file, open_from_image_info, paste, paste_image_from_file, please_enter_a_number, read_image_file, redo, render_canvas_view, render_history_as_gif, reset_canvas_and_history, reset_file, reset_selected_colors, resize_canvas_and_save_dimensions, resize_canvas_without_saving_dimensions, sanity_check_blob, save_as_prompt, save_selection_to_file, select_all, select_tool, select_tools, set_all_url_params, set_magnification, show_about_paint, show_convert_to_black_and_white, show_custom_zoom_window, show_document_history, show_error_message, show_file_format_errors, show_multi_user_setup_dialog, show_news, show_resource_load_error_message, switch_to_polychrome_palette, toggle_grid, toggle_thumbnail, try_exec_command, undo, undoable, update_canvas_rect, update_css_classes_for_conditional_messages, update_disable_aa, update_from_saved_file, update_helper_layer, update_helper_layer_immediately, update_magnified_canvas_size, update_title, view_bitmap, write_image_file diff --git a/src/menus.js b/src/menus.js index 323f43120..fd108eb27 100644 --- a/src/menus.js +++ b/src/menus.js @@ -3,7 +3,7 @@ /* global $canvas_area, $colorbox, $status_area, $toolbox, available_languages, get_iso_language_name, get_language, get_language_emoji, get_language_endonym, localize, magnification, main_canvas, menu_bar, MENU_DIVIDER, redos, selection, set_language, show_grid, show_thumbnail, systemHooks, undos */ // import { available_languages, get_iso_language_name, get_language, get_language_emoji, get_language_endonym, localize, set_language } from "./app-localization.js"; import { received, show_text_client } from "./archipelago.js"; -import { are_you_sure, change_url_param, clear, delete_selection, deselect, edit_copy, edit_cut, file_new, file_open, file_print, file_save, file_save_as, image_attributes, image_flip_and_rotate, image_invert_colors, redo, render_history_as_gif, sanity_check_blob, save_selection_to_file, select_all, set_magnification, show_about_paint, show_custom_zoom_window, show_document_history, toggle_grid, toggle_thumbnail, undo, update_magnified_canvas_size, view_bitmap } from "./functions.js"; +import { are_you_sure, change_url_param, clear, delete_selection, deselect, edit_copy, edit_cut, file_new, file_open, file_print, file_save, file_save_as, image_attributes, image_flip_and_rotate, image_invert_colors, load_saved_drawing, redo, render_history_as_gif, sanity_check_blob, save_selection_to_file, select_all, set_magnification, show_about_paint, show_custom_zoom_window, show_document_history, toggle_grid, toggle_thumbnail, undo, update_magnified_canvas_size, view_bitmap } from "./functions.js"; import { show_help } from "./help.js"; import { is_discord_embed } from "./helpers.js"; import { show_imgur_uploader } from "./imgur.js"; @@ -40,14 +40,14 @@ const menus = { description: localize("Opens an existing document."), }, { - label: localize("&Load Your Image From File"), + label: localize("&Load Saved Drawing"), ...shortcut("Ctrl+Alt+O"), speech_recognition: [ - "open target", + "load saved drawing", ], enabled: true, - action: () => { file_open(false); }, - description: localize("Writes the provided file as your target image."), + action: () => { load_saved_drawing(); }, + description: localize("Writes the provided file as your drawing."), }, { label: localize("&Save"), From 221f52b7bf2ed3667bebf193b0d7444e72088ced Mon Sep 17 00:00:00 2001 From: Robert Curtin Date: Sun, 1 Mar 2026 23:43:17 -0500 Subject: [PATCH 4/4] Typos --- help/archipelago.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help/archipelago.html b/help/archipelago.html index a17972dc2..017e1a4c9 100644 --- a/help/archipelago.html +++ b/help/archipelago.html @@ -31,7 +31,7 @@
  • Your progress is automatically saved within your browser, but you can also use File->Save or Ctrl+S to save your image. You can then load the saved image - using Load Saved Drawing or Ctrl+Alt+O, + using File->Load Saved Drawing or Ctrl+Alt+O.