C# Text in Powerpoint shape not being detected - c#

I'm trying to extract all the text in each slide of a powerpoint file. For some reason I'm only getting some text and not all of them. I'm looping through all shapes in the slide and checking for both textframes and tables. But some slides with text will print out nothing.
Here's a sceenshot of the slide that only printed the title and no other text.
Code
foreach (PowerPoint.Slide _slide in pptPresentation.Slides) {
foreach(PowerPoint.Shape _shape in _slide.Shapes) {
//check for textframes
if (_shape.HasTextFrame == MsoTriState.msoTrue) {
var textFrame = _shape.TextFrame;
if (textFrame.HasText == MsoTriState.msoTrue) {
var textRange = textFrame.TextRange;
PrintAllParagraphs(textRange);
}
}
//check for tables
if(_shape.HasTable == MsoTriState.msoTrue) {
var slideTable = _shape.Table;
int rowCount = slideTable.Rows.Count;
int colCount = slideTable.Columns.Count;
for(int y = 1; y <= rowCount; y++) {
for(int x = 1; x <= colCount; x++) {
var tRange = slideTable.Cell(y, x).Shape.TextFrame.TextRange;
PrintAllParagraphs(tRange);
}
}
}
} //loop shapes
} //loop slides
print function
public void PrintAllParagraphs(PowerPoint.TextRange textRange) {
for (int i = 1; i <= textRange.Paragraphs().Count; i++) {
PowerPoint.BulletFormat bulletFormat = textRange.Paragraphs(i).ParagraphFormat.Bullet;
Console.WriteLine( (bulletFormat.Type == PowerPoint.PpBulletType.ppBulletNone) ? textRange.Paragraphs(i).Text.ToString() : "* " + textRange.Paragraphs(i).Text.ToString());
}
}
Are there other things i should be checking within the shape of a slide? Any help would be appreciated. Thanks.

Okay, turns out that this is a SmartArt that's the reason why checking Shapes/Tables did not detect it.
All i had to do was to loop the nodes within the Smart Art and grab the text from TextRange. I noticed the text is seperated by "\r" so by splitting it i was able to get the correct output from it.
//check for SmartArt
if(_shape.HasSmartArt == MsoTriState.msoTrue) {
foreach( SmartArtNode node in _shape.SmartArt.AllNodes) {
var txtRange = node.TextFrame2.TextRange;
var txt = txtRange.Paragraphs.Text.Split(new string[] { "\r" }, StringSplitOptions.None);
foreach(string line in txt)
Console.WriteLine(line);
}
}

Related

C# Filling a 2D array with objects from a txt file at specific positions

