Change only specific text color + itext - itext

I am using below code, which is changing the color of blue links to black from pdf:
void testAllRgbBlueToBlackConverter(String resourceName, String resultName) throws IOException {
System.out.printf("\nConverting '%s'.\n", resourceName);
try ( InputStream resource = getClass().getResourceAsStream(resourceName);
PdfReader pdfReader = new PdfReader(resource);
OutputStream result = new FileOutputStream(new File(RESULT_FOLDER, resultName));
PdfWriter pdfWriter = new PdfWriter(result);
PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter) ) {
PdfCanvasEditor editor = new AllRgbBlueToBlackConverter();
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++)
{
editor.editPage(pdfDocument, i);
}
}
}
class AllRgbBlueToBlackConverter extends PdfCanvasEditor {
#Override
protected void write(PdfCanvasProcessor processor, PdfLiteral operator, List<PdfObject> operands)
{
String operatorString = operator.toString();
if (RGB_SETTER_CANDIDATES.contains(operatorString) && operands.size() == 4) {
if (isBlue(operands.get(0), operands.get(1), operands.get(2))) {
PdfNumber number0 = new PdfNumber(0);
operands.set(0, number0);
operands.set(1, number0);
operands.set(2, number0);
}
}
super.write(processor, operator, operands);
}
boolean isBlue(PdfObject red, PdfObject green, PdfObject blue) {
if (red instanceof PdfNumber && green instanceof PdfNumber && blue instanceof PdfNumber) {
float r = ((PdfNumber)red).floatValue();
float g = ((PdfNumber)green).floatValue();
float b = ((PdfNumber)blue).floatValue();
return b > .5f && r < .9f*b && g < .9f*b;
}
return false;
}
final Set<String> RGB_SETTER_CANDIDATES = new HashSet<>(Arrays.asList("rg", "RG", "sc", "SC", "scn", "SCN"));
}
Can I restrict above code, in which i restrict that change color only when text is equal to "bla bla". Otherwise dont change color? This code changes the color of graph line as well, if there is any graph available in pdf.
I am using itext. If anyone have any code available in other library. Please share it with me. I am stuck on this since month. I want to change the color of specific text from blue to black.

Related

how to cross out a certain text displayed on the screen?

