diff --git a/.gitignore b/.gitignore index ea6fe01..aeec836 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ media/vendor/ coverage/ .DS_Store npm-debug.log* + +.v004/ diff --git a/.v004/CHANGELOG.md.gz.b64 b/.v004/CHANGELOG.md.gz.b64 deleted file mode 100644 index baf8e45..0000000 --- a/.v004/CHANGELOG.md.gz.b64 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.v004/README.md.gz.b64 b/.v004/README.md.gz.b64 deleted file mode 100644 index d85454c..0000000 --- a/.v004/README.md.gz.b64 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.v004/main.js.gz.b64.part00 b/.v004/main.js.gz.b64.part00 deleted file mode 100644 index 9809874..0000000 --- a/.v004/main.js.gz.b64.part00 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.v004/main.js.gz.b64.part01 b/.v004/main.js.gz.b64.part01 deleted file mode 100644 index 8b6c662..0000000 --- a/.v004/main.js.gz.b64.part01 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.v004/main.js.gz.b64.part02 b/.v004/main.js.gz.b64.part02 deleted file mode 100644 index 1ac8e63..0000000 --- a/.v004/main.js.gz.b64.part02 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.v004/package-lock.json.gz.b64 b/.v004/package-lock.json.gz.b64 deleted file mode 100644 index 5811379..0000000 --- a/.v004/package-lock.json.gz.b64 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.v004/package.json.gz.b64 b/.v004/package.json.gz.b64 deleted file mode 100644 index 6194b0f..0000000 --- a/.v004/package.json.gz.b64 +++ /dev/null @@ -1 +0,0 @@ -H4sIAG5hi2oC/51XbU8cNxD+zq+waIXa6tZ3vLUFKVKiQCO1TYJK1UitiOTbnbtz2LUt23twJPz3zNj74r07KIEPsOsZz8zzzMsOn3cY21Wigt1TtmuKWbaUcAM2g0J6bXdHJC6kM6VYvWu0Ls5+Y/8ELbbHzlM9cLmVxkutSO8Vm+m8dlCwpXS1KBldjHbZjfQLVkgLuWcebj1zUOIz3hwxC6hrYVbqmxGTlZhDuCXVfMSEKsKLmJbAwm/HpMJwgoNLXxdSs9e6AB5DWoJ1TTgTPuFH8dTU01K6BVg6d/VdIUpQ1zorYBkVSpmDcgHtqzcXf2aHfJJpm5XCQ4PVgtGOoKxQ6TOe4JlfmXBlLn1QwqPalnSy8N640/EYJYt6ynNdjYduxxvUc7KCRu6Du2k9d72j51sdS+dqcL3hha7AIMXPtPcdJqvAsgi2cqRnrq0ECvW/GGrMjLwToSoaVt574h6fr8K9a1jdaFskt9BPqxvdtW9JWRLhWDntcyyYTkKl0XsANZcKEgaXLsciIdAf9/nJz3zSM4I2MfcY7R9SFX1ItWxtY6zXzog8sV8JGWqMj53Nx50F/slFZgSW9jJQcL4E5ROkWr2unddV7KNTBB5bK77zIV5U1lWFPbChpw2oD5i2PqRcGDGVJfZNirtW3qI/KD60IHoho14wRlsU4yEqwqgVrLU2dfLvYikuwyEToXMdExawqR1xX3B2ht1fEdpwbqxGZzQNSp2Lslzx3WD8vsuz9Vgpg7gohC4vucbY5bT2KZ48Ia9nlXWImgL6u+nMR+mNQJ8261q+wtTSNvE89B60ZhI7CA1eCI/zIxD4E6cST9TuR994HyMb3O+er5L4jJXYj55mFKZwJurSt5fihUYZyQ119QCFjXQbg13hJV699GVg7z0K46j/Hx6bybF6AuUyjyX4/Q9ES4bx/LgdEpZePShuuDWltmDHVEk0OdKkpZR/I14aCQsIQVlwurY5nN96Shh78YJRotmXL2ybiHI4sDO3ujZkSImlnIeB8fJg0ue5zfLVoHUQz0zOayua9uwQd4l4jFMsEgRlB3OiHcID6E0B/at1NVBMvnyqrqZgh5jaujtl+/zgeCCqpJJVTdYmGyJx24iO16wNBtFZNB7qiz5j7A6jYzNBTckT3kYPw0JPf4EqwF7IWyjd86AdHE3CzwPw9rdJO4SNdE2+hvRtVGcxDqZnzIR4WdiwvMYCIxBMBB6eiL0BcCmW8DZ+D7didzh41XyIHburWht71J0qt0BDX5QDdarSEoRKR9bVA1w+aCT4POtpcZv+L7DNwC5xN1wAw9GHn33cC2lShNVRGGzfguULoebg+HqIb4SdInlZrkua6+EKzgKDRl2wSC8leKB6449h2VqkGJnsdiFWIeExeTcLiq/Zcflmt8e/992XMBpPvoIYoMFvbChTstoo4KAzqwwXjgJT3awiYblVgWZw9MR4tzNhtvMF5Nck9C5nmWGfXBwueB1DzjKlz6t+u8VPse+cZll4bWdSa0iZitlaseBrb4+175239jC9HdezU8IVV/XUUoM2NRa9NZdxe7huNlq0g5tHfA/R4xZLFQAql+kWjLvtWSromH1JYbqxapfFgyP8L2LSemqkm8tkK48SUojiQ37CD7pd1rWZ+HjCD0/6azMxtTInwS/8qD+uatoZ8BTn6K/9cYghJDyYOuYn6Tbbfi7D/1FuTK/cYC/v3O98BYVTHtn7DQAA \ No newline at end of file diff --git a/.v004/pdf-engine.js.gz.b64.part00 b/.v004/pdf-engine.js.gz.b64.part00 deleted file mode 100644 index 58bfcdc..0000000 --- a/.v004/pdf-engine.js.gz.b64.part00 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.v004/pdf-engine.js.gz.b64.part01 b/.v004/pdf-engine.js.gz.b64.part01 deleted file mode 100644 index 0a67705..0000000 --- a/.v004/pdf-engine.js.gz.b64.part01 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.v004/pdf-engine.test.mjs.gz.b64 b/.v004/pdf-engine.test.mjs.gz.b64 deleted file mode 100644 index af77b59..0000000 --- a/.v004/pdf-engine.test.mjs.gz.b64 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.v004/styles.css.gz.b64 b/.v004/styles.css.gz.b64 deleted file mode 100644 index 811e652..0000000 --- a/.v004/styles.css.gz.b64 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.vscodeignore b/.vscodeignore index 382ff9d..1ba9637 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -8,3 +8,4 @@ eslint.config.js jsconfig.json package-lock.json *.vsix +.v004/** diff --git a/CHANGELOG.md b/CHANGELOG.md index c0b4447..783d7ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ Todos los cambios relevantes de este proyecto se documentan aquí. +## 0.0.4 - 2026-08-23 + +### Corregido + +- La edición de texto deja de depender de rectángulos Fabric sobre bloques completos; la selección se realiza directamente sobre el texto visible. +- Arrastrar sobre una palabra o frase permite editar, borrar o cambiar el formato solo de ese rango. +- Un clic sobre una línea selecciona su párrafo sin dibujar el antiguo recuadro azul gigante. +- La selección parcial conserva el resto del párrafo y vuelve a calcular el reflujo cuando cambia el contenido o el tamaño de fuente. +- Las imágenes originales e insertadas se pueden seleccionar directamente; el botón `Imagen` reemplaza la imagen seleccionada manteniendo su zona. +- Las imágenes insertadas siguen pudiéndose mover, redimensionar y eliminar; las imágenes originales pueden reemplazarse o eliminarse. +- Se incorporan de forma completa las piezas de selección por rango e inserción contextual que no habían quedado consolidadas en `main` tras la 0.0.3. +- Nuevo icono de Marketplace incluido en el paquete de la extensión. + +### Pruebas + +- Se mantienen las pruebas de segmentación visual de párrafos, edición de rangos con reflujo e inserción de imágenes/tablas en el flujo. +- El pipeline de CI valida lint, tipos, pruebas y empaquetado VSIX antes del merge. + ## 0.0.3 - 2026-08-23 ### Corregido diff --git a/README.md b/README.md index 82ddf38..bfc2b16 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Editor visual de PDF gratuito para Visual Studio Code, construido en JavaScript con MuPDF.js y Fabric.js. -La versión `0.0.3` se concentra en una tarea: **seleccionar y editar el contenido visible de forma natural**. Abre el PDF como una pestaña editable de VS Code y participa en el ciclo normal de Guardar, Guardar como, Deshacer, Rehacer, recuperación y copias de seguridad. +La versión `0.0.4` se concentra en una tarea: **seleccionar y editar directamente el contenido visible de forma natural**. Abre el PDF como una pestaña editable de VS Code y participa en el ciclo normal de Guardar, Guardar como, Deshacer, Rehacer, recuperación y copias de seguridad. > Conserva una copia del documento original cuando trabajes con archivos importantes. Un PDF describe objetos colocados en coordenadas y no siempre contiene párrafos equivalentes a los de Word; esta extensión reconstruye bloques editables a partir de la estructura visual detectada por MuPDF. @@ -103,7 +103,7 @@ npm run package | `npm run typecheck` | Comprueba el host de la extensión con TypeScript `checkJs` | | `npm test` | Ejecuta pruebas unitarias y de integración contra MuPDF/WASM | | `npm run check` | Ejecuta lint, typecheck y pruebas | -| `npm run package` | Genera `pdf-viewer-editor-0.0.3.vsix` | +| `npm run package` | Genera `pdf-viewer-editor-0.0.4.vsix` | El script `prepare` copia MuPDF y Fabric a `media/vendor`; esa carpeta se genera y no se versiona. diff --git a/images/icon.png b/images/icon.png new file mode 100644 index 0000000..5e13d79 Binary files /dev/null and b/images/icon.png differ diff --git a/media/webview/main.js b/media/webview/main.js index 5e8380b..b836ed6 100644 --- a/media/webview/main.js +++ b/media/webview/main.js @@ -30,7 +30,9 @@ const state = { fabricCanvas: null, overlayObjects: [], selected: null, + textRange: null, editing: null, + insertionAnchor: null, pendingImage: null, pendingTable: null, drawStart: null, @@ -57,6 +59,8 @@ const elements = Object.fromEntries([ 'table-rows', 'table-columns', 'table-color', 'table-border-width', 'apply-table', 'image-context', 'image-kind', 'image-help', 'pages-sidebar', 'thumbnail-list', 'page-viewport', 'page-stage', 'pdf-canvas', 'text-layer', 'editor-canvas', + 'insertion-layer', 'insert-menu', 'insert-text-here', 'insert-image-here', + 'insert-table-here', 'edit-range-button', 'block-editor', 'block-editor-text', 'cancel-block-edit', 'apply-block-edit', 'status-message', 'document-info', 'loading-overlay', 'loading-message', 'dialog-backdrop', 'editor-dialog', 'dialog-form', 'dialog-title', @@ -121,7 +125,7 @@ async function loadDocument(message) { await renderCurrentPage(); void renderThumbnails(); elements.app.setAttribute('aria-busy', 'false'); - setStatus('Selecciona un bloque de texto para editarlo.'); + setStatus('Haz clic en un párrafo, selecciona una frase o usa + para insertar.'); } catch (error) { reportError(error); } finally { @@ -135,6 +139,7 @@ async function renderCurrentPage(options = {}) { if (state.pageCount === 0) { return; } + hideInsertMenu(); setBusy(true, `Renderizando página ${state.currentPage + 1}…`); try { state.pageModel = engine.getPageModel(state.currentPage); @@ -149,6 +154,7 @@ async function renderCurrentPage(options = {}) { initializeOrResizeFabricCanvas(); buildTextLayer(); buildEditingOverlay(); + buildInsertionLayer(); updatePageControls(); updateDocumentInfo(); if (!restoreSelection(options)) { @@ -201,7 +207,7 @@ function initializeOrResizeFabricCanvas() { state.fabricCanvas.on('selection:created', selectionChanged); state.fabricCanvas.on('selection:updated', selectionChanged); state.fabricCanvas.on('selection:cleared', () => { - if (!state.editing) { + if (!state.editing && state.selected?.kind !== 'text') { clearSelection(); } }); @@ -227,21 +233,288 @@ function buildTextLayer() { layer.replaceChildren(); layer.style.width = `${state.render.width}px`; layer.style.height = `${state.render.height}px`; + layer.classList.toggle('disabled', state.tool !== 'edit'); + layer.classList.toggle('placement-mode', state.tool !== 'edit'); for (const line of state.pageModel.textLines) { const screen = pdfRectToScreen(line.rect); const item = document.createElement('span'); item.className = 'text-layer-line'; item.textContent = line.text; + item.dataset.blockIndex = String(line.blockIndex); + item.dataset.lineIndex = String(line.lineIndex); + item.dataset.textStart = String(line.textStart); + item.dataset.textEnd = String(line.textEnd); + item.title = 'Haz clic para editar este párrafo; arrastra para seleccionar texto'; item.style.left = `${screen[0]}px`; item.style.top = `${screen[1]}px`; item.style.width = `${Math.max(1, screen[2] - screen[0])}px`; item.style.height = `${Math.max(1, screen[3] - screen[1])}px`; item.style.fontSize = `${Math.max(4, line.font.size * state.render.scale)}px`; item.style.fontFamily = line.font.family; + item.style.fontWeight = line.font.weight; + item.style.fontStyle = line.font.style; + item.addEventListener('click', textLineClicked); + item.addEventListener('dblclick', () => window.requestAnimationFrame(updateTextRangeFromSelection)); layer.appendChild(item); } } +function textLineClicked(event) { + if (state.tool !== 'edit' || state.busy) { + return; + } + hideInsertMenu(); + const blockIndex = Number(event.currentTarget.dataset.blockIndex); + window.requestAnimationFrame(() => { + const selection = window.getSelection(); + if (selection && !selection.isCollapsed && selectionInsideTextLayer(selection)) { + updateTextRangeFromSelection(); + } else { + selectTextBlock(blockIndex); + } + }); +} + +function selectTextBlock(blockIndex, options = {}) { + const block = state.pageModel?.textBlocks.find((candidate) => candidate.index === blockIndex); + if (!block) { + return false; + } + if (!options.preserveRange) { + state.textRange = null; + hideEditRangeButton(); + } + const meta = { + kind: 'text', + rect: block.rect, + blockIndex: block.index, + block + }; + state.selected = meta; + if (state.fabricCanvas?.getActiveObject()) { + state.fabricCanvas.discardActiveObject(); + state.fabricCanvas.requestRenderAll(); + } + for (const line of elements['text-layer'].querySelectorAll('.text-layer-line')) { + line.classList.toggle('selected', Number(line.dataset.blockIndex) === blockIndex); + } + selectMeta(meta); + return true; +} + +function updateTextRangeFromSelection() { + if (state.busy || state.editing) { + return; + } + const selection = window.getSelection(); + if (!selection || selection.isCollapsed || !selectionInsideTextLayer(selection)) { + hideEditRangeButton(); + return; + } + const range = selection.getRangeAt(0); + const start = selectionEndpointToTextOffset(range.startContainer, range.startOffset); + const end = selectionEndpointToTextOffset(range.endContainer, range.endOffset); + if (!start || !end || start.blockIndex !== end.blockIndex || end.offset <= start.offset) { + state.textRange = null; + hideEditRangeButton(); + setStatus('Para editar, selecciona texto dentro de un mismo párrafo.'); + return; + } + const block = state.pageModel.textBlocks.find((candidate) => + candidate.index === start.blockIndex + ); + if (!block) { + return; + } + state.textRange = { + blockIndex: block.index, + start: start.offset, + end: end.offset, + text: block.text.slice(start.offset, end.offset) + }; + selectTextBlock(block.index, { preserveRange: true }); + showEditRangeButton(range); + setStatus('Texto seleccionado: pulsa “Editar selección”, cambia su formato o elimínalo.'); +} + +function selectionInsideTextLayer(selection) { + const anchor = selection.anchorNode; + const focus = selection.focusNode; + return Boolean( + anchor && focus && + elements['text-layer'].contains(anchor) && + elements['text-layer'].contains(focus) + ); +} + +function selectionEndpointToTextOffset(node, offset) { + const element = node.nodeType === window.Node.TEXT_NODE ? node.parentElement : node; + const line = element instanceof window.Element ? element.closest('.text-layer-line') : null; + if (!line || !elements['text-layer'].contains(line)) { + return null; + } + let localOffset = 0; + try { + const localRange = document.createRange(); + localRange.selectNodeContents(line); + localRange.setEnd(node, offset); + localOffset = localRange.toString().length; + } catch { + localOffset = offset > 0 ? line.textContent.length : 0; + } + return { + blockIndex: Number(line.dataset.blockIndex), + offset: Number(line.dataset.textStart) + clamp(localOffset, 0, line.textContent.length) + }; +} + +function showEditRangeButton(range) { + const button = elements['edit-range-button']; + const selectionRect = range.getBoundingClientRect(); + const stageRect = elements['page-stage'].getBoundingClientRect(); + const width = 126; + button.style.left = `${clamp( + selectionRect.left - stageRect.left + selectionRect.width / 2 - width / 2, + 4, + Math.max(4, state.render.width - width - 4) + )}px`; + button.style.top = `${clamp( + selectionRect.bottom - stageRect.top + 5, + 4, + Math.max(4, state.render.height - 34) + )}px`; + button.classList.remove('hidden'); +} + +function hideEditRangeButton() { + elements['edit-range-button'].classList.add('hidden'); +} + +function buildInsertionLayer() { + const layer = elements['insertion-layer']; + layer.replaceChildren(); + layer.style.width = `${state.render.width}px`; + layer.style.height = `${state.render.height}px`; + const blocks = [...state.pageModel.textBlocks].sort((left, right) => + left.rect[1] - right.rect[1] || left.rect[0] - right.rect[0] + ); + const bounds = state.pageModel.bounds; + const anchors = []; + + if (blocks.length === 0) { + anchors.push({ + x: bounds[0] + 24, + y: bounds[1] + 36, + width: Math.max(100, bounds[2] - bounds[0] - 48), + displayY: bounds[1] + 36, + label: 'Insertar contenido en la página' + }); + } else { + const first = blocks[0]; + anchors.push({ + x: first.rect[0], + y: Math.max(bounds[1] + 6, first.rect[1] - 10), + width: Math.max(80, first.rect[2] - first.rect[0]), + displayY: Math.max(bounds[1] + 6, first.rect[1] - 10), + label: 'Insertar antes del primer párrafo' + }); + for (let index = 1; index < blocks.length; index += 1) { + const previous = blocks[index - 1]; + const current = blocks[index]; + if (!rectanglesShareScreenFlow(previous.rect, current.rect)) { + continue; + } + const displayY = Math.max( + previous.rect[3] + 2, + (previous.rect[3] + current.rect[1]) / 2 + ); + anchors.push({ + x: current.rect[0], + y: displayY, + width: Math.max(80, current.rect[2] - current.rect[0]), + displayY, + label: `Insertar antes de “${current.text.slice(0, 36)}”` + }); + } + const last = blocks.at(-1); + const afterY = Math.min(bounds[3] - 8, last.rect[3] + 10); + anchors.push({ + x: last.rect[0], + y: afterY, + width: Math.max(80, last.rect[2] - last.rect[0]), + displayY: afterY, + label: 'Insertar después del último párrafo' + }); + } + + const usedPositions = []; + for (const anchor of anchors) { + const screenPoint = pdfPointToScreen([anchor.x, anchor.displayY]); + if (usedPositions.some((position) => Math.abs(position - screenPoint[1]) < 8)) { + continue; + } + usedPositions.push(screenPoint[1]); + const button = document.createElement('button'); + button.type = 'button'; + button.className = 'insertion-marker'; + button.setAttribute('aria-label', anchor.label); + button.title = `${anchor.label}: texto, imagen o tabla`; + button.style.left = `${Math.max(2, screenPoint[0] - 24)}px`; + button.style.top = `${clamp(screenPoint[1] - 9, 1, state.render.height - 19)}px`; + button.style.width = `${Math.min( + state.render.width - Math.max(2, screenPoint[0] - 24) - 2, + Math.max(54, anchor.width * state.render.scale + 24) + )}px`; + button.innerHTML = '+'; + button.addEventListener('click', (event) => { + event.preventDefault(); + event.stopPropagation(); + openInsertMenu(anchor, button); + }); + layer.appendChild(button); + } +} + +function rectanglesShareScreenFlow(left, right) { + const overlap = Math.max(0, Math.min(left[2], right[2]) - Math.max(left[0], right[0])); + const minimumWidth = Math.max(1, Math.min(left[2] - left[0], right[2] - right[0])); + return overlap / minimumWidth >= 0.25; +} + +function pdfPointToScreen(point) { + const bounds = state.render.bounds; + return [ + (point[0] - bounds[0]) * state.render.scale, + (point[1] - bounds[1]) * state.render.scale + ]; +} + +function openInsertMenu(anchor, marker) { + state.insertionAnchor = anchor; + const menu = elements['insert-menu']; + const markerRect = marker.getBoundingClientRect(); + const stageRect = elements['page-stage'].getBoundingClientRect(); + menu.classList.remove('hidden'); + const menuWidth = Math.max(220, menu.offsetWidth); + menu.style.left = `${clamp( + markerRect.left - stageRect.left, + 4, + Math.max(4, state.render.width - menuWidth - 4) + )}px`; + menu.style.top = `${clamp( + markerRect.bottom - stageRect.top + 3, + 4, + Math.max(4, state.render.height - menu.offsetHeight - 4) + )}px`; +} + +function hideInsertMenu(options = {}) { + elements['insert-menu'].classList.add('hidden'); + if (!options.preserveAnchor) { + state.insertionAnchor = null; + } +} + function buildEditingOverlay() { const currentHits = state.searchResults.filter((result) => result.pageIndex === state.currentPage @@ -289,18 +562,6 @@ function buildEditingOverlay() { } } - for (const block of state.pageModel.textBlocks) { - addOverlayObject({ - kind: 'text', - rect: block.rect, - blockIndex: block.index, - block - }, { - stroke: '#1473e6', - movable: true, - resizable: false - }); - } state.fabricCanvas.requestRenderAll(); } @@ -369,6 +630,12 @@ function selectionChanged(event) { function selectMeta(meta) { state.selected = meta; + if (meta.kind !== 'text') { + state.textRange = null; + hideEditRangeButton(); + clearTextLineHighlights(); + clearNativeTextSelection(); + } elements['delete-tool'].disabled = false; elements['selection-context'].classList.remove('hidden'); elements['text-context'].classList.toggle('hidden', meta.kind !== 'text'); @@ -380,7 +647,9 @@ function selectMeta(meta) { if (meta.kind === 'text') { setTextControlsFromBlock(meta.block); - setStatus('Bloque seleccionado: cambia el formato o pulsa “Editar contenido”.'); + setStatus(state.textRange + ? 'Texto seleccionado: edítalo, cambia su formato o elimínalo.' + : 'Párrafo seleccionado: pulsa “Editar contenido” o selecciona una frase.'); } else if (meta.kind === 'table') { elements['table-rows'].value = String(meta.table.rows); elements['table-columns'].value = String(meta.table.columns); @@ -389,17 +658,20 @@ function selectMeta(meta) { setStatus('Tabla seleccionada: cambia filas/columnas, muévela o elimínala.'); } else if (meta.kind === 'inserted-image') { elements['image-kind'].textContent = 'Imagen insertada'; - elements['image-help'].textContent = 'Arrastra para mover; usa las esquinas para redimensionar.'; - setStatus('Imagen seleccionada.'); + elements['image-help'].textContent = 'Arrastra para mover, usa las esquinas para redimensionar o pulsa Imagen para reemplazarla.'; + setStatus('Imagen seleccionada: puedes moverla, redimensionarla, reemplazarla o eliminarla.'); } else { elements['image-kind'].textContent = 'Imagen original'; - elements['image-help'].textContent = 'Esta imagen original se puede eliminar permanentemente.'; - setStatus('Imagen original seleccionada.'); + elements['image-help'].textContent = 'Pulsa Imagen para reemplazarla manteniendo su zona, o Eliminar para quitarla.'; + setStatus('Imagen original seleccionada: puedes reemplazarla o eliminarla.'); } } function clearSelection() { state.selected = null; + state.textRange = null; + hideEditRangeButton(); + clearTextLineHighlights(); elements['delete-tool'].disabled = true; elements['selection-context'].classList.add('hidden'); elements['text-context'].classList.add('hidden'); @@ -411,6 +683,19 @@ function clearSelection() { } } +function clearTextLineHighlights() { + for (const line of elements['text-layer'].querySelectorAll('.text-layer-line.selected')) { + line.classList.remove('selected'); + } +} + +function clearNativeTextSelection() { + const selection = window.getSelection(); + if (selection && selectionInsideTextLayer(selection)) { + selection.removeAllRanges(); + } +} + function overlayMouseDown(event) { if (state.busy) { return; @@ -480,7 +765,7 @@ function overlayMouseUp(event) { const table = state.pendingTable; state.pendingTable = null; setTool('edit'); - engine.addTable( + engine.insertTableBlock( state.currentPage, screenRectToPdf(screenRect), table.rows, @@ -492,8 +777,8 @@ function overlayMouseUp(event) { function overlayDoubleClick(event) { const meta = event.target?.editorMeta; - if (meta?.kind === 'text') { - openExistingTextEditor(meta.block); + if (meta?.kind === 'table') { + void applyTableProperties(); } } @@ -505,10 +790,7 @@ async function overlayObjectModified(event) { } const targetRect = objectScreenRectToPdf(object); try { - if (meta.kind === 'text') { - engine.moveTextBlock(state.currentPage, meta.blockIndex, targetRect); - await commitAndRefresh('Mover texto', { restoreText: meta.block.text }); - } else if (meta.kind === 'inserted-image') { + if (meta.kind === 'inserted-image') { engine.updateAnnotationRect(state.currentPage, meta.annotationIndex, targetRect); await commitAndRefresh('Mover o redimensionar imagen', { restoreKind: 'image-last' @@ -619,12 +901,27 @@ async function textFormatChanged() { } state.formatBusy = true; const block = state.selected.block; + const selectedRange = state.textRange; try { - engine.editTextBlock(state.currentPage, block.index, { - text: block.text, - ...getTextFormat() - }); - await commitAndRefresh('Cambiar formato de texto', { restoreText: block.text }); + if (selectedRange?.blockIndex === block.index) { + engine.editTextRange( + state.currentPage, + block.index, + selectedRange.start, + selectedRange.end, + selectedRange.text, + getTextFormat() + ); + await commitAndRefresh('Cambiar formato de la selección', { + restoreText: selectedRange.text + }); + } else { + engine.editTextBlock(state.currentPage, block.index, { + text: block.text, + ...getTextFormat() + }); + await commitAndRefresh('Cambiar formato de texto', { restoreText: block.text }); + } } catch (error) { reportError(error); } finally { @@ -633,6 +930,9 @@ async function textFormatChanged() { } function openExistingTextEditor(block) { + state.textRange = null; + hideEditRangeButton(); + clearNativeTextSelection(); state.selected = { kind: 'text', rect: block.rect, @@ -649,11 +949,41 @@ function openExistingTextEditor(block) { }); } -function openNewTextEditor(point) { +function openSelectedRangeEditor() { + const selectedRange = state.textRange; + if (!selectedRange || state.busy) { + return; + } + const block = state.pageModel.textBlocks.find((candidate) => + candidate.index === selectedRange.blockIndex + ); + if (!block) { + return; + } + setTextControlsFromBlock(block); + showTextContext(); + openBlockEditor({ + mode: 'range', + blockIndex: block.index, + start: selectedRange.start, + end: selectedRange.end, + rect: block.rect, + text: selectedRange.text + }); +} + +function openNewTextEditor(pointOrAnchor) { const bounds = state.pageModel.bounds; + const point = Array.isArray(pointOrAnchor) + ? pointOrAnchor + : [pointOrAnchor.x, pointOrAnchor.y]; const x = clamp(point[0], bounds[0] + 8, bounds[2] - 70); const y = clamp(point[1], bounds[1] + 8, bounds[3] - 24); - const width = Math.min(300, Math.max(60, bounds[2] - x - 24)); + const requestedWidth = Array.isArray(pointOrAnchor) ? null : pointOrAnchor.width; + const width = Math.min( + requestedWidth || 300, + Math.max(60, bounds[2] - x - 24) + ); setDefaultTextControls(); showTextContext(); openBlockEditor({ @@ -674,6 +1004,8 @@ function showTextContext() { function openBlockEditor(editing) { state.editing = editing; + hideEditRangeButton(); + clearNativeTextSelection(); const screen = pdfRectToScreen(editing.rect); const editor = elements['block-editor']; editor.style.left = `${clamp(screen[0], 0, Math.max(0, state.render.width - 190))}px`; @@ -687,7 +1019,9 @@ function openBlockEditor(editing) { elements['block-editor-text'].select(); setStatus(editing.mode === 'add' ? 'Escribe el texto nuevo y pulsa Aplicar.' - : 'Edita el bloque; el contenido inferior se desplazará automáticamente.'); + : (editing.mode === 'range' + ? 'Edita la selección; el párrafo se recompondrá automáticamente.' + : 'Edita el párrafo; el contenido inferior se desplazará automáticamente.')); } function syncBlockEditorPreview() { @@ -725,9 +1059,13 @@ function autoGrowBlockEditor() { } function cancelBlockEditor() { + const rangeWasOpen = state.editing?.mode === 'range'; state.editing = null; elements['block-editor'].classList.add('hidden'); elements['block-editor-text'].value = ''; + if (rangeWasOpen) { + state.textRange = null; + } if (!state.selected) { clearSelection(); } @@ -748,6 +1086,18 @@ async function applyBlockEditor() { } engine.insertTextBlock(state.currentPage, editing.rect, values); await commitAndRefresh('Añadir texto', { restoreText: text }); + } else if (editing.mode === 'range') { + engine.editTextRange( + state.currentPage, + editing.blockIndex, + editing.start, + editing.end, + text, + values + ); + await commitAndRefresh(text ? 'Editar selección' : 'Eliminar selección', { + restoreText: text || null + }); } else { engine.editTextBlock(state.currentPage, editing.blockIndex, values); await commitAndRefresh(text ? 'Editar texto' : 'Eliminar texto', { @@ -761,10 +1111,22 @@ async function deleteSelection() { return; } const selected = state.selected; + const selectedRange = state.textRange; clearSelection(); if (selected.kind === 'text') { - engine.editTextBlock(state.currentPage, selected.blockIndex, { text: '' }); - await commitAndRefresh('Eliminar texto'); + if (selectedRange?.blockIndex === selected.blockIndex) { + engine.editTextRange( + state.currentPage, + selected.blockIndex, + selectedRange.start, + selectedRange.end, + '' + ); + await commitAndRefresh('Eliminar selección'); + } else { + engine.editTextBlock(state.currentPage, selected.blockIndex, { text: '' }); + await commitAndRefresh('Eliminar texto'); + } } else if (selected.kind === 'native-image') { engine.deleteExistingContent(state.currentPage, selected.rect, { images: true, @@ -782,7 +1144,9 @@ async function deleteSelection() { } async function copySelectedText() { - const text = state.selected?.kind === 'text' ? state.selected.block.text : ''; + const text = state.selected?.kind === 'text' + ? (state.textRange?.text || state.selected.block.text) + : ''; if (!text) { return; } @@ -818,10 +1182,10 @@ async function applyTableProperties() { await commitAndRefresh('Actualizar tabla', { restoreKind: 'table-last' }); } -async function chooseTableTool() { +async function chooseTableTool(anchor = null) { const values = await showFieldsDialog({ title: 'Crear tabla', - confirmText: 'Elegir zona', + confirmText: anchor ? 'Insertar' : 'Elegir zona', fields: [ { name: 'rows', label: 'Filas', type: 'number', value: '3', min: '1', max: '30' }, { name: 'columns', label: 'Columnas', type: 'number', value: '3', min: '1', max: '20' }, @@ -831,6 +1195,24 @@ async function chooseTableTool() { grid: true }); if (!values) { + hideInsertMenu(); + return; + } + if (anchor) { + hideInsertMenu(); + const rowCount = Number(values.rows); + const tableHeight = clamp(rowCount * 24, 54, 360); + engine.insertTableBlock( + state.currentPage, + [anchor.x, anchor.y, anchor.x + anchor.width, anchor.y + tableHeight], + rowCount, + Number(values.columns), + { + color: hexToPdfColor(values.color), + borderWidth: Number(values.borderWidth) + } + ); + await commitAndRefresh('Insertar tabla', { restoreKind: 'table-last' }); return; } state.pendingTable = { @@ -851,8 +1233,45 @@ async function handleImageFile(event) { } try { const bytes = await fileToBytes(file); + const selectedImage = ['native-image', 'inserted-image'].includes(state.selected?.kind) + ? state.selected + : null; + + if (selectedImage?.kind === 'native-image') { + const targetRect = [...selectedImage.rect]; + engine.replaceExistingImage( + state.currentPage, + selectedImage.rect, + targetRect, + bytes + ); + clearSelection(); + await commitAndRefresh('Reemplazar imagen original', { restoreKind: 'image-last' }); + return; + } + + if (selectedImage?.kind === 'inserted-image') { + const targetRect = [...selectedImage.rect]; + engine.replaceAnnotationImage( + state.currentPage, + selectedImage.annotationIndex, + targetRect, + bytes + ); + clearSelection(); + await commitAndRefresh('Reemplazar imagen', { restoreKind: 'image-last' }); + return; + } + const dimensions = engine.getImageDimensions(bytes); state.pendingImage = { bytes, dimensions }; + const anchor = state.insertionAnchor; + if (anchor) { + hideInsertMenu({ preserveAnchor: true }); + await placePendingImage([anchor.x, anchor.y], anchor); + state.insertionAnchor = null; + return; + } setTool('place-image'); setStatus('Haz clic en la página para colocar la imagen.'); } catch (error) { @@ -860,7 +1279,7 @@ async function handleImageFile(event) { } } -async function placePendingImage(point) { +async function placePendingImage(point, anchor = null) { const pending = state.pendingImage; if (!pending) { return; @@ -869,13 +1288,15 @@ async function placePendingImage(point) { setTool('edit'); const bounds = state.pageModel.bounds; const aspectRatio = pending.dimensions.height / Math.max(1, pending.dimensions.width); - let width = Math.min(180, Math.max(40, bounds[2] - point[0] - 18)); + let width = anchor + ? Math.min(Math.max(80, anchor.width), 240) + : Math.min(180, Math.max(40, bounds[2] - point[0] - 18)); let height = width * aspectRatio; - if (point[1] + height > bounds[3] - 18) { + if (!anchor && point[1] + height > bounds[3] - 18) { height = Math.max(30, bounds[3] - point[1] - 18); width = height / Math.max(0.01, aspectRatio); } - engine.addImage(state.currentPage, [ + engine.insertImageBlock(state.currentPage, [ point[0], point[1], point[0] + width, @@ -911,9 +1332,10 @@ function restoreSelection(options) { let entry = null; if (options.restoreText) { const prefix = String(options.restoreText).trim().slice(0, 48); - entry = state.overlayObjects.find(({ meta }) => - meta.kind === 'text' && meta.block.text.includes(prefix) + const block = state.pageModel.textBlocks.find((candidate) => + candidate.text.includes(prefix) ); + return block ? selectTextBlock(block.index) : false; } else if (options.restoreKind === 'table-last') { entry = state.overlayObjects.findLast(({ meta }) => meta.kind === 'table'); } else if (options.restoreKind === 'image-last') { @@ -1053,6 +1475,8 @@ function updateDocumentInfo() { function setTool(tool) { state.tool = tool; + elements['text-layer']?.classList.toggle('placement-mode', tool !== 'edit'); + elements['insertion-layer']?.classList.toggle('disabled', tool !== 'edit'); if (state.fabricCanvas) { state.fabricCanvas.skipTargetFind = tool !== 'edit'; state.fabricCanvas.selection = false; @@ -1066,7 +1490,7 @@ function setTool(tool) { button.classList.toggle('active', button.dataset.tool === visibleTool); } const hints = { - edit: 'Selecciona un bloque para editarlo.', + edit: 'Haz clic en un párrafo, selecciona cualquier texto o usa + para insertar.', 'add-text': 'Haz clic donde quieras escribir.', 'place-image': 'Haz clic donde quieras colocar la imagen.', table: 'Arrastra para definir el tamaño de la tabla.' @@ -1131,21 +1555,27 @@ function initializeEventHandlers() { elements['save-button'].addEventListener('click', () => postCommand('save')); elements['edit-text-tool'].addEventListener('click', () => { + hideInsertMenu(); setTool('edit'); if (state.selected?.kind === 'text') { openExistingTextEditor(state.selected.block); } }); elements['add-text-tool'].addEventListener('click', () => { + hideInsertMenu(); cancelBlockEditor(); clearSelection(); setTool('add-text'); setStatus('Haz clic en cualquier punto de la página para escribir.'); }); elements['image-tool'].addEventListener('click', () => { + hideInsertMenu(); elements['image-file-input'].click(); }); - elements['table-tool'].addEventListener('click', chooseTableTool); + elements['table-tool'].addEventListener('click', () => { + hideInsertMenu(); + void chooseTableTool(); + }); elements['delete-tool'].addEventListener('click', deleteSelection); elements['edit-content'].addEventListener('click', () => { if (state.selected?.kind === 'text') { @@ -1160,6 +1590,25 @@ function initializeEventHandlers() { elements['text-bold'].addEventListener('click', () => toggleFormatButton(elements['text-bold'])); elements['text-italic'].addEventListener('click', () => toggleFormatButton(elements['text-italic'])); elements['apply-table'].addEventListener('click', applyTableProperties); + elements['edit-range-button'].addEventListener('click', openSelectedRangeEditor); + elements['insert-text-here'].addEventListener('click', () => { + const anchor = state.insertionAnchor; + hideInsertMenu(); + if (anchor) { + cancelBlockEditor(); + clearSelection(); + openNewTextEditor(anchor); + } + }); + elements['insert-image-here'].addEventListener('click', () => { + elements['image-file-input'].click(); + }); + elements['insert-table-here'].addEventListener('click', () => { + const anchor = state.insertionAnchor; + if (anchor) { + void chooseTableTool(anchor); + } + }); elements['image-file-input'].addEventListener('change', handleImageFile); elements['block-editor-text'].addEventListener('input', autoGrowBlockEditor); elements['block-editor-text'].addEventListener('keydown', (event) => { @@ -1176,6 +1625,20 @@ function initializeEventHandlers() { elements['dialog-form'].addEventListener('submit', submitDialog); elements['dialog-cancel'].addEventListener('click', () => closeDialog(null)); + elements['page-stage'].addEventListener('pointerdown', (event) => { + if (!elements['insert-menu'].contains(event.target) && + !event.target.closest?.('.insertion-marker')) { + hideInsertMenu(); + } + if (state.tool === 'edit' && state.selected?.kind === 'text' && + !event.target.closest?.('.text-layer-line, .edit-range-button, .block-editor')) { + clearNativeTextSelection(); + clearSelection(); + } + }); + document.addEventListener('selectionchange', () => { + window.requestAnimationFrame(updateTextRangeFromSelection); + }); document.addEventListener('keydown', keyboardHandler); window.addEventListener('resize', debounce(async () => { if (state.zoomMode !== 'numeric' && state.pageCount > 0) { diff --git a/media/webview/pdf-engine.js b/media/webview/pdf-engine.js index a430bae..ab95f09 100644 --- a/media/webview/pdf-engine.js +++ b/media/webview/pdf-engine.js @@ -186,7 +186,7 @@ export class PdfEngine { return { bounds: [...page.getBounds()], textBlocks, - textLines: textBlocks.flatMap((block) => block.lines), + textLines: textBlocks.flatMap((block) => block.visualLines), images, annotations: this.readAnnotations(page), widgets: this.readWidgets(page) @@ -369,6 +369,77 @@ export class PdfEngine { }; } + /** + * Replaces an arbitrary character range inside an extracted text block. The + * complete paragraph is reflowed afterwards, so a longer replacement or a + * larger font creates real room and moves the following content down. + */ + editTextRange(pageIndex, blockIndex, start, end, replacement, properties = {}) { + const model = this.getPageModel(pageIndex); + const block = model.textBlocks.find((candidate) => candidate.index === blockIndex); + if (!block) { + throw new Error('The selected text block no longer exists. Select it again.'); + } + + const rangeStart = Math.max(0, Math.min(block.text.length, Math.round(Number(start) || 0))); + const rangeEnd = Math.max( + rangeStart, + Math.min(block.text.length, Math.round(Number(end) || 0)) + ); + const replacementText = String(replacement || '').replaceAll('\0', ''); + const originalValues = normalizeBlockProperties(block, { text: block.text }); + const replacementValues = normalizeBlockProperties(block, { + ...properties, + text: replacementText + }); + const runs = [ + { text: block.text.slice(0, rangeStart), values: originalValues }, + { text: replacementText, values: replacementValues }, + { text: block.text.slice(rangeEnd), values: originalValues } + ].filter((run) => run.text.length > 0); + const resultingText = runs.map((run) => run.text).join(''); + const layout = layoutRichTextBlock( + block.rect, + runs, + block.metrics, + replacementValues.alignment + ); + const oldHeight = Math.max(0, block.rect[3] - block.rect[1]); + const delta = layout.height - oldHeight; + const followingBlocks = findFollowingBlocks(model.textBlocks, block.rect, block.index); + const shiftedEntries = followingBlocks.flatMap((followingBlock) => + textEntriesForExistingBlock(followingBlock, delta) + ); + + this.withOperation(resultingText ? 'Edit text selection' : 'Delete text selection', () => { + this.withPage(pageIndex, (page) => { + for (const sourceBlock of [block, ...followingBlocks]) { + this.removeContentInRect(page, expandRect(sourceBlock.rect, 0.35), { + images: false, + lineArt: false, + text: true + }); + } + const entries = resultingText + ? [...layout.entries, ...shiftedEntries] + : shiftedEntries; + const maximumBottom = Math.max( + resultingText ? block.rect[1] + layout.height : block.rect[1], + ...followingBlocks.map((candidate) => candidate.rect[3] + delta) + ); + this.extendPageToFit(page, maximumBottom); + this.appendStaticText(page, entries); + }); + }); + + return { + delta, + shiftedBlocks: followingBlocks.length, + text: resultingText, + rect: [block.rect[0], block.rect[1], block.rect[2], block.rect[1] + layout.height] + }; + } + /** * Inserts a new static text block and makes room by moving intersecting text * blocks and all lower blocks in the same visual column. @@ -435,6 +506,71 @@ export class PdfEngine { }; } + /** + * Inserts an image as a flow object. Text intersecting the insertion point + * and all text below it in the same column is rewritten lower on the page. + */ + insertImageBlock(pageIndex, rect, imageBytes) { + return this.insertFlowObject(pageIndex, rect, 'Add image block', (page, targetRect) => { + this.createImageStamp(page, targetRect, imageBytes); + }); + } + + /** + * Inserts an editable table as a flow object and makes room for it by moving + * lower text blocks instead of covering them. + */ + insertTableBlock(pageIndex, rect, rows = 2, columns = 2, properties = {}) { + const rowCount = Math.max(1, Math.min(30, Math.round(Number(rows) || 2))); + const columnCount = Math.max(1, Math.min(20, Math.round(Number(columns) || 2))); + return this.insertFlowObject(pageIndex, rect, 'Add table block', (page, targetRect) => { + this.createTableAnnotation(page, targetRect, rowCount, columnCount, properties); + }); + } + + insertFlowObject(pageIndex, rect, label, createObject) { + const model = this.getPageModel(pageIndex); + const normalizedRect = normalizeRect(rect); + const objectHeight = Math.max(8, normalizedRect[3] - normalizedRect[1]); + const spacing = 6; + const delta = objectHeight + spacing; + const anchorRect = [ + normalizedRect[0], + normalizedRect[1], + normalizedRect[2], + normalizedRect[1] + ]; + const followingBlocks = findBlocksAtOrBelow(model.textBlocks, anchorRect); + const shiftedEntries = followingBlocks.flatMap((followingBlock) => + textEntriesForExistingBlock(followingBlock, delta) + ); + + this.withOperation(label, () => { + this.withPage(pageIndex, (page) => { + for (const sourceBlock of followingBlocks) { + this.removeContentInRect(page, expandRect(sourceBlock.rect, 0.35), { + images: false, + lineArt: false, + text: true + }); + } + const maximumBottom = Math.max( + normalizedRect[3], + ...followingBlocks.map((candidate) => candidate.rect[3] + delta) + ); + this.extendPageToFit(page, maximumBottom); + this.appendStaticText(page, shiftedEntries); + createObject(page, normalizedRect); + }); + }); + + return { + delta, + shiftedBlocks: followingBlocks.length, + rect: normalizedRect + }; + } + moveTextBlock(pageIndex, blockIndex, targetRect) { const model = this.getPageModel(pageIndex); const block = model.textBlocks.find((candidate) => candidate.index === blockIndex); @@ -1451,27 +1587,28 @@ function extractTextBlocks(structuredText) { const lines = currentBlock.lines.filter((line) => line.text.length > 0); if (lines.length > 0) { const visualLines = buildVisualLines(lines); - const rect = unionRects([ - currentBlock.sourceRect, - ...lines.map((line) => line.rect) - ]); - const blockStyle = dominantLineStyle(lines); - const index = blocks.length; - blocks.push({ - index, - rect, - text: visualLines.map((line) => line.text.trim()).join(' ').trim(), - lines: lines.map((line, lineIndex) => ({ - ...line, - blockIndex: index, - lineIndex - })), - visualLines, - font: blockStyle.font, - color: blockStyle.color, - alignment: inferTextAlignment(rect, visualLines), - metrics: metricsForBlock(rect, visualLines, blockStyle.font.size) - }); + for (const paragraphLines of splitVisualLinesIntoParagraphs(visualLines)) { + const paragraphFragments = paragraphLines.flatMap((line) => line.fragments); + const rect = unionRects(paragraphLines.map((line) => line.rect)); + const blockStyle = dominantLineStyle(paragraphFragments); + const index = blocks.length; + const decoratedLines = decorateParagraphLines(paragraphLines, index); + blocks.push({ + index, + rect, + text: decoratedLines.text, + lines: paragraphFragments.map((line, lineIndex) => ({ + ...line, + blockIndex: index, + lineIndex + })), + visualLines: decoratedLines.lines, + font: blockStyle.font, + color: blockStyle.color, + alignment: inferTextAlignment(rect, paragraphLines), + metrics: metricsForBlock(rect, paragraphLines, blockStyle.font.size) + }); + } } currentBlock = null; } @@ -1555,6 +1692,7 @@ function buildVisualLines(lines) { const style = dominantLineStyle(row.fragments); return { text, + fragments: row.fragments, rect: row.rect, baseline: [row.fragments[0].baseline[0], row.baseline[1]], font: style.font, @@ -1699,6 +1837,261 @@ function resolveBase14Font(family, bold, italic) { return 'Helvetica'; } + +function splitVisualLinesIntoParagraphs(visualLines) { + if (!Array.isArray(visualLines) || visualLines.length === 0) { + return []; + } + if (visualLines.length === 1) { + return [[visualLines[0]]]; + } + + const lines = [...visualLines].sort((left, right) => { + const yDifference = left.baseline[1] - right.baseline[1]; + return Math.abs(yDifference) > 0.75 + ? yDifference + : left.rect[0] - right.rect[0]; + }); + const paragraphs = []; + let paragraph = [lines[0]]; + + for (const line of lines.slice(1)) { + const previous = paragraph.at(-1); + const previousHeight = Math.max(1, previous.rect[3] - previous.rect[1]); + const currentHeight = Math.max(1, line.rect[3] - line.rect[1]); + const fontSize = Math.max( + 1, + Number(previous.font?.size || 0), + Number(line.font?.size || 0) + ); + const verticalGap = line.rect[1] - previous.rect[3]; + const baselineGap = line.baseline[1] - previous.baseline[1]; + const expectedLineHeight = Math.max(previousHeight, currentHeight, fontSize * 1.05); + const paragraphGap = Math.max(3, fontSize * 0.55); + const startsNewParagraph = + verticalGap > paragraphGap || + baselineGap > expectedLineHeight * 1.75; + + if (startsNewParagraph) { + paragraphs.push(paragraph); + paragraph = [line]; + } else { + paragraph.push(line); + } + } + + paragraphs.push(paragraph); + return paragraphs; +} + +function decorateParagraphLines(paragraphLines, blockIndex) { + let text = ''; + const lines = []; + + for (const sourceLine of paragraphLines) { + const lineText = String(sourceLine.text || '').trim(); + if (!lineText) { + continue; + } + const separator = text ? ' ' : ''; + const start = text.length + separator.length; + text += separator + lineText; + const end = text.length; + const lineIndex = lines.length; + lines.push({ + ...sourceLine, + text: lineText, + blockIndex, + lineIndex, + start, + end, + startOffset: start, + endOffset: end, + textStart: start, + textEnd: end + }); + } + + return { text, lines }; +} + +function layoutRichTextBlock(rect, runs, metrics, alignment = 0) { + const normalizedRuns = (Array.isArray(runs) ? runs : []) + .map((run) => ({ + text: String(run?.text || '').replaceAll('\r\n', '\n').replaceAll('\r', '\n'), + values: run?.values || {} + })) + .filter((run) => run.text.length > 0); + + if (normalizedRuns.length === 0) { + return { height: 0, entries: [], lines: [] }; + } + + const width = Math.max(24, rect[2] - rect[0]); + const fonts = new Map(); + const getFont = (fontName) => { + const name = String(fontName || 'Helvetica'); + if (!fonts.has(name)) { + fonts.set(name, new mupdf.Font(name)); + } + return fonts.get(name); + }; + const itemWidth = (item) => measureText( + getFont(item.values.fontName), + item.character, + Math.max(4, Number(item.values.fontSize || 12)) + ); + const lineWidth = (items) => items.reduce((sum, item) => sum + itemWidth(item), 0); + const trimLine = (items) => { + let start = 0; + let end = items.length; + while (start < end && /\s/u.test(items[start].character)) { + start += 1; + } + while (end > start && /\s/u.test(items[end - 1].character)) { + end -= 1; + } + return items.slice(start, end); + }; + + try { + const items = []; + for (const run of normalizedRuns) { + for (const character of run.text) { + items.push({ character, values: run.values }); + } + } + + const wrappedLines = []; + let current = []; + let currentWidth = 0; + + const commitLine = (lineItems) => { + wrappedLines.push(trimLine(lineItems)); + }; + + for (const item of items) { + if (item.character === '\n') { + commitLine(current); + current = []; + currentWidth = 0; + continue; + } + + const widthToAdd = itemWidth(item); + if (current.length > 0 && currentWidth + widthToAdd > width + 0.5) { + let breakAt = -1; + for (let index = current.length - 1; index >= 0; index -= 1) { + if (/\s/u.test(current[index].character)) { + breakAt = index; + break; + } + } + + if (breakAt >= 0) { + const carry = current.slice(breakAt + 1); + commitLine(current.slice(0, breakAt)); + current = carry; + currentWidth = lineWidth(current); + } else { + commitLine(current); + current = []; + currentWidth = 0; + } + } + + if (/\s/u.test(item.character) && current.length === 0) { + continue; + } + current.push(item); + currentWidth += widthToAdd; + } + commitLine(current); + + const maximumFontSize = Math.max( + 4, + ...normalizedRuns.map((run) => Math.max(4, Number(run.values.fontSize || 12))) + ); + const baselineOffset = clampNumber( + Number(metrics?.baselineOffsetRatio || 1.05) * maximumFontSize, + maximumFontSize * 0.75, + maximumFontSize * 1.5 + ); + const lineHeight = clampNumber( + Number(metrics?.lineHeightRatio || 1.25) * maximumFontSize, + maximumFontSize, + maximumFontSize * 2 + ); + const descent = clampNumber( + Number(metrics?.descentRatio || 0.25) * maximumFontSize, + maximumFontSize * 0.12, + maximumFontSize * 0.6 + ); + const height = baselineOffset + Math.max(0, wrappedLines.length - 1) * lineHeight + descent; + const entries = []; + + wrappedLines.forEach((lineItems, lineIndex) => { + const measuredWidth = lineWidth(lineItems); + let x = rect[0]; + if (alignment === 1) { + x = rect[0] + (width - measuredWidth) / 2; + } else if (alignment === 2) { + x = rect[2] - measuredWidth; + } + const baselineY = rect[1] + baselineOffset + lineIndex * lineHeight; + let segment = []; + let segmentKey = null; + + const flushSegment = () => { + if (segment.length === 0) { + return; + } + const values = segment[0].values; + const text = segment.map((entry) => entry.character).join(''); + if (text) { + entries.push({ + text, + baseline: [x, baselineY], + fontName: values.fontName || 'Helvetica', + fontSize: Math.max(4, Number(values.fontSize || 12)), + color: normalizeColor(values.color, [0, 0, 0]) + }); + x += measureText( + getFont(values.fontName), + text, + Math.max(4, Number(values.fontSize || 12)) + ); + } + segment = []; + segmentKey = null; + }; + + for (const entry of lineItems) { + const values = entry.values; + const key = JSON.stringify([ + values.fontName || 'Helvetica', + Math.max(4, Number(values.fontSize || 12)), + normalizeColor(values.color, [0, 0, 0]) + ]); + if (segmentKey !== null && key !== segmentKey) { + flushSegment(); + } + segmentKey = key; + segment.push(entry); + } + flushSegment(); + }); + + return { + height, + entries, + lines: wrappedLines.map((line) => line.map((item) => item.character).join('')) + }; + } finally { + destroyAll(fonts.values()); + } +} + function layoutTextBlock(rect, values, metrics, originalBlock = null) { if (!values.text) { return { height: 0, entries: [], lines: [] }; diff --git a/media/webview/styles.css b/media/webview/styles.css index cf287f7..3c52e12 100644 --- a/media/webview/styles.css +++ b/media/webview/styles.css @@ -332,6 +332,7 @@ input[type="color"] { #pdf-canvas, .text-layer, +.insertion-layer, .page-stage > .canvas-container { position: absolute !important; inset: 0; @@ -342,7 +343,7 @@ input[type="color"] { } .text-layer { - z-index: 2; + z-index: 4; overflow: hidden; pointer-events: none; } @@ -351,15 +352,133 @@ input[type="color"] { position: absolute; overflow: hidden; color: transparent; + border-radius: 2px; line-height: 1; white-space: pre; + cursor: text; + pointer-events: auto; + user-select: text; transform-origin: 0 0; + transition: background-color 80ms ease; +} + +.text-layer-line:hover { + background: color-mix(in srgb, var(--focus) 9%, transparent); +} + +.text-layer-line.selected { + background: color-mix(in srgb, var(--focus) 12%, transparent); + box-shadow: inset 2px 0 0 color-mix(in srgb, var(--focus) 75%, transparent); +} + +.text-layer-line::selection { + color: transparent; + background: color-mix(in srgb, var(--focus) 38%, transparent); +} + +.text-layer.placement-mode .text-layer-line { + pointer-events: none; + user-select: none; } .page-stage > .canvas-container { z-index: 3; } +.insertion-layer { + z-index: 5; + overflow: visible; + pointer-events: none; +} + +.insertion-marker { + position: absolute; + display: flex; + align-items: center; + min-height: 18px; + height: 18px; + padding: 0; + border: 0; + color: var(--focus); + background: transparent; + opacity: 0.32; + pointer-events: auto; + transition: opacity 100ms ease; +} + +.insertion-marker:hover, +.insertion-marker:focus-visible { + border: 0; + background: transparent; + opacity: 1; +} + +.insertion-layer.disabled .insertion-marker { + opacity: 0; + pointer-events: none; +} + +.insertion-plus { + display: grid; + flex: 0 0 18px; + width: 18px; + height: 18px; + place-items: center; + border-radius: 50%; + color: #fff; + background: var(--focus); + font-size: 16px; + font-weight: 700; + line-height: 18px; +} + +.insertion-guide { + flex: 1 1 auto; + height: 1px; + margin-left: 4px; + background: var(--focus); +} + +.insert-menu { + position: absolute; + z-index: 7; + display: flex; + align-items: center; + gap: 5px; + min-width: 220px; + padding: 5px; + border: 1px solid var(--focus); + border-radius: 5px; + color: var(--foreground); + background: var(--surface); + box-shadow: 0 5px 18px rgba(0, 0, 0, 0.28); +} + +.insert-menu span { + margin-right: 3px; + color: var(--muted); + font-size: 11px; +} + +.insert-menu button { + min-height: 25px; + padding: 3px 8px; +} + +.edit-range-button { + position: absolute; + z-index: 7; + width: 126px; + min-height: 28px; + color: var(--primary-text); + background: var(--primary); + box-shadow: 0 3px 12px rgba(0, 0, 0, 0.28); +} + +.edit-range-button:hover:not(:disabled) { + background: var(--primary-hover); +} + .block-editor { position: absolute; z-index: 8; diff --git a/package-lock.json b/package-lock.json index 4d361f4..28239b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pdf-viewer-editor", - "version": "0.0.2", + "version": "0.0.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pdf-viewer-editor", - "version": "0.0.2", + "version": "0.0.4", "license": "AGPL-3.0-or-later", "devDependencies": { "@types/node": "^24.0.0", diff --git a/package.json b/package.json index 18cc749..006cdaa 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "pdf-viewer-editor", "displayName": "PDF Viewer & Editor", - "description": "A focused visual PDF editor for real text-block reflow, images, and editable tables in Visual Studio Code.", - "version": "0.0.3", + "description": "A focused visual PDF editor with direct text selection, real reflow, image editing, and editable tables in Visual Studio Code.", + "version": "0.0.4", "publisher": "suzdalenko-dev", "license": "AGPL-3.0-or-later", "repository": { @@ -127,5 +127,6 @@ "fabric": "7.4.0", "mupdf": "1.28.0", "typescript": "^5.9.0" - } + }, + "icon": "images/icon.png" } diff --git a/test/pdf-engine.test.mjs b/test/pdf-engine.test.mjs index b0a16fa..97f00ac 100644 --- a/test/pdf-engine.test.mjs +++ b/test/pdf-engine.test.mjs @@ -67,6 +67,37 @@ function createFlowingTextPdf() { return bytes; } +function createMergedParagraphPdf() { + const document = new mupdf.PDFDocument(); + const resources = document.newDictionary(); + const fonts = document.newDictionary(); + const font = new mupdf.Font('Helvetica'); + const fontReference = document.addSimpleFont(font, 'Latin'); + fonts.put('F0', fontReference); + resources.put('Font', fonts); + const contents = [ + 'BT /F0 12 Tf', + '30 365 Td (First visual paragraph starts here) Tj', + '0 -15 Td (and continues on its second line.) Tj', + '0 -42 Td (Second visual paragraph starts after a gap) Tj', + '0 -15 Td (and has another wrapped line.) Tj', + 'ET' + ].join('\n'); + const page = document.addPage([0, 0, 300, 420], 0, resources, contents); + document.insertPage(-1, page); + const buffer = document.saveToBuffer('garbage=4,compress=yes'); + const bytes = new Uint8Array(buffer.asUint8Array()).slice(); + + buffer.destroy(); + page.destroy(); + fontReference.destroy(); + font.destroy(); + fonts.destroy(); + resources.destroy(); + document.destroy(); + return bytes; +} + test('password-protected PDFs require and accept authentication', () => { const engine = new PdfEngine(); try { @@ -246,6 +277,86 @@ test('text blocks reflow, move following content, and remain searchable', () => } }); +test('visual paragraph detection avoids one giant selection block', () => { + const engine = new PdfEngine(); + try { + engine.load(createMergedParagraphPdf()); + const model = engine.getPageModel(0); + assert.equal(model.textBlocks.length, 2); + assert.equal(model.textLines.length, 4); + assert.equal(model.textBlocks[0].visualLines.length, 2); + assert.equal(model.textBlocks[1].visualLines.length, 2); + assert.equal(model.textLines[0].blockIndex, model.textLines[1].blockIndex); + assert.notEqual(model.textLines[1].blockIndex, model.textLines[2].blockIndex); + assert.ok(model.textBlocks[0].rect[3] < model.textBlocks[1].rect[1]); + } finally { + engine.destroy(); + } +}); + +test('a selected text range can change content and format with real reflow', () => { + const engine = new PdfEngine(); + try { + engine.load(createFlowingTextPdf()); + const originalModel = engine.getPageModel(0); + const firstBlock = originalModel.textBlocks.find((block) => + block.text.includes('First paragraph') + ); + const originalSecond = originalModel.textLines.find((line) => + line.text.includes('Second paragraph') + ); + const start = firstBlock.text.indexOf('paragraph'); + const result = engine.editTextRange( + 0, + firstBlock.index, + start, + start + 'paragraph'.length, + 'much larger selected passage that wraps', + { fontFamily: 'Times-Roman', fontSize: 28, color: [0.8, 0.1, 0.1] } + ); + assert.ok(result.delta > 0); + assert.equal(engine.search('First').length, 1); + assert.equal(engine.search('much larger selected').length, 1); + assert.equal(engine.search('First paragraph').length, 0); + const shiftedSecond = engine.getPageModel(0).textLines.find((line) => + line.text.includes('Second paragraph') + ); + assert.ok(shiftedSecond.rect[1] > originalSecond.rect[1]); + } finally { + engine.destroy(); + } +}); + +test('flow image and table insertion move lower text instead of covering it', () => { + const engine = new PdfEngine(); + try { + engine.load(createFlowingTextPdf()); + const originalSecond = engine.getPageModel(0).textLines.find((line) => + line.text.includes('Second paragraph') + ); + const imageBytes = engine.exportPageImage(0, 'png', 24); + const imageResult = engine.insertImageBlock(0, [30, 90, 150, 150], imageBytes); + assert.ok(imageResult.shiftedBlocks > 0); + const afterImage = engine.getPageModel(0); + const imageShiftedSecond = afterImage.textLines.find((line) => + line.text.includes('Second paragraph') + ); + assert.ok(imageShiftedSecond.rect[1] > originalSecond.rect[1]); + assert.ok(afterImage.annotations.some((annotation) => annotation.type === 'Stamp')); + + const tableResult = engine.insertTableBlock(0, [30, 155, 270, 225], 3, 4); + assert.ok(tableResult.shiftedBlocks > 0); + const afterTable = engine.getPageModel(0); + const tableShiftedSecond = afterTable.textLines.find((line) => + line.text.includes('Second paragraph') + ); + assert.ok(tableShiftedSecond.rect[1] > imageShiftedSecond.rect[1]); + assert.ok(afterTable.annotations.some((annotation) => annotation.table)); + } finally { + engine.destroy(); + } +}); + test('text insertion, free positioning, and editable tables work as PDF objects', () => { const engine = new PdfEngine(); try {