I am building an Excel file with EEPlus under MVC-5 C# application. Everything goes as planned until I set a height on a row (so an image can fit).
I load de images and set the height on column 20, like so:
Image cfPhoto = null;
Bitmap cfBm = null;
ExcelPicture pictureCf = null;
var photoInitialColumn = 0;
i++;
completedFormPhotos.ForEach(delegate(CompletedFormPhoto cfP)
{
cfPhoto = Image.FromFile(HostingEnvironment.MapPath("~/Content/Images/FormPhotos/" + cfP.Id + ".jpg"));
cfBm = new Bitmap(cfPhoto, new Size(215, 170));
pictureCf = worksheet.Drawings.AddPicture(cfP.Id.ToString(), cfBm);
pictureCf.SetPosition(i+1, 0, photoInitialColumn, 10);
worksheet.Cells[_alpha[photoInitialColumn] + (i + 3) + ':' + _alpha[photoInitialColumn + 1] + (i + 3)].Merge = true;
worksheet.Cells[_alpha[photoInitialColumn] + (i + 3) + ':' + _alpha[photoInitialColumn + 1] + (i + 3)].Value = cfP.comment;
worksheet.Cells[_alpha[photoInitialColumn] + (i + 3) + ':' + _alpha[photoInitialColumn + 1] + (i + 3)].Style.WrapText = true;
photoInitialColumn += 2;
//HERE I SET THE HEIGHT. At this point, i == 18
worksheet.Row(i+2).Height = 180;
});
But, I have a company logo at the top of the Excel file (A1 cell) which gets resized as well (on height). That is defined like this:
Image _keyLogo = Image.FromFile(HostingEnvironment.MapPath("~/Content/Images/key_logo.png"));
var pictureLogo = worksheet.Drawings.AddPicture("Logo Key Quimica", _keyLogo);
pictureLogo.SetPosition(0, 0, 0, 0);
Resulting on this:
Any help would be really appreciated.
Here is the excel file in question.
It comes down to the EditAs setting of the picture logo. By default it will be set to OneCell but setting it to TwoCell I believe will solve your problem. The documentation on it (looking at EPP 4.0.1) is rather cryptic but it basically says this setting will tell the drawing to maintain its original row/column position and size. The names seem a bit counter intuitive though.
I had to guess what your code looks like (let me know if I got it wrong) and I was able to reproduce the problem you were having and then solve with the EditAs setting:
[TestMethod]
public void Image_Stretch_Test()
{
//http://stackoverflow.com/questions/27873762/weird-behavior-when-setting-a-rows-height-on-epplus
var existingFile = new FileInfo(#"c:\temp\temp.xlsx");
if (existingFile.Exists)
existingFile.Delete();
using (var package = new ExcelPackage(existingFile))
{
var workbook = package.Workbook;
var worksheet = workbook.Worksheets.Add("newsheet");
var _keyLogo = Image.FromFile("C:/Users/Ernie/Desktop/key_logo.png");
var pictureLogo = worksheet.Drawings.AddPicture("Logo Key Quimica", _keyLogo);
pictureLogo.SetPosition(0, 0, 0, 0);
pictureLogo.EditAs = eEditAs.TwoCell; //REMOVE THIS TO SHOW THE STRETCH PROBLEM
var cfPhoto = Image.FromFile("C:/Users/Ernie/Desktop/Main_Pic.png");
var cfBm = new Bitmap(cfPhoto, new Size(215, 170));
var pictureCf = worksheet.Drawings.AddPicture("Main_Pic", cfBm);
pictureCf.SetPosition(10, 0, 0, 0);
worksheet.Row(11).Height = 280;
package.Save();
}
}
The other thing that fix it was add the logo AFTER the row resize but not sure if that is practical to what you are trying to do.
Related
I have C# code writing to Excel. The following code works:
var probForExcel = new string[profileSize, 1];
Range range3 = worksheet.Range["C5", "C" + (startRow + profileSize - 1)];
range3.Value = probForExcel;
range3.NumberFormat = "0.00000000000E+0";
range3.Formula = range3.Value2; //NEEDED FOR ACTUAL FORMULAS otherwise writes in xls as string
Now I am trying to use a List of Type Range:
var formulaForExcel = new List<string[,]>();
var formularange1 = new List<Range>();
for (var i = 0; i < profileSize; i++)
{
var count = formulas[i].Count();
formularange1.Add(worksheet.Range[worksheet.Cells[rowTracker, 2], worksheet.Cells[rowTracker, count]]);
formulaForExcel.Add(new string[1, count]);
var j = 0;
foreach (var formula in formulas[i])
{
formulaForExcel[i][0, j] = formula;
j++;
}
formularange1[i].Value = formulaForExcel[i];
formularange1[i].Formula = formularange1[i].Value2;//CRASHES HERE
rowTracker++;
}
The program runs without the following line of code:
formularange1[i].Formula = formularange1[i].Value2;//CRASHES HERE
System.Runtime.InteropServices.COMException: 'Exception from HRESULT: 0x800A03EC'
But it prints the formula as a string without that line of code and I have to go into each cell and hit enter for it to evaluate as a formula.
Why does the syntax work, no compile errors. And it runs in the first part of the code, where it's not in a list. I put Range in a list and it crashes.
Unsure if the .Formula is causing the crash or the .Value2.
I get the same error if I do this
Range temp = formularange1[i];
temp.Formula = temp.Value2; //CRASHES HERE
Found another post about Excel that helped me find my bug. Because my excel formulas were automatically being built and very large, I didn't realize some of my formulas ended in a + sign. Because I was adding things and checking length, some ended in +.
So I was doing a find and replace "=" with "=" and that would cause all the formulas to evaluate. Except for the ones with a + at the end, excel threw an error. Once I found this and updated my formula builder, now this works:
for (var i = 0; i < profileSize; i++)
{
var count = formulas[i].Count();
sumrangeForExcel[i, 0] = "=sum(C" + rowTracker + ":c" + rowTracker + ")";
formularange1.Add(worksheet.Range[worksheet.Cells[rowTracker, 3], worksheet.Cells[rowTracker,3+ count-1]]);
formulaForExcel.Add(new string[1, count]);
var j = 0;
foreach (var formula in formulas[i])
{
formulaForExcel[i][0, j] = formula;
//formularange1[i][0, j].Formula = formularange1[i][0, j].Value2; Erased my formulas
j++;
}
formularange1[i].Value = formulaForExcel[i];
formularange1[i].Formula = formularange1[i].Value2;//NO CRASHING
formularange1[i].NumberFormat = "###,###,##0";
rowTracker++;
}
So, using interop is not easy and does not have the best error checking. The error I had was unrelated to my actual problem.
I'm making a telegram bot with c#.
I want to read a number of names (not more than 20 tough thy could be less) and give them to the user as keyboardMarkup. With a one dimensional array they go all in one line and it's unreadable. I wanted to make 4 line with 5 names so i tried a 4x5 array. But i get this error
Error CS0029 Cannot implicitly convert type 'NetTelegramBotApi.Types.KeyboardButton[,]' to 'NetTelegramBotApi.Types.KeyboardButton[][]'
if (text == "/lista")
{
// Read a text file line by line.
listapz = System.IO.File.ReadAllLines("listapz.txt");
string selezione = "Seleziona il paziente:";
int i = 0;
int x = 0;
int y = 0;
var arrays = new KeyboardButton[4,5];
for (i = 0; i < listapz.Length; i++)
{
y = i / 5;
x = i - (y * 5);
arrays[y,x] = new KeyboardButton("$" + (i + 1) + " " + listapz[i]);
selezione += "\n$" + (i + 1) + " " + listapz[i] + "";
}
var keyb = new ReplyKeyboardMarkup()
{
Keyboard = arrays,
OneTimeKeyboard = true,
ResizeKeyboard = true
};
var reqAction = new SendMessage(update.Message.Chat.Id, selezione) { ReplyMarkup = keyb };
bot.MakeRequestAsync(reqAction).Wait();
Console.WriteLine(reqAction);
continue;
}
any solution?
You can create new one dimensional array for every line
Then
keyb.row(first_array) //you need get only values in python it will like keyb.row(*array)
keyb.row(second_array) //and so on
and add all keyboards in one reply_markup=keyb
I am creating an Excel export that contains several pie charts which are dynamically created based on data from a database that is dumped into a range of cells within the spreadsheet. I need the data labels for the pie charts to be on the outside end of the pie chart. The data labels by default are set to best fit.
I have tried to manipulate the data label positions with eLabelPosition which has an OutEnd property but have had no luck. Doing this causes the data labels to completely disappear.
Below is the method I am using to generate my pie charts.
private void AddPieChart(ExcelWorksheet worksheet, int firstDataRow, int firstDataColumn, int lastDataRow, int nextColumn, int firstColumn)
{
ExcelPieChart pieChart = worksheet.Drawings.AddChart(worksheet.Name.ToString() + " Pie Chart", eChartType.Pie3D) as ExcelPieChart;
var serie = pieChart.Series.Add(ExcelCellBase.GetAddress(firstDataRow + 3, firstDataColumn, lastDataRow + 3, firstDataColumn),
ExcelCellBase.GetAddress(firstDataRow + 3, firstColumn, lastDataRow + 3, firstColumn));
pieChart.DataLabel.ShowCategory = true;
pieChart.DataLabel.ShowLeaderLines = true;
pieChart.DataLabel.Font.Bold = true;
pieChart.DataLabel.Font.Size = 12;
pieChart.Legend.Remove();
pieChart.SetSize(500, 350);
pieChart.SetPosition(lastDataRow + 5, 0, nextColumn - 1, 0);
pieChart.Border.Fill.Color = Color.White;
pieChart.Series.Chart.RoundedCorners = false;
var pieSerie = (ExcelPieChartSerie)serie;
pieSerie.DataLabel.Position = eLabelPosition.OutEnd;
}
It appears that if you have DataLabel properties assigned to your ExcelPieChart and then also attempt to assign the DataLabel properties on the ExcelPieChartSerie is does not apply the property to the ExcelPieChartSerie. In order to fix this remove any of the DataLabel properties on the ExcelPieChart and instead add them to the ExcelPieChartSerie as shown below.
private void AddPieChart(ExcelWorksheet worksheet, int firstDataRow, int firstDataColumn, int lastDataRow, int nextColumn, int firstColumn)
{
ExcelPieChart pieChart = worksheet.Drawings.AddChart(worksheet.Name.ToString() + " Pie Chart", eChartType.Pie3D) as ExcelPieChart;
var serie = pieChart.Series.Add(ExcelCellBase.GetAddress(firstDataRow + 3, firstDataColumn, lastDataRow + 3, firstDataColumn),
ExcelCellBase.GetAddress(firstDataRow + 3, firstColumn, lastDataRow + 3, firstColumn));
pieChart.Legend.Remove();
pieChart.SetSize(500, 350);
pieChart.SetPosition(lastDataRow + 5, 0, nextColumn - 1, 0);
pieChart.Border.Fill.Color = Color.White;
pieChart.Series.Chart.RoundedCorners = false;
var pieSerie = (ExcelPieChartSerie)serie;
pieSerie.DataLabel.ShowCategory = true;
pieSerie.DataLabel.ShowLeaderLines = true;
pieSerie.DataLabel.Font.Bold = true;
pieSerie.DataLabel.Font.Size = 12;
pieSerie.DataLabel.Position = eLabelPosition.OutEnd;
}
so in unity im creating randomly generating rooms. inside of these rooms i will "randomly" place objects, enemy,objects,items etc. based on nodes. nodes are transform objects that are separated from each other by 1 unit. the idea is that i can now pick a node and instantiate something at that node. The code works great when the room is 10x10(x,z since its a 3d game) i get a nice grid pattern it also works as expected when x is any multiple of 2. however when z changes from 10 it doesn't create the grid properly. there is also a problem if the room changes locations other then 0,0.
floor is a child object of the room.
void RoomSetup()
{
bool first = true;
int collCount = -1;
GameObject placeHolder = new GameObject("temp");
float colls;
float offX, offZ;
colls = floor.transform.localScale.x - 1;
print(colls);
for (int i = 0; i < ((floor.transform.localScale.x-1)
*(floor.transform.localScale.z-1)); i++)
{
//creating a for loop that stops when its greater then the area of the rectangle, subtract one from x,z so theres a one unit of padding from the walls.
offX = floor.transform.lossyPosition.x;
offZ = floor.transform.lossyPosition.z;
//getting the offset of the room in world space this is where i believe the issues arise
collCount++;
GameObject temp = new GameObject(i + " Node");
temp.transform.SetParent(floor.transform);
temp.AddComponent<BoxCollider>();
temp.GetComponent<BoxCollider>().isTrigger = true;
if(!first)
{
temp.transform.position = new Vector3((placeHolder.transform.position.x + 1), 6, placeHolder.transform.position.z);
placeHolder = temp;
if (collCount >= colls)
{
print("new line on " + temp.name + " coll " + collCount);
collCount = 0;
placeHolder.transform.position = new Vector3((-(floor.transform.localScale.x / 2) + 1)+offX, 6, (placeHolder.transform.position.z - 1)-offZ);
}
}
if (first)
{
// print(colls);
temp.transform.position = new Vector3((-(floor.transform.localScale.x / 2) + 1) + offX, 6, floor.transform.localScale.z - offZ);
placeHolder = temp;
first = false;
}
nodes.Add(temp);
}
}
Here are some pictures to help illustrate the issue
the first image is when the room is at 0,0 and it creates a nice grid pattern
when the room is offest it creates the grid still at 0,0
i figured it out, it happend to do with with the local and world scale/pos of the floor and the room
void RoomSetup()
{
bool first = true;
int collCount = -1;
GameObject placeHolder = new GameObject("temp");
float colls;
colls = floor.transform.localScale.x - 1;
offX = floor.transform.localScale.x;
offZ = floor.transform.localScale.z;
offX = (offX / 2) - offX + 1;
offZ = (offZ / 2) - 1;
offX = offX + floor.transform.position.x;
offZ = (offZ + floor.transform.position.z);
print(colls);
for (int i = 0; i < ((floor.transform.localScale.x-1) * (floor.transform.localScale.z-1)); i++)
{
collCount++;
//print(collCount);
GameObject temp = new GameObject(i + " Node");
temp.transform.SetParent(floor.transform);
temp.AddComponent<BoxCollider>();
temp.GetComponent<BoxCollider>().isTrigger = true;
if(!first)
{
temp.transform.position = new Vector3((placeHolder.transform.position.x + 1), 6, placeHolder.transform.position.z);
placeHolder = temp;
if (collCount >= colls)
{
print("new line on " + temp.name + " coll " + collCount);
collCount = 0;
temp.transform.position = new Vector3(floor.transform.localPosition.x + offX, 6, placeHolder.transform.position.z - 1);
placeHolder = temp;
}
}
if (first)
{
// print(colls);
temp.transform.position = new Vector3(floor.transform.localPosition.x+offX, 6, floor.transform.localPosition.z+offZ);
placeHolder = temp;
first = false;
}
nodes.Add(temp);
}
}
works as intended, creates a grid of nodes on the floor of anyroom square room
Hi I would like to add some extra space after a image in my iTextSharp generated pdf document. But for some reason whatever I try to do it will not prevent my text from wrapping
Example image
As you can see the "to read everyth..." does not indent like the rest
This is the codesnip that should do this:
var brevityBox = iTextSharp.text.Image.GetInstance("http://" + domain + "/ImageGen.ashx?Text=" + brevityScore + "&FontSize=120&&FontStyle=Bold&Font=Calibri&Align=Center&image=/media/images/PDF/BrevityBox.jpg");
brevityBox.ScaleToFit(80f, 220f);
brevityBox.Alignment = Image.TEXTWRAP;
brevityBox.SpacingAfter = 460f;
doc.Add(brevityBox);
Chunk c3 = new Chunk(brevityText, FontFactory.GetFont("Verdana", 12, Font.NORMAL)); ;
Paragraph p3 = new Paragraph();
p3.IndentationLeft = 20;
p3.IndentationRight = 20;
p3.Alignment = Element.ALIGN_LEFT;
p3.Add(c3);
doc.Add(p3);
Just to prove the point the SpacingAfter is 460 points.
IndentationRight
works fine
Any ideas?
I believe that iTextSharp is not even using the SpacingAfter property. I modified the method
iTextSharp.text.pdf.PdfDocument.Add(iTextSharp.text.Image image){}
to this:
if (imageEnd < 0 || imageEnd < currentHeight + image.ScaledHeight + diff + image.SpacingAfter)
{
imageEnd = currentHeight + image.ScaledHeight + diff + image.SpacingAfter;
}
From v5.2.1 it was line 2244 in PdfDocument.cs