Im trying to fill a 2D array with a txt file from my computer.
I have tried doing this in two different ways but i have not gotten either to work.
Save objects position number in the file using the following code.
for (int row = 0; row < 100; row++)
{
for (int col = 0; col < 2; col++)
{
if (cpp[row, col] == null)
{
break;
}
else
{
if (cpp[row, col] == null) continue;
save.WriteLine(string.Format("{0}, {1}, {2}, {3}", row + 1, cpp[row, col].RegNumber, cpp[row, col].VehicleTypes, cpp[row, col].TimeOfArrival));
}
}
}
Second way i have tried is to save the file with the empty lines aswell.
foreach (var temp in cpp)
{
if (temp == null) save.WriteLine("");
if (temp == null) continue;
save.WriteLine("{{0},{1},{2}", temp.RegNumber, temp.VehicleTypes, temp.TimeOfArrival);
}
I have gotten nowhere with the load function and i would appreciate any help i can get with this. I need to load the file in to my 2D array and the objects have to be assigned to the same position it was before.
The only code i have for the load function is this.
string[] lines = File.ReadAllLines("CarParkPrague.txt");
var vehicles = new List<Vehicle>();
{
foreach (var line in lines)
{
var values = line.Split(",");
Enum.TryParse(values[1], out VehicleType type);
var time = DateTime.Parse(values[2]);
vehicles.Add(new Vehicle(values[0], type, time));
}
}
Text file line example = AAA111,CAR,2020-10-11 14:19:04
Or with the position saved = 1,AAA111,CAR,2020-10-11 14:19:04
Can be either, which ever is easiest.
This is a test method that works but it saves the vehicles on first best available spot in the array so its not quite right. The text file is in this case saved without a position number. And looks like the first example above.
static void LoadTestFile() //Loads the array using the test file which is filled with examples.
{
string[] lines = File.ReadAllLines("testfile.txt");
var vehicles = new List<Vehicle>();
foreach (var line in lines)
{
var values = line.Split(",");
Enum.TryParse(values[1], out VehicleType type);
var time = DateTime.Parse(values[2]);
vehicles.Add(new Vehicle(values[0], type, time));
}
int counter = 0;
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 2; j++)
{
if (counter >= vehicles.Count)
break;
if (cpp[i, 0] != null)
{
if (cpp[i, 0].VehicleTypes == VehicleType.CAR)
{
continue;
}
}
if (vehicles[counter].VehicleTypes == VehicleType.CAR)
{
cpp[i, j] = vehicles[counter++];
}
else
{
cpp[i, j] = vehicles[counter++];
}
}
}
Let's start with something that's entirely trivial - mirror the save and load methods. The only thing you really need to add is the dimensions of the array:
var rowCount = cpp.GetLength(0);
var colCount = cpp.GetLength(1);
save.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0},{1}", rowCount, colCount));
for (var row = 0; row < rowCount; row++)
{
for (var col = 0; col < colCount; col++)
{
if (cpp[row, col] == null) save.WriteLine();
else save.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", cpp[row, col].RegNumber, cpp[row, col].VehicleTypes, cpp[row, col].TimeOfArrival));
}
}
To read this very straight-forward file format, do the same thing in reverse:
using (var sr = new StreamReader("CarParkPrague.txt"))
{
var dimensions = sr.ReadLine()?.Split(',');
if (dimensions == null
|| !int.TryParse(dimensions[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var rowCount)
|| !int.TryParse(dimensions[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var colCount)
)
throw new Exception("Invalid dimensions.");
var cpp = new Vehicle[rowCount, colCount];
for (var row = 0; row < rowCount; row++)
{
for (var col = 0; col < colCount; col++)
{
if (!(sr.ReadLine() is {} line) throw new Exception("Unexpected end of file.");
if (string.IsNullOrWhitespace(line)) continue;
var values = line.Split(",");
if (!Enum.TryParse(values[1], out var vehicleType)) throw new Exception($"Unexpected vehicle type '{values[1]}'.");
if (!DateTime.TryParse(values[2], CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTime) throw new Exception($"Invalid time '{values[2]}'.");
cpp[row, col] = new Vehicle(values[0], type, time);
}
}
}
There's plenty of ways to optimize this, but there's little reason to bother if the resulting file is just a few kilobytes (or even tens of kilobytes).
Your loading function will crash if you have empty lines, so I can't quite believe it works to read a file with blank lines on. The big problem with it though is that it doesn't do anything if it encounters a blank line when really it should be putting a blank (null) vehicle at that position in the list
Save blank lines if the vehicle is null, and also save dates in a fixed format:
foreach (var temp in cpp)
{
if (temp == null)
save.WriteLine();
else
save.WriteLine("{{0},{1},{2}", temp.RegNumber, temp.VehicleTypes, temp.TimeOfArrival.ToString("yyyyMMddHHmmss"));
}
Load, catering for blank lines by putting no vehicle (null) in that position:
string[] lines = File.ReadAllLines("CarParkPrague.txt");
var vehicles = new List<Vehicle>();
foreach (var line in lines)
{
if(string.IsNullOrWhiteSpace(line))
{
vehicles.Add(null);
continue;
}
var values = line.Split(",");
Enum.TryParse(values[1], out VehicleType type); //should really test this with an if
var time = DateTime.ParseExact(values[2], "yyyyMMddHHmmss", null);
vehicles.Add(new Vehicle(values[0], type, time));
}
}
Hopefully you can see how your "if the parking space is empty the vehicle is null and this becomes a blank line during save" is translated back upon load to "if the line is blank then the space is marked as empty by putting a null vehicle there"
Edit; as you seem to have a fixed number of parking spaces and are using null to represent emptiness, having a collection like a List, which dynamically sizes to fit the contents is perhaps not ideal. Switch to using an array that represents the size of the car park:
string[] lines = File.ReadAllLines("CarParkPrague.txt");
var vehicles = new Vehicle[100];
for (int i = 0; i < lines.Length && i < vehicles.Length; i++)
{
var line = lines[i];
if(string.IsNullOrWhiteSpace(line))
continue;
var values = line.Split(",");
Enum.TryParse(values[1], out VehicleType type); //should really test this with an if
var time = DateTime.ParseExact(values[2], "yyyyMMddHHmmss", null);
vehicles[i] = new Vehicle(values[0], type, time);
}
}
Don't forget that the vehicles in the load method should be assigned to the same variable that cpp in the save method represents. Really, you ought to use the same class wide variable in both methods
Thanks for all the help. This is a solution that works for my project. Save file and load in to the 2d array.
static void SaveFile() //Saves the current array using streamwriter.
{
Console.Clear();
StreamWriter save = new StreamWriter("CarParkPrague.txt");
using (save)
{
foreach (var temp in cpp)
{
if (temp == null) save.WriteLine();
else
save.WriteLine("{0},{1},{2}", temp.RegNumber, temp.VehicleTypes, temp.TimeOfArrival);
}
}
Console.WriteLine("File saved succesfully");
Console.WriteLine("----------------------------------------------------------------");
}
static void LoadFile() //Loads the array using the saved file.
{
try
{
string[] lines = File.ReadAllLines("CarParkPrague.txt");
var vehicles = new List<Vehicle>();
{
foreach (var line in lines)
{
if (string.IsNullOrWhiteSpace(line))
{
vehicles.Add(null);
continue;
}
var values = line.Split(",");
Enum.TryParse(values[1], out VehicleType type);
var time = DateTime.Parse(values[2]);
vehicles.Add(new Vehicle(values[0], type, time));
}
}
int counter = 0;
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 2; j++)
{
if (vehicles[counter] == null)
{
cpp[i, j] = vehicles[counter++];
}
else if (vehicles[counter] != null)
{
cpp[i, j] = vehicles[counter++];
}
}
}
}
catch (FileNotFoundException ex)
{
Console.WriteLine(ex);
Console.WriteLine("File could not be found. Please make sure there is a file named (CarParkPrague.txt) in your folder.");
}
Console.Clear();
Console.WriteLine("File have been loaded succesfully");
Console.WriteLine("----------------------------------------------------------------");
}

