Skip to content

OCR integration#13313

Closed
Kaan0029 wants to merge 61 commits into
JabRef:mainfrom
Kaan0029:gsoc-ocr-tess4j-initial-implementation
Closed

OCR integration#13313
Kaan0029 wants to merge 61 commits into
JabRef:mainfrom
Kaan0029:gsoc-ocr-tess4j-initial-implementation

Conversation

@Kaan0029

@Kaan0029 Kaan0029 commented Jun 12, 2025

Copy link
Copy Markdown
Contributor

Closes #13267.

Mandatory checks

  • I own the copyright of the code submitted and I license it under the MIT license
  • [.] Change in CHANGELOG.md described in a way that is understandable for the average user (if change is visible to the user)
  • [.] Tests created for changes (if applicable)
  • [.] Manually tested changed features in running JabRef (always required)
  • [.] Screenshots added in PR description (if change is visible to the user)
  • [.] Checked developer's documentation: Is the information available and up to date? If not, I outlined it in this pull request.
  • [.] Checked documentation: Is the information available and up to date? If not, I created an issue at https://github.com/JabRef/user-documentation/issues or, even better, I submitted a pull request to the documentation repository.

@calixtus calixtus changed the title Initial implementation using tess4j OCR integration Jun 12, 2025
Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrService.java Outdated
Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrService.java Outdated
Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrService.java Outdated
Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrException.java Outdated
Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrResult.java Outdated
Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrService.java Outdated
Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrResult.java Outdated
Comment thread jabgui/src/main/java/org/jabref/gui/linkedfile/OcrAction.java Outdated
Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrResult.java Outdated
Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrService.java Outdated
@subhramit

Copy link
Copy Markdown
Member

Your pull request conflicts with the target branch.

Please merge upstream/main with your code. For a step-by-step guide to resolve merge conflicts, see https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line.

Tip for future - always take a fresh pull from upstream/main before beginning to work on a branch (if there has been a decent time gap).

Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrService.java Outdated
@koppor koppor added this to the 6.0 milestone Jul 4, 2025
@jabref-machine

Copy link
Copy Markdown
Collaborator

Your code currently does not meet JabRef's code guidelines. We use Checkstyle to identify issues. You can see which checks are failing by locating the box "Some checks were not successful" on the pull request page. To see the test output, locate "Tests / Checkstyle (pull_request)" and click on it.

In case of issues with the import order, double check that you activated Auto Import. You can trigger fixing imports by pressing Ctrl+Alt+O to trigger Optimize Imports.

Please carefully follow the setup guide for the codestyle. Afterwards, please run checkstyle locally and fix the issues, commit, and push.

@Kaan0029 Kaan0029 force-pushed the gsoc-ocr-tess4j-initial-implementation branch from 9f91505 to db1f577 Compare July 10, 2025 10:49

this.ocrService = new OcrService(filePreferences);

// Log if OCR is not available but don't fail

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment simply restates what the code does in the next lines. It doesn't provide additional information about why this approach was chosen or any other valuable context.

Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrService.java
}
return false; // nothing usable found
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching generic Exception is too broad and masks specific issues. Should catch specific exceptions like IOException or SecurityException for better error handling.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, trag bot probably selected wrong lines, but overall he's right, the Exception is too generic

Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrService.java
Comment thread jablib/src/main/java/org/jabref/logic/FilePreferences.java

@InAnYan InAnYan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some refactoring comments

Localization.lang("Failed to initialize AI service. OCR functionality will be unavailable.") + "\n\n" +
Localization.lang("Error details: ") + e.getMessage());
// Set aiService to null - the application can continue without AI features
JabRefGUI.aiService = null;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it can't.

Trust me. It must be present and not null.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is outdated, right?

dialogService,
taskExecutor);
Injector.setModelOrService(AiService.class, aiService);
} catch (OcrException e) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove the throw of exception and not use them?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is outdated, right?

);

// Add OCR menu item for PDF files
if (linkedFile.getFile().getFileType().equalsIgnoreCase("pdf")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to search a method in class FilesUtil (or FileUtil) like isPDF

}

