Images in RTF getting lost on Mac - objective-c

I have RTF text which I am showing to the user on Mac. Now I need to replace some text. The text has some images inline. When I execute the following code, the images are getting lost. I am using c#, Mono and Monobjc to run this on mac.
NSText _questionView;
// some initialisation code which I have skipped
//
NSRange range = NSRange.NSMakeRange(0, _questionView.TextStorage.Length);
NSData oldString = _questionView.RTFFromRange(range);
if (oldString != null)
{
string s = oldString.ConvertRTFToString();
_questionView.ReplaceCharactersInRangeWithRTF(range, s.ConvertToNSData());
_questionView.SelectedRange = NSRange.NSMakeRange(0,0);
// After this line the inline images are lost.
}

You are losing the images because you are converting the RTF content to NSString. NSString can only carry text, not attributes. You should consider using NSAttributedString instead for the text manipulation, in order to keep the RTF attributes (style, images, etc.).

Related

How do you add a picture to the ID3 Album tag using taglib#

I've been searching the internet and trying various methods to save a picturbox image to the the id3 Album picture tag. One sample code says the Album cover tag name is taglib.ipicture another says taglibVariable.Image and yet another says taglibVariable.picture(0).
I am becoming so confused I'm starting to repeat sample test code.
Where is the documentation that will explain what I have to do.?
What little information I can find are dead links to sample code or incomplete code using variables without explanations. When I look up the commands and try to format or convert to the needed data type, I get an error. Usually system.image.bmp cannot be converted to iPicture.
Can anyone give me some working code or a pointer on how to word the proper search term to add a picturebox.image to the Album picture tag. Saving the image as a file then opening as image to put in tag then deleting file is not an option. I need to create a memory image and add that to the picture tag.
This is what I use:
public void SavePicture(string fileName, string picName) {
try {
IPicture[] pics = new TagLib.IPicture[1];
pics[0] = new TagLib.Picture(picName);
using (var songTag = TagLib.File.Create(fileName)) {
songTag.Tag.Pictures = pics;
songTag.Save();
}
}
catch {
// process
// mpeg header is corrupt
}
}
fileName is the full path to the audio file;
picName is the full path to the picture.
You can add multiple pics by setting the array size for the IPicture array accordingly...

HTML string to PDF conversion

I need to create various reports in PDF format and email it to specific person. I managed to load HTML template into string and am replacing certain "custom markers" with real data. At the end I have a fulle viewable HTML file. This file must now be printed into PDF format which I am able todo after following this link : https://www.appcoda.com/pdf-generation-ios/. My problem is that I do not understand how to determine the number of pages from the HTML file as the pdf renderer requires creating page-by-page.
I know this is an old thread, I would like to leave this answer here. I also used the same tutorial you've mention and here's what I did to make multiple pages. Just modify the drawPDFUsingPrintPageRenderer method like this:
func drawPDFUsingPrintPageRenderer(printPageRenderer: UIPrintPageRenderer) -> NSData! {
let data = NSMutableData()
UIGraphicsBeginPDFContextToData(data, CGRect.zero, nil)
printPageRenderer.prepare(forDrawingPages: NSMakeRange(0, printPageRenderer.numberOfPages))
let bounds = UIGraphicsGetPDFContextBounds()
for i in 0...(printPageRenderer.numberOfPages - 1) {
UIGraphicsBeginPDFPage()
printPageRenderer.drawPage(at: i, in: bounds)
}
UIGraphicsEndPDFContext()
return data
}
In your custom PrintPageRenderer you can access the numberOfPages to have the total count of the pages

iTextSharp - PDF field contents become invisible

