Is there an easy way to copy the format of a cell (eg background color, font type, borders etc...) from one cell to another with EPPlus v4.5.3.3?
Ive noticed the following question from a while back, but the accepted answer doesn't make any sense to me!
EPPlus: Copy Style to a range
At the moment I'm having to hard code each individual property across one by one using a custom function, but was hoping there was a better way to do it? Im also hitting some limitations with this method, particularly around colours, because if I have used a more unusual colour (eg picked from a colour wheel) then I cant seem to set all the color properties on the new cell in order to replicate the colour (they are marked as "get" only", eg Theme")
private void ApplyStyleToCell(OfficeOpenXml.Style.ExcelStyle cellStyle, ExcelRangeBase cellsToApplyTo )
{
// You cant write the whole ExcelStyle object to a new cell, so we need to update each part of the style individually
cellsToApplyTo.Style.Border = cellStyle.Border;
cellsToApplyTo.Style.Fill.PatternType = cellStyle.Fill.PatternType;
if(cellStyle.Fill.BackgroundColor.Rgb != null){ cellsToApplyTo.Style.Fill.BackgroundColor.SetColor(ColorTranslator.FromHtml("#" + cellStyle.Fill.BackgroundColor.Rgb)); }
cellsToApplyTo.Style.Fill.PatternType = cellStyle.Fill.PatternType;
cellsToApplyTo.Style.Font.Bold = cellStyle.Font.Bold;
if (cellStyle.Font.Color.Rgb != null && cellStyle.Font.Color.Rgb != "") { cellsToApplyTo.Style.Font.Color.SetColor(ColorTranslator.FromHtml("#" + cellStyle.Font.Color.Rgb)); }
if (cellStyle.Font.Color.Rgb != null && cellStyle.Font.Color.Theme != "") { cellsToApplyTo.Style.Font.Color.Theme = cellStyle.Font.Color.Theme; }
cellsToApplyTo.Style.Font.Family = cellStyle.Font.Family;
cellsToApplyTo.Style.Font.Italic = cellStyle.Font.Italic;
// etc...
}
Related
I would like to take a PowerPoint slide (the "source"), and insert it into another PowerPoint slide (the "target") that already contains some content, at a specific position in the source PowerPoint slide.
I've tried several ways to research code that does this, but I keep getting results for merging slides into PowerPoint presentations, which is not what I want. I want to take an existing slide and insert it into another, much like one would insert a picture into an existing slide.
I have code that another coworker wrote that clones all of the elements from the source slide, but it is convoluted and uses different code variations for different element types. Here is a representative sample of that code:
foreach (OpenXmlElement element in sourceSlide.CommonSlideData.ShapeTree.ChildElements.ToList())
{
string elementTypeName = element.GetType().ToString();
if (elementTypeName.EndsWith(".Picture"))
{
// Deep clone the element.
elementClone = element.CloneNode(true);
// Adjust the offsets so it is positioned correctly.
((Picture)elementClone).ShapeProperties.Transform2D.Offset.X += (Int64)shapeStruct.OffsetX;
((Picture)elementClone).ShapeProperties.Transform2D.Offset.Y += (Int64)shapeStruct.OffsetY;
// Get the shape tree that we're adding the clone to and append to it.
ShapeTree shapeTree = slideCard.CommonSlideData.ShapeTree;
shapeTree.Append(elementClone);
string rId = ((Picture)element).BlipFill.Blip.Embed.Value;
ImagePart imagePart = (ImagePart)slideInstProc.SlidePart.GetPartById(rId);
string contentType = imagePart.ContentType;
// Locate the same object we cloned over to the slide.
var blip = ((Picture)elementClone).BlipFill.Blip;
slidePart = slideCard.SlidePart;
try
{
ImagePart imagePart1 = slidePart.AddImagePart(contentType, rId);
imagePart1.FeedData(imagePart.GetStream());
}
catch (XmlException)
{
//Console.WriteLine(xe.ToString());
Console.WriteLine("Duplicate rId (" + rId + ")");
}
}
if (elementTypeName.EndsWith(".GroupShape"))
{
... etc
The code continues with an else-if ladder containing blocks of code for element type names ending with .GroupShape, .GraphicFrame, .Shape, and .ConnectionShape, concluding with a catchall else at the bottom.
The problem is this code doesn't process some types of objects properly. For one thing, it doesn't process drawings at all (perhaps because some of them originated from an older version of PowerPoint), and when it does, it does things like change the color of the drawing.
What I was hoping is that there was a more fundamental way (i.e. simpler, generic code) to embed a source PowerPoint slide into another, treating it like a single object, without looking at element types within the source PowerPoint specifically.
Alternatively, what would be the way to process drawings or images in ordinary "shapes" that don't identify themselves specifically as images?
This is the code that solved the specific problem I was describing above:
using A = DocumentFormat.OpenXml.Drawing;
foreach(A.BlipFill blipFill in shape.Descendants<A.BlipFill>())
{
string rId = blipFill.Blip.Embed.Value;
ImagePart imagePart = (ImagePart)slideInstProc.SlidePart.GetPartById(rId);
string contentType = imagePart.ContentType;
try
{
ImagePart imagePart1 = slidePart.AddImagePart(contentType, rId);
imagePart1.FeedData(imagePart.GetStream());
}
catch (XmlException)
{
Console.WriteLine("Duplicate rId (" + rId + ")");
}
}
Which, when applied to elementTypeName.EndsWith(".shape"); produces exactly the result I want.
For composing complete slides into a presentation (which doesn't require some of the generation mechanics that we do), OpenXmlPowerTools is a much better approach.
My TableView is populated with data from a list of objects. The first column is a Boolean value.
Instead of displaying True or False in the cell, I would like to display an image if True and leave the cell empty if it's False.
This is how I populate the TableView:
colStarred.setCellValueFactory(new PropertyValueFactory<>("starred"));
colDate.setCellValueFactory(new PropertyValueFactory<>("date"));
colTime.setCellValueFactory(new PropertyValueFactory<>("time"));
I know that I need to use a custom TableCell and a CellValueFactory but I'm having a hard time wrapping my head around the documentation (I have not used Java factories in the past).
My research has lead to several answers regarding similar situations, but they all seem to deal with just displaying an image in the cell. I have been unable to find a solution for checking a boolean to determine whether an image should be displayed or not.
How do I check the starredProperty of my objects and show an image if it is True?
Thank you for all the help everyone has provided me in the past!
I'll assume the column to be a TableColumn<MyItemClass, Boolean>.
You simply create TableCells that adjust their look according to the item that gets passed to the updateItem method.
In this case we'll use a ImageView as graphic of the cell.
The following images are displayed depending on the item of the cell:
no image if the cell is empty or contains null
imageTrue if the item is true
imageFalse otherwise
You may of course use imageFalse = null for an empty cell when the item is false.
final Image imageTrue = ...
final Image imageFalse = ...
// set cellfactory
colStarred.setCellFactory(col -> new TableCell<MyItemClass, Boolean>() {
private final ImageView imageView = new ImageView();
{
// initialize ImageView + set as graphic
imageView.setFitWidth(20);
imageView.setFitHeight(20);
setGraphic(imageView);
}
#Override
protected void updateItem(Boolean item, boolean empty) {
if (empty || item == null) {
// no image for empty cells
imageView.setImage(null);
} else {
// set image for non-empty cell
imageView.setImage(item ? imageTrue : imageFalse);
}
}
});
What happens when the program is displayed is this:
The TableView creates cells needed to display the items using the cellfactories.
The TableView assigns the items to the cells. These items may be changed multiple times. Cells may also become empty after being filled. When this happens the updateItem methods of the TableCells are called.
I know how to use VS Extensibility to get the entire active document's text. Unfortunately, that only gets me the text and doesn't give me the formatting, and I want that too.
I can, for example, get an IWpfTextView but once I get it, I'm not sure what to do with it. Are there examples of actually getting all the formatting from it? I'm only really interested in text foreground/background color, that's it.
Note: I need the formatted text on every edit, so unfortunately doing cut-and-paste using the clipboard is not an option.
Possibly the simplest method is to select all of the text and copy it to the clipboard. VS puts the rich text into the clipboard, so when you paste, elsewhere, you'll get the colors (assuming you handle rich text in your destination).
Here's my not-the-simplest solution. TL;DR: you can jump to the code at https://github.com/jimmylewis/GetVSTextViewFormattedTextSample.
The VS editor uses "classifications" to show segments of text which have special meaning. These classifications can then be formatted differently according to the language and user settings.
There's an API for getting the classifications in a document, but it didn't work for me. Or other people, apparently. But we can still get the classifications through an ITagAggregator<IClassificationTag>, as described in the preceding link, or right here:
[Import]
IViewTagAggregatorFactoryService tagAggregatorFactory = null;
// in some method...
var classificationAggregator = tagAggregatorFactory.CreateTagAggregator<IClassificationTag>(textView);
var wholeBufferSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, 0, textBuffer.CurrentSnapshot.Length);
var tags = classificationAggregator.GetTags(wholeBufferSpan);
Armed with these, we can rebuild the document. It's important to note that some text is not classified, so you have to piece everything together in chunks.
It's also notable that at this point, we have no idea how any of these tags are formatted - i.e. the colors used during rendering. If you want to, you can define your own mapping from IClassificationType to a color of your choice. Or, we can ask VS for what it would do using an IClassificationFormatMap. Again, remember, this is affected by user settings, Light vs. Dark theme, etc.
Either way, it could look something like this:
// Magic sauce pt1: See the example repo for an RTFStringBuilder I threw together.
RTFStringBuilder sb = new RTFStringBuilder();
var wholeBufferSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, 0, textBuffer.CurrentSnapshot.Length);
// Magic sauce pt2: see the example repo, but it's basically just
// mapping the spans from the snippet above with the formatting settings
// from the IClassificationFormatMap.
var textSpans = GetTextSpansWithFormatting(textBuffer);
int currentPos = 0;
var formattedSpanEnumerator = textSpans.GetEnumerator();
while (currentPos < wholeBufferSpan.Length && formattedSpanEnumerator.MoveNext())
{
var spanToFormat = formattedSpanEnumerator.Current;
if (currentPos < spanToFormat.Span.Start)
{
int unformattedLength = spanToFormat.Span.Start - currentPos;
SnapshotSpan unformattedSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, currentPos, unformattedLength);
sb.AppendText(unformattedSpan.GetText(), System.Drawing.Color.Black);
}
System.Drawing.Color textColor = GetTextColor(spanToFormat.Formatting.ForegroundBrush);
sb.AppendText(spanToFormat.Span.GetText(), textColor);
currentPos = spanToFormat.Span.End;
}
if (currentPos < wholeBufferSpan.Length)
{
// append any remaining unformatted text
SnapshotSpan unformattedSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, currentPos, wholeBufferSpan.Length - currentPos);
sb.AppendText(unformattedSpan.GetText(), System.Drawing.Color.Black);
}
return sb.ToString();
Hope this helps with whatever you're doing. The example repo will ask if you you want the formatted text in the clipboard after each edit, but that was just a dirty way that I could test and see that it worked. It's annoying, but it was just a PoC.
As part of a project I am realizing, there are given pdfdocuments which include forms as JPEG Images within A4 pages inside this documents. If have to extract those JPGs out of the PDF. Later on those JPGs are used to build PDF Documents again.
When I simply open up those Documents with any PDFViewer they seem to have no rotation at all, at least it is not visible. So like this icon the have vertical format.
but when I use this sample code to extract the images :
PDDocument doc = PDDocument.load("/path/to/file);
List pages = doc.getDocumentCatalog().getAllPages();
Iterator iter = pages.iterator();
int i = 0;
while (iter.hasNext()) {
PDPage page = (PDPage) iter.next();
System.out.println(page.getRotation());
System.out.println("ROTATION = " + page.getRotation());;
PDResources resources = page.getResources();
Map pageImages = resources.getXObjects();
if (pageImages != null) {
Iterator imageIter = pageImages.keySet().iterator();
while (imageIter.hasNext()) {
String key = (String) imageIter.next();
if(((PDXObjectImage) pageImages.get(key)) instanceof PDXObjectImage){
PDXObjectImage image = (PDXObjectImage) pageImages.get(key);
image.write2file("/path/to/file" + i);
}
i ++;
}
}
}
all extracted JPGs are horizontal format. Further the sysout on the page.rotation tells me that the rotation is set to 270°.
How is that possible? 270 is set, but the PDF is shown vertical (I am no expert on PDF). I even did page.setRotate(0) before extracting the JPGs, but the images still remain horizontally. I read the following Thread telling how to rotate images before drawing them on the pdf. But i need to rotate them before writing them on the filesystem. What is the best way to achieve that?
Unfortunately, I can not attach any of the documents since they are confidential.
I have a 5 ViewModels. Every view has their own VM. When I start the program, the ViewModel changes the bindings, i.e.
private string _bruttolohn;
public string Bruttolohn
{
get { return _bruttolohn; }
set
{
if (value != null)
{
if (value != _bruttolohn)
{
_bruttolohn = value;
Calculate();
RaisePropertyChanged(() => Bruttolohn);
}
}
}
}
Bruttolohn = some value I put in to calculate and set the new values. I have ~100 other propertys, which are all using Binding. If I start the program, the calculation is fine and works fast! But when I change the View (All views are in a ContentControl. If I click on a button, the view is being changed like this: MyContent.Content = new FirstView();). Now here's the problem: If I change the view ~30 times, the ViewModel needs way too long to set the bindings. Why!?
+ If I debug and I'm at this point:
RaisePropertyChanged(() => Bruttolohn);
Error pops up: ObservableObject.cs is missing...?
There is nothing wrong with the code you've shown so I suspect the Calculation method. Profile it.
If the Calculation() method is too long to post, it shouldn't be in a property setter :)
I guess I found the solution. Every time I click on the button "FirstView", the Content of the ContentControl gets a NEW VIEW()! So every time I click on the button, it'll do:
MyContent.Content = new FirstView();
This means that there are still somehow Views in the background open... I can't explain it by myself, but if I set the View globally like
FirstView fw;
and say in the constructor of the MainViewModel
fw = new FirstView();
I can easily assign the content of my ContentControl like this (without creating a new View):
MyContent.Content = fw;
You can download a test app here: http://www65.zippyshare.com/v/89159114/file.html
It has a MainView and 2 Views. It shows my problem. If you click on the Button "FirstView", the content of the contentcontrol will be "FirstView.xaml". It has 2 textboxes, which calculate the sum and has a for-loop (for i = 0, i < 500, i++). If you calculate right at the start, the calculation takes only ~1 sec, but if you click the Button "FirstView" ~30 times and try to calculate again, the calculation takes more than 10 sec!!!
I thinks it's because of MyContent.Content = new FirstView(); You can check my program and correct me if I'm wrong or say if I'm right... Like I said, I think that this is the solution, but I'm not 100% sure.
if Calculate() isn't an async method, it blocks the UI.
You could use
Task.Run(() =>
{
Calculate();
RaisePropertyChanged(() => Bruttolohn);
});
Not relevant to your question, but maybe interesting:
if (value != _bruttolohn)
Strings should be compared using .Equals, as the same string can be referenced to different places in the heap.
So:
if (value == null || !value.Equals(_bruttolohn))