How to group and name series chart in visual studio c#

I have DataGridView which consist of these data
From these data i would like to make the first column, airport name to group the third column and sum to their corresponding ActLoadQuantityTo which is in the fifth column, the cargo type which landed on the airport. right now my chart is messed up as it look like this
for (int j = 0; j < dgv_3.Rows.Count; j++)
{
double Load_qty = 0;
double new_load_qty = 0;
DiscPort = dgv_3.Rows[j].Cells["ActDiscDischargingPort"].Value.ToString();
DestType = dgv_3.Rows[j].Cells["SchLoadDestination"].Value.ToString();
CargoType = dgv_3.Rows[j].Cells["SchLoadCargoType"].Value.ToString();
string CargoType2 = "Series-" + CargoType;
Load_qty = Convert.ToDouble(dgv_3.Rows[j].Cells["ActLoadQuantityTon"].Value);
if (chart3.Series.IndexOf(DiscPort) != -1)
{
chart3.Series["000 - Port"].Points.AddY(Load_qty);
}
else
{
chart3.Series["000 - Port"].Points.AddXY(DiscPort, Load_qty);
}
}
no grouping of series,etc. i've tried adding more series but it just doesn't make sense toward the DataGridView. and my expectation is that i would like the chart to look like this as I've described before
Any idea what set of code should it be?
I found my desired result by using this code
public void isichartdomestic(System.Data.DataTable initialDataSource)
{
chart3.Titles.Add("Your title");
chart3.Legends.Add("Your Legend");
for (int i = 1; i < initialDataSource.Columns.Count; i++)
{
System.Windows.Forms.DataVisualization.Charting.Series series = new System.Windows.Forms.DataVisualization.Charting.Series();
foreach (DataRow dr in initialDataSource.Rows)
{
double y = (double)dr[i];
series.Points.AddXY(dr["DiscPort"].ToString(), y);
TotalDomestic += y;
}
chart3.Series.Add(series);
string NamaSeries = series.ToString();
NamaSeries = NamaSeries.Replace("Series-","");
chart3.Series[NamaSeries].IsValueShownAsLabel = true;
chart3.Series[NamaSeries].IsVisibleInLegend = true;
if (NamaSeries == "Series1")
{
chart3.Series[NamaSeries].LegendText = "Bag";
}
else if (NamaSeries == "Series2")
{
chart3.Series[NamaSeries].LegendText = "Bulk";
}
else if (NamaSeries == "Series3")
{
chart3.Series[NamaSeries].LegendText = "Clinker";
}
else if (NamaSeries == "Series4")
{
chart3.Series[NamaSeries].LegendText = "Container";
}
}
lb_TotalDomestic.Text = Convert.ToString("Total Domestic: " + TotalDomestic);
TotalDomesticExport += TotalDomestic;
}