I have a PDF where I add some TextFields.
var txtFld = new TextField(stamper.Writer, new Rectangle(cRightX - cWidthX, cTopY3, cRightX, cTopY), FieldNameProtocol) { Font = bf, FontSize = cHeaderFontSize, Alignment = Element.ALIGN_RIGHT, Options = PdfFormField.FF_MULTILINE };
stamper.AddAnnotation(txtFld.GetTextField(), 1);
The ‘bf’ above is a Unicode font that gets embedded in the PDF:
BaseFont bf = BaseFont.CreateFont(UnicodeFontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); // Create a Unicode font to write in Greek...
Later-on I fill those fields with greek text.
var acrof = stamper.AcroFields;
acrof.SetField(fieldName, field.Value/*, field.Value*/); // Set the text of the form field.
acrof.SetFieldProperty(fieldName, "setfflags", PdfFormField.FF_READ_ONLY, null); // Make it readonly.
When I view the PDF, most of the times the text is missing and if I click on the (invisible) TextField in Acrobat, then the text becomes visible (until it loses focus again).
Any idea what is going on here?
I have also tried using non-embedded font, but I get the same thing (although I still seem to get embedded fonts in PDF that are similar to the font I use). I don't know if I am missing sth.
It seemed that I was doing the following at the wrong order (the following is the correct):
acrof.SetFieldProperty(field.Name, "setfflags", PdfFormField.FF_READ_ONLY, null); // Make it readonly.
acrof.SetFieldProperty(field.Name, "textfont", bf, null);
acrof.SetField(field.Name, field.Value/*, field.Value*/); // Set the text of the form field.
At least that's hat I think it was wrong.
I have made many changes.

Resizing .tif image with imgscalr

I am trying to resize a .tif image and then display it on the browser by converting it to a base64 string. Since ImageIo doesn't support TIF images by default, i have added imageio_alpha-1.1.jar(got it here - http://www.findjar.com/jar/geoserver/jai/jars/jai_imageio-1.1-alpha.jar.html). Now ImageIO is able to register the plugin, which i checked by doing this
String[] writerNames = ImageIO.getWriterFormatNames();
writerNames has TIF in it, this means ImageIO has registered the plugin.
I am resizing the image like this
Map resizeImage(BufferedImage imageData, int width, int height, String imageFormat){
BufferedImage thumbnail = Scalr.resize(imageData, Scalr.Method.SPEED, Scalr.Mode.FIT_EXACT ,
width, height, Scalr.OP_ANTIALIAS);
String[] writerNames = ImageIO.getWriterFormatNames();
ByteArrayOutputStream baos = new ByteArrayOutputStream()
ImageIO.write(thumbnail, imageFormat, baos)
baos.flush()
byte[] imageBytes = baos.toByteArray()
baos.close()
return [imageBytes:imageBytes, imageFormat:imageFormat]
}
String encodeImageToBase64(byte[] imageData){
return Base64.encodeBase64String(imageData)
}
BufferedImage getBufferedImage(byte[] imageData){
ByteArrayInputStream bais = new ByteArrayInputStream(imageData)
BufferedImage bImageFromConvert = ImageIO.read(bais)
bais.close()
return bImageFromConvert
}
String resizeToDimensions(byte[] imageData, String imageFormat, int width, int height){
def bimg = getBufferedImage(imageData)
Map resizedImageData = resizeImage(bimg, width, height, imageFormat)
return encodeImageToBase64(resizedImageData.imageBytes)
}
now i am displaying the image like this
< img src = "data:image/tif;base64,TU0AKgAAAAgADAEAAAMAAA...." /> with this i get failed to load url message(on hovering)
as far as i know the base64 string usually starts with /9j/(may be i am wrong). when i am appending /9j/. I get an error - "image corrupt or truncated". I am not able to figure out the problem here, please help.
At first glance your use of the Data URI format looks correct -- try and narrow down exactly where the failure is.
I would recommend:
In your method where you return the string to the front end, I would recommend printing the entire thing out to the console to get the raw data in Data URI format.
Take the Data URI string, create a sample HTML file with the hard-coded value in it, try and load it... does the image display? If so, great, then your problem is with how you are streaming that back to the front end or how you are trying to load it. (Likely a JavaScript/DOM issue)
If that doesn't work, try and chop the Base64 section out of the example and save it into an example TXT file. In your Java code, load it, decode it and try and create an image out of it and write it back out to a TIFF -- if that didn't work, then there is something wrong with your Base64 handling and the encoding is invalid most likely.
Getting that far should answer most of the questions.
Actually now that I think about it, try and use ImageIO to read the image into a BufferedImage, then process it with imgscalr, then immediately call ImageIO.write and try and write it out to a new TIF someplace else and make sure the ImageIO decoding/encoding process is working correctly.
Hope that helps!

