Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proof-of-concept for auto-trimming of page margins #21

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions de.vonloesch.pdf4eclipse/OSGI-INF/l10n/bundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ command.description.0 = Set the zoom level
command.name.0 = Zoom
commandParameter.name = zoomlevel
command.name.1 = Toggle highlight
command.name.2 = Toggle auto-trimming
command.tooltip = Zoom out
command.tooltip.0 = Fit page to window
command.tooltip.1 = Fit page to window width
command.tooltip.2 = Zoom in
command.tooltip.3 = Toggle link highlighting
command.tooltip.4 = Trim Page Margins
context.name = PDF viewer
Binary file added de.vonloesch.pdf4eclipse/icons/autotrim.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions de.vonloesch.pdf4eclipse/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,27 @@
</class>
</state>
</command>
<command
categoryId="de.vonloesch.pdf4Eclipse.category"
defaultHandler="de.vonloesch.pdf4eclipse.editors.handlers.ToggleAutoTrimHandler"
helpContextId="de.vonloesch.pdf4eclipse.annotationsToggleAutoTrim"
id="PDFViewer.command.ToggleAutoTrim"
name="%command.name.2">
<state
id="org.eclipse.ui.commands.toggleState">
<class
class="org.eclipse.ui.handlers.RegistryToggleState">
<parameter
name="persisted"
value="true">
</parameter>
<parameter
name="default"
value="false">
</parameter>
</class>
</state>
</command>
<category
id="de.vonloesch.pdf4Eclipse.category"
name="Pdf4Eclipse">
Expand Down Expand Up @@ -190,6 +211,18 @@
</reference>
</visibleWhen>
</command>
<command
commandId="PDFViewer.command.ToggleAutoTrim"
icon="icons/autotrim.png"
style="toggle"
tooltip="%command.tooltip.4">
<visibleWhen
checkEnabled="false">
<reference
definitionId="PDFViewer.definitions.isPDFEditorActive">
</reference>
</visibleWhen>
</command>
</toolbar>
</menuContribution>
</extension>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*
* Contributors:
* Boris von Loesch - initial API and implementation
* Robert Bamler - auto-trimming of page margins
******************************************************************************/
package de.vonloesch.pdf4eclipse;

Expand All @@ -16,6 +17,7 @@
import java.awt.geom.Rectangle2D.Double;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
Expand All @@ -39,6 +41,7 @@
import org.eclipse.swt.widgets.Display;

import de.vonloesch.pdf4eclipse.editors.PDFEditor;
import de.vonloesch.pdf4eclipse.editors.handlers.ToggleAutoTrimHandler;
import de.vonloesch.pdf4eclipse.editors.handlers.ToggleLinkHighlightHandler;
import de.vonloesch.pdf4eclipse.model.IPDFLinkAnnotation;
import de.vonloesch.pdf4eclipse.model.IPDFPage;
Expand Down Expand Up @@ -72,6 +75,11 @@ public class PDFPageViewer extends Canvas implements PaintListener, IPreferenceC

private float zoomFactor;

private boolean autoTrimOn = true;
private Point trimOffset = new Point(0, 0);
private float horizontalTrimFactor = 1.0f;
private float verticalTrimFactor = 1.0f;

//private org.eclipse.swt.graphics.Image swtImage;

