Extraction of images present inside a paragraph - itext

I am building an application where i need to parse a pdf which is generated by a system and with that parsed information i need to populate my applications database columns but unfortunaltely the pdf structure that i am dealing with is having a column called comments which has both text and image. I found the way of reading the images and text separately from the pdf but my ultimate aim was to add a place holder something like {2} in the place of image inside the parsed content and whenever my parser ( the application code ) parse this line the system will render the appropriate image in that area which is also stored in a separate table inside my application.
Please help me with resolving this problem.
Thanks in advance.

As already mentioned in comments, a solution would be to essentially use a customized text extraction strategy to insert a "[ 2]" text chunk at the coordinates of the image.
Code
You can e.g. extend the LocationTextExtractionStrategy like this:
class SimpleMixedExtractionStrategy extends LocationTextExtractionStrategy
{
SimpleMixedExtractionStrategy(File outputPath, String name)
{
this.outputPath = outputPath;
this.name = name;
}
#Override
public void renderImage(final ImageRenderInfo renderInfo)
{
try
{
PdfImageObject image = renderInfo.getImage();
if (image == null) return;
int number = counter++;
final String filename = String.format("%s-%s.%s", name, number, image.getFileType());
Files.write(new File(outputPath, filename).toPath(), image.getImageAsBytes());
LineSegment segment = UNIT_LINE.transformBy(renderInfo.getImageCTM());
TextChunk location = new TextChunk("[" + filename + "]", segment.getStartPoint(), segment.getEndPoint(), 0f);
Field field = LocationTextExtractionStrategy.class.getDeclaredField("locationalResult");
field.setAccessible(true);
List<TextChunk> locationalResult = (List<TextChunk>) field.get(this);
locationalResult.add(location);
}
catch (IOException | NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ioe)
{
ioe.printStackTrace();
}
}
final File outputPath;
final String name;
int counter = 0;
final static LineSegment UNIT_LINE = new LineSegment(new Vector(0, 0, 1) , new Vector(1, 0, 1));
}
(Unfortunately for this kind of work, some members of LocationTextExtractionStrategy are private. Thus, I used some Java reflection. Alternatively you can copy the whole class and change your copy accordingly.)
Example
Using that strategy you can extract mixed contents like this:
#Test
public void testSimpleMixedExtraction() throws IOException
{
InputStream resourceStream = getClass().getResourceAsStream("book-of-vaadin-page14.pdf");
try
{
PdfReader reader = new PdfReader(resourceStream);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
SimpleMixedExtractionStrategy listener = new SimpleMixedExtractionStrategy(OUTPUT_PATH, "book-of-vaadin-page14");
parser.processContent(1, listener);
Files.write(new File(OUTPUT_PATH, "book-of-vaadin-page14.txt").toPath(), listener.getResultantText().getBytes());
}
finally
{
if (resourceStream != null)
resourceStream.close();
}
}
E.g. for my test file (which contains page 14 of the Book of Vaadin):
You get this text
Getting Started with Vaadin
• A version of Book of Vaadin that you can browse in the Eclipse Help system.
You can install the plugin as follows:
1. Start Eclipse.
2. Select Help   Software Updates....
3. Select the Available Software tab.
4. Add the Vaadin plugin update site by clicking Add Site....
[book-of-vaadin-page14-0.png]
Enter the URL of the Vaadin Update Site: http://vaadin.com/eclipse and click OK. The
Vaadin site should now appear in the Software Updates window.
5. Select all the Vaadin plugins in the tree.
[book-of-vaadin-page14-1.png]
Finally, click Install.
Detailed and up-to-date installation instructions for the Eclipse plugin can be found at http://vaad-
in.com/eclipse.
Updating the Vaadin Plugin
If you have automatic updates enabled in Eclipse (see Window   Preferences   Install/Update
  Automatic Updates), the Vaadin plugin will be updated automatically along with other plugins.
