I use Aspose.Word. When you try to resize the page, everything changes. BUT the images go beyond the boundaries of the text space.
There are several images in the document and I have no idea how to fix it.
`
var input = #"d:\1.docx";
var output = #"d:\2.docx";
Document doc = new Document(input);
DocumentBuilder builder = new DocumentBuilder(doc);
if (project.Variables["flagsize"].Value=="69")
{
builder.PageSetup.PageWidth = ConvertUtil.MillimeterToPoint(152.4);
builder.PageSetup.PageHeight = ConvertUtil.MillimeterToPoint(228.6);
Node[] runs = doc.GetChildNodes(NodeType.Run, true).ToArray();
for (int j = 0; j < runs.Length; j++)
{ Run run = (Run)runs[j];
run.Font.Size = 18;
}
}
foreach (Section section in doc)
{
section.PageSetup.PaperSize = Aspose.Words.PaperSize.Custom;
section.PageSetup.LeftMargin= ConvertUtil.MillimeterToPoint(22);
section.PageSetup.RightMargin= ConvertUtil.MillimeterToPoint(22);
}
doc.Save(output);
`
Try to find correct method of word.
Expecting all images at doc will be right dimensions
I think this code i need:
foreach (Aspose.Words.Drawing.Shape shape in doc)
{
shape.Width ...
}
But i have error :
Не удалось привести тип объекта "Aspose.Words.Section" к типу "Aspose.Words.Drawing.Shape".
To get all shapes in the document, you can use Document.GetChildNodes method passing the appropriate NodeType as a parameter. For example the following code returns all shapes in the document:
NodeCollection shapes = doc.GetChildNodes(NodeType.Shape, true);
You can use LINQ to filter the collection, for example the following code returns shapes that has an image:
List<Shape> shapes = doc.GetChildNodes(NodeType.Shape, true)
.Cast<Shape>().Where(s => s.HasImage).ToList();
It looks like your requirement is to fit the image to image size. I think the example provided here might be useful for you. In the provided example an image is instead into the document and page is adjusted to the actual image size. Then the result document is converted to PDF.
NodeCollection shapes = doc.GetChildNodes(NodeType.Shape, true);
PageSetup page_Setup = doc.FirstSection.PageSetup;
foreach (Shape shape in shapes)
{
shape.HorizontalAlignment = HorizontalAlignment.Center;
shape.Width = page_Setup.PageWidth - page_Setup.LeftMargin - page_Setup.RightMargin;
}
Related
The code below copies all pages from a PDF file to a new file and inserts on the first page a rectangle at the top with a red border holding a short text.
If I don't move it, a gap will be left at the top (here enlarged a lot, font size is 8 only):
However, if I move the rectangle up by an empiric value of 4:
iText.Kernel.Geom.Rectangle pageSize = firstPage.GetCropBox().MoveUp(4);
there will be a perfect match at the top:
The value 4 is not related to the font size.
I dislike magic numbers in code so, my question is: Why 4? What expression would reveal this value of 4?
The code line is in the first method here. The second is where it is used, and third is called from the first; it just supplies a style:
private static void RegisterDocument(PdfDocument pdfDocument, string registration)
{
// Magic value to close gap between top of page and top of rectangle with the registration.
const float moveUp = 4F;
Document document = new Document(pdfDocument, new PageSize(PageSize.A4));
PdfPage firstPage = document.GetPdfDocument().GetFirstPage();
Paragraph paragraph = new Paragraph(registration).AddStyle(RegistrationStyle());
iText.Kernel.Geom.Rectangle pageSize = firstPage.GetCropBox().MoveUp(moveUp);
LayoutContext layoutContext = new LayoutContext(new LayoutArea(1, pageSize));
IRenderer renderer = paragraph.CreateRendererSubTree();
renderer.SetParent(document.GetRenderer()).Layout(layoutContext);
Canvas canvas = new Canvas(new PdfCanvas(firstPage, true), pageSize);
canvas.Add(paragraph);
document.Close();
}
public static void RegisterPdf(string sourceFilename, string targetFilename, string registration)
{
if (registration.Length > 0)
{
// Open source and target PDF files.
PdfDocument sourcePdf = new PdfDocument(new PdfReader(sourceFilename));
PdfDocument targetPdf = new PdfDocument(new PdfWriter(targetFilename));
// Copy all pages from source PDF to target PDF.
sourcePdf.CopyPagesTo(1, sourcePdf.GetNumberOfPages(), targetPdf);
// Add registration to page 1 of target and save the document.
RegisterDocument(targetPdf, registration);
// Close the files.
sourcePdf.Close();
targetPdf.Close();
}
}
private static Style RegistrationStyle()
{
// Fixed design values for font and rectangle.
PdfFont font = PdfFontFactory.CreateFont(StandardFonts.HELVETICA);
const float fontSize = 8F;
const float rightPadding = 3F;
TextAlignment textAlignment = TextAlignment.RIGHT;
iText.Kernel.Colors.Color borderColor = ColorConstants.RED;
iText.Kernel.Colors.Color fillColor = ColorConstants.WHITE;
const float borderWidth = 0.7F;
Style style = new Style()
.SetFont(font)
.SetFontSize(fontSize)
.SetPaddingRight(rightPadding)
.SetTextAlignment(textAlignment)
.SetBackgroundColor(fillColor)
.SetBorder(new SolidBorder(borderColor, borderWidth));
return style;
}
You wonder
I dislike magic numbers in code so, my question is: Why 4? What expression would reveal this value of 4?
iText, when calculating the layout of some entity, retrieves properties from multiple sources, in particular the entity itself and its renderer. And it does not only ask them for explicitly set properties but also for defaults.
In the case at hand you see the default top margin value of the Paragraph class at work:
public override T1 GetDefaultProperty<T1>(int property) {
switch (property) {
case Property.LEADING: {
return (T1)(Object)new Leading(Leading.MULTIPLIED, childElements.Count == 1 && childElements[0] is Image ?
1 : 1.35f);
}
case Property.FIRST_LINE_INDENT: {
return (T1)(Object)0f;
}
case Property.MARGIN_TOP:
case Property.MARGIN_BOTTOM: {
return (T1)(Object)UnitValue.CreatePointValue(4f);
}
case Property.TAB_DEFAULT: {
return (T1)(Object)50f;
}
default: {
return base.GetDefaultProperty<T1>(property);
}
}
}
(iText Layout Paragraph method)
If you set the top margin of your paragraph to 0, you can simplify your code considerably:
public static void RegisterPdfImproved(string sourceFilename, string targetFilename, string registration)
{
using (PdfDocument pdf = new PdfDocument(new PdfReader(sourceFilename), new PdfWriter(targetFilename)))
using (Document document = new Document(pdf))
{
document.SetMargins(0, 0, 0, 0);
Paragraph paragraph = new Paragraph(registration)
.AddStyle(RegistrationStyle())
.SetMarginTop(0);
document.Add(paragraph);
}
}
Without any magic values you now get
There is no way to tell, without seeing all the details of your code. It could depend on an arbitrary number of circumstances and combinations of them. Examples:
default values in the PDF library you are using
margins defined in the document
According to this post (Removing Watermark from PDF iTextSharp) , #mkl code works fine for ExGstate graphical watermarks but I have tested this code to remove watermark from some files which have Text based watermarks behind PDF contents (like this file : http://s000.tinyupload.com/index.php?file_id=05961025831018336372)
I have tried multiple solutions that found in this site but get no success.
Can anyone help to remove this watermark types by changing above #mkl solution?
thanks
Just like in the case of the question the OP references (Removing Watermark from PDF iTextSharp), you can remove the watermark from your sample file by building upon the PdfContentStreamEditor class presented in my answer to that question.
In contrast to the solution in that other answer, though, we do not want to hide vector graphics based on some transparency value but instead the writing "Archive of SID" from this:
First we have to select a criterion to recognize the background text by. Let's use the fact that the writing is by far the largest here. Using this criterion makes the task at hand essentially the iTextSharp/C# pendant to this iText/Java solution.
There is a problem, though: As mentioned in that answer:
The gs().getFontSize() used in the second sample may not be what you expect it to be as sometimes the coordinate system has been stretched by the current transformation matrix and the text matrix. The code can be extended to consider these effects.
Exactly this is happening here: A font size of 1 is used and that small text then is stretched by means of the text matrix:
/NxF0 1 Tf
49.516754 49.477234 -49.477234 49.516754 176.690933 217.316086 Tm
Thus, we need to take the text matrix into account. Unfortunately the text matrix is a private member. Thus, we will also need some reflection magic.
Thus, a possible background remover for that file looks like this:
class BigTextRemover : PdfContentStreamEditor
{
protected override void Write(PdfContentStreamProcessor processor, PdfLiteral operatorLit, List<PdfObject> operands)
{
if (TEXT_SHOWING_OPERATORS.Contains(operatorLit.ToString()))
{
Vector fontSizeVector = new Vector(0, Gs().FontSize, 0);
Matrix textMatrix = (Matrix) textMatrixField.GetValue(this);
Matrix curentTransformationMatrix = Gs().GetCtm();
Vector transformedVector = fontSizeVector.Cross(textMatrix).Cross(curentTransformationMatrix);
float transformedFontSize = transformedVector.Length;
if (transformedFontSize > 40)
return;
}
base.Write(processor, operatorLit, operands);
}
System.Reflection.FieldInfo textMatrixField = typeof(PdfContentStreamProcessor).GetField("textMatrix", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
List<string> TEXT_SHOWING_OPERATORS = new List<string>{"Tj", "'", "\"", "TJ"};
}
The 40 has been chosen with that text matrix in mind.
Applying it like this
[Test]
public void testRemoveBigText()
{
string source = #"sid-1.pdf";
string dest = #"sid-1-noBigText.pdf";
using (PdfReader pdfReader = new PdfReader(source))
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(dest, FileMode.Create, FileAccess.Write)))
{
PdfContentStreamEditor editor = new BigTextRemover();
for (int i = 1; i <= pdfReader.NumberOfPages; i++)
{
editor.EditPage(pdfStamper, i);
}
}
}
to your sample file results in:
This is an issue I have been trying to tackle for a while and decided to reach out for help. I am creating an ESRI ArcGIS Desktop Add-In that allows the user to draw a polygon and then have it added to the map. I am able to capture the polygon and add it to the map, the issue is the transparency. Currently and by default it is 100% opacity and solid. I want to make it around 50% opacity so the user can see the data behind it.
Here is the code I have so far:
public static void AddPolygonToMap(IActiveView ActiveViewInstance, IGeometry NewGeo)
{
//Local Variable Declaration
var fillShapeElement = default(IFillShapeElement);
var element = default(IElement);
var graphicsContainer = default(IGraphicsContainer);
var simpleFilleSymbol = default(ISimpleFillSymbol);
var newRgbColor = default(IRgbColor);
var lineSymbol = default(ILineSymbol);
//Use the IElement interface to set the Envelope Element's geo
element = new PolygonElement();
element.Geometry = NewGeo;
//QI for the IFillShapeElement interface so that the symbol property can be set
fillShapeElement = element as IFillShapeElement;
//Create a new fill symbol
simpleFilleSymbol = new SimpleFillSymbol();
//Create a new color marker symbol of the color black;
newRgbColor = new RgbColor();
newRgbColor.Red = 0;
newRgbColor.Green = 0;
newRgbColor.Blue = 0;
//Create a new line symbol so that we can set the width outline
lineSymbol = new SimpleLineSymbol();
lineSymbol.Color = newRgbColor;
lineSymbol.Width = 2;
//Setup the Simple Fill Symbol
simpleFilleSymbol.Color = newRgbColor;
simpleFilleSymbol.Style = esriSimpleFillStyle.esriSFSHollow;
simpleFilleSymbol.Outline = lineSymbol;
fillShapeElement.Symbol = simpleFilleSymbol;
//QI for the graphics container from the active view allows access to basic graphics layer
graphicsContainer = ActiveViewInstance as IGraphicsContainer;
//Add the new element at Z order 0
graphicsContainer.AddElement((IElement)fillShapeElement, 0);
//Show the new graphic
ActiveViewInstance.Refresh();
}
I know that this is possible somehow and I am sure it's just a line or two missing but any help would be much appreciated.
V/r,
Josh
This looks to be a graphic element that you are creating. Graphic elements do not support transparency other than 100% transparent or 0% transparent. This is outlined in the following documentation:
IColor.Transparency Property
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/index.html#//001w000000nt000000
For graphic elements, 0 for transparent and 255 for opaque are the only supported values.
I hope this helps!
I'm updating software that cuts up and stitches PowerPoint slides together for end users. The slides contain charts. I need to find a way of hiding the raw chart data from the users that receive the files.
Is there anyway of doing this natively within the PowerPoint interop?
I've tried Read-Only but the user can still get at the data.
Ok. Here is my final answer to my question.
This shows the completed code that can perfectly replicate the slide while keeping the charts from being edited i.e. buy turning it into a .png.
This also solves the previous problem of the placeholders being left.
Hopefully some of this code is helpful to someone trawling the internet like I did.
//Open the slides presentation
var pres = _application.Presentations.Open2007(item.PresentationPath,
Microsoft.Office.Core.MsoTriState.msoFalse,
Microsoft.Office.Core.MsoTriState.msoFalse,
Microsoft.Office.Core.MsoTriState.msoFalse,
Microsoft.Office.Core.MsoTriState.msoFalse);
//For slide ranges
foreach (var i in range)
{
//Get the old slide
var oldSlide = pres.Slides[i];
oldSlide.Copy();
//Paste the slide into the new presentation
var newSlide = newPresentation.Slides.Paste(totalSlides + 1);
newSlide.Design = oldSlide.Design;
newSlide.ColorScheme = oldSlide.ColorScheme;
/* The shapes haven't retained their content because we are not in slide...
view because there is no window. */
//Delete all the shapes that were just pasted in because of the slide paste.
for (int k = newSlide.Shapes.Count; k > 0; k--)
{
newSlide.Shapes[k].Delete();
}
//Put in our shapes
//Loop forwards, because we arn't editing the list and forward is required to
//maintain the zorder we want on some slides.
for (int j = 1; j <= oldSlide.Shapes.Count; j++)
{
var oldShape = oldSlide.Shapes[j];
oldShape.Copy();
//Paste Put it where it should be on the page
/* This is a special case where the client have put textboxes in the
Powerpoint and rotated throwing off the position, so we need treat as rotated
shapes to make it right. */
if (oldShape.HasTextFrame == MsoTriState.msoTrue && Math.Abs(oldShape.Rotation) > 0)
{
//Paste as a shape because it's a more complex object
//set ALL THE PROPERTIES just in case.
var newShape = newSlide.Shapes.PasteSpecial(PpPasteDataType.ppPasteShape);
newShape.Rotation = oldShape.Rotation;
newShape.Top = oldShape.Top;
newShape.Left = oldShape.Left;
newShape.TextFrame.Orientation = oldShape.TextFrame.Orientation;
newShape.TextFrame.WordWrap = oldShape.TextFrame.WordWrap;
newShape.TextFrame.VerticalAnchor = oldShape.TextFrame.VerticalAnchor;
}
else // Act normally
{
//Paste the old shape into the new slide as an image to ENSURE FORMATTING
var newShape = newSlide.Shapes.PasteSpecial(PpPasteDataType.ppPastePNG);
newShape.Top = oldShape.Top;
newShape.Left = oldShape.Left;
}
}
totalSlides += ((item.EndIndex - item.StartIndex) + 1);
pres.Close();
}
After the new presentation has been compiled, you must delete all placeholders.
//Loop through all slides
foreach (Slide exportSlide in newPresentation.Slides)
{
//Delete the placeholders
for (int i = exportSlide.Shapes.Placeholders.Count; i > 0; i--)
{
exportSlide.Shapes.Placeholders[i].Delete();
}
}
VBA to ungroup a chart (in order to remove any connection to the original data)
Sub UngroupAChart()
Dim oSh As Shape
Dim oNewSh As Shape
Dim oNewShapes As ShapeRange
Dim oSl As Slide
' for demo purposes, use the currently selected
' shape; up to tester to select a chart
Set oSh = ActiveWindow.Selection.ShapeRange(1)
' Get a reference to the shape's parent slide
' We'll need it later
Set oSl = oSh.Parent
' put the shape on the clipboard
oSh.Copy
Set oNewSh = oSl.Shapes.PasteSpecial(ppPasteEnhancedMetafile)(1)
oNewSh.Ungroup
' once you're done testing, delete the original chart
'oSh.Delete
End Sub
Using the principals of Steve's code I've created a bespoke one for my use. As I am interacting with PowerPoint as a Component Service, I don't have an ActiveWindow or anything.
//Loop through all slides
foreach (Slide exportSlide in newPresentation.Slides)
{
//Loop through all shapes
foreach (Shape shape in exportSlide.Shapes)
{
//If the shape is a chart
if (shape.HasChart == MsoTriState.msoTrue)
{
//Copy to clipboard
shape.Copy();
//Paste as an image
var newShape = exportSlide.Shapes.PasteSpecial(PpPasteDataType.ppPastePNG);
//Move back to chart position
newShape.Left = shape.Left;
newShape.Top = shape.Top;
//Delete the original shape
shape.Delete();
}
}
}
This works fine for replacing the charts with images (no data at all). The only issue now is that because the slides where created with a layout containing chart, when you open the slide in Powerpoint the GUI displays an "Insert Chart" box. I've tried:
exportSlide.Layout = PpSlideLayout.ppLayoutBlank;
However because of my clients custom templates this is not blank, so it's not usable.
I created some code to extract text and font height from a PDF file using iTextSharp, but does not handle text rotation. How can that information be extracted/computed?
Here is the code:
// Create PDF reader
var reader = new PdfReader("myfile.pdf");
for (var k = 1; k <= reader.NumberOfPages; ++k)
{
// Get page resources
var page = reader.GetPageN(k);
var pdfResources = page.GetAsDict(PdfName.RESOURCES);
// Create custom render listener, processor, and process page!
var listener = new FunnyRenderListener();
var processor = new PdfContentStreamProcessor(listener);
var bytes = ContentByteUtils.GetContentBytesForPage(reader, k);
processor.ProcessContent(bytes, pdfResources);
}
[...]
public class FunnyRenderListener : IRenderListener
{
[...]
void RenderText(TextRenderInfo renderInfo)
{
// Get text
var text = renderInfo.GetText();
// Get (computed) font size
var bottomLeftPoint = renderInfo.GetDescentLine().GetStartPoint();
var topRightPoint = renderInfo.GetAscentLine().GetEndPoint();
var rectangle = new Rectangle(
bottomLeftPoint[Vector.I1], bottomLeftPoint[Vector.I2],
topRightPoint[Vector.I1], topRightPoint[Vector.I2]
);
var fontSize = Convert.ToDouble(rectangle.Height);
Console.WriteLine("Text: {0}, FontSize: {1}", text, fontSize);
}
}
The information you need, i.e. the text rotation, is not directly available via a TextRenderInfo member but it does have the method
/**
* Gets the baseline for the text (i.e. the line that the text 'sits' on)
* This value includes the Rise of the draw operation - see getRise() for the amount added by Rise
*/
public LineSegment GetBaseline()
Most likely by text rotation you mean the rotation of this line against a horizontal one. Doing some easy math, therefore, you can calculate the rotation from this LineSegment.
PS: Looking at your code you actually already use the ascent line and descent line. You can use any of these lines as well instead of the base line.