Looking for word api which can perform mail merge type of functionality with richtext. Basically, text will be richtext/formatted text with fonts styles and WILL have
a) images
b) bullets
c) tables
Overall purpose: Create a word template with bookmarks. Get get data from DB(for those fields) and insert. Data will be html text/richtext. Autogenerate word document. python or .net api will be preferred.
Can Aspose.words work with richtext as described above? Any other recommendations for excellent word APIs?
Yes, you can achieve this using Aspose.Words. You can use IFieldMergingCallback to insert formatted text upon mail merge. For example, see the following link
https://apireference.aspose.com/words/net/aspose.words.mailmerging/ifieldmergingcallback
In case of reach text (if you mean RTF or MarkDown formats) you first need to read this content into a separate instance of Document and then use DocumentBuilder.InsertDocument method
https://apireference.aspose.com/words/net/aspose.words/documentbuilder/methods/insertdocument
The following code example shows how to use InsertHtml method in IFieldMergingCallback
[Test]
public void Test001()
{
Document doc = new Document(#"C:\Temp\in.docx");
doc.MailMerge.FieldMergingCallback = new HandleMergeFieldInsertHtml();
const string html = #"<h1>Hello world!</h1>";
doc.MailMerge.Execute(new string[] { "myField" }, new object[] { html });
doc.Save(#"C:\Temp\out.docx");
}
private class HandleMergeFieldInsertHtml : IFieldMergingCallback
{
void IFieldMergingCallback.FieldMerging(FieldMergingArgs args)
{
FieldMergeField field = args.Field;
// Insert the text for this merge field as HTML data, using DocumentBuilder
DocumentBuilder builder = new DocumentBuilder(args.Document);
builder.MoveToMergeField(args.DocumentFieldName);
builder.Write(field.TextBefore ?? "");
builder.InsertHtml((string)args.FieldValue);
// The HTML text itself should not be inserted
// We have already inserted it as an HTML
args.Text = "";
}
void IFieldMergingCallback.ImageFieldMerging(ImageFieldMergingArgs args)
{
// Do nothing
}
}
If you would like manually format the text, then you can use DocumentBuilder appropriate properties.
[Test]
public void Test001()
{
Document doc = new Document(#"C:\Temp\in.docx");
doc.MailMerge.FieldMergingCallback = new HandleMergeFieldInsertText();
const string text = #"Hello world!";
doc.MailMerge.Execute(new string[] { "myField" }, new object[] { text });
doc.Save(#"C:\Temp\out.docx");
}
private class HandleMergeFieldInsertText : IFieldMergingCallback
{
void IFieldMergingCallback.FieldMerging(FieldMergingArgs args)
{
FieldMergeField field = args.Field;
DocumentBuilder builder = new DocumentBuilder(args.Document);
builder.MoveToMergeField(args.DocumentFieldName);
// Apply style or other formatting.
builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;
builder.Write(field.TextBefore ?? "");
builder.Write((string)args.FieldValue);
// The text itself should not be inserted
// We have already inserted it using DocumentBuilder.
args.Text = "";
}
void IFieldMergingCallback.ImageFieldMerging(ImageFieldMergingArgs args)
{
// Do nothing
}
}
Hope this helps.
Disclosure: I work at Aspose.Words team.
The aspose.barcode reader is unable to read the barcode of type DecodeType.Code128
Workflow Steps
1>Using Aspose.Barcode we have created a barcode using DecodeType.Code128 and put on PDF page ( our clients use this page as separator sheet)
2>Our client then insert this barcode page between several physical documents and scanned them all, which creates big single PDF
3>Our splitting process then, loop through all pages and check if any page is barcode page, and splits the big PDF into individual small PDF
Issue is some times the scanned quality of the barcode is not that great, and in such case ASPOSE.Barcode unable to read the barcode.
I have attached couple of barcode PDF with low scanned quality, and aspose is not able to read these barcodes. I have tried different combinations of RecognitionMode and ManualHints options without any luck
Below is my code to identity barcode page
using (var fs = new FileStream(file, FileMode.Open))
{
var pdfDocument = new Document(fs);
foreach (Page page in pdfDocument.Pages)
{
var isSeparator = splitter.IsSeparator(page);
Assert.IsTrue(isSeparator);
}
}
public bool IsSeparator(Page page)
{
if (page.Resources.Images != null && page.Resources.Images.Count >= 1)
{
var img = page.Resources.Images[1];
using (MemoryStream barcodeImage = new MemoryStream())
{
img.Save(barcodeImage, ImageFormat.Jpeg);
barcodeImage.Seek(0L, SeekOrigin.Begin);
using (BarCodeReader barcodeReader = new BarCodeReader(barcodeImage, _barcodeDecodeType))
{
barcodeReader.RecognitionMode = RecognitionMode.MaxQuality;
while (barcodeReader.Read())
{
var barcodeText = barcodeReader.GetCodeText();
if (barcodeText.ToLower() == "eof")
{
return true;
}
}
}
}
}
return false;
}
Unable to reproduce the issue at my end. I used the following sample code snippet to recognize the barcode along with latest version of the API. It is always recommended to use the latest version of the API as it contains new features and improvements.
CODE:
Aspose.Pdf.License licensePdf = new Aspose.Pdf.License();
licensePdf.SetLicense(#"Aspose.Total.lic");
// bind the pdf document
Aspose.Pdf.Facades.PdfExtractor pdfExtractor = new Aspose.Pdf.Facades.PdfExtractor();
pdfExtractor.BindPdf(#"173483_2.pdf");
// extract the images
pdfExtractor.ExtractImage();
// save images to stream in a loop
while (pdfExtractor.HasNextImage())
{
// save image to stream
System.IO.MemoryStream imageStream = new System.IO.MemoryStream();
pdfExtractor.GetNextImage(imageStream);
imageStream.Position = 0;
Aspose.BarCode.BarCodeRecognition.BarCodeReader barcodeReader =
new Aspose.BarCode.BarCodeRecognition.BarCodeReader(imageStream);
while (barcodeReader.Read())
{
Console.WriteLine("Codetext found: " + barcodeReader.GetCodeText() + ", Symbology: " + barcodeReader.GetCodeType().ToString());
}
// close the reader
barcodeReader.Close();
}
Further to update you that the same query has been post on Aspose.BarCode support forum. You may please visit the link for details.
I work as developer evangelist at Aspose.
I'm working on upgrading from 8.1 to 8.2 update 3. I understand that the search/indexing was changed and some code is obsolete or no longer works.
Unfortunately in one of our class projects there were some methods our sitecore partners had built for us that are no longer working due to obsolete code and now I need help updating that code. I've been able to narrow it down to just 2 files, with some simple code.
Here is the first set of code:
public partial class TagResults
{
/// <summary>
/// Searches against the Lucene index for pages given a specific tag
/// </summary>
/// <returns></returns>
public List<BasePage> GetPagesForTag(string Tag, int page, int pageSize, out int totalCount)
{
var tags = new List<BasePage>();
Index searchIndex = SearchManager.GetIndex(Constants.LuceneIndexes.Tags);
using (IndexSearchContext context = searchIndex.CreateSearchContext())
{
//The wildcard search allows us to pull back all items with the given tag
var query = new WildcardQuery(new Term(Constants.LuceneFields.Tags, Tag));
SearchHits hits = context.Search(query);
totalCount = hits.Length;
//Go through the results
SearchResultCollection results = hits.FetchResults(page * pageSize, pageSize);
foreach (SearchResult result in results)
{
var searchItem = result.GetObject<Item>();
Item currentDbItem = ItemUtility.GetItem(searchItem.ID);
//Store the item if it exists and is a descendant of the news listing
if (currentDbItem != null)
{
tags.Add(new BasePage(currentDbItem));
}
}
}
return tags.ToList();
}
public static bool IsItemCastable(Item sitecoreItem)
{
return sitecoreItem != null && !string.IsNullOrEmpty(sitecoreItem[FieldIds.IsTagResultsComponent]);
}
}
I think I have some of this changed correctly:
ISearchIndex searchIndex = ContentSearchManager.GetIndex(Constants.LuceneIndexes.tags);
using (IProviderSearchContext context = searchIndex.CreateSearchContent())
But then I get stuck on
SearchHits hits = context.Search(query);
totalCount = hits.Length;
//Go through the results
SearchResultCollection results = hits.FetchResults(page * pageSize, pageSize);
foreach (SearchResult result in results)
Now I'm asking a lot but I am learning. If someone could help me correct this, I would be really appreciative. I've been doing a lot of searching to try to figure out how to correct this but I feel like I'm missing something and I just need some help.
Thank you in advance.
I'm using Aspose.words in .net API and getting in an issue to add a separate table in word footer using this tool. Can anyone expedite me to do this?
You can Insert a Table in Word footer with three cells using below piece of code:
var doc = new Document();
var builder = new DocumentBuilder(doc)
{
PageSetup =
{
Orientation = Orientation.Portrait,
PaperSize = PaperSize.Letter
},
};
builder.MoveToHeaderFooter(Word.HeaderFooterType.FooterPrimary);
builder.StartTable();
builder.InsertCell();
builder.CurrentParagraph.ParagraphFormat.Alignment = Word.ParagraphAlignment.Center;
builder.Write("Cell 1");
builder.InsertCell();
builder.CurrentParagraph.ParagraphFormat.Alignment = Word.ParagraphAlignment.Center;
builder.Write("Cell 2");
builder.InsertCell();
builder.CurrentParagraph.ParagraphFormat.Alignment = Word.ParagraphAlignment.Center;
builder.Write("Cell 3");
builder.EndTable();
builder.MoveToDocumentEnd();
When loading the Facebook feeds from one page, if a picture exist in the feed, I want to display the large picture.
How can I get with the graph API ? The picture link in the feed is not the large one.
Thanks.
The Graph API photo object has a picture connection (similar to that the user object has):
“The album-sized view of the photo. […] Returns: HTTP 302 redirect to the URL of the picture.”
So requesting https://graph.facebook.com/{object-id-from-feed}/picture will redirect you to the album-sized version of the photo immediately. (Usefull not only for displaying it in a browser, but also if f.e. you want to download the image to your server, using cURL with follow_redirect option set.)
Edit:
Beginning with API v2.3, the /picture edge for feed posts is deprecated.
However, as a field the picture can still be requested – but it will be a small one.
But full_picture is available as well.
So /{object-id-from-feed}?fields=picture,full_picture can be used to request those, or they can be requested directly with the rest of feed data, like this /page-id/feed?fields=picture,full_picture,… (additional fields, such as message etc., must be specified the same way.)
What worked for me :
getting the picture link from the feed and replacing "_s.jpg" with "_n.jpg"
OK, I found a better way. When you retrieve a feed with the graph API, any feed item with a type of photo will have a field called object_id, which is not there for plain status type items. Query the Graph API with that ID, e.g. https://graph.facebook.com/1234567890. Note that the object ID isn't an underscore-separated value like the main ID of that feed item is.
The result of the object_id query will be a new JSON dictionary, where you will have a source attribute containing a URL for an image that has so far been big enough for my needs.
There is additionally an images array that contains more image URLs for different sizes of the image, but the sizes there don't seem to be predictable, and don't all actually correspond to the physical dimensions of the image behind that URL.
I still wish there was a way to do this with a single Graph API call, but it doesn't look like there is one.
For high res image links from:
Link posts
Video posts
Photo posts
I use the following:
Note: The reason I give the _s -> _o hack precedence over the object_id/picture approach is because the object_id approach was not returning results for all images.
var picture = result.picture;
if (picture) {
if (result.type === 'photo') {
if (picture.indexOf('_s') !== -1) {
console.log('CONVERTING');
picture = picture.replace(/_s/, '_o');
} else if (result.object_id) {
picture = 'https://graph.facebook.com/' + result.object_id + '/picture?width=9999&height=9999';
}
} else {
var qps = result.picture.split('&');
for (var i = 0; i < qps.length; i++) {
var qp = qps[i];
var matches = qp.match(/(url=|src=)/gi);
if (matches && matches.length > 0) picture = decodeURIComponent(qp.split(matches[0])[1]);
}
}
}
This is a new method to get a big image. it was born after the previews method doesn't works
/**
* return a big url of facebook
* works onky for type PHOTO
* #param picture
* #param is a post type link
* #return url of image
*/
#Transactional
public String getBigImageByFacebookPicture(String pictrue,Boolean link){
if(link && pictrue.contains("url=http")){
String url = pictrue.substring(pictrue.indexOf("url=") + 4);
try {
url = java.net.URLDecoder.decode(url, "UTF-8");
} catch (UnsupportedEncodingException e) {
StringBuffer sb = new StringBuffer("Big image for Facebook link not found: ");
sb.append(link);
loggerTakePost.error(sb.toString());
return null;
}
return url;
}else{
try {
Document doc = Jsoup.connect(pictrue).get();
return doc.select("#fbPhotoImage").get(0).attr("src");
} catch (Exception e) {
StringBuffer sb = new StringBuffer("Big image for Facebook link not found: ");
sb.append(link);
loggerTakePost.error(sb.toString());
return null;
}
}
}
Enjoy your large image :)
Actually, you need two different solutions to fully fix this.
1] https://graph.facebook.com/{object_id}/picture
This solution works fine for images and videos posted to Facebook, but sadly, it returns small images in case the original image file was not uploaded to Facebook directly. (When posting a link to another site on your page for example).
2] The Facebook Graph API provides a way to get the full images in the feed itself for those external links. If you add 'full_picture' to the fields like in this example below when calling the API, you will be provided a link to the higher resolution version.
https://graph.facebook.com/your_facebook_id/posts?fields=id,link,full_picture,description,name&access_token=123456
Combining these two solutions I ended up filtering the input in PHP as follows:
if ( isset( $post['object_id'] ) ){
$image_url = 'https://graph.facebook.com/'.$post['object_id'].'/picture';
}else if ( isset( $post['full_picture'] ) ) {
$image_url = $post['full_picture'];
}else{
$image_url = '';
}
See: http://api-portal.anypoint.mulesoft.com/facebook/api/facebook-graph-api/docs/reference/pictures
Just put "?type=large" after the URL to get the big picture.
Thanks to #mattdlockyer for the JS solution. Here is a similar thing in PHP:
$posts = $facebook->api('/[page]/posts/', 'get');
foreach($posts['data'] as $post)
{
if(stristr(#$post['picture'], '_s.'))
{
$post['picture'] = str_replace('_s.', '_n.', #$post['picture']);
}
if(stristr(#$post['picture'], 'url='))
{
parse_str($post['picture'], $picturearr);
if($picturearr['url'])
$post['picture'] = $picturearr['url'];
}
//do more stuff with $post and $post['picture'] ...
}
After positive comment from #Lachezar Todorov I decided to post my current approach (including paging and using Json.NET ;):
try
{
FacebookClient fbClient = new FacebookClient(HttpContext.Current.Session[SessionFacebookAccessToken].ToString());
JObject posts = JObject.Parse(fbClient.Get(String.Format("/{0}/posts?fields=message,picture,link,attachments", FacebookPageId)).ToString());
JArray newsItems = (JArray)posts["data"];
List<NewsItem> result = new List<NewsItem>();
while (newsItems.Count > 0)
{
result.AddRange(GetItemsFromJsonData(newsItems));
if (result.Count > MaxNewsItems)
{
result.RemoveRange(MaxNewsItems, result.Count - MaxNewsItems);
break;
}
JToken paging = posts["paging"];
if (paging != null)
{
if (paging["next"] != null)
{
posts = JObject.Parse(fbClient.Get(paging.Value<String>("next")).ToString());
newsItems = (JArray)posts["data"];
}
}
}
return result;
}
And the helper method to retieve individual items:
private static IEnumerable<NewsItem> GetItemsFromJsonData(IEnumerable<JToken> items)
{
List<NewsItem> newsItems = new List<NewsItem>();
foreach (JToken item in items.Where(item => item["message"] != null))
{
NewsItem ni = new NewsItem
{
Message = item.Value<String>("message"),
DateTimeCreation = item.Value<DateTime?>("created_time"),
Link = item.Value<String>("link"),
Thumbnail = item.Value<String>("picture"),
// http://stackoverflow.com/questions/28319242/simplify-looking-up-nested-json-values-with-json-net/28359155#28359155
Image = (String)item.SelectToken("attachments.data[0].media.image.src") ?? (String)item.SelectToken("attachments.data[0].subattachments.data[0].media.image.src")
};
newsItems.Add(ni);
}
return newsItems;
}
NewsItem class I use:
public class NewsItem
{
public String Message { get; set; }
public DateTime? DateTimeCreation { get; set; }
public String Link { get; set; }
public String Thumbnail { get; set; }
public String Image { get; set; }
}