, , , . .
Java/iText; , Java #/iTextSharp.
Java iText
iText 5.5.8-SNAPSHOT.
, , RenderListener
:
public class TextLineFinder implements RenderListener
{
@Override
public void beginTextBlock() { }
@Override
public void endTextBlock() { }
@Override
public void renderImage(ImageRenderInfo renderInfo) { }
@Override
public void renderText(TextRenderInfo renderInfo)
{
LineSegment ascentLine = renderInfo.getAscentLine();
LineSegment descentLine = renderInfo.getDescentLine();
float[] yCoords = new float[]{
ascentLine.getStartPoint().get(Vector.I2),
ascentLine.getEndPoint().get(Vector.I2),
descentLine.getStartPoint().get(Vector.I2),
descentLine.getEndPoint().get(Vector.I2)
};
Arrays.sort(yCoords);
addVerticalUseSection(yCoords[0], yCoords[3]);
}
void addVerticalUseSection(float from, float to)
{
if (to < from)
{
float temp = to;
to = from;
from = temp;
}
int i=0, j=0;
for (; i<verticalFlips.size(); i++)
{
float flip = verticalFlips.get(i);
if (flip < from)
continue;
for (j=i; j<verticalFlips.size(); j++)
{
flip = verticalFlips.get(j);
if (flip < to)
continue;
break;
}
break;
}
boolean fromOutsideInterval = i%2==0;
boolean toOutsideInterval = j%2==0;
while (j-- > i)
verticalFlips.remove(j);
if (toOutsideInterval)
verticalFlips.add(i, to);
if (fromOutsideInterval)
verticalFlips.add(i, from);
}
final List<Float> verticalFlips = new ArrayList<Float>();
}
(TextLineFinder.java)
RenderListener
, y. , , .
PageVerticalAnalyzer
, .
, , iText LocationTextExtractionStrategy
:
public class HorizontalTextExtractionStrategy extends LocationTextExtractionStrategy
{
public class HorizontalTextChunk extends TextChunk
{
public HorizontalTextChunk(String string, Vector startLocation, Vector endLocation, float charSpaceWidth)
{
super(string, startLocation, endLocation, charSpaceWidth);
}
@Override
public int compareTo(TextChunk rhs)
{
if (rhs instanceof HorizontalTextChunk)
{
HorizontalTextChunk horRhs = (HorizontalTextChunk) rhs;
int rslt = Integer.compare(getLineNumber(), horRhs.getLineNumber());
if (rslt != 0) return rslt;
return Float.compare(getStartLocation().get(Vector.I1), rhs.getStartLocation().get(Vector.I1));
}
else
return super.compareTo(rhs);
}
@Override
public boolean sameLine(TextChunk as)
{
if (as instanceof HorizontalTextChunk)
{
HorizontalTextChunk horAs = (HorizontalTextChunk) as;
return getLineNumber() == horAs.getLineNumber();
}
else
return super.sameLine(as);
}
public int getLineNumber()
{
Vector startLocation = getStartLocation();
float y = startLocation.get(Vector.I2);
List<Float> flips = textLineFinder.verticalFlips;
if (flips == null || flips.isEmpty())
return 0;
if (y < flips.get(0))
return flips.size() / 2 + 1;
for (int i = 1; i < flips.size(); i+=2)
{
if (y < flips.get(i))
{
return (1 + flips.size() - i) / 2;
}
}
return 0;
}
}
@Override
public void renderText(TextRenderInfo renderInfo)
{
textLineFinder.renderText(renderInfo);
LineSegment segment = renderInfo.getBaseline();
if (renderInfo.getRise() != 0){
Matrix riseOffsetTransform = new Matrix(0, -renderInfo.getRise());
segment = segment.transformBy(riseOffsetTransform);
}
TextChunk location = new HorizontalTextChunk(renderInfo.getText(), segment.getStartPoint(), segment.getEndPoint(), renderInfo.getSingleSpaceWidth());
getLocationalResult().add(location);
}
public HorizontalTextExtractionStrategy() throws NoSuchFieldException, SecurityException
{
locationalResultField = LocationTextExtractionStrategy.class.getDeclaredField("locationalResult");
locationalResultField.setAccessible(true);
textLineFinder = new TextLineFinder();
}
@SuppressWarnings("unchecked")
List<TextChunk> getLocationalResult()
{
try
{
return (List<TextChunk>) locationalResultField.get(this);
}
catch (IllegalArgumentException | IllegalAccessException e)
{
e.printStackTrace();
throw new RuntimeException(e);
}
}
final Field locationalResultField;
final TextLineFinder textLineFinder;
}
(HorizontalTextExtractionStrategy.java)
TextExtractionStrategy
TextLineFinder
, .
. . . LocationTextExtractionStrategy
.
, :
String extract(PdfReader reader, int pageNo) throws IOException, NoSuchFieldException, SecurityException
{
return PdfTextExtractor.getTextFromPage(reader, pageNo, new HorizontalTextExtractionStrategy());
}
( ExtractSuperAndSubInLine.java)
. 11 OP " " :
monoxide (CO) in flue gas in accordance with the following formula: C.E. = [CO 2/(CO + CO 2 )]
# iTextSharp
, , Java, , :
iTextSharp 5.5.7.
public class TextLineFinder : IRenderListener
{
public void BeginTextBlock() { }
public void EndTextBlock() { }
public void RenderImage(ImageRenderInfo renderInfo) { }
public void RenderText(TextRenderInfo renderInfo)
{
LineSegment ascentLine = renderInfo.GetAscentLine();
LineSegment descentLine = renderInfo.GetDescentLine();
float[] yCoords = new float[]{
ascentLine.GetStartPoint()[Vector.I2],
ascentLine.GetEndPoint()[Vector.I2],
descentLine.GetStartPoint()[Vector.I2],
descentLine.GetEndPoint()[Vector.I2]
};
Array.Sort(yCoords);
addVerticalUseSection(yCoords[0], yCoords[3]);
}
void addVerticalUseSection(float from, float to)
{
if (to < from)
{
float temp = to;
to = from;
from = temp;
}
int i=0, j=0;
for (; i<verticalFlips.Count; i++)
{
float flip = verticalFlips[i];
if (flip < from)
continue;
for (j=i; j<verticalFlips.Count; j++)
{
flip = verticalFlips[j];
if (flip < to)
continue;
break;
}
break;
}
bool fromOutsideInterval = i%2==0;
bool toOutsideInterval = j%2==0;
while (j-- > i)
verticalFlips.RemoveAt(j);
if (toOutsideInterval)
verticalFlips.Insert(i, to);
if (fromOutsideInterval)
verticalFlips.Insert(i, from);
}
public List<float> verticalFlips = new List<float>();
}
public class HorizontalTextExtractionStrategy : LocationTextExtractionStrategy
{
public class HorizontalTextChunk : TextChunk
{
public HorizontalTextChunk(String stringValue, Vector startLocation, Vector endLocation, float charSpaceWidth, TextLineFinder textLineFinder)
: base(stringValue, startLocation, endLocation, charSpaceWidth)
{
this.textLineFinder = textLineFinder;
}
override public int CompareTo(TextChunk rhs)
{
if (rhs is HorizontalTextChunk)
{
HorizontalTextChunk horRhs = (HorizontalTextChunk) rhs;
int rslt = CompareInts(getLineNumber(), horRhs.getLineNumber());
if (rslt != 0) return rslt;
return CompareFloats(StartLocation[Vector.I1], rhs.StartLocation[Vector.I1]);
}
else
return base.CompareTo(rhs);
}
public override bool SameLine(TextChunk a)
{
if (a is HorizontalTextChunk)
{
HorizontalTextChunk horAs = (HorizontalTextChunk) a;
return getLineNumber() == horAs.getLineNumber();
}
else
return base.SameLine(a);
}
public int getLineNumber()
{
Vector startLocation = StartLocation;
float y = startLocation[Vector.I2];
List<float> flips = textLineFinder.verticalFlips;
if (flips == null || flips.Count == 0)
return 0;
if (y < flips[0])
return flips.Count / 2 + 1;
for (int i = 1; i < flips.Count; i+=2)
{
if (y < flips[i])
{
return (1 + flips.Count - i) / 2;
}
}
return 0;
}
private static int CompareInts(int int1, int int2){
return int1 == int2 ? 0 : int1 < int2 ? -1 : 1;
}
private static int CompareFloats(float float1, float float2)
{
return float1 == float2 ? 0 : float1 < float2 ? -1 : 1;
}
TextLineFinder textLineFinder;
}
public override void RenderText(TextRenderInfo renderInfo)
{
textLineFinder.RenderText(renderInfo);
LineSegment segment = renderInfo.GetBaseline();
if (renderInfo.GetRise() != 0){
Matrix riseOffsetTransform = new Matrix(0, -renderInfo.GetRise());
segment = segment.TransformBy(riseOffsetTransform);
}
TextChunk location = new HorizontalTextChunk(renderInfo.GetText(), segment.GetStartPoint(), segment.GetEndPoint(), renderInfo.GetSingleSpaceWidth(), textLineFinder);
getLocationalResult().Add(location);
}
public HorizontalTextExtractionStrategy()
{
locationalResultField = typeof(LocationTextExtractionStrategy).GetField("locationalResult", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
textLineFinder = new TextLineFinder();
}
List<TextChunk> getLocationalResult()
{
return (List<TextChunk>) locationalResultField.GetValue(this);
}
System.Reflection.FieldInfo locationalResultField;
TextLineFinder textLineFinder;
}
string extract(PdfReader reader, int pageNo)
{
return PdfTextExtractor.GetTextFromPage(reader, pageNo, new HorizontalTextExtractionStrategy());
}
: LocationTextExtractionStrategy
iText 5.5.9-SNAPSHOT Commits 53526e4854fcb80c86cbc2e113f7a07401dc9a67 ( " LocationTextExtractionStrategy..." ) 1ab350beae148be2a4bef5e663b3d67a004ff9f8 ( " TextChunkLocation a Comparable < > class..." ), LocationTextExtractionStrategy
, , .
, HorizontalTextExtractionStrategy. iText :
public class HorizontalTextExtractionStrategy2 extends LocationTextExtractionStrategy
{
public static class HorizontalTextChunkLocationStrategy implements TextChunkLocationStrategy
{
public HorizontalTextChunkLocationStrategy(TextLineFinder textLineFinder)
{
this.textLineFinder = textLineFinder;
}
@Override
public TextChunkLocation createLocation(TextRenderInfo renderInfo, LineSegment baseline)
{
return new HorizontalTextChunkLocation(baseline.getStartPoint(), baseline.getEndPoint(), renderInfo.getSingleSpaceWidth());
}
final TextLineFinder textLineFinder;
public class HorizontalTextChunkLocation implements TextChunkLocation
{
private final Vector startLocation;
private final Vector endLocation;
private final Vector orientationVector;
private final int orientationMagnitude;
private final int distPerpendicular;
private final float distParallelStart;
private final float distParallelEnd;
private final float charSpaceWidth;
public HorizontalTextChunkLocation(Vector startLocation, Vector endLocation, float charSpaceWidth)
{
this.startLocation = startLocation;
this.endLocation = endLocation;
this.charSpaceWidth = charSpaceWidth;
Vector oVector = endLocation.subtract(startLocation);
if (oVector.length() == 0)
{
oVector = new Vector(1, 0, 0);
}
orientationVector = oVector.normalize();
orientationMagnitude = (int)(Math.atan2(orientationVector.get(Vector.I2), orientationVector.get(Vector.I1))*1000);
Vector origin = new Vector(0,0,1);
distPerpendicular = (int)(startLocation.subtract(origin)).cross(orientationVector).get(Vector.I3);
distParallelStart = orientationVector.dot(startLocation);
distParallelEnd = orientationVector.dot(endLocation);
}
public int orientationMagnitude() { return orientationMagnitude; }
public int distPerpendicular() { return distPerpendicular; }
public float distParallelStart() { return distParallelStart; }
public float distParallelEnd() { return distParallelEnd; }
public Vector getStartLocation() { return startLocation; }
public Vector getEndLocation() { return endLocation; }
public float getCharSpaceWidth() { return charSpaceWidth; }
public boolean sameLine(TextChunkLocation as)
{
if (as instanceof HorizontalTextChunkLocation)
{
HorizontalTextChunkLocation horAs = (HorizontalTextChunkLocation) as;
return getLineNumber() == horAs.getLineNumber();
}
else
return orientationMagnitude() == as.orientationMagnitude() && distPerpendicular() == as.distPerpendicular();
}
public float distanceFromEndOf(TextChunkLocation other)
{
float distance = distParallelStart() - other.distParallelEnd();
return distance;
}
public boolean isAtWordBoundary(TextChunkLocation previous)
{
if (getCharSpaceWidth() < 0.1f)
return false;
float dist = distanceFromEndOf(previous);
return dist < -getCharSpaceWidth() || dist > getCharSpaceWidth()/2.0f;
}
public int getLineNumber()
{
Vector startLocation = getStartLocation();
float y = startLocation.get(Vector.I2);
List<Float> flips = textLineFinder.verticalFlips;
if (flips == null || flips.isEmpty())
return 0;
if (y < flips.get(0))
return flips.size() / 2 + 1;
for (int i = 1; i < flips.size(); i+=2)
{
if (y < flips.get(i))
{
return (1 + flips.size() - i) / 2;
}
}
return 0;
}
@Override
public int compareTo(TextChunkLocation rhs)
{
if (rhs instanceof HorizontalTextChunkLocation)
{
HorizontalTextChunkLocation horRhs = (HorizontalTextChunkLocation) rhs;
int rslt = Integer.compare(getLineNumber(), horRhs.getLineNumber());
if (rslt != 0) return rslt;
return Float.compare(getStartLocation().get(Vector.I1), rhs.getStartLocation().get(Vector.I1));
}
else
{
int rslt;
rslt = Integer.compare(orientationMagnitude(), rhs.orientationMagnitude());
if (rslt != 0) return rslt;
rslt = Integer.compare(distPerpendicular(), rhs.distPerpendicular());
if (rslt != 0) return rslt;
return Float.compare(distParallelStart(), rhs.distParallelStart());
}
}
}
}
@Override
public void renderText(TextRenderInfo renderInfo)
{
textLineFinder.renderText(renderInfo);
super.renderText(renderInfo);
}
public HorizontalTextExtractionStrategy2() throws NoSuchFieldException, SecurityException
{
this(new TextLineFinder());
}
public HorizontalTextExtractionStrategy2(TextLineFinder textLineFinder) throws NoSuchFieldException, SecurityException
{
super(new HorizontalTextChunkLocationStrategy(textLineFinder));
this.textLineFinder = textLineFinder;
}
final TextLineFinder textLineFinder;
}
(HorizontalTextExtractionStrategy2.java)