Otherwise, you can update the Vaadin plugin (there are actually multiple plugins) manually as
follows:
1. Select Help   Software Updates..., the Software Updates and Add-ons window will
open.
2. Select the Installed Software tab.
14 Vaadin Plugin for Eclipse
and two images book-of-vaadin-page14-0.png
and book-of-vaadin-page14-1.png
in OUTPUT_PATH.
Improvements to make
As also already mentioned in comments, this solution is for the easy situation in which the image has text above and/or below but neither left nor right.
If there is text left and/or right, too, there is the problem that the code above calculates LineSegment segment as the bottom line of the image but the text strategy usually works with the base line of text which is above the bottom line.
But in this case one first has to decide at which position on which line one wants the marker in the text to be anyways. Having decided that, one can adapt the source above.

Related

Open DialectEditor programmatically outside of main editor area (E3/E4 hybrid)

what I want to do:
In my RCP an E3/E4 hybrid I have a project and library based on sirius tree. The User can drag an drop item from the library tree to the project tree. This works fine and was no great problem to build in. So now I want to make the UI more usable. It should looks like this layout:
what works:
After application startup I open my library presentation with the DialectUIManager.
final DialectEditor editor = (DialectEditor)
DialectUIManager.INSTANCE.openEditor(siriusSession, description, monitor);
Okay, this works. But it open it in the editor in the part market as org.eclipse.ui.editorss. This it not what I want
what does not work:
I want to show it in the "Library Part". I can move it manually with the mouse after open the editor, but how can i tell DialectUIManager to open it direct there. Or how can I programmatically it move there.
I do a lot of google research but i don't found a solution. The only thing I found was a hint Pierre-Charles David https:// www. eclipse.org/forums/index.php?t=msg&th=998476&goto=1631138&#msg_1631138
If you need is simply to show the editor outside of the main editor
area, this is possible since Eclipse 4.2 (e4 does not really treat the
main editor area as something special), so you can have your editor
"around" another editor in the middle of other views.
But at this step I stuck. I also ask it in the Sirius Forum but they say its a Eclipse E4 problem
Thanks for help, code snippets or links to correct part of manual.
I've found a solution. It's not very nice, but it works. I execute these code here after the editors have opened.
What the code does:
He is looking for the MPlaceholder which has the ID: org. eclipse. ui. editorss. There he descends until he is with the parts. These are in the Compatibly editor mode. Then he chooses the part we wants to move out of and Attach them to the MPartStack target.
public static void movePart(MApplication application,
EModelService modelService) {
MPart partToMove = null;
MUIElement muiElement =
modelService.find("org.eclipse.ui.editorss", application);
if (muiElement instanceof MPlaceholder) {
MPlaceholder placeholder = (MPlaceholder) muiElement;
MUIElement ref = placeholder.getRef();
if (ref instanceof MArea) {
MArea area = (MArea) ref;
List<MPartSashContainerElement> children = area.getChildren();
for (MPartSashContainerElement mPartSashContainerElement
: children) {
if (mPartSashContainerElement instanceof MPartStack) {
MPartStack partStack = (MPartStack) mPartSashContainerElement;
List<MStackElement> children2 = partStack.getChildren();
for (MStackElement mStackElement : children2) {
if (mStackElement instanceof MPart) {
MPart part = (MPart) mStackElement;
// Library is the Editor Name wiche I want to move
if (part.getLabel().equals("Library")) {
partToMove = part;
break;
}
}
}
}
}
}
}
if (partToMove != null) {
moveElement(modelService, application, partToMove);
}
}
private static void moveElement(EModelService modelService,
MApplication application, MPart part) {
// target PartStack
MUIElement find = modelService.find("de.bsg.onesps.rcp.
partstack.library", application);
if (find instanceof MPartStack) {
MPartStack mPartStack = (MPartStack) find;
mPartStack.getChildren().add(part);
mPartStack.setSelectedElement(part);
}
}

E4: drag an object from a TableViewer to Windows Explorer (or OS specific file system)

In my Eclipse RCP application I display some business data in a TableViewer.
I want the user to be able to drag a row from the table viewer and drop it on the windows desktop/explorer. Windows should then create a file with the data from the selected row that I could provide in the dragSetData(..) method of the DragSourceAdapter class.
How to implement this? It seems that using FileTransfer as the dragSourceSupport on the table viewer is the way to go as it trigger a call to the dragSetData() method. But what object should I create and assign to "event.data" in this method?
A working example would be appreciated.
I've implemented the reverse without problem, i.e. drag a file from windows explorer onto the TableViewer and add a row in the table. There are plenty on sample for this on the net but can't find a sample of the opposite, drag from eclipse to the OS
[edit + new requirement]
So I understand that I have to create a temporary file somewhere and set the name of that temp file in event.data in dragSetData()
Q: is there a simpler way to do that, eg set somewhere (iun data) the content of the file directly without the temp file?
There is another requirement. When the drop operation is about to occur, I want to show a popup to the user that will have to choose what "business data" from the "row" he wants to export and the name of the file that will be created. I tried the following (only asking for the filename for now) but it does not work as expected as the popup shows up as soon as the cursor reach the first pixel outside my app. I would like to show the popup just "before" the drop operation occurs.
Q: is there a way to have this popup show just before the drop operation occurs, ie when the user "release" the mouse button?
#Override
public void dragSetData(final DragSourceEvent event){
if (FileTransfer.getInstance().isSupportedType(event.dataType)) {
// Will be a more complex dialog with multiple fields..
InputDialog inputDialog = new InputDialog(shell, "Please enter a file name", "File Name:", "", null);
if (inputDialog.open() != Window.OK) {
event.doit = false;
return;
}
event.data = new String[] { inputDialog.getValue() };
}
}
The event.data for FileTransfer is an array of file path strings.
You DragSourceAdapter class might look something like:
public class MyDragSourceAdapter extends DragSourceAdapter
{
private final StructuredViewer viewer;
public MyDragSourceAdapter(final StructuredViewer viewer)
{
super();
this.viewer = viewer;
}
#Override
public void dragStart(final DragSourceEvent event)
{
IStructuredSelection selection = viewer.getStructuredSelection();
if (selection == null)
return;
// TODO check if the selection contains any files
// TODO set event.doit = false if not
}
#Override
public void dragSetData(final DragSourceEvent event)
{
if (!FileTransfer.getInstance().isSupportedType(event.dataType))
return;
IStructuredSelection selection = viewer.getStructuredSelection();
List<String> files = new ArrayList<>(selection.size());
// TODO add files in the selection to 'files'
event.data = files.toArray(new String [files.size()]);
}
}
and you install it on your viewer with:
MyDragSourceAdapter adapter = new MyDragSourceAdapter(viewer);
viewer.addDragSupport(DND.DROP_COPY, new Transfer [] {FileTransfer.getInstance()}, adapter);

How to pass an object from one part to another part in Eclispe e4 RCP?

I am building an application with eclipse e4 RCP. I have a navigator (similar to Navigator in eclipse IDE) and I would like to link it to an editor (similar to how a file in Navigator in eclipse IDE is linked to an editor). Currently I am using EPartService to open up my editor Part (by creating a new instance) when the user double clicks on a file in the Navigator tree. But I would like to pass it a parameter (a String or an Object) to let it know which file to open in the editor. I want to be able to open multiple editors for different nodes of the Navigator tree. I have done a lot of research on internet but could not find a solution. I think its a common problem and the e4 framework should provide an mechanism to pass such parameters from one Part to another Part. Current code is as below:
viewer.addDoubleClickListener(event -> {
final IStructuredSelection selection = (IStructuredSelection) event.getSelection();
FileNode file = null;
boolean partExists = false;
if (selection.getFirstElement() instanceof FileNode ) {
file = (FileNode ) selection.getFirstElement();
for (MPart part1 : partService.getParts()) {
if (part1.getLabel().equals(file.getName())) {
partService.showPart(part1, PartState.ACTIVATE);
partExists = true;
break;
}
}
if (!partExists) {
MPart part2 = partService
.createPart("com.parts.partdescriptor.fileeditor");
part2.setLabel(file.getName());
partService.showPart(part2, PartState.ACTIVATE);
}
}
});
Is it possible to say something like part2.setParameter("PARAM_NAME", "FILE_NAME"); ?
When you have an MPart you can call:
MPart mpart = ...
MyClass myClass = (MyClass)mpart.getObject();
to get your class for the part (the class defined in the 'Class URI' for the part in the Application.e4xmi). You can then call any methods you have defined on your part class.
You can also set data in the 'transient data' area of a part:
mpart.getTransientData().put("key", "data");
Object data = mpart.getTransientData().get("key");

Making Ctrl-C copy from whichever SourceViewer has focus in Eclipse plug-in

I successfully extended the PyDev editor in Eclipse with a side-by-side display, but I can't copy the contents of the extra SourceViewer that I added. I can select some text in the display, but when I press Ctrl+C, it always copies the main PyDev editor's selected text.
I found an article on key bindings in Eclipse editors, but the code there seems incomplete and a bit out-of-date. How can I configure the copy command to copy from whichever SourceViewer has focus?
The reason I want to do this is that I've written a tool for live coding in Python, and it would be much easier for users to submit bug reports if they could just copy the display and paste it into the bug description.
David Green's article was a good start, but it took a bit of digging to make it all work. I published a full example project on GitHub, and I'll post a couple of snippets here.
The TextViewerSupport class wires up a new action handler for each command you want to delegate to the extra text viewer. If you have multiple text viewers, just instantiate a TextViewerSupport object for each of them. It wires up everything in its constructor.
public TextViewerSupport(TextViewer textViewer) {
this.textViewer = textViewer;
StyledText textWidget = textViewer.getTextWidget();
textWidget.addFocusListener(this);
textWidget.addDisposeListener(this);
IWorkbenchWindow window = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
handlerService = (IHandlerService) window
.getService(IHandlerService.class);
if (textViewer.getTextWidget().isFocusControl()) {
activateContext();
}
}
The activateContext() method has a list of all the commands you want to delegate, and registers a new handler for each one. This was one of the changes from David's article; his ITextEditorActionDefinitionIds has been deprecated and replaced with IWorkbenchCommandConstants.
protected void activateContext() {
if (handlerActivations.isEmpty()) {
activateHandler(ITextOperationTarget.COPY,
IWorkbenchCommandConstants.EDIT_COPY);
}
}
// Add a single handler.
protected void activateHandler(int operation, String actionDefinitionId) {
StyledText textWidget = textViewer.getTextWidget();
IHandler actionHandler = createActionHandler(operation,
actionDefinitionId);
IHandlerActivation handlerActivation = handlerService.activateHandler(
actionDefinitionId, actionHandler,
new ActiveFocusControlExpression(textWidget));
handlerActivations.add(handlerActivation);
}
// Create a handler that delegates to the text viewer.
private IHandler createActionHandler(final int operation,
String actionDefinitionId) {
Action action = new Action() {
#Override
public void run() {
if (textViewer.canDoOperation(operation)) {
textViewer.doOperation(operation);
}
}
};
action.setActionDefinitionId(actionDefinitionId);
return new ActionHandler(action);
}
The ActiveFocusControlExpression gives the new handler a high enough priority that it will replace the standard handler, and it's almost identical to David's version. However, to get it to compile, I had to add extra dependencies to my plug-in manifest: I imported packages org.eclipse.core.expressions and org.eclipse.ui.texteditor.

Eclipse: selection autocopy to clipboard

I love an Emacs feature to copy selection to clipboard automatically. Is it possible to do the same on Eclipse?
Environment: Windows XP, Helios
To copy a String from Eclipse to the clipboard, you can use
void copyToClipboard (String toClipboard, Display display){
String toClipboard = "my String";
Clipboard clipboard = new Clipboard(display);
TextTransfer [] textTransfer = {TextTransfer.getInstance()};
clipboard.setContents(new Object [] {toClipboard}, textTransfer);
clipboard.dispose();
}
Then you can call this method from a MouseAdapter or KeyAdapter, depending on where you want to get your String from. In your case it could be MouseAdapter, which listens to doubleclicks, gets the current cursor position of the text, marks the word and then adds the String to the clipboard.
edit to answer a question: You can set up your own MouseAdapater and attach it to buttons, text fields or whateer you like. Here's an example for a button:
Button btnGo1 = new Button(parent, SWT.NONE);
btnGo1.setText("Go");
btnGo1.addMouseListener(new MouseAdapter() {
#Override
public void mouseDoubleClick(MouseEvent e) {
//do what you want to do in here
}
});
If you want to implement mouseUp and mouseDown events, too, you can just add MouseListenerinstead of the Adapter. The only advantage of the Adapter is, that you don't have to override the other methods of the interface.
Since the original question was to automatically get the selection of the text of an editor: the way to get the selection from an editor is explained here.
You can try this plugin. Along with auto copy points mentioned in Eclipse show number of lines and/or file size also addressed.