Adding an Items into Listview

I have completely split the string in text file that is delimited by a comma.
My problem is that I cannot show the data on my list view.
I have use this code, but when I run it and debug, there is value inside the variables. but then I finished the debugging, No Items were added in the Listview.
private void ColumnHeaders()
{
lvResult.View = View.Details;
lvResult.Columns.Add("ファイル名");
lvResult.Columns.Add("フォルダ");
lvResult.Columns.Add("比較結果");
lvResult.Columns.Add("左日付");
lvResult.Columns.Add("右日付");
lvResult.Columns.Add("拡張子");
for (int i = 0; i <= lvResult.Columns.Count; i++)
{
lvResult.Columns[i].Width = lvResult.Width / 6;
}
}
private void viewTextFile()
{
string[] lines = File.ReadAllLines(txtResultPath.Text + "A.YMD6063_new.txt");
for (int x = 0 ; x <= lines.Length; x++)
{
string[] col = lines[x].Split(new char[] { ',' });
ListViewItem lvItem = new ListViewItem();
for (int i = 0; i <= col.Length; i++)
{
lvItem.Text = col[i].ToString();
if (i == 0)
{
lvResult.Items.Add(lvItem);
}
else
{
lvResult.Items[x].SubItems[i].Text = lvItem.Text;
}
}
}
}
here is a sample code I tried. Hope this would help you.
listView1.Columns.Add("column1");
listView1.Columns.Add("column2");
listView1.Columns.Add("column3");
listView1.Columns.Add("column4");
string[] lines = new string[] { "value01,value02,value03,value04", "value11,value12,value13,value14" };
foreach (string line in lines)
{
listView1.Items.Add(new ListViewItem(line.Split(',')));
}
Set the ListView.View to Details. This can either be achieved in the Designer or programatically like this:
lvResult.View = View.Details;
Add each line of your file:
private void viewTextFile()
{
foreach(var line in File.ReadAllLines(somefilepath))
AddLineToListView(line);
}
private void AddLineToListView(string line)
{
if (string.IsNullOrEmpty(line))
return;
var lvItem = new ListViewItem(line.Split(','));
lvResult.Items.Add(lvItem);
}

Steganography extraction issue C#

I am able to hide my text inside an Image. But when I tried to extract the text from my image, I always only able manage to get only the first character. I don't know where went wrong?
My embed operation code:
public static Bitmap embedMessage(string hiddenText, Bitmap oriImage)
{
Color currentPixel;
int[] colorRGB = new int[3];
List<int> messageValue = new List<int>();
messageValue = ConvertMessage(messageValue, hiddenText);
int messageIndex = messageValue.Count;
int binaryCount = 0;
int zeroAdded = 0;
for(int row = 0; row < oriImage.Height; row++)
{
for(int col = 0; col < oriImage.Width; col++)
{
currentPixel = oriImage.GetPixel(col, row);
colorRGB[0] = ConvertEven(currentPixel.R);
colorRGB[1] = ConvertEven(currentPixel.G);
colorRGB[2] = ConvertEven(currentPixel.B);
for(int rgbIndex = 0; rgbIndex < colorRGB.Length; rgbIndex++)
{
if(messageIndex > 0)
{
colorRGB[rgbIndex] += messageValue[messageValue.Count - messageIndex] % 2;
messageValue[messageValue.Count - messageIndex] /= 2;
}
}
if (messageIndex == 0 && zeroAdded < 8)
{
oriImage.SetPixel(col, row, Color.FromArgb(colorRGB[0], colorRGB[1], colorRGB[2]));
zeroAdded++;
Console.WriteLine("Adding zero number: " + zeroAdded);
}
else
{
Console.WriteLine("Set Pixel");
oriImage.SetPixel(col, row, Color.FromArgb(colorRGB[0], colorRGB[1], colorRGB[2]));
}
if (zeroAdded == 8)
{
Console.WriteLine("Final Pixel Add");
oriImage.SetPixel(col, row, Color.FromArgb(colorRGB[0], colorRGB[1], colorRGB[2]));
return oriImage;
}
binaryCount++;
if (binaryCount % 8 == 0) { messageIndex--; Console.WriteLine("Message Index deducted"); }
}
}
return oriImage;
}
My embed implementation is the same to this example As for extraction I used the exact extraction code from the example. No matter what I tried, I am still only getting the first character of my embedded text. I tried checking my code by printing each operations and all of them fires without any issue which means the embed operation should be working as expected.
Just found my problem. Everything in my embed method should be in the R G B for loop.

Selecting Hexagons around a radius

I have a map made of hexagons. When a hexagon is clicked on which a troop resides, other hexagons around the clicked one should be highlighted based on the troop's range variable.
I have tried quite a few methods on my own, but failed. I can't seem to get a list with the correct ones highlighted. In this example I will be using a troop of a range of 2 tiles.
The method I have tried to implement is as following:
There are 3 lists.
Open list contains nodes to be expanded by 1
Close list contains nodes that will be highlighted
remove list contains nodes that have already been expanded
I followed the following algorithm:
Add the start node to all lists.
Expand the nodes in open list by 1 tile.
Remove the nodes within open list using remove list.
add open list nodes to closed list.
clear remove list.
copy open list contents to remove list.
Repeat for whatever the range of the troop is.
My goal is to highlight a hex tiles of radius r, around the clicked tile; r = troop range.
Im quite lost, and I was probably doing some obvious mistakes. Any help will be appreciated!
(Below is the code that I made)
private List<string> expand(List<string> open, bool odd)
{
List<string> newopen = new List<string>();
int oddEven = 1;
if (odd == false)
{
oddEven = -1;
}
foreach (string s in open)
{
string[] rc = s.Split('.'); //row + col of the current hex
int Row = int.Parse(rc[0]);
int Col = int.Parse(rc[1]);
for (int r = 1; r >= -1; r--)
{
for (int c = -1; c <= 1; c++)
{
if (!((r == oddEven && c != 0) || (r== 0 && c == 0)))
{
if (((Row + r) > -1 && (Col + c) > -1) && ((Row + r) < 9 && (Col + c) < 18)) //mapcheck
{
if (Hexmap[Row + r, Col + c] == '-') //mapcheck
{
newopen.Add((Row + r).ToString() + "." + (Col + c).ToString());
}
}
}
}
}
}
return newopen;
}
private void Remove(ref List<string> rem, ref List<string> open)
{
foreach (string s in rem)
{
open.Remove(s);
}
}
private void Add(ref List<string> closed, ref List<string> open)
{
foreach (string s in open)
{
closed.Add(s);
}
}
private void TroopSelect(int row, int col, int range)
{
bool odd = true;
if ((row % 2) == 0)
{
odd = false;
}
List<string> open = new List<string>();
List<string> close = new List<string>();
List<string> remove = new List<string>();
open.Add(row.ToString() + "." + col.ToString());
close.Add(row.ToString() + "." + col.ToString());
remove.Add(row.ToString() + "." + col.ToString());
for (int i = 0; i < range; i++)
{
open = expand(open, odd); //row and col of the current point being checked --- REMOVE ROW COL, find it out from the list within the function
Remove(ref remove, ref open); //remove from open the remove hex values
Add(ref close, ref open); //add to closed what's in open
remove.Clear(); //clear remove
remove = open; //set remove the same as open
}
foreach (string s in close)
{
string[] rc = s.Split('.'); //row + col of the current hex
int Row = int.Parse(rc[0]);
int Col = int.Parse(rc[1]);
Hexagons.Add(new PointF(Row, Col));
}
}
private void CheckTroop(int row, int col)
{
if (Hexmap[row, col] == 'o') //it's a friendly troop
{
foreach (Troops t in playertroops)
{
if (t.row == row && t.column == col)
{
TroopSelect(row, col, t.range);
this.battlegrid.Invalidate();
}
}
}
}
private void battlegrid_MouseClick(object sender, MouseEventArgs e)
{
int row, col;
PointToHex(e.X, e.Y, HexHeight, out row, out col); //gets the hex in the x/y position
CheckTroop(row, col);
//this.Invalidate();
}
Below are also two images: (Ignore the rock in the background!)
First of troop range = 1, works ok
Second image of troop range = 2, doesn't work ok
Thanks once again for any help.

Categories