Page by page conversion of PDF into TIFF with proper compression

Problem
There are PDF documents with different type of objects inside. There are simple texts. There can be scanned images that are B&W, and also other images, that are true color. The resolution can be quite high for both (~1789X2711).
I need to convert the PDF into a set of single page TIFF files. There are quite good tools for that. For example Irfanview, ImageMagick. The problem is that I have to define a single compression type for all the pages.
Using JPG for all pages would result in loosing details for B&W images and they would be huge compared to lossless fax compression.
Using lossless fax for all would wanish colors and details of true color images.
Idea
It would be nice to examine the PDF page by page. I could check the content of the page. What kind of images are there inside, and which compression is recommanded for the particular page. I think this can be done with IText, but I don't know exactly, how it should be done. A second thing is that I want to do this analysis without fully reading the PDF file. Is it possible?
Maybe the fastest solution would be to create a list of pages for each compression type with IText analysis, and then to call Irfanview to process the choosen pages with the proper compression.
Any ideas and recommendations are welcome.
UPDATE:
I have now an answer. It does not cover all requirements, and its not freeware. Any opensource ideas? Maybe Java based solutions?
This can be done with DotImage DotPdf from Atalasoft (cue the obligatory "I work there and work on these products"). Here is how I would do this task in C#:
PdfImageSource source = new PdfImageSource(pdfStream);
while (source.HasMoreImages()) {
AtalaImage image = source.AcquireNext();
string fileName = GetNextTiffName();
using (FileStream outStm = new FileStream(fileName, FileMode.Create)) {
TiffEncoder encoder = new TiffEncoder();
encoder.Compression = SelectCompression(image.PixelFormat);
image.Save(outStm, encoder, null);
}
source.Release(image);
}
private TiffCompression SelectCompression(PixelFormat pf)
{
switch (pf) {
// 1 bit? use CCITT G4
case PixelFormat.Pixel1bbIndexed: return TiffCompression.Group4FaxEncoding;
// 24 bit? use JPEG
case PixelFormat.Pixel24bppBgr: return TiffCompression.JpegCompression;
// all else, Lzw
default: return TiffCompression.Lzw;
}
}
You can make SelectCompression do pretty much whatever you want. If you select an invalid compression for that pixel format, the encoder will use an appropriate lossless one in its place (for example, if you select CCITT for 24bit color, the encoder will instead use Lzw).
Our PDF decoder knows when a PDF page is just gray and returns a gray image. It does NOT do anything to get you to 1 bit (this is so antialiased text looks good), however you could threshold the gray image and look at the overall differences between it and the gray image to determine if it could go to 1 bit).
Here's how you could do a set of pages:
public void ExtractNPages(Stream pdfStream, params int[] pageIndexes)
{
PdfImageSource source = new PdfImageSource(pdfStream);
for (int i in pageIndexes) {
AtalaImage image = source[i]; // implied Acquire
string fileName = GetNextTiffName();
using (FileStream outStm = new FileStream(fileName, FileMode.Create)) {
TiffEncoder = new TiffEncoder();
encoder.Compression = SelectCompression(image.PixelFormat);
image.Save(outStm, encoder, null);
}
source.Release(image);
}
}
so now you can just do ExtractNPages(stm, 0, 2, 4, 6);