OCR fix and Mobile QR changes (#5433)

# Description of Changes
## OCR / Tesseract path handling

Makes tessDataPath resolution deterministic with priority: config >
TESSDATA_PREFIX env > default.
Updates language discovery to use runtimePathConfig.getTessDataPath()
instead of raw config value.
Ensure default OCR dir is debian based not alpine

## Mobile scanner: feature gating + new conversion settings
Adds system.mobileScannerSettings (convert-to-PDF + resolution + page
format + stretch) exposed via backend config and configurable in the
proprietary admin UI.
Enforces enableMobileScanner on the MobileScannerController endpoints
(403 when disabled).
Frontend mobile upload flow can now optionally convert received images
to PDF (pdf-lib + canvas).

## Desktop/Tauri connectivity work
Expands tauri-plugin-http permissions and enables dangerous-settings.
Adds a very comprehensive multi-stage server connection diagnostic
routine (with lots of logging).


<img width="688" height="475" alt="image"
src="https://github.com/user-attachments/assets/6f9c1aec-58c7-449b-96b0-52f25430d741"
/>


---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
This commit is contained in:
Anthony Stirling
2026-01-12 11:18:37 +00:00
committed by GitHub
parent 0ae108ca11
commit d2677e64dd
20 changed files with 1478 additions and 133 deletions
@@ -8,6 +8,8 @@ import { useFileManagerContext } from '@app/contexts/FileManagerContext';
import { useGoogleDrivePicker } from '@app/hooks/useGoogleDrivePicker';
import { useFileActionTerminology } from '@app/hooks/useFileActionTerminology';
import { useFileActionIcons } from '@app/hooks/useFileActionIcons';
import { useAppConfig } from '@app/contexts/AppConfigContext';
import { useIsMobile } from '@app/hooks/useIsMobile';
import MobileUploadModal from '@app/components/shared/MobileUploadModal';
interface FileSourceButtonsProps {
@@ -24,6 +26,9 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({
const icons = useFileActionIcons();
const UploadIcon = icons.upload;
const [mobileUploadModalOpen, setMobileUploadModalOpen] = useState(false);
const { config } = useAppConfig();
const isMobile = useIsMobile();
const isMobileUploadEnabled = config?.enableMobileScanner && !isMobile;
const handleGoogleDriveClick = async () => {
try {
@@ -127,15 +132,17 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({
onClick={handleMobileUploadClick}
fullWidth={!horizontal}
size={horizontal ? "xs" : "sm"}
disabled={!isMobileUploadEnabled}
styles={{
root: {
backgroundColor: 'transparent',
border: 'none',
'&:hover': {
backgroundColor: 'var(--mantine-color-gray-0)'
backgroundColor: isMobileUploadEnabled ? 'var(--mantine-color-gray-0)' : 'transparent'
}
}
}}
title={!isMobileUploadEnabled ? t('fileManager.mobileUploadNotAvailable', 'Mobile upload not available') : undefined}
>
{horizontal ? t('fileManager.mobileShort', 'Mobile') : t('fileManager.mobileUpload', 'Mobile Upload')}
</Button>
@@ -9,6 +9,7 @@ import CheckRoundedIcon from '@mui/icons-material/CheckRounded';
import WarningRoundedIcon from '@mui/icons-material/WarningRounded';
import { Z_INDEX_OVER_FILE_MANAGER_MODAL } from '@app/styles/zIndex';
import { withBasePath } from '@app/constants/app';
import { convertImageToPdf, isImageFile } from '@app/utils/imageToPdfUtils';
interface MobileUploadModalProps {
opened: boolean;
@@ -132,10 +133,25 @@ export default function MobileUploadModal({ opened, onClose, onFilesReceived }:
if (downloadResponse.ok) {
const blob = await downloadResponse.blob();
const file = new File([blob], fileMetadata.filename, {
let file = new File([blob], fileMetadata.filename, {
type: fileMetadata.contentType || 'image/jpeg'
});
// Convert images to PDF if enabled
if (isImageFile(file) && config?.mobileScannerConvertToPdf !== false) {
try {
file = await convertImageToPdf(file, {
imageResolution: config?.mobileScannerImageResolution as 'full' | 'reduced' | undefined,
pageFormat: config?.mobileScannerPageFormat as 'keep' | 'A4' | 'letter' | undefined,
stretchToFit: config?.mobileScannerStretchToFit,
});
console.log('Converted image to PDF:', file.name);
} catch (convertError) {
console.warn('Failed to convert image to PDF, using original file:', convertError);
// Continue with original image file if conversion fails
}
}
processedFiles.current.add(fileMetadata.filename);
setFilesReceived((prev) => prev + 1);
onFilesReceived([file]);
@@ -256,10 +272,15 @@ export default function MobileUploadModal({ opened, onClose, onFilesReceived }:
variant="light"
>
<Text size="sm">
{t(
'mobileUpload.description',
'Scan this QR code with your mobile device to upload photos directly to this page.'
)}
{config?.mobileScannerConvertToPdf !== false
? t(
'mobileUpload.description',
'Scan this QR code with your mobile device to upload photos. Images will be automatically converted to PDF.'
)
: t(
'mobileUpload.descriptionNoConvert',
'Scan this QR code with your mobile device to upload photos.'
)}
</Text>
</Alert>
@@ -308,10 +329,15 @@ export default function MobileUploadModal({ opened, onClose, onFilesReceived }:
)}
<Text size="xs" c="dimmed" ta="center" style={{ maxWidth: '300px' }}>
{t(
'mobileUpload.instructions',
'Open the camera app on your phone and scan this code. Files will be uploaded through the server.'
)}
{config?.mobileScannerConvertToPdf !== false
? t(
'mobileUpload.instructions',
'Open the camera app on your phone and scan this code. Images will be automatically converted to PDF.'
)
: t(
'mobileUpload.instructionsNoConvert',
'Open the camera app on your phone and scan this code. Files will be uploaded through the server.'
)}
</Text>
<Text