In my game, there are certain objects that are tagged with "TargetObj", these objects have their names displayed on the screen like this:
GameObject[] targetObjects;
List<GameObject> targetObjectsList;
private TextMeshProUGUI mytext;
public TMP_FontAsset FontAssetA;
[SerializeField] GameObject TargetsCanvas;
void Start()
{
mainCamera = Camera.main;
targetObjects = GameObject.FindGameObjectsWithTag("TargetObj");
targetObjectsList = new List<GameObject>();
foreach (var obj in targetObjects)
{
mytext = CreateText(TargetsCanvas.transform);
mytext.text = "• " + obj.name;
mytext.font = FontAssetA;
}
}
static TextMeshProUGUI CreateText(Transform parent)
{
var go = new GameObject();
go.transform.parent = parent;
var text = go.AddComponent<TextMeshProUGUI>();
text.fontSize = 20;
return text;
}
They look like this:
The TargetsCanvas inspector:
Once the player picks up all tagged objects, he wins:
if (PickingUp)
{
if (currentlyPickedUpObject == null)
{
if (lookObject != null)
{
PickupObject();
if (lookObject.CompareTag("TargetObj") && !targetObjectsList.Contains(lookObject.gameObject))
{
if (aSource)
{
aSource.Play();
}
targetObjectsList.Add(lookObject.gameObject);
if (targetObjectsList.Count == targetObjects.Length)
{
winUI.SetActive(true);
Time.timeScale = 0f;
//SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
//Time.timeScale = 1f;
}
}
}
public void PickupObject()
{
physicsObject = lookObject.GetComponentInChildren<PhysicsObjects>();
currentlyPickedUpObject = lookObject;
pickupRB = currentlyPickedUpObject.GetComponent<Rigidbody>();
pickupRB.constraints = RigidbodyConstraints.FreezeRotation;
physicsObject.playerInteractions = this;
pickupRB.transform.parent = PickupParent.transform;
//StartCoroutine(physicsObject.PickUp());
}
I'm trying to cross out the name object on the screen once this object is picked up. I know that I can use this line to cross out a text:
mytext.fontStyle = FontStyles.Strikethrough;
but in my case, I don't know where exactly to use it to achieve what I want. any idea?
When using TextMeshPro Text, you can add a rich text tags to strikethrough any part of your string.
For example:
Make sure Rich Text is enabled under Extra Settings in your TMP Text Component
Use start tag <s> and end tag </s> to define where the strikethrough starts and ends
An example of setting this in code would be something like
public string textToStrike; //"Coffee Cup"
const string STRIKE_START = "<s>";
const string STRIKE_END = "</s>";
outputText = STRIKE_START + textToStrike + STRIKE_END;
Result outputText = Coffee Cup
You could even make a method that returns the inputted value as striked out if you wanted.
For example
private string StrikeText(string input)
{
string output = STRIKE_START + input + STRIKE_END;
return output;
}

multiple signing pdf iText

im trying to sign a document several times simulating a signature by different users using itext 5.5.13.1, PdfStamper is on AppendMode. If document has not signatures, the certification level is CERTIFIED_NO_CHANGES_ALLOWED or CERTIFIED_FORM_FILLING_AND_ANNOTATIONS, else i dont set this param for PdfSignatureAppearence. After the second signing the first signature is invalid, because the document was changed. Any ideas how to fix this?
Here's my code:
public void Sign(string Thumbprint, string document, string logoPath) {
X509Certificate2 certificate = FindCertificate(Thumbprint);
PdfReader reader = new PdfReader(document);
//Append mode
PdfStamper st = PdfStamper.CreateSignature(reader, new FileStream(SignedDocumentPath(document), FileMode.Create, FileAccess.Write), '\0', null, true);
int signatureWidth = 250;
int signatureHeight = 100;
int NewXPos = 0;
int NewYPos = 0;
SetStampCoordinates(reader, st, ref NewXPos, ref NewYPos, signatureWidth, signatureHeight);
PdfSignatureAppearance sap = st.SignatureAppearance;
if (reader.AcroFields.GetSignatureNames().Count == 0)
{
SetSignatureFieldOptions(certificate, sap, reader, "1", 1, NewXPos, NewYPos, signatureWidth, signatureHeight);
}
else {
SetSignatureFieldOptions(certificate, sap, reader, "2", NewXPos, NewYPos, signatureWidth, signatureHeight);
}
Image image = Image.GetInstance(logoPath);
image.ScaleAbsolute(50, 50);
Font font1 = SetFont("TIMES.TTF", BaseColor.BLUE, 10, 0);
Font font2 = SetFont("TIMES.TTF", BaseColor.BLUE, 8, 0);
PdfTemplate layer = sap.GetLayer(2);
Chunk chunk1 = new Chunk($"\r\nДОКУМЕНТ ПОДПИСАН\r\nЭЛЕКТРОННОЙ ПОДПИСЬЮ\r\n", font1);
Chunk chunk2 = new Chunk($"Сертификат {certificate.Thumbprint}\r\n" +
$"Владелец {certificate.GetNameInfo(X509NameType.SimpleName, false)}\r\n" +
$"Действителен с {Convert.ToDateTime(certificate.GetEffectiveDateString()).Date.ToShortDateString()} " +
$"по {Convert.ToDateTime(certificate.GetExpirationDateString()).Date.ToShortDateString()}\r\n", font2);
PdfTemplate layer0 = sap.GetLayer(0);
image.SetAbsolutePosition(5, 50);
layer0.AddImage(image);
Paragraph para1 = SetParagraphOptions(chunk1, 1, 50, 0, 2, 1.1f);
Paragraph para2 = SetParagraphOptions(chunk2, 0, 5, 15, 0.5f, 1.1f);
ColumnText ct = new ColumnText(layer);
ct.SetSimpleColumn(3f, 3f, layer.BoundingBox.Width - 3f, layer.BoundingBox.Height);
ct.AddElement(para1);
ct.AddElement(para2);
ct.Go();
layer.SetLineWidth(3);
layer.SetRGBColorStroke(0, 0, 255);
layer.Rectangle(0, 0, layer.BoundingBox.Right, layer.BoundingBox.Top);
layer.Stroke();
EncryptDocument(certificate, sap);
}
public X509Certificate2 FindCertificate(string Thumbprint) {
X509Store store = new X509Store("My", StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
X509Certificate2Collection found = store.Certificates.Find(
X509FindType.FindByThumbprint, Thumbprint, true);
X509Certificate2 certificate = found[0];
if (certificate.PrivateKey is Gost3410_2012_256CryptoServiceProvider cert_key)
{
var cspParameters = new CspParameters
{
KeyContainerName = cert_key.CspKeyContainerInfo.KeyContainerName,
ProviderType = cert_key.CspKeyContainerInfo.ProviderType,
ProviderName = cert_key.CspKeyContainerInfo.ProviderName,
Flags = cert_key.CspKeyContainerInfo.MachineKeyStore
? (CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore)
: (CspProviderFlags.UseExistingKey),
KeyPassword = new SecureString()
};
certificate = new X509Certificate2(certificate.RawData)
{
PrivateKey = new Gost3410_2012_256CryptoServiceProvider(cspParameters)
};
}
return certificate;
}
public Font SetFont(string TTFFontName, BaseColor color, float size, int style) {
string ttf = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), TTFFontName);
BaseFont baseFont = BaseFont.CreateFont(ttf, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Font font = new Font(baseFont, size, style);
font.Color = color;
return font;
}
public Paragraph SetParagraphOptions(Chunk chunk, int ParagraphAligment, float marginLeft, float marginTop, float fixedLeading, float multipledLeading) {
Paragraph paragraph = new Paragraph();
paragraph.Alignment = ParagraphAligment;
paragraph.IndentationLeft = marginLeft;
paragraph.SpacingBefore = marginTop;
paragraph.SetLeading(fixedLeading, multipledLeading);
paragraph.Add(chunk);
return paragraph;
}
public string SignedDocumentPath(string document) {
string filename = String.Concat(Path.GetFileNameWithoutExtension(document), "_signed.pdf");
string path = Path.Combine(Path.GetDirectoryName(document), filename);
return path;
}
public void SetSignatureFieldOptions(X509Certificate2 certificate, PdfSignatureAppearance sap, PdfReader reader, string field, int level, int XPos, int YPos, int width, int height)
{
X509CertificateParser parser = new X509CertificateParser();
try
{
Rectangle rectangle = new Rectangle(XPos, YPos, XPos + width, YPos + height);
sap.SetVisibleSignature(rectangle, reader.NumberOfPages, field);
sap.Certificate = parser.ReadCertificate(certificate.RawData);
sap.Reason = "I agree";
sap.Location = "Location";
sap.Acro6Layers = true;
sap.SignDate = DateTime.Now;
sap.CertificationLevel = level;
}
catch (Exception ex)
{
if (ex.Message == $"The field {certificate.Thumbprint} already exists.")
throw new Exception("Вы уже подписали данный документ");
}
}
public void SetSignatureFieldOptions(X509Certificate2 certificate, PdfSignatureAppearance sap, PdfReader reader,string field, int XPos, int YPos, int width, int height) {
X509CertificateParser parser = new X509CertificateParser();
try
{
Rectangle rectangle = new Rectangle(XPos, YPos, XPos + width, YPos + height);
sap.SetVisibleSignature(rectangle, reader.NumberOfPages, field);
sap.Certificate = parser.ReadCertificate(certificate.RawData);
sap.Reason = "I agree";
sap.Location = "Location";
sap.Acro6Layers = true;
sap.SignDate = DateTime.Now;
}
catch (Exception ex) {
if (ex.Message == $"The field {certificate.Thumbprint} already exists.")
throw new Exception("Вы уже подписали данный документ");
}
}
public void EncryptDocument(X509Certificate2 certificate, PdfSignatureAppearance sap) {
PdfName filterName;
if (certificate.PrivateKey is Gost3410CryptoServiceProvider)
filterName = new PdfName("CryptoPro#20PDF");
else
filterName = PdfName.ADOBE_PPKLITE;
PdfSignature dic = new PdfSignature(filterName, PdfName.ADBE_PKCS7_DETACHED);
dic.Date = new PdfDate(sap.SignDate);
dic.Name = certificate.GetNameInfo(X509NameType.SimpleName, false);
if (sap.Reason != null)
dic.Reason = sap.Reason;
if (sap.Location != null)
dic.Location = sap.Location;
sap.CryptoDictionary = dic;
int intCSize = 4000;
Dictionary<PdfName, int> hashtable = new Dictionary<PdfName, int>();
hashtable[PdfName.CONTENTS] = intCSize * 2 + 2;
sap.PreClose(hashtable);
Stream s = sap.GetRangeStream();
MemoryStream ss = new MemoryStream();
int read = 0;
byte[] buff = new byte[8192];
while ((read = s.Read(buff, 0, 8192)) > 0)
{
ss.Write(buff, 0, read);
}
ContentInfo contentInfo = new ContentInfo(ss.ToArray());
SignedCms signedCms = new SignedCms(contentInfo, true);
CmsSigner cmsSigner = new CmsSigner(certificate);
signedCms.ComputeSignature(cmsSigner, false);
byte[] pk = signedCms.Encode();
byte[] outc = new byte[intCSize];
PdfDictionary dic2 = new PdfDictionary();
Array.Copy(pk, 0, outc, 0, pk.Length);
dic2.Put(PdfName.CONTENTS, new PdfString(outc).SetHexWriting(true));
sap.Close(dic2);
}
The Change
The most important part of your screenshot
is the text "1 Page(s) Modified" between the signatures on the signature panel. This tells us that you do other changes than merely adding and filling signature fields. Inspecting the file itself one quickly recognizes the change:
In the original sample.pdf
there is just a single content stream.
In sample_signed.pdf with one signature
there are three content streams, the original one enveloped by the new ones.
In sample_signed_signed.pdf with two signatures
there are five content streams, the former three enveloped by two new ones.
So in each signing pass you change the page content. As you can read in this answer, changes to the page content of signed documents are always disallowed. It doesn't even help that the contents of the added streams are trivial, each stream added in front contains:
q
and each stream added at the end contains
Q
q
Q
i.e. only some saving and restoring the graphics state happens.
The Cause
The changes described above are typical preparation steps done by the PdfStamper method GetOverContent, wrapping the original content in a q ... Q (save & restore graphics state) envelope to prevent changes there to influence additions in the OverContent and starting a new block also enveloped in such an envelope. That the latter block remained empty, indicates that the OverContent has not been edited.
I don't find such a call in the code you posted, but in your code the method SetStampCoordinates is missing. Do you probably call GetOverContent for the PdfStamper argument in that method?

change pdf image background using Itextsharp

I am trying to change background color of all images of pdf using Itextshap.
How can i loop through all images and change background color of the images
I used below code to extract pdf images
public static void ExtractImagesFromPDF(string sourcePdf, string outputPath)
{
// NOTE: This will only get the first image it finds per page.
PdfReader pdf = new PdfReader(sourcePdf);
RandomAccessFileOrArray raf = new iTextSharp.text.pdf.RandomAccessFileOrArray(sourcePdf);
try
{
for (int pageNumber = 1; pageNumber <= pdf.NumberOfPages; pageNumber++)
{
PdfDictionary pg = pdf.GetPageN(pageNumber);
// recursively search pages, forms and groups for images.
PdfObject obj = FindImageInPDFDictionary(pg);
if (obj != null)
{
int XrefIndex = Convert.ToInt32(((PRIndirectReference)obj).Number.ToString(System.Globalization.CultureInfo.InvariantCulture));
PdfObject pdfObj = pdf.GetPdfObject(XrefIndex);
PdfStream pdfStrem = (PdfStream)pdfObj;
byte[] bytes = PdfReader.GetStreamBytesRaw((PRStream)pdfStrem);
if ((bytes != null))
{
using (System.IO.MemoryStream memStream = new System.IO.MemoryStream(bytes))
{
memStream.Position = 0;
System.Drawing.Image img = System.Drawing.Image.FromStream(memStream);
// must save the file while stream is open.
if (!Directory.Exists(outputPath))
Directory.CreateDirectory(outputPath);
string path = Path.Combine(outputPath, String.Format(#"{0}.jpg", pageNumber));
System.Drawing.Imaging.EncoderParameters parms = new System.Drawing.Imaging.EncoderParameters(1);
parms.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Compression, 0);
System.Drawing.Imaging.ImageCodecInfo jpegEncoder = Utilities.GetImageEncoder("JPEG");
img.Save(path, jpegEncoder, parms);
}
}
}
}
}
catch
{
throw;
}
finally
{
pdf.Close();
raf.Close();
}
}
private static PdfObject FindImageInPDFDictionary(PdfDictionary pg)
{
PdfDictionary res =
(PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));
PdfDictionary xobj =
(PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
if (xobj != null)
{
foreach (PdfName name in xobj.Keys)
{
PdfObject obj = xobj.Get(name);
if (obj.IsIndirect())
{
PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(obj);
PdfName type =
(PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));
//image at the root of the pdf
if (PdfName.IMAGE.Equals(type))
{
return obj;
}// image inside a form
else if (PdfName.FORM.Equals(type))
{
return FindImageInPDFDictionary(tg);
} //image inside a group
else if (PdfName.GROUP.Equals(type))
{
return FindImageInPDFDictionary(tg);
}
}
}
}
return null;
}
Many thanks in advance

How can I combine multiple PDF files excluding page breaks using iTextSharp?

I wonder if anyone has done this with iTextSharp, but I would like to combine multiple PDF files into one but leave the page breaks out. For example, I would like to create 4 PDF files containing 3 lines of text each, so I want the resulting file to have all 12 lines in 1 page. Is this possible?
As the OP also tagged this question with [iText] and I am more at home with Java than .Net, here an answer for iText/Java. It should be easy to translate to iTextSharp/C#.
The original question
I would like to combine multiple PDF files into one but leave the page breaks out. For example, I would like to create 4 PDF files containing 3 lines of text each, so I want the resulting file to have all 12 lines in 1 page.
For PDF files as indicated in that example you can use this simple utility class:
public class PdfDenseMergeTool
{
public PdfDenseMergeTool(Rectangle size, float top, float bottom, float gap)
{
this.pageSize = size;
this.topMargin = top;
this.bottomMargin = bottom;
this.gap = gap;
}
public void merge(OutputStream outputStream, Iterable<PdfReader> inputs) throws DocumentException, IOException
{
try
{
openDocument(outputStream);
for (PdfReader reader: inputs)
{
merge(reader);
}
}
finally
{
closeDocument();
}
}
void openDocument(OutputStream outputStream) throws DocumentException
{
final Document document = new Document(pageSize, 36, 36, topMargin, bottomMargin);
final PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
this.document = document;
this.writer = writer;
newPage();
}
void closeDocument()
{
try
{
document.close();
}
finally
{
this.document = null;
this.writer = null;
this.yPosition = 0;
}
}
void newPage()
{
document.newPage();
yPosition = pageSize.getTop(topMargin);
}
void merge(PdfReader reader) throws IOException
{
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
for (int page = 1; page <= reader.getNumberOfPages(); page++)
{
merge(reader, parser, page);
}
}
void merge(PdfReader reader, PdfReaderContentParser parser, int page) throws IOException
{
TextMarginFinder finder = parser.processContent(page, new TextMarginFinder());
Rectangle pageSizeToImport = reader.getPageSize(page);
float heightToImport = finder.getHeight();
float maxHeight = pageSize.getHeight() - topMargin - bottomMargin;
if (heightToImport > maxHeight)
{
throw new IllegalArgumentException(String.format("Page %s content too large; height: %s, limit: %s.", page, heightToImport, maxHeight));
}
if (heightToImport > yPosition - pageSize.getBottom(bottomMargin))
{
newPage();
}
else if (!writer.isPageEmpty())
{
heightToImport += gap;
}
yPosition -= heightToImport;
PdfImportedPage importedPage = writer.getImportedPage(reader, page);
writer.getDirectContent().addTemplate(importedPage, 0, yPosition - (finder.getLly() - pageSizeToImport.getBottom()));
}
Document document = null;
PdfWriter writer = null;
float yPosition = 0;
final Rectangle pageSize;
final float topMargin;
final float bottomMargin;
final float gap;
}
If you have a list of PdfReader instances inputs, you can merge them like this into an OutputStream output:
PdfDenseMergeTool tool = new PdfDenseMergeTool(PageSize.A4, 18, 18, 5);
tool.merge(output, inputs);
This creates a merged document using an A4 page size, a top and bottom margin of 18/72" each and a gap between contents of different PDF pages of 5/72".
The comments
The iText TextMarginFinder (used in the PdfDenseMergeTool above) only considers text. If other content types also are to be considered, this class has to be extended somewhat.
Each PDF has just a few lines, perhaps a table or an image, but I want the end result in one page.
If the tables contain decorations reaching above or below the text content (e.g. lines or colored backgrounds), you should use a larger gap value. Unfortunately the parsing framework used by the TextMarginFinder does not forward vector graphics commands to the finder.
If the images are bitmap images, the TextMarginFinder should be extended by implementing its renderImage method to take the image area into account, too.
Also, some of the PDFs may contain fields, so I'd like to keep those fields in the resulting combined PDF as well.
If AcroForm fields are also to be considered, you have to
extend the rectangle represented by the TextMarginFinder to also include the visualization rectangles of the widget annotations, and
extend the PdfDenseMergeTool.merge(PdfReader, PdfReaderContentParser, int) method to also copy those widget annotations.
Update
I wrote above
Unfortunately the parsing framework used by the TextMarginFinder does not forward vector graphics commands to the finder.
Meanwhile (in version 5.5.6) that parsing framework has been extended to also forward vector graphics commands.
If you replace the line
TextMarginFinder finder = parser.processContent(page, new TextMarginFinder());
by
MarginFinder finder = parser.processContent(page, new MarginFinder());
using the MarginFinder class presented at the bottom of this answer, all content is considered, not merely text.
For those of you who want the above code in C#, here you go.
using System;
using System.Collections.Generic;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
namespace Test.WebService.Support {
public class PDFMerge {
private Rectangle PageSize;
private float TopMargin;
private float BottomMargin;
private float Gap;
private Document Document = null;
private PdfWriter Writer = null;
private float YPosition = 0;
public PDFMerge(Rectangle size, float top, float bottom, float gap) {
this.PageSize = size;
this.TopMargin = top;
this.BottomMargin = bottom;
this.Gap = gap;
} // PDFMerge
public void Merge(MemoryStream outputStream, List<PdfReader> inputs) {
try {
this.OpenDocument(outputStream);
foreach (PdfReader reader in inputs) {
this.Merge(reader);
}
} finally {
this.CloseDocument();
}
} // Merge
private void Merge(PdfReader reader) {
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
for (int p = 1; p <= reader.NumberOfPages; p++) {
this.Merge(reader, parser, p);
}
} // Merge
private void Merge(PdfReader reader, PdfReaderContentParser parser, int pageIndex) {
TextMarginFinder Finder = parser.ProcessContent(pageIndex, new TextMarginFinder());
Rectangle PageSizeToImport = reader.GetPageSize(pageIndex);
float HeightToImport = Finder.GetHeight();
float MaxHeight = PageSize.Height - TopMargin - BottomMargin;
if (HeightToImport > MaxHeight) {
throw new ArgumentException(string.Format("Page {0} content too large; height: {1}, limit: {2}.", pageIndex, HeightToImport, MaxHeight));
}
if (HeightToImport > YPosition - PageSize.GetBottom(BottomMargin)) {
this.NewPage();
} else if (!Writer.PageEmpty) {
HeightToImport += Gap;
}
YPosition -= HeightToImport;
PdfImportedPage ImportedPage = Writer.GetImportedPage(reader, pageIndex);
Writer.DirectContent.AddTemplate(ImportedPage, 0, YPosition - (Finder.GetLly() - PageSizeToImport.Bottom));
} // Merge
private void OpenDocument(MemoryStream outputStream) {
Document Document = new Document(PageSize, 36, 36, this.TopMargin, BottomMargin);
PdfWriter Writer = PdfWriter.GetInstance(Document, outputStream);
Document.Open();
this.Document = Document;
this.Writer = Writer;
this.NewPage();
} // OpenDocument
private void CloseDocument() {
try {
Document.Close();
} finally {
this.Document = null;
this.Writer = null;
this.YPosition = 0;
}
} // CloseDocument
private void NewPage() {
Document.NewPage();
YPosition = PageSize.GetTop(TopMargin);
} // NewPage
}
}

Google Maps output=kml broken?

All
I was using the google maps KML output in my iPhone app.
If I type the following on my browser, it used to give an option to save the kml file:
http://maps.google.com/maps?q=restaurant&mrt=yp&num=10&sll=37.786945,-122.406013&radius=5&output=kml
But all of a sudden today, it is returning an html file. What happened? any ideas?
I use it in my iPhone app and it is throwing error as it is not a valid xml returned. Obviously....
Thanks,
mbh
This way of extracting the Google Directions from Google by parsing the KML file is no longer available since 27 July 2012 (because Google has changed the structure of retrieving Google Directions, now you can only get it by JSON or XML), it is time to migrate your code to JSON instead of KML.
See the answer (for Android only but maybe for iPhone can understand the algorithm and apply it) in my own question here.
Google changed something and now shows major turns only. But when using JSON, it's showing the path correctly:
public class DrivingDirectionActivity extends MapActivity {
Point p1 = new Point();
Point p2 = new Point();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MapView mapView = (MapView) findViewById(R.id.map);
// setting a default value
double src_lat = 18.5535;
double src_long = 73.7966;
double dest_lat = 18.5535;
double dest_long = 73.7966;
Geocoder coder = new Geocoder(getApplicationContext(),
Locale.getDefault());
List<Address> address_src = null;
List<Address> address_dest = null;
try {
address_src = coder
.getFromLocationName(
"Deepmala Housing Complex, Pimple Saudagar, Pimpri Chinchwad",
1);
if (address_src.size() > 0) {
Address loc = address_src.get(0);
src_lat = loc.getLatitude();
src_long = loc.getLongitude();
}
} catch (IOException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
try {
address_dest = coder.getFromLocationName(
"Infosys Phase 2, Hinjewadi Phase II, Hinjewadi", 1);
if (address_dest.size() > 0) {
Address loc = address_dest.get(0);
dest_lat = loc.getLatitude();
dest_long = loc.getLongitude();
}
} catch (IOException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
mapView.setBuiltInZoomControls(true);
GeoPoint srcGeoPoint = new GeoPoint((int) (src_lat * 1E6),
(int) (src_long * 1E6));
GeoPoint destGeoPoint = new GeoPoint((int) (dest_lat * 1E6),
(int) (dest_long * 1E6));
DrawPath(srcGeoPoint, destGeoPoint, Color.GREEN, mapView);
mapView.getController().animateTo(srcGeoPoint);
mapView.getController().setZoom(13);
}
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
private void DrawPath(GeoPoint src, GeoPoint dest, int color,
MapView mMapView) {
// connect to map web service
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(makeUrl(src, dest));
HttpResponse response;
try {
response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
InputStream is = null;
is = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
sb.append(reader.readLine() + "\n");
String line = "0";
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
reader.close();
String result = sb.toString();
JSONObject jsonObject = new JSONObject(result);
JSONArray routeArray = jsonObject.getJSONArray("routes");
JSONObject routes = routeArray.getJSONObject(0);
JSONObject overviewPolylines = routes
.getJSONObject("overview_polyline");
String encodedString = overviewPolylines.getString("points");
List<GeoPoint> pointToDraw = decodePoly(encodedString);
mMapView.getOverlays().add(new MyOverLay(pointToDraw));
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
}
private List<GeoPoint> decodePoly(String encoded) {
List<GeoPoint> poly = new ArrayList<GeoPoint>();
int index = 0, len = encoded.length();
int lat = 0, lng = 0;
while (index < len) {
int b, shift = 0, result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
GeoPoint p = new GeoPoint((int) (((double) lat / 1E5) * 1E6),
(int) (((double) lng / 1E5) * 1E6));
poly.add(p);
}
return poly;
}
private String makeUrl(GeoPoint src, GeoPoint dest) {
// TODO Auto-generated method stub
StringBuilder urlString = new StringBuilder();
urlString.append("http://maps.googleapis.com/maps/api/directions/json");
urlString.append("?origin=");// from
urlString.append(Double.toString((double) src.getLatitudeE6() / 1.0E6));
urlString.append(",");
urlString
.append(Double.toString((double) src.getLongitudeE6() / 1.0E6));
urlString.append("&destination=");// to
urlString
.append(Double.toString((double) dest.getLatitudeE6() / 1.0E6));
urlString.append(",");
urlString
.append(Double.toString((double) dest.getLongitudeE6() / 1.0E6));
urlString.append("&sensor=false");
Log.d("xxx", "URL=" + urlString.toString());
return urlString.toString();
}
class MyOverLay extends Overlay {
private int pathColor;
private final List<GeoPoint> points;
private boolean drawStartEnd;
public MyOverLay(List<GeoPoint> pointToDraw) {
// TODO Auto-generated constructor stub
this(pointToDraw, Color.GREEN, true);
}
public MyOverLay(List<GeoPoint> points, int pathColor,
boolean drawStartEnd) {
this.points = points;
this.pathColor = pathColor;
this.drawStartEnd = drawStartEnd;
}
private void drawOval(Canvas canvas, Paint paint, Point point) {
Paint ovalPaint = new Paint(paint);
ovalPaint.setStyle(Paint.Style.FILL_AND_STROKE);
ovalPaint.setStrokeWidth(2);
ovalPaint.setColor(Color.BLUE);
int _radius = 6;
RectF oval = new RectF(point.x - _radius, point.y - _radius,
point.x + _radius, point.y + _radius);
canvas.drawOval(oval, ovalPaint);
}
public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
long when) {
Projection projection = mapView.getProjection();
if (shadow == false && points != null) {
Point startPoint = null, endPoint = null;
Path path = new Path();
// We are creating the path
for (int i = 0; i < points.size(); i++) {
GeoPoint gPointA = points.get(i);
Point pointA = new Point();
projection.toPixels(gPointA, pointA);
if (i == 0) { // This is the start point
startPoint = pointA;
path.moveTo(pointA.x, pointA.y);
} else {
if (i == points.size() - 1)// This is the end point
endPoint = pointA;
path.lineTo(pointA.x, pointA.y);
}
}
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(pathColor);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setAlpha(90);
if (getDrawStartEnd()) {
if (startPoint != null) {
drawOval(canvas, paint, startPoint);
}
if (endPoint != null) {
drawOval(canvas, paint, endPoint);
}
}
if (!path.isEmpty())
canvas.drawPath(path, paint);
}
return super.draw(canvas, mapView, shadow, when);
}
public boolean getDrawStartEnd() {
return drawStartEnd;
}
public void setDrawStartEnd(boolean markStartEnd) {
drawStartEnd = markStartEnd;
}
}
}
I wish Google had not stopped supporting their documented KML without notice.
I migrated my code to google places API now using their xml output.
https://developers.google.com/places/documentation/
-well i just edited my answer-
lets face it, google has change their sistem, we have to follow them
so lets use JSON or XML
:)
--edited part two--
i just found the best solution, it use JSON and parse into polyline, so we can do it!
Google Maps API Version difference
I found the way to get KML outputs as before using standard google maps links for routes.
It seems that google analyze the referrer for such links and if it is https://code.google.com then it will generate KML attachment instead of showing the map.
So, at first, you need to make a project at https://code.google.com.
Then make an issue with you route link in a comment.
Now you can tap the link and get KML attachment.
As for Android now I am using:
Intent myIntent =
new Intent( android.content.Intent.ACTION_VIEW,
Uri.parse( "geo:0,0?q="+ lat +","+ lon ) );
startActivity(myIntent);
I think there should be something like that in iOS.
KML creation lives again!
The dead link simply needs to be modified to point to earth instead of maps
Dead Link:
http://maps.google.com/maps?q=restaurant&mrt=yp&num=10&sll=37.786945,-122.406013&radius=5&output=kml
Working Link:
https://earth.google.com/earth/rpc/search?q=restaurant&mrt=yp&num=10&sll=37.786945,-122.406013&radius=5&output=kml