I have a method that returns NSData from a CGPathRef like so ...
+ (NSData *) createPDFDataWithCGPath: (CGPathRef) path mediaBox: (CGRect) mediaBox
{
CFMutableDataRef data = NULL;
if (path) {
CFAllocatorRef allocator = NULL;
data = CFDataCreateMutable(allocator, 0);
CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData(data);
CGContextRef context = CGPDFContextCreate(consumer, &mediaBox, NULL);
CFTypeRef keys[1] = { kCGPDFContextMediaBox };
CFTypeRef values[1] = { CFDataCreate(allocator, (const UInt8 *)&mediaBox, sizeof(CGRect)) };
CFDictionaryRef pageInfo = CFDictionaryCreate(allocator, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CGPDFContextBeginPage(context, pageInfo);
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, 0, -mediaBox.size.height);
CGContextAddPath(context, path);
CGContextSetRGBFillColor(context, 0, 0, 0, 1);
CGContextFillPath(context);
CGPDFContextEndPage(context);
CFRelease(pageInfo);
CFRelease(values[0]);
CGPDFContextClose(context);
CGContextRelease(context);
CGDataConsumerRelease(consumer);
}
return (NSData *)data;
}
When I attempt to use this and write a PDF file from the data I get my file at the correct size but the paths are not drawn into the PDF ... it's an empty document basically.
Is it enough to just write the file like so ...
[maskData writeToFile: DOCUMENTS_PATH_WITH_STRING(#"maskData.pdf") atomically: YES];
or are their more hoops to jump though to write it as a PDF?
You're right.
If you have data in an NSData object then you can just write it on the disk. But you should add the correct extension (in your case .pdf).
It works for everything (videos, pictures, etc...)
This was a bit of a red herring. The paths were being drawn but had no strokes or fills. The code in my question above is sound and works as expected.
Related
I am writing and IOS app where I need to save a CGImage as a JPEG file. It is important that I control the quality of the compression.
I've written the function provided below. It works, in that I get a JPEG file. But no matter what I set for the compression, I am always getting the same result. i.e. the file size is always the same.
Can anyone tell me what I am doing wrong?
void CGImageWriteJPEG(CGImageRef image, NSString *path) {
NSMutableData * data = [[NSMutableData alloc] init];
CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)data, kUTTypeJPEG, 1, NULL);
float compression = .8; // What I put here does not seem to matter...
CFStringRef myKeys[1];
CFTypeRef myValues[1];
CFDictionaryRef myOptions = NULL;
myKeys[0] = kCGImageDestinationLossyCompressionQuality;
myValues[0] = CFNumberCreate(NULL, kCFNumberFloatType, &compression);
myOptions = CFDictionaryCreate( NULL, (const void **)myKeys, (const void **)myValues, 1,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CGImageDestinationSetProperties(destination, myOptions);
CGImageDestinationAddImage(destination, image, nil);
CGImageDestinationFinalize(destination);
[data writeToURL:[NSURL fileURLWithPath:path] atomically:NO];
CFRelease(destination);
CFRelease(myOptions);
CFRelease(myValues[0]);
}
Try passing myOptions to CGImageDestinationAddImage() instead
CGImageDestinationAddImage(destination, image, myOptions);
It's what I had to do in swift, so I assume it's the same. e.g.
let imageProperties = [kCGImageDestinationLossyCompressionQuality as String: 0.8]
CGImageDestinationAddImage(destination, image, imageProperties)
Updated answer for swift 3
let imageProperties = [kCGImageDestinationLossyCompressionQuality as String: 0.8] as CFDictionary
CGImageDestinationAddImage(destination, image, imageProperties)
I have to show PDF First Page in UITableViewCell's ImageView.
My PDF Documents are located in document directory of app.
Here is my code in CellForRowAtIndexPath
NSURL* url =[self.arrayOfBooks objectAtIndex:indexPath.row];
UIImage *cellImage = [self buildThumbnailImage:MyGetPDFDocumentRef(url.absoluteString)];
cell.imageView.image = cellImage;
And Here is buildThumbnailImage Method.
- (UIImage *)buildThumbnailImage:(CGPDFDocumentRef)pdfDocument
{
BOOL hasRetinaDisplay = FALSE; // by default
CGFloat pixelsPerPoint = 1.0; // by default (pixelsPerPoint is just the "scale" property of the screen)
if ([UIScreen instancesRespondToSelector:#selector(scale)]) // the "scale" property is only present in iOS 4.0 and later
{
// we are running iOS 4.0 or later, so we may be on a Retina display; we need to check further...
if ((pixelsPerPoint = [[UIScreen mainScreen] scale]) == 1.0)
hasRetinaDisplay = FALSE;
else
hasRetinaDisplay = TRUE;
}
else
{
// we are NOT running iOS 4.0 or later, so we can be sure that we are NOT on a Retina display
pixelsPerPoint = 1.0;
hasRetinaDisplay = FALSE;
}
size_t imageWidth = 320; // width of thumbnail in points
size_t imageHeight = 460; // height of thumbnail in points
if (hasRetinaDisplay)
{
imageWidth *= pixelsPerPoint;
imageHeight *= pixelsPerPoint;
}
size_t bytesPerPixel = 4; // RGBA
size_t bitsPerComponent = 8;
size_t bytesPerRow = bytesPerPixel * imageWidth;
void *bitmapData = malloc(imageWidth * imageHeight * bytesPerPixel);
// in the event that we were unable to mallocate the heap memory for the bitmap,
// we just abort and preemptively return nil:
if (bitmapData == NULL)
return nil;
// remember to zero the buffer before handing it off to the bitmap context:
bzero(bitmapData, imageWidth * imageHeight * bytesPerPixel);
CGContextRef theContext = CGBitmapContextCreate(bitmapData, imageWidth, imageHeight, bitsPerComponent, bytesPerRow,
CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedLast);
//CGPDFDocumentRef pdfDocument = MyGetPDFDocumentRef(); // NOTE: you will need to modify this line to supply the CGPDFDocumentRef for your file here...
CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDocument, 1); // get the first page for your thumbnail
CGAffineTransform shrinkingTransform =
CGPDFPageGetDrawingTransform(pdfPage, kCGPDFMediaBox, CGRectMake(0, 0, imageWidth, imageHeight), 0, YES);
CGContextConcatCTM(theContext, shrinkingTransform);
CGContextDrawPDFPage(theContext, pdfPage); // draw the pdfPage into the bitmap context
CGPDFDocumentRelease(pdfDocument);
//
// create the CGImageRef (and thence the UIImage) from the context (with its bitmap of the pdf page):
//
CGImageRef theCGImageRef = CGBitmapContextCreateImage(theContext);
free(CGBitmapContextGetData(theContext)); // this frees the bitmapData we malloc'ed earlier
CGContextRelease(theContext);
UIImage *theUIImage;
// CAUTION: the method imageWithCGImage:scale:orientation: only exists on iOS 4.0 or later!!!
if ([UIImage respondsToSelector:#selector(imageWithCGImage:scale:orientation:)])
{
theUIImage = [UIImage imageWithCGImage:theCGImageRef scale:pixelsPerPoint orientation:UIImageOrientationUp];
}
else
{
theUIImage = [UIImage imageWithCGImage:theCGImageRef];
}
CFRelease(theCGImageRef);
return theUIImage;
}
CGPDFDocumentRef MyGetPDFDocumentRef(NSString *inputPDFFile)
{
//NSString *inputPDFFile = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"test.pdf"];
const char *inputPDFFileAsCString = [inputPDFFile cStringUsingEncoding:NSASCIIStringEncoding];
//NSLog(#"expecting pdf file to exist at this pathname: \"%s\"", inputPDFFileAsCString);
CFStringRef path = CFStringCreateWithCString(NULL, inputPDFFileAsCString, kCFStringEncodingUTF8);
CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, 0);
CFRelease (path);
CGPDFDocumentRef document = CGPDFDocumentCreateWithURL(url);
CFRelease(url);
if (CGPDFDocumentGetNumberOfPages(document) == 0)
{
printf("Warning: No pages in pdf file \"%s\" or pdf file does not exist at this path\n", inputPDFFileAsCString);
return NULL;
}
return document;
}
And Here is how i load pdf file list from document directory.
- (NSMutableArray *)loadBookFromDocumentDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [NSString stringWithFormat:#"%#",[paths objectAtIndex:0]];
NSFileManager *manager = [NSFileManager defaultManager];
NSError *error;
NSArray *files = [manager contentsOfDirectoryAtURL:[NSURL fileURLWithPath:documentsDirectory]
includingPropertiesForKeys:[NSArray arrayWithObject:NSURLContentModificationDateKey]
options:NSDirectoryEnumerationSkipsHiddenFiles
error:&error];
NSArray* sortArray = [files sortedArrayUsingComparator:
^(NSURL *file1, NSURL *file2)
{
NSDate *file1Date;
[file1 getResourceValue:&file1Date forKey:NSURLContentModificationDateKey error:nil];
NSDate *file2Date;
[file2 getResourceValue:&file2Date forKey:NSURLContentModificationDateKey error:nil];
// Ascending:
//return [file1Date compare: file2Date];
// Descending:
return [file2Date compare: file1Date];
}];
NSMutableArray *sortedContents = [[NSMutableArray alloc] initWithArray:sortArray];
return sortedContents;
}
When i run my app , it doesn't show anything at Cell ImageView and showing this message.
file:///Users/MacUser/Library/Application%20Support/iPhone%20Simulator/7.1-64/Applications/08BE9071-6251-44ED-A8E0-55CD478380FC/Documents/CGPDFDocument.pdf" or pdf file does not exist at this path
I am sure i have that pdf and even showing PDF Name in TableView.
Where am i wroning?
Okay. I think I understand what's going on here.
You've "added your PDF files via iTunes". I have NO idea how that is supposed to actually work.
But it's clear to me that the PDF files in your simulator folder are zero bytes in size.
The code you have right now should work, you just need to get valid PDF files into there to start with.
In Terminal, you can open that folder using the command
open ~/Library/Application\ Support/iPhone\ Simulator/7.1-64/Applications/08BE9071-6251-44ED-A8E0-55CD478380FC/Documents
And when it opens in the Macintosh Finder, you'll see that all the PDF files in there are zero bytes in size. Manually copy in your correct PDF files and your app should begin to magically work in the simulator.
Now, for production code, you need to write code to REALLY copy the PDF files into the documents folder. Where do the PDF files come from originally? Do you download them or are they built into the app somewhere?
I'm trying to print a PDF document pulled from a web server from my iPad app.
The document is in landscape (proved with Preview) but the UiPrinterInteractionController prints the document in portrait mode.
I set printInfo.orientation = UiPrintInfoOrientationLandscape; but it doesn't seem to help.
I try to print the document to the Printer Simulator. When I go into the folder where the documents are saved, I got to documents. One, the original file, one the printed one.
The original file is in landscape and oriented the right way. But the second one, the print output, is in portrait and the borders are cut.
Any ideas?
Thanks for help, Julian
Salute,
I guess we can rotate PDF data manually before sending it to printer.
Here is some code below (sorry actually not really tested) which I hope could be helpful (not sure it is a best solution but anyway). Make sure that "QuartzCore/QuartzCore.h" is imported.
- (NSData *) prepareForPrinting:(NSData *) data
{
NSData *result = nil;
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((CFDataRef)data);
CGPDFDocumentRef document = CGPDFDocumentCreateWithProvider(dataProvider);
CGPDFPageRef page = CGPDFDocumentGetPage(document, 1);
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
if (pageRect.size.width > pageRect.size.height)
{
GLuint w = pageRect.size.width;
GLuint h = pageRect.size.height;
pageRect.size.width = h;
pageRect.size.height = w;
CFMutableDataRef mutableData = CFDataCreateMutable(NULL, 0);
CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData(mutableData);
CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, &pageRect, NULL);
int numPages = CGPDFDocumentGetNumberOfPages(document);
if (numPages > 0)
{
for (int i = 0; i < numPages; i++)
{
page = CGPDFDocumentGetPage(document, i + 1);
CGPDFContextBeginPage(pdfContext, NULL);
CGContextRotateCTM(pdfContext, M_PI_2);
CGContextTranslateCTM(pdfContext, 0, -pageRect.size.width);
CGContextDrawPDFPage(pdfContext, page);
CGPDFContextEndPage(pdfContext);
}
}
else
{
NSLog(#"Invalid PDF");
}
CGContextRelease(pdfContext);
result = [NSData dataWithData:(NSData *)mutableData];
CGDataConsumerRelease(dataConsumer);
CFRelease(mutableData);
}
else
{
result = data;
}
CGDataProviderRelease(dataProvider);
CGPDFDocumentRelease(document);
return result;
}
I am completing the final part of localizations for a project. The translated text has come back to me split between .txt and .docx formats.
The .txt once entered into the localizable.strings works fine, but that copied from word document doesn't work.
This is what I've tried so far:
save .docx as .txt and let word encode
save .txt as korean (Mac OS X),
then copy this text to XCode and reinterpret as korean (Mac OS X), then
convert to utf-16
Have tried many options to convert to utf-16, but just can't seem to crack it.
Any ideas would be much appreciated.
Here is the localized help view implementation:
helpText = [NSArray arrayWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:
NSLocalizedString(#" The Actions Tab", nil), kHelpTextKeyString,
#"Arial", kHelpTextKeyFontName,
[NSNumber numberWithInt:20], kHelpTextKeyFontSize,
[[UIColor blackColor] CGColor], kHelpTextKeyColor,
CGRectCreateDictionaryRepresentation(CGRectMake(30.0, 55.0, 200.0, 28.0)), kHelpTextKeyRect,
nil],
[NSDictionary dictionaryWithObjectsAndKeys:
[NSArray arrayWithObjects:
NSLocalizedString(#"
- (void)displaySelectedHelpImage:(UIImage *)orgImage withTextArray:(NSArray *)textArr {
CGImageRef cgImage = [orgImage CGImage];
int pixelsWide = CGImageGetWidth(cgImage);
int pixelsHigh = CGImageGetHeight(cgImage);
int bitsPerComponent = CGImageGetBitsPerComponent(cgImage);//8; // fixed
int bitsPerPixel = CGImageGetBitsPerPixel(cgImage);//bitsPerComponent * numberOfCompnent;
int bytesPerRow = CGImageGetBytesPerRow(cgImage);//(pixelsWide * bitsPerPixel) // 8; // bytes
int byteCount = (bytesPerRow * pixelsHigh);
CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage);//CGColorSpaceCreateDeviceRGB();
// Allocate data
NSMutableData *data = [NSMutableData dataWithLength:byteCount];
// Create a bitmap context
CGContextRef context = CGBitmapContextCreate([data mutableBytes], pixelsWide, pixelsHigh, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast); //kCGImageAlphaPremultipliedLast);//kCGImageAlphaNoneSkipLast); //kCGImageAlphaOnly);
// Set the blend mode to copy to avoid any alteration of the source data or to invert to invert image
CGContextSetBlendMode(context, kCGBlendModeCopy);
// Set alpha
CGContextSetAlpha(context, 1.0);
// Color image
//CGContextSetRGBFillColor(context, 1 ,1, 1, 1.0);
//CGContextFillRect(context, CGRectMake(0.0, 0.0, pixelsWide, pixelsHigh));
// Draw the image to extract the alpha channel
CGContextDrawImage(context, CGRectMake(0.0, 0.0, pixelsWide, pixelsHigh), cgImage);
// add text to image
// Changes the origin of the user coordinate system in a context
//CGContextTranslateCTM (context, pixelsWide, pixelsHigh);
// Rotate context upright
//CGContextRotateCTM (context, -180. * M_PI/180);
for (NSDictionary *dic in textArr) {
CGContextSelectFont (context,
//todo
[[dic objectForKey:kHelpTextKeyFontName] UTF8String],
[[dic objectForKey:kHelpTextKeyFontSize] intValue],
kCGEncodingMacRoman);
CGContextSetCharacterSpacing (context, 2);
CGContextSetTextDrawingMode (context, kCGTextFillStroke);
CGColorRef color = (CGColorRef)[dic objectForKey:kHelpTextKeyColor];
CGRect rect;
CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)[dic objectForKey:kHelpTextKeyRect], &rect);
CGContextSetFillColorWithColor(context, color);
CGContextSetStrokeColorWithColor(context, color);
if ([[dic objectForKey:kHelpTextKeyString] isKindOfClass:[NSArray class]]) {
for (NSString *str in [dic objectForKey:kHelpTextKeyString]) {
CGContextShowTextAtPoint(context,
rect.origin.x,
pixelsHigh - rect.origin.y,
[str cStringUsingEncoding:[NSString defaultCStringEncoding]],
[str length]);
rect.origin.y += [[dic objectForKey:kHelpTextKeyFontSize] intValue];
}
For anyone facing this issue, it was solved by using the coretext foundation class.
What do the Word documents contain? What do you mean by "doesn't work?"
If they contain strings, couldn't you simply append them to the existing localizable.strings file? Since that works there is no encoding issue in this file, you could just copy/paste them from Word into the localizable.strings file in XCode.
i render Thumbnails of newly recieved PDF Document to the Documents-Directory.
I'm using the following code:
CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("thedoc.pdf"), NULL, NULL);
CGPDFDocumentRef bookPDF = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
UIGraphicsBeginImageContext(CGSizeMake(100, 130));
NSUInteger totalNum = CGPDFDocumentGetNumberOfPages(bookPDF);
CGContextRef context = UIGraphicsGetCurrentContext();
for(int i = 0; i < totalNum; i++ ) {
CGRect arect = CGRectMake(0,0,200,282);
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, 141);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetGrayFillColor(context, 1.0, 1.0);
CGContextFillRect(context, arect);
// Grab the first PDF page
CGPDFPageRef page = CGPDFDocumentGetPage(bookPDF, i + 1);
CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFMediaBox, arect, 0, true);
// And apply the transform.
CGContextConcatCTM(context, pdfTransform);
CGContextDrawPDFPage(context, page);
// Create the new UIImage from the context
UIImage* thumbnailImage = UIGraphicsGetImageFromCurrentImageContext();
if (thumbnailImage == nil) {
NSLog(#"ERROR during creation of PNG");
}
// SAVE THE IMAGE TO DOCUMENTS-DIRECTORY
NSString *pngPath = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"%#/thumbPage%i.png",theLocalFolder ,i]];
// Write image to PNG
BOOL writtenBool = [UIImagePNGRepresentation(thumbnailImage) writeToFile:pngPath atomically:YES];
// END SAVE THE IMAGE TO DOCUMENT-DIRECTORY
CGContextRestoreGState(context);
NSLog(#"Rendering PDF-Thumbnail %i (%i): %#", i, writtenBool, [NSString stringWithFormat:#"%#/thumbPage%i.png",theLocalFolder ,i]);
}
There is no error in Console, but the PNGs are not stored to the documents-Directory. The BOOL
writtenBool
is "0", what means that the write-action was not succuessful. I don't know why. I write the path in
pngPath
also to the console and the path is correct. If i open a terminal and write
open <<copyed path from console>>
it opens the correct path in finder.
What could cause this not to work? I had a look at the api but there seems to be no
error:
for UIImagePNGRepresentation: writeToFile:
Thanks for your help!
UIImagePNGRepresentation(thumbnailImage) return a NSData object
for NSData object, you can use these methods:
writeToFile:atomically:,
writeToFile:options:error:,
writeToURL:atomically:,
writeToURL:options:error:,
so, you can try use code like BOOL writtenBool = [UIImagePNGRepresentation(thumbnailImage) writeToFile:pngPath options:NSDataWritingAtomic error:&error]; to see what happened.