/**
Expand Down Expand Up @@ -178,6 +186,7 @@ public void run() {
prefs.addPreferenceChangeListener(this);

highlightLinks = prefs.getBoolean(ToggleLinkHighlightHandler.PREF_LINKHIGHTLIGHT_ID, true);
autoTrimOn = prefs.getBoolean(ToggleAutoTrimHandler.PREF_AUTOTRIM_ID, false);
}


Expand Down Expand Up @@ -299,13 +308,17 @@ public void showPage(IPDFPage page) {
highlight = null;

boolean resize = false;
int newW = Math.round(zoomFactor*page.getWidth());
int newH = Math.round(zoomFactor*page.getHeight());
// always round _down_ so that the fit-to-screen commands work properly
int newW = (int) (zoomFactor*page.getWidth());
int newH = (int) (zoomFactor*page.getHeight());

Point sz = getSize();

if (sz.x == 0 || sz.y == 0) return;
currentImage = page.getImage(newH, newW);
if (autoTrimOn) {
trimCurrentImage();
}

newW = currentImage.getWidth(null);
newH = currentImage.getHeight(null);
Expand All @@ -329,16 +342,97 @@ public void showPage(IPDFPage page) {
}
}

private void trimCurrentImage() {
if (currentImage==null)
return;

int origw = currentImage.getWidth(null);
int origh = currentImage.getHeight(null);
if (origw<1 || origh<1)
return;

BufferedImage img = new BufferedImage(origw, origh, BufferedImage.TYPE_INT_ARGB);
img.getGraphics().drawImage(currentImage, 0, 0, origw, origh, 0, 0, origw, origh, null);

int[] srcbuf = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();

// detect upper margin
int trimy1 = origh;
int referenceColor = srcbuf[0];
for (int i=0; i!=srcbuf.length; i++) {
if (srcbuf[i] != referenceColor) {
trimy1 = i/origw;
break;
}
}

// detect lower margin
int trimy2 = 0;
referenceColor = srcbuf[srcbuf.length-1];
for (int i=srcbuf.length-1; i!=trimy1*origw-1; i--) {
if (srcbuf[i] != referenceColor) {
trimy2 = i/origw + 1;
break;
}
}

// detect left margin
int trimx1 = 0;
referenceColor = srcbuf[0];
int offset = trimy1*origw;
int end = trimy2*origw;
trimx1loop:
while (trimx1 != origw) {
for (int i=offset+trimx1; i<end; i+=origw) {
if (srcbuf[i] != referenceColor)
break trimx1loop;
}
trimx1++;
}

// detect right margin
int trimx2 = origw-1;
referenceColor = srcbuf[srcbuf.length-1];
trimx2loop:
while (trimx2 != trimy1) {
for (int i=offset+trimx2; i<end; i+=origw) {
if (srcbuf[i] != referenceColor)
break trimx2loop;
}
trimx2--;
}
trimx2++;

// add some margin (2% of the smaller one of the two dimensions)
int margin = Math.min(trimx2-trimx1, trimy2-trimy1) / 50;
trimx1 = Math.max(0, trimx1-margin);
trimx2 = Math.min(origw, trimx2+margin);
trimy1 = Math.max(0, trimy1-margin);
trimy2 = Math.min(origh, trimy2+margin);

// remember trim margins
trimOffset .x = trimx1;
trimOffset.y = trimy1;
horizontalTrimFactor = 1.0f * (trimx2-trimx1) / origw;
verticalTrimFactor = 1.0f * (trimy2-trimy1) / origh;

// crop image
currentImage = img.getSubimage(trimx1, trimy1, trimx2-trimx1, trimy2-trimy1);
}

private Rectangle getRectangle(Rectangle2D r) {
return new Rectangle((int)Math.round(r.getX()), (int)Math.round(r.getY()), (int)Math.round(r.getWidth()), (int)Math.round(r.getHeight()));
}

public Rectangle2D convertPDF2ImageCoord(Rectangle2D r) {
return currentPage.pdf2ImageCoordinates(r);
Rectangle2D coord = currentPage.pdf2ImageCoordinates(r);
coord.setRect(coord.getX()-trimOffset.x, coord.getY()-trimOffset.y, coord.getWidth(), coord.getHeight());
return coord;
}

public Rectangle2D convertImage2PDFCoord(Rectangle2D r) {
return currentPage.image2PdfCoordinates(r);
java.awt.Rectangle coord = new java.awt.Rectangle((int)r.getX()+trimOffset.x, (int)r.getY()+trimOffset.y, (int)r.getWidth(), (int)r.getHeight());
return currentPage.image2PdfCoordinates(coord);
}

/**
Expand Down Expand Up @@ -423,6 +517,15 @@ public void preferenceChange(PreferenceChangeEvent event) {
if (ToggleLinkHighlightHandler.PREF_LINKHIGHTLIGHT_ID.equals(event.getKey())) {
highlightLinks = Boolean.parseBoolean((String)(event.getNewValue()));
redraw();
} else if (ToggleAutoTrimHandler.PREF_AUTOTRIM_ID.equals(event.getKey())) {
autoTrimOn = Boolean.parseBoolean((String)(event.getNewValue()));
if (!autoTrimOn) {
trimOffset.x = 0;
trimOffset.y = 0;
horizontalTrimFactor = 1.0f;
verticalTrimFactor = 1.0f;
}
showPage(currentPage);
}
}

Expand All @@ -445,4 +548,14 @@ public void dispose() {
IEclipsePreferences prefs = (new InstanceScope()).getNode(de.vonloesch.pdf4eclipse.Activator.PLUGIN_ID);
prefs.removePreferenceChangeListener(this);
}


public float getHorizontalTrimFactor() {
return horizontalTrimFactor;
}


public float getVerticalTrimFactor() {
return verticalTrimFactor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* Contributors:
* Boris von Loesch - initial API and implementation
* MeisterYeti - pseudo-continuous scrolling and zooming by mouse wheel
* Robert Bamler - auto-trimming of page margins
******************************************************************************/
package de.vonloesch.pdf4eclipse.editors;

