Is there a way to preserve the text formatting when extracting a PDF with PDFBox?
I have a program that parses a PDF document for information. When a new version of the PDF is released the authors use bold or italic text to indicate new information and Strike through or underlined to indicated omitted text. Using the base Stripper class in PDFbox returns all the text but the formatting is removed so I have no way of telling if the text is new or omitted. I'm currently using the project example code below:
Dim doc As PDDocument = Nothing
Try
doc = PDDocument.load(RFPFilePath)
Dim stripper As New PDFTextStripper()
stripper.setAddMoreFormatting(True)
stripper.setSortByPosition(True)
rtxt_DocumentViewer.Text = stripper.getText(doc)
Finally
If doc IsNot Nothing Then
doc.close()
End If
End Try
I have my parsing code working well if I simply copy and paste the PDF text into a richtextbox which preservers the formatting. I was thinking of doing this programatically by opening the PDF, select all, Copy, close the document then paste it in my richtextbox but that seems clunky.
As the OP mentioned in a comment that a Java example would do and I've yet only used PDFBox with Java, this answer features a Java example. Furthermore, this example has been developed and tested with PDFBox version 1.8.11 only.
A customized text stripper
As already mentioned in a comment,
The bold and italic effects in the OP's sample document are generated by using a different font (containing bold or italic versions of the letters) to draw the text. The underline and strike-through effects in the sample document are generated by drawing a rectangle under / through the text line which has the width of the text line and a very small height. To extract these information, therefore, one has to extend the PDFTextStripper to somehow react to font changes and rectangles nearby text.
This is an example class extending the PDFTextStripper just like that:
public class PDFStyledTextStripper extends PDFTextStripper
{
public PDFStyledTextStripper() throws IOException
{
super();
registerOperatorProcessor("re", new AppendRectangleToPath());
}
#Override
protected void writeString(String text, List<TextPosition> textPositions) throws IOException
{
for (TextPosition textPosition : textPositions)
{
Set<String> style = determineStyle(textPosition);
if (!style.equals(currentStyle))
{
output.write(style.toString());
currentStyle = style;
}
output.write(textPosition.getCharacter());
}
}
Set<String> determineStyle(TextPosition textPosition)
{
Set<String> result = new HashSet<>();
if (textPosition.getFont().getBaseFont().toLowerCase().contains("bold"))
result.add("Bold");
if (textPosition.getFont().getBaseFont().toLowerCase().contains("italic"))
result.add("Italic");
if (rectangles.stream().anyMatch(r -> r.underlines(textPosition)))
result.add("Underline");
if (rectangles.stream().anyMatch(r -> r.strikesThrough(textPosition)))
result.add("StrikeThrough");
return result;
}
class AppendRectangleToPath extends OperatorProcessor
{
public void process(PDFOperator operator, List<COSBase> arguments)
{
COSNumber x = (COSNumber) arguments.get(0);
COSNumber y = (COSNumber) arguments.get(1);
COSNumber w = (COSNumber) arguments.get(2);
COSNumber h = (COSNumber) arguments.get(3);
double x1 = x.doubleValue();
double y1 = y.doubleValue();
// create a pair of coordinates for the transformation
double x2 = w.doubleValue() + x1;
double y2 = h.doubleValue() + y1;
Point2D p0 = transformedPoint(x1, y1);
Point2D p1 = transformedPoint(x2, y1);
Point2D p2 = transformedPoint(x2, y2);
Point2D p3 = transformedPoint(x1, y2);
rectangles.add(new TransformedRectangle(p0, p1, p2, p3));
}
Point2D.Double transformedPoint(double x, double y)
{
double[] position = {x,y};
getGraphicsState().getCurrentTransformationMatrix().createAffineTransform().transform(
position, 0, position, 0, 1);
return new Point2D.Double(position[0],position[1]);
}
}
static class TransformedRectangle
{
public TransformedRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3)
{
this.p0 = p0;
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
}
boolean strikesThrough(TextPosition textPosition)
{
Matrix matrix = textPosition.getTextPos();
// TODO: This is a very simplistic implementation only working for horizontal text without page rotation
// and horizontal rectangular strikeThroughs with p0 at the left bottom and p2 at the right top
// Check if rectangle horizontally matches (at least) the text
if (p0.getX() > matrix.getXPosition() || p2.getX() < matrix.getXPosition() + textPosition.getWidth() - textPosition.getFontSizeInPt() / 10.0)
return false;
// Check whether rectangle vertically is at the right height to underline
double vertDiff = p0.getY() - matrix.getYPosition();
if (vertDiff < 0 || vertDiff > textPosition.getFont().getFontDescriptor().getAscent() * textPosition.getFontSizeInPt() / 1000.0)
return false;
// Check whether rectangle is small enough to be a line
return Math.abs(p2.getY() - p0.getY()) < 2;
}
boolean underlines(TextPosition textPosition)
{
Matrix matrix = textPosition.getTextPos();
// TODO: This is a very simplistic implementation only working for horizontal text without page rotation
// and horizontal rectangular underlines with p0 at the left bottom and p2 at the right top
// Check if rectangle horizontally matches (at least) the text
if (p0.getX() > matrix.getXPosition() || p2.getX() < matrix.getXPosition() + textPosition.getWidth() - textPosition.getFontSizeInPt() / 10.0)
return false;
// Check whether rectangle vertically is at the right height to underline
double vertDiff = p0.getY() - matrix.getYPosition();
if (vertDiff > 0 || vertDiff < textPosition.getFont().getFontDescriptor().getDescent() * textPosition.getFontSizeInPt() / 500.0)
return false;
// Check whether rectangle is small enough to be a line
return Math.abs(p2.getY() - p0.getY()) < 2;
}
final Point2D p0, p1, p2, p3;
}
final List<TransformedRectangle> rectangles = new ArrayList<>();
Set<String> currentStyle = Collections.singleton("Undefined");
}
(PDFStyledTextStripper.java)
In addition to what the PDFTextStripper does, this class also
collects rectangles from the content (defined using the re instruction) using an instance of the AppendRectangleToPath operator processor inner class,
checks text for the style variants from the sample document in determineStyle, and
whenever the style changes, adds the new style to the result in writeString.
Beware: This merely is a proof of concept! In particular
the implementations of the tests in TransformedRectangle.underlines(TextPosition) and TransformedRectangle#strikesThrough(TextPosition) are very simplistic and only work for horizontal text without page rotation and horizontal rectangular strikeThroughs and underlines with p0 at the left bottom and p2 at the right top;
all rectangles are collected, not checking whether they actually are filled with a visible color;
the tests for "bold" and "italic" merely inspect the name of the used font which may not suffice in general.
A test output
Using the PDFStyledTextStripper like this
String extractStyled(PDDocument document) throws IOException
{
PDFTextStripper stripper = new PDFStyledTextStripper();
stripper.setSortByPosition(true);
return stripper.getText(document);
}
(from ExtractText.java, called from the test method testExtractStyledFromExampleDocument)
one gets the result
[]This is an example of plain text
[Bold]This is an example of bold text
[]
[Underline]This is an example of underlined text[]
[Italic]This is an example of italic text
[]
[StrikeThrough]This is an example of strike through text[]
[Italic, Bold]This is an example of bold, italic text
for the OP's sample document
PS The code of the PDFStyledTextStripper meanwhile has been slightly changed to also work for a sample document shared in a github issue, in particular the code of its inner class TransformedRectangle, cf. here.
Related
I am trying to generate a plot with MPAndroidChart. Specifically, a function which mainly depends on logarithms. For that reason I created the following for loop of data point entries (I am pretty sure this is not the best approach, but I decided to go for it)
yValues.add(new Entry(value3,value1));
float PointData = 100.0f;
for (int i=1 ; i<PointData ; i++){
yValues.add( new Entry( value3+(i/PointData)*(value4-value3),value1+(value2-value1) * Float.parseFloat(String.valueOf(Math.log(value3+(i/PointData)*(value4-value3)/value3)/Math.log(value4/value3))) ) );
}
yValues.add(new Entry(value4,value2));
My problem is that I have to set
set1.setDrawCircles(false);
set1.setDrawValues(false);
otherwise my plot will be filled with circles and numbers. I would like though to be able to draw these two (circles and numbers) for just the first (defined by "yValues.add(new Entry(value3,value1));") and last (defined by "yValues.add(new Entry(value4,value2));") data set points. I spent a considerable amount of time but with no luck unfortunately. As a result, I would really appreciate if someone can help me towards solving this issue. I have also attached the whole java file in case someone wants to have a look at the code.
public class cyl_1plane_tempplot extends AppCompatActivity {
LineChart mChart;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cyl_1plane_tempplot);
Intent localintent = getIntent();
float value1 = localintent.getFloatExtra("key1", -1);
float value2 = localintent.getFloatExtra("key2", -1);
float value3 = localintent.getFloatExtra("key4", -1);
float value4 = localintent.getFloatExtra("key5", -1);
mChart = findViewById(R.id.cond_cyl_1layer_plot);
mChart.setDragEnabled(true);
mChart.setScaleEnabled(false);
mChart.getDescription().setEnabled(false);
mChart.getXAxis().setPosition(XAxis.XAxisPosition.BOTH_SIDED);
float graph_excess_X = 10f;
XAxis bottomAxis = mChart.getXAxis();
bottomAxis.setAxisMinimum(value3 - (value4 - value3)/graph_excess_X);
bottomAxis.setAxisMaximum(value4 + (value4 - value3)/graph_excess_X);
ArrayList<Entry> yValues = new ArrayList<>();
yValues.add(new Entry(value3,value1));
float PointData = 100.0f;
for (int i=1 ; i<PointData ; i++){
yValues.add( new Entry( value3+(i/PointData)*(value4-value3),value1+(value2-value1) * Float.parseFloat(String.valueOf(Math.log(value3+(i/PointData)*(value4-value3)/value3)/Math.log(value4/value3))) ) );
}
yValues.add(new Entry(value4,value2));
ArrayList<ILineDataSet> lineDataSets = new ArrayList<>();
LineDataSet set1 = new LineDataSet(yValues, "Title");
set1.setFillAlpha(110);
int color = getResources().getColor(R.color.blue_chart_color);
set1.setColor(color);
set1.setDrawCircles(false);
set1.setDrawValues(false);
set1.setLineWidth(3f);
lineDataSets.add(set1);
LineData data = new LineData(lineDataSets);
mChart.setData(data);
}
}
Thank you all in advance.
Oh buddy this can be done please follow instructions below:
Design an icon which you want to display instead of circle on first and last value.
Place that icon in drawable folder of you project.
Set draw values and circles to false. This will hide circles and values for every entry.
set1.setDrawCircles(false);
set1.setDrawValues(false);
Get your specific value on which you want to display your icon as:
set1.getEntryForIndex(index).setIcon(getDrawable(R.drawable.icon));
In above line replace index with your entry index for example for first entry use 0. Also replace icon with your icon name in drawables.
I have implemented functionality to add link annotation to any pdf using pdfbox. It works well for most of pdfs, but for some pdfs it not placing markups at correct coordinates. And when I opened that pdf in some pdf editor, it gave me warning that the pdf contains an untitled viewport which might affect measurements for that pdf. So, I feel viewport is most probably causing the problem. Is there a way that I can modify the coordinates of markup according to viewport, so that it is placed at correct location in pdf. Here is a link to a pdf which contains the viewport.
According to Tilman's suggestion, I extracted the C entry from viewport's measure dictionary. And tried to modify rectangle's coordinate, but they are not getting added at the right location.Below is the code that I tried. Also, the viewport does not have effect on annotations, but it is causing problem when I try to draw something into the pdf.
COSArray vps = (COSArray)page.getCOSObject().getDictionaryObject(COSName.getPDFName("VP"));
if (vps != null)
{
for (int v = 0; v < vps.size(); ++v)
{
COSDictionary vp = (COSDictionary)vps.getObject(v);
PDViewportDictionary viewportDict = new PDViewportDictionary(vp);
PDRectangle vpRect = viewportDict.getBBox();
PDMeasureDictionary measureDict = viewportDict.getMeasure();
PDRectlinearMeasureDictionary rectilinearDict = new PDRectlinearMeasureDictionary(measureDict.getCOSObject());
bool pointLieInVP = UtilityClass.RectangleContainsPoint(new PointF(leftX, bottomY), vpRect);
if (pointLieInVP)
{
COSArray xArray = (COSArray)measureDict.getCOSObject().getDictionaryObject(COSName.getPDFName("X"));
float xScale = 1;
if (xArray!=null)
{
xScale = ((COSFloat)(((COSDictionary)xArray.getObject(0)).getDictionaryObject(COSName.getPDFName("C")))).floatValue();
}
leftX /= xScale;
rightX /= xScale;
COSBase yObj = measureDict.getCOSObject().getDictionaryObject(COSName.getPDFName("Y"));
if (yObj != null)
{
COSArray yArray = (COSArray)yObj;
float yScale = ((COSFloat)(((COSDictionary)yArray.getObject(0)).getDictionaryObject(COSName.getPDFName("C")))).floatValue();
bottomY /= yScale;
topY /= yScale;
}
else
{
bottomY /= xScale;
topY /= xScale;
}
}
}
}
Here is the link to pdf markups are added without adjusting for viewports. The 5 red colored markups are added at bottom right end of the page. But they should have been placed over the link annotations in the pdf which are placed at correct positions. And here is the link for pdf , in which markups are placed after modifying their coordinates using the above code. The markups do not appear at all.
This code (which does not avoid ClassCastExceptions) will show you the viewports in each page:
try (PDDocument doc = PDDocument.load(new File("S115-STRUCTURALHIGH ROOF FRAMING(WEST)ENLARGED PLANS.pdf")))
{
for (int p = 0; p < doc.getNumberOfPages(); ++p)
{
PDPage page = doc.getPage(p);
COSArray vps = (COSArray) page.getCOSObject().getDictionaryObject(COSName.getPDFName("VP"));
if (vps != null)
{
for (int v = 0; v < vps.size(); ++v)
{
COSDictionary vp = (COSDictionary) vps.getObject(v);
PDRectangle rect = new PDRectangle((COSArray) vp.getDictionaryObject(COSName.BBOX));
System.out.println("Viewport " + vp.getString(COSName.NAME) + ": " + rect);
}
}
}
}
How to adjust annotations is up to you... most likely, these should be inside the bbox. All you need to do is to adjust the rectangle of the annotations.
I am trying to find table border lines in pdf. I used PrintTextLocations class of pdfBox to make words. Now I am looking to find the coordinates of different lines that form the table. I tried using org.apache.pdfbox.pdfviewer.PageDrawer, but I am unable to find any character/graphic containing those lines. I tried two ways:
First:
Graphics g = null;
Dimension d = new Dimension();
d.setSize(700, 700);
PageDrawer pageDrawer = new PageDrawer();
pageDrawer.drawPage(g, myPage, d);
It gave me null pointer exception. So secondly, I tried to override processStream function, but I am unable to get any stroke. Kindly help me out. I am open in using any other library which gives me coordinates of the lines in the table. And another quick question, what kind of objects are those table border lines in pdfbox? Are these graphics or are these characters?
Here is the link to the sample pdf I am trying to parse:
http://stats.bls.gov/news.release/pdf/empsit.pdf
and trying to get the table lines on page number 8.
Edit : I faced another problem, while parsing this pdf's page number 1, I am unable to get any lines as the pathIterator in printPath() function is empty, although strokePath() function is called for each line. How to work with this pdf?
In the 1.8.* versions PDFBox parsing capabilities had been implemented in a not very generic way, in particular the OperatorProcessor implementations were tightly associated with specific parser classes, e.g. the implementations dealing with path drawing operations assumed to interact with a PageDrawer instance.
Thus, unless one wanted to copy & paste all those OperatorProcessor classes with minute changes, one had to derive from such a specific parser class.
In your case, therefore, we also will derive our parser from PageDrawer, after all we are interested in path drawing operations:
public class PrintPaths extends PageDrawer
{
//
// constructor
//
public PrintPaths() throws IOException
{
super();
}
//
// method overrides for mere path observation
//
// ignore text
#Override
protected void processTextPosition(TextPosition text) { }
// ignore bitmaps
#Override
public void drawImage(Image awtImage, AffineTransform at) { }
// ignore shadings
#Override
public void shFill(COSName shadingName) throws IOException { }
#Override
public void processStream(PDPage aPage, PDResources resources, COSStream cosStream) throws IOException
{
PDRectangle cropBox = aPage.findCropBox();
this.pageSize = cropBox.createDimension();
super.processStream(aPage, resources, cosStream);
}
#Override
public void fillPath(int windingRule) throws IOException
{
printPath();
System.out.printf("Fill; windingrule: %s\n\n", windingRule);
getLinePath().reset();
}
#Override
public void strokePath() throws IOException
{
printPath();
System.out.printf("Stroke; unscaled width: %s\n\n", getGraphicsState().getLineWidth());
getLinePath().reset();
}
void printPath()
{
GeneralPath path = getLinePath();
PathIterator pathIterator = path.getPathIterator(null);
double x = 0, y = 0;
double coords[] = new double[6];
while (!pathIterator.isDone()) {
switch (pathIterator.currentSegment(coords)) {
case PathIterator.SEG_MOVETO:
System.out.printf("Move to (%s %s)\n", coords[0], fixY(coords[1]));
x = coords[0];
y = coords[1];
break;
case PathIterator.SEG_LINETO:
double width = getEffectiveWidth(coords[0] - x, coords[1] - y);
System.out.printf("Line to (%s %s), scaled width %s\n", coords[0], fixY(coords[1]), width);
x = coords[0];
y = coords[1];
break;
case PathIterator.SEG_QUADTO:
System.out.printf("Quad along (%s %s) and (%s %s)\n", coords[0], fixY(coords[1]), coords[2], fixY(coords[3]));
x = coords[2];
y = coords[3];
break;
case PathIterator.SEG_CUBICTO:
System.out.printf("Cubic along (%s %s), (%s %s), and (%s %s)\n", coords[0], fixY(coords[1]), coords[2], fixY(coords[3]), coords[4], fixY(coords[5]));
x = coords[4];
y = coords[5];
break;
case PathIterator.SEG_CLOSE:
System.out.println("Close path");
}
pathIterator.next();
}
}
double getEffectiveWidth(double dirX, double dirY)
{
if (dirX == 0 && dirY == 0)
return 0;
Matrix ctm = getGraphicsState().getCurrentTransformationMatrix();
double widthX = dirY;
double widthY = -dirX;
double widthXTransformed = widthX * ctm.getValue(0, 0) + widthY * ctm.getValue(1, 0);
double widthYTransformed = widthX * ctm.getValue(0, 1) + widthY * ctm.getValue(1, 1);
double factor = Math.sqrt((widthXTransformed*widthXTransformed + widthYTransformed*widthYTransformed) / (widthX*widthX + widthY*widthY));
return getGraphicsState().getLineWidth() * factor;
}
}
(PrintPaths.java)
As we do not want to actually draw the page but merely extract the paths which would be drawn, we have to strip down the PageDrawer like this.
This sample parser outputs path drawing operations to show how to do it. Obviously you can instead collect them for automatized processing...
You can use the parser like this:
PDDocument document = PDDocument.load(resource);
List<?> allPages = document.getDocumentCatalog().getAllPages();
int i = 7; // page 8
System.out.println("\n\nPage " + (i+1));
PrintPaths printPaths = new PrintPaths();
PDPage page = (PDPage) allPages.get(i);
PDStream contents = page.getContents();
if (contents != null)
{
printPaths.processStream(page, page.findResources(), page.getContents().getStream());
}
(ExtractPaths.java)
The output is:
Page 8
Move to (35.92070007324219 724.6490478515625)
Line to (574.72998046875 724.6490478515625), scaled width 0.5981000089123845
Stroke; unscaled width: 5.981
Move to (35.92070007324219 694.4660034179688)
Line to (574.72998046875 694.4660034179688), scaled width 0.5981000089123845
Stroke; unscaled width: 5.981
Move to (292.2610168457031 468.677001953125)
Line to (292.8590087890625 468.677001953125), scaled width 512.9430076434463
Stroke; unscaled width: 5129.43
Move to (348.9360046386719 468.677001953125)
Line to (349.53399658203125 468.677001953125), scaled width 512.9430076434463
Stroke; unscaled width: 5129.43
Move to (405.6090087890625 468.677001953125)
Line to (406.2070007324219 468.677001953125), scaled width 512.9430076434463
Stroke; unscaled width: 5129.43
Move to (462.281982421875 468.677001953125)
Line to (462.8799743652344 468.677001953125), scaled width 512.9430076434463
Stroke; unscaled width: 5129.43
Move to (518.9549560546875 468.677001953125)
Line to (519.553955078125 468.677001953125), scaled width 512.9430076434463
Stroke; unscaled width: 5129.43
Move to (35.92070007324219 725.447998046875)
Line to (574.72998046875 725.447998046875), scaled width 0.5981000089123845
Stroke; unscaled width: 5.981
Move to (35.92070007324219 212.5050048828125)
Line to (574.72998046875 212.5050048828125), scaled width 0.5981000089123845
Stroke; unscaled width: 5.981
Quite peculiar: The vertical lines actually are drawn as very short (ca 0.6 units) very thick (ca 513 units) horizontal lines...
I have a pdf file in which some text and images are highlighted using highlight text(U) tool. Is there a way to automatically extract all the highlighted content as separate images and save it to a folder? I dont want readable text. I just want all the highlighted content as images. Thanks
You would need to use PDF library to iterate through all the Annotation objects and their properties to see which ones are using a highlight annotation. Once you have found the highlight annotation you can then extract the position and size (bounding box) of the annotation.
Once you have a list of the annotation bounding boxes you will need to render the PDF file to an image format such as PNG/JPEG/TIFF so that you can extract / clip the rendered image of the annotation text you want. You could use GDI+ or something like LibTIFF
There are various PDF libraries that could do this including
http://www.quickpdflibrary.com (I consult for QuickPDF) or
http://www.itextpdf.com
Here is a C# function based on Quick PDF Library that does what you need.
private void ExtractAnnots_Click(object sender, EventArgs e)
{
int dpi = 300;
Rectangle r;
List<Rectangle> annotList = new List<Rectangle>();
QP.LoadFromFile("samplefile.pdf", "");
for (int p = 1; p <= QP.PageCount(); p++)
{
QP.SelectPage(p); // Select the current page.
QP.SetOrigin(1); // Set origin to top left.
annotList.Clear();
for (int i = 1; i <= QP.AnnotationCount(); i++)
{
if (QP.GetAnnotStrProperty(i, 101) == "Highlight")
{
r = new Rectangle((int)(QP.GetAnnotDblProperty(i, 105) * dpi / 72.0), // x
(int)(QP.GetAnnotDblProperty(i, 106) * dpi / 72.0), // y
(int)(QP.GetAnnotDblProperty(i, 107) * dpi / 72.0), // w
(int)(QP.GetAnnotDblProperty(i, 108) * dpi / 72.0)); // h
annotList.Add(r); // Add the bounding box to the annotation list for this page.
string s = String.Format("page={0}: x={1} y={2} w={3} h={4}\n", p, r.X, r.Y, r.Width, r.Height);
OutputTxt.AppendText(s);
}
}
// Now we have a list of annotations for the current page.
// Delete the annotations from the PDF in memory so we don't render them.
for (int i = QP.AnnotationCount(); i >= 0; i--)
QP.DeleteAnnotation(i);
QP.RenderPageToFile(dpi, p, 0, "page.bmp"); // 300 dpi, 0=bmp
Bitmap bmp = Image.FromFile("page.bmp") as Bitmap;
for (int i=0;i<annotList.Count;i++)
{
Bitmap cropped = bmp.Clone(annotList[i], bmp.PixelFormat);
string filename = String.Format("annot_p{0}_{1}.bmp", p, i+1);
cropped.Save(filename);
}
bmp.Dispose();
}
QP.RemoveDocument(QP.SelectedDocument());
}
Do you want each piece of text as a separate highlight or all the higlhights on a separate pane?
I'm new to actionscript. What I'm tryin to do is simulate traffic flow near a 2 lane intersection, following Wolfram's rule 184. To begin with, I'm trying to create a grid (8x8 of which the intersection is between the middle two rows and the middle two columns, like a plus sign) whose cells have the following attributes:
color = white;
car = false;
when clicked:
color = red;
car = true (a car is present);
So, after the user clicks cells to position the cars initially and presses the start button, the simulation will begin.
Here's my code so far (apologies for incorrect formatting):
class Main
{
private var parent:MovieClip;
public static function main(mc:MovieClip)
{
var app = new Main(mc);
}
public function Main(mc:MovieClip)
{
this.parent = mc;
//grid settings
var Cell:MovieClip = mc.createEmptyMovieClip("cell", mc.getNextHighestDepth());
var x:Number = 0;
var y:Number = 0;
var color:Number = 0xffffff;
var car:Boolean = false;
for (y = 0; y < 3 * Stage.height / 8; y += Stage.height / 8)
{
for (x = 3*Stage.width/8; x < 5*Stage.width/8; x+=Stage.width/8)
{
UI.drawRect(Cell, x, y, (Stage.width / 8) - 5, (Stage.height / 8) - 5, color, 100);
}
}
for (y = 3*Stage.height/8; y < 5 * Stage.height / 8; y += Stage.height / 8)
{
for (x = 0; x < Stage.width; x+=Stage.width/8)
{
UI.drawRect(Cell, x, y, (Stage.width / 8)-5, (Stage.height / 8)-5, color, 100);
}
}
for (y = 5*Stage.height/8; y < Stage.height; y += Stage.height / 8)
{
for (x = 3*Stage.width/8; x < 5*Stage.width/8; x+=Stage.width/8)
{
UI.drawRect(Cell, x, y, (Stage.width / 8)-5, (Stage.height / 8)-5, color, 100);
}
}
Cell.onMouseDown()
{
Cell.color = UI.RED;
Cell.car = true;
}
}
}
I know there's quite a few things gone wrong here. First of all, the cell color doesn't change on mouse down. Do i need to make movie clip for each cell in the for loops? I think it would be easier to make a grid of objects with given attributes, but i don't know how to do that. Would really appreciate if someone helps me out.
From what I can tell, issue with your current approach is that using drawRect() literally draws pixels on to the stage, which means you'll have no reference to those shapes in future frames. right now, you've got one MovieClip that has been drawn many times. What you need is a lot of MovieClips so you have a reference to each cell that you can update/edit every frame.
Your best bet is to do the following (I'll just provide pseudo because I'm a bit shaky on AS2 syntax):
A) Create an array to hold all of the Cells. Call it:
var Cells:Array = new Array();
B) During each step of the loops in your constructor, do 4 things.
1) Create a new MovieClip `var tempCell:MovieClip = new MovieClip();
2) Draw a rectangle on to each MovieClip: A tutorial for the graphics API in AS2 http://www.actionscript.org/resources/articles/727/1/Drawing-shapes-with-AS2/Page1.html
3) Add an event listenerto each MovieClip that points to a common event handler. This listener listens for mouse clicks on that MovieClip (or MOUSE_DOWN)
4) and use Cells.push(tempClip) to add that new MovieClip to your array so you now have one object that contains a reference to all of your cells.
C) Create an click event handler that redraws the cell that has been clicked. Try MouseEvent.target
You have another option to using the graphics API to draw rectangles, and that is to simply add and remove stock graphics from your Flash library. You'll have to draw these graphics in Flash and then 'Export for Actionscript' to call them up.
Hope this points you in the right direction!
J