themeWindowManager.setDarkModeForWindowFrame(stage, darkMode);
// themeWindowManager.setDarkModeForWindowFrame(stage, darkMode);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this doesn't solve the original problem? Shouldn't you made a try/catch, so that other people who use JabRef could still use dark theme, if for some other machines it doesn't work

NotificationService notificationService,
TaskExecutor taskExecutor
) {
) throws OcrException {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the best idea

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is outdated, right?

/**
* Factory method for creating a success result.
*/
static OcrResult success(@NonNull String text) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove @NonNull and always assume that the input is not null

Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrService.java
Comment thread jablib/src/main/java/org/jabref/logic/ocr/OcrService.java
}
return false; // nothing usable found
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, trag bot probably selected wrong lines, but overall he's right, the Exception is too generic

getBoolean(OPEN_FILE_EXPLORER_IN_LAST_USED_DIRECTORY));
getBoolean(OPEN_FILE_EXPLORER_IN_LAST_USED_DIRECTORY),
// TODO: replace placeholder once real source tag / persistence is implemented
"");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are able to handle this. This is not hard

Comment on lines +121 to +122
// Create the OCR action
OcrAction ocrAction = new OcrAction(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is trivial and doesn't add any new information beyond what is clearly visible in the code. It simply restates what the code is doing.

Comment on lines +132 to +135
// Set the action to execute when clicked
ocrItem.setOnAction(event -> ocrAction.execute());

// Disable if the action is not executable (file doesn't exist)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both comments are redundant and simply describe what the code does without providing additional context or reasoning for the implementation choices.

/**
* Factory method for creating a success result with text and output file.
*/
static OcrResult success(@NonNull String text, Path outputFile) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The outputFile parameter lacks @nonnull annotation, and the method doesn't validate if the path is null before wrapping it in Optional.of(), which could cause NullPointerException.

*/
record Failure(String errorMessage) implements OcrResult {
public Failure {
// Provide default message instead of throwing exception

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment merely restates what the code does without providing additional insight or reasoning. Comments should add new information not plainly derived from the code.

@calixtus

Copy link
Copy Markdown
Member

Commit pushed about one hour ago. We sadly had no time to review the changes in time for the meeting.
grafik

Comment on lines +127 to +131
public boolean skipTextPages = true;
public boolean clean = false;
public boolean forceOcr = false;
public String language = "eng";
public int optimizeLevel = 1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fields in OcrMyPdfOptions are declared public, violating encapsulation principles. They should be private with getter/setter methods to maintain proper encapsulation.

*
* @return Configuration error message, or empty string if properly configured
*/
String getConfigurationError();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method returns String which could be null. According to modern Java practices and clean architecture, Optional should be used to handle potential empty states.

* @param method The method to use for creating the searchable PDF
* @return The result of the operation
*/
public OcrResult createSearchablePdf(Path inputPdfPath, Path outputPdfPath, OcrMethod method) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method parameters lack null validation. All parameters should be validated against null at the start of the method to prevent NullPointerException.

* Gets the list of default tessdata paths based on the operating system.
*/
private List<String> getDefaultTessdataPaths() {
List<String> paths = new ArrayList<>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usage of ArrayList constructor instead of modern Java collections factory methods. Should use List.of() and new methods for building collections.

@calixtus

calixtus commented Oct 9, 2025

Copy link
Copy Markdown
Member

Closing this for housekeeping. Maybe if you or sbdy else is interested in picking this up again, this can be reopened.
Work is not lost, but archived. Thank you for your efforts.

@calixtus calixtus closed this Oct 9, 2025
@Suswetha6

Copy link
Copy Markdown

hey..I would like to work on this issue . Can I know why it is close without integration ? As far as I could understand the approach had a lot native dependency issues , are you planning on continuing the same path for the feature or can we have a seperate API for OCR integration , like either an integrated CLI or a 3rd party service ?

@calixtus

calixtus commented Feb 27, 2026

Copy link
Copy Markdown
Member

This is not an issue, but was an unfinished gsoc project.
The issue is again open this year as a gsoc project. Please continue the discussion in the corresponding issue or in the chat.
I believe most of the questions are already answered in the issue and the former discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GSoC meta issue: OCR Integration in JabRef

8 participants