Expand Down Expand Up @@ -742,12 +743,12 @@ private void updateStatusLine() {

public void fitHorizontal() {
int w = sc.getClientArea().width;
pv.setZoomFactor((1.0f*w)/pv.getPage().getWidth());
pv.setZoomFactor((1.0f/pv.getHorizontalTrimFactor()*w)/pv.getPage().getWidth());
}

public void fit() {
float w = 1.f * sc.getClientArea().width;
float h = 1.f * sc.getClientArea().height;
float w = 1.f/pv.getHorizontalTrimFactor() * sc.getClientArea().width;
float h = 1.f/pv.getVerticalTrimFactor() * sc.getClientArea().height;
float pw = pv.getPage().getWidth();
float ph = pv.getPage().getHeight();
if (w/pw < h/ph) pv.setZoomFactor(w/pw);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*******************************************************************************
* Copyright (c) 2011 Boris von Loesch.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Boris von Loesch - initial API and implementation
* Robert Bamler - auto-trimming of page margins
******************************************************************************/
package de.vonloesch.pdf4eclipse.editors.handlers;

import java.util.Map;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.State;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.commands.IElementUpdater;
import org.eclipse.ui.handlers.RegistryToggleState;
import org.eclipse.ui.menus.UIElement;
import org.osgi.service.prefs.BackingStoreException;

public class ToggleAutoTrimHandler extends AbstractHandler implements IElementUpdater{

public final static String PREF_AUTOTRIM_ID = "de.vonloesch.pdf4eclipse.preferences.autoTrim";

private final static String COMMAND_ID = "PDFViewer.command.ToggleAutoTrim";
private final static String STATE_ID = RegistryToggleState.STATE_ID;

@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
Command command = event.getCommand();
State state = command.getState(STATE_ID);
state.setValue(!(Boolean) state.getValue());

ICommandService service =
(ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);
service.refreshElements(command.getId(), null);
IEclipsePreferences prefs = (new InstanceScope()).getNode(de.vonloesch.pdf4eclipse.Activator.PLUGIN_ID);
prefs.putBoolean(PREF_AUTOTRIM_ID, ((Boolean) state.getValue()).booleanValue());
try {
prefs.flush();
} catch (BackingStoreException e) {
//Do nothing
}
return null;
}

@Override
public void updateElement(UIElement element, Map parameters) {
ICommandService service =
(ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);
Command command = service.getCommand(COMMAND_ID);
State state = command.getState(STATE_ID);
element.setChecked(((Boolean) state.getValue()).booleanValue());
}

}