I need to load some pictures into a ListView. I've figured out how to do this with images stored on my local drive: when run, the code below displays exactly what I need.
private void getLocalImages()
{
List<string> imageList = new List<string>();
imageList.Add("C:\\....\\Pic1.png");
imageList.Add("C:\\....\\Pic2.png");
imageList.Add("C:\\....\\Pic3.png");
ImageList imgl = new ImageList();
imgl.ImageSize = new Size(200, 300);
imgl.ColorDepth = ColorDepth.Depth32Bit;
for (int i = 0; i < imageList.Count; i++)
{
imgl.Images.Add(Image.FromFile(imageList[i]));
listView1.Items.Add("", i);
}
listView1.LargeImageList = imgl;
}
How do I now modify this to load pictures stored on the web instead?
Edit: I'm using .NET Core 6.0, and this is a Windows Form application
I figured it out:
private void getWebImages()
{
HttpClient client = new HttpClient();
List<string> imageList = new List<string>();
imageList.Add("https://www. ... .com/.../Pic1.jpg");
imageList.Add("https://www. ... .com/.../Pic1.jpg");
imageList.Add("https://www. ... .com/.../Pic1.jpg");
ImageList imgl = new ImageList();
imgl.ImageSize = new Size(300, 200);
imgl.ColorDepth = ColorDepth.Depth32Bit;
for (int i = 0; i < imageList.Count; i++)
{
Stream r = client.GetStreamAsync(imageList[i]).Result;
imgl.Images.Add(Image.FromStream(r));
listView1.Items.Add("", i);
}
listView1.LargeImageList = imgl;
}
Related
I'm trying to extract some text from an image using tesseract, and I've noticed if I divide the image to 9 smaller pieces the system is more accurate, so what I'm trying to accomplish is to process all 9 images at once (parallel) and this is the way I wanted to do it:
private static int GetImageText(Image src)
{
string[] words = { words-to-check };
List<string> found = new();
string path = Environment.CurrentDirectory;
try
{
using (var engine = new TesseractEngine(path, "eng", EngineMode.LstmOnly))
{
Parallel.ForEach(CutUpImage(src), (img) =>
{
using (var ms = new MemoryStream())
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
using (var loadedImg = Pix.LoadFromMemory(ms.ToArray()))
using (var page = engine.Process(loadedImg))
{
var c = page.GetText();
foreach (var word in words) if (c.Contains(word)) found.Add(word);
}
}
});
return found.Count;
}
}
catch (Exception ex)
{
throw ex;
}
}
but I'm getting an error (Only one image can be processed at once. Please make sure you dispose of the page once your finished with it.).
So I had to move the new TesseractEngine into the loop like this:
private static int GetImageText(Image src)
{
string[] words = { words-to-check };
List<string> found = new();
string path = Environment.CurrentDirectory;
Parallel.ForEach(CutUpImage(src), (img) =>
{
using (var engine = new TesseractEngine(path, "eng", EngineMode.LstmOnly))
{
using (var ms = new MemoryStream())
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
using (var loadedImg = Pix.LoadFromMemory(ms.ToArray()))
using (var page = engine.Process(loadedImg))
{
var c = page.GetText();
foreach (var word in words) if (c.Contains(word)) found.Add(word);
}
}
}
});
return found.Count;
}
but then it takes a full minute to finish processing all images.
so my question is how do I make the new TesseractEngine work outside the loop, and more generally how do I make this work faster?
ok so the solution to my problem is simple... don't use parallel processing!
I switched the Parallel.ForEach to a traditional foreach (idk why I decided to try parallel processing first...) and it now takes 12 seconds to process them all, this is the code :
private static int GetImageText(Image src)
{
string[] words = { words-to-check };
List<string> found = new();
string path = Environment.CurrentDirectory;
using (var engine = new TesseractEngine(path, "eng", EngineMode.LstmOnly))
using (var ms = new MemoryStream())
foreach (var img in CutUpImage(src))
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
using (var loadedImg = Pix.LoadFromMemory(ms.ToArray()))
using (var page = engine.Process(loadedImg))
{
var c = page.GetText();
foreach (var word in words) if (c.Contains(word)) found.Add(word);
}
ms.SetLength(0);
}
return found.Count;
}
p.s. this is the CutUpImage code if someone ever wants to use it...
private static Image[] CutUpImage(Image src)
{
int widthThird = (int)((double)src.Width / 3.0 + 0.5);
int heightThird = (int)((double)src.Height / 3.0 + 0.5);
var imgarray = new Image[9];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
var index = i*3+j;
imgarray[index] = new Bitmap(widthThird, heightThird);
Graphics g = Graphics.FromImage(imgarray[index]);
g.DrawImage(src, new Rectangle(0, 0, widthThird, heightThird),
new Rectangle(j * widthThird, i * heightThird, widthThird, heightThird),
GraphicsUnit.Pixel);
g.Dispose();
}
return imgarray;
}
I‘m trying to add the second .txt file (book2) into Text Expander control, unfortunately without success.
public Form1()
{
InitializeComponent();
CreateAccordion();
}
private void CreateAccordion(string book1)
{
Accordion accordion = new Accordion();
accordion.Size = new Size(400, 350);
accordion.Left = 10;
Expander expander1 = new Expander();
expander1.BorderStyle = BorderStyle.FixedSingle;
ExpanderHelper.CreateLabelHeader(expander1, "Book1", SystemColors.ActiveBorder);
CreateContentLabel(expander1, book1, 140);
accordion.Add(expander1);
Expander expander2 = new Expander();
expander2.BorderStyle = BorderStyle.FixedSingle;
ExpanderHelper.CreateLabelHeader(expander2, "Book2", SystemColors.ActiveBorder);
CreateContentLabel(expander2, "book2", 120);
accordion.Add(expander2);
this.Controls.Add(accordion);
}
The following code reads only a single txt.file. Can anyone help me please?
private void CreateAccordion()
{
ReadTxtFiles();
}
private void ReadTxtFiles()
{
string path = #"C:\..\..\READBOOKS";
string[] files = new string[] { "book1.txt", "book2.txt" };
foreach (string file in files)
{
string fullPath = Path.Combine(path, file);
string booktxt = File.ReadAllText(fullPath);
string book1 = booktxt;
CreateAccordion(book1);
}
}
I‘m trying to add the second .txt file (book2) into Text Expander control, unfortunately without success.
The main reason behind this is because you're only passing the string from your first book, you'll need to pass all of the text.
private void ReadTxtFiles()
{
string path = #"C:\..\..\READBOOKS";
string[] files = new string[] { "book1.txt", "book2.txt" };
List<string> books = new List<string>();
foreach (string file in files)
{
string fullPath = Path.Combine(path, file);
string booktxt = File.ReadAllText(fullPath);
books.Add(booktxt);
}
CreateAccordion(books);
}
Change the signature of CreateAccordion:
private void CreateAccordion(List<string) books)
{
Accordion accordion = new Accordion();
accordion.Size = new Size(400, 350);
accordion.Left = 10;
Expander expander1 = new Expander();
expander1.BorderStyle = BorderStyle.FixedSingle;
ExpanderHelper.CreateLabelHeader(expander1, "Book1", SystemColors.ActiveBorder);
CreateContentLabel(expander1, books[0], 140);
accordion.Add(expander1);
Expander expander2 = new Expander();
expander2.BorderStyle = BorderStyle.FixedSingle;
ExpanderHelper.CreateLabelHeader(expander2, "Book2", SystemColors.ActiveBorder);
CreateContentLabel(expander2, books[1], 120);
accordion.Add(expander2);
this.Controls.Add(accordion);
}
Please note that I'm accessing index's here, you may want to check that the index exist before trying to access it. Also there's more way's than this, but should give you a better understanding to accomplish this.
I have no idea how to put doubleclick events to multiple pushpins that are initialized in the program itself(not in the xaml). The program will get lat and long data from a text file.
here's my current code:
public partial class BingMaps : Window
{
string role;
string nick;
int countLines=0;
public BingMaps(string value,string role2)
{
InitializeComponent();
nick = value;
role = role2;
setCount();
int cLines = 0;
Pushpin[] pushpins = new Pushpin [countLines];
StreamReader z = new StreamReader("dorms.txt");
while (z.Peek() > 0)
{
var pushpinLayer = new MapLayer();
pushpinLayer.Name = "PushPinLayer";
intraMap.Children.Add(pushpinLayer);
string line = z.ReadLine();
string[] temp = line.Split(new char[] { ';' });
var location = new Location(double.Parse(temp[3]), double.Parse(temp[4]));
var pushpin = new Pushpin();
pushpin.Name = "MyNewPushpin";
pushpin.Background = new SolidColorBrush(Colors.Blue);
pushpin.Location = location;
pushpin.ToolTip = "" + temp[0];
pushpins[cLines] = pushpin;
pushpinLayer.Children.Add(pushpins[cLines]);
cLines = cLines + 1;
}
z.Close();
}
public void setCount()
{
using (StreamReader cRead = new StreamReader("dorms.txt"))
{
while (cRead.Peek() > 0) {
cRead.ReadLine();
countLines = countLines + 1;
}
}
}
}
i'm quite new to c# so please bear with me. I need to display different data for each pushpin.
you can register to MouseDoubleClick event
var pushpin = new Pushpin();
pushpin.MouseDoubleClick += (sender, ea) => {
// do something
};
With the below code I'm able to process the requests one by one. This is an asynchronous process so I don't need to get a response. I am only passing the requests.
class Program
{
static void Main(string[] args)
{
ProfileRequestData();
}
private static void ProfileRequestData()
{
ProfileRequest.Request[] req = new ProfileRequest.Request[4];
//req.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
req[0] = new ProfileRequest.Request();
req[1] = new ProfileRequest.Request();
req[2] = new ProfileRequest.Request();
req[3] = new ProfileRequest.Request();
req[0].Record = new ProfileRequest.RequestRecord();
req[1].Record = new ProfileRequest.RequestRecord();
req[2].Record = new ProfileRequest.RequestRecord();
req[3].Record = new ProfileRequest.RequestRecord();
req[0].Record.Id = "asdasd123";
req[1].Record.Id = "asdasd456";
req[2].Record.Id = "asdasd789";
req[3].Record.Id = "addjlk123";
ProfileRequest.ProfileRequestClient serviceClient = new ProfileRequest.ProfileRequestClient();
serviceClient.ClientCredentials.UserName.UserName = #"Liberty\nzy0105";
serviceClient.ClientCredentials.UserName.Password = "abcddf";
serviceClient.ProfileRequest(req[0]);
serviceClient.ProfileRequest(req[1]);
serviceClient.ProfileRequest(req[2]);
serviceClient.ProfileRequest(req[3]);
}
}
What I want to do is to process all the requests at a time not one by one.
Can anyone, please, provide the code for the requirement???
For simultaneous jobs like this you should use a threading mechanism. Here you can use backgroundworkers.
var asyncServiceRequester = new BackgroundWorker();
asyncServiceRequester.DoWork += asyncServiceRequester_DoWork;
foreach(var request in req)
{
asyncServiceRequester.RunWorkerAsync(req);
}
this is the code snippet that you should use instead of:
serviceClient.ProfileRequest(req[0]);
serviceClient.ProfileRequest(req[1]);
serviceClient.ProfileRequest(req[2]);
serviceClient.ProfileRequest(req[3]);
and here is the DoWork method of the backgroundworker:
static void asyncServiceRequester_DoWork(object sender, DoWorkEventArgs e)
{
var request = e.Argument as ProfileRequest;//whatever your request type is
serviceClient.ProfileRequest(request);
}
UPDATE:
I am assuming that your user inputs are in a list for dynamic purposes, since you didn't gave any specific information about it. In this case you'll traverse through the list of inputs, and extract the values into your object array. Here is how you would first fill the list of inputs, then how you'll assign those values to your object array.
List<TextBox> inputs = new List<TextBox>();
inputs.Add(input1);
inputs.Add(input2);
...
inputs.Add(inputN);
If your inputs are static than this is how you do it, else;
List<TextBox> inputs = new List<TextBox>();
for(int i = 0; i < someNumber; i++)
{
inputs.Add(new TextBox(){
Text = "some text",
Location = new Point(10, i * 75),
Height = 60,
Width = 150,
Font = new Font(ActiveControl.Font.FontFamily, 10, FontStyle.Regular)
});
}
Rest is pretty straightforward;
var index = 0;
foreach(var tb in inputs)
{
var newReq = new ProfileRequest.Request(){
Record = new ProfileRequest.RequestRecord(){
Id = tb.Text
}
}
req[index++] = req;
// I would suggest you to use generic lists here too since they are simpler and more flexible.
// req.Add(newReq);
}
Gathering the input from a text file or xml should be the topic of another question, but you can do them in the same manner. Just read the file, or xml then extract the values in dynamic manner.
You can create threads to process requests in parallel -
for (int i = 0; i < req.Length; i++)
{
new System.Threading.Thread(() => serviceClient.ProfileRequest(req[i])).Start();
}
I made a simple user control for a tab, however when I call it it shows up very small and can resize it to any size at all, here is the code. What do I wrong?
public class tabController : UserControl
{
public tabController(string id)
{
InitializeComponent(id);
}
public void InitializeComponent(string id)
{
TabControl tabControl;
TabPage tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8, tab9, tab10;
tabControl = new TabControl();
tabControl.Location = new Point(500, 250);
tabControl.Size = new Size(500, 500);
tabControl.ClientSize = new Size(500, 500);
var xmlData = Binder.fSelect.GetData(3, 1, 1, 0, "", "", 0, 25);
StringReader sr = new StringReader(xmlData);
//dsData.ReadXml(xmlData);
//string xmlString = sw.ToString();
DataSet ds = new DataSet();
ds.ReadXml(sr);
int i = 0;
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
//string v = ds.Tables[0].Rows[i].ItemArray[2].ToString();
if ((ds.Tables[0].Rows[i].ItemArray[4].ToString()) == "114")
{
if (i == 0)
{
tab1 = new TabPage(ds.Tables[0].Rows[i].ItemArray[1].ToString());
tabControl.TabPages.Add(tab1);
}
}
}
tabControl.Dock = DockStyle.Fill;
this.Controls.Add(tabControl);
Hie
Try using the Dockstyle property of the user control to Dockstyle.Fill when you call it.