static void quartz_format(GVJ_t *job) { /* image destination -> data consumer -> job's gvdevice */ /* data provider <- job's imagedata */ CGDataConsumerRef data_consumer = CGDataConsumerCreate(job, &device_data_consumer_callbacks); CGImageDestinationRef image_destination = CGImageDestinationCreateWithDataConsumer(data_consumer, format_uti[job->device.id], 1, NULL); CGDataProviderRef data_provider = CGDataProviderCreateDirect(job->imagedata, BYTES_PER_PIXEL * job->width * job->height, &memory_data_provider_callbacks); /* add the bitmap image to the destination and save it */ CGColorSpaceRef color_space = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); CGImageRef image = CGImageCreate ( job->width, /* width in pixels */ job->height, /* height in pixels */ BITS_PER_COMPONENT, /* bits per component */ BYTES_PER_PIXEL * 8, /* bits per pixel */ BYTES_PER_PIXEL * job->width, /* bytes per row: exactly width # of pixels */ color_space, /* color space: sRGB */ kCGImageAlphaPremultipliedFirst, /* bitmap info: corresponds to CAIRO_FORMAT_ARGB32 */ data_provider, /* data provider: from imagedata */ NULL, /* decode: don't remap colors */ FALSE, /* don't interpolate */ kCGRenderingIntentDefault /* rendering intent (what to do with out-of-gamut colors): default */ ); CGImageDestinationAddImage(image_destination, image, NULL); CGImageDestinationFinalize(image_destination); /* clean up */ CGImageRelease(image); CGColorSpaceRelease(color_space); CGDataProviderRelease(data_provider); if (image_destination) CFRelease(image_destination); CGDataConsumerRelease(data_consumer); }
void Picture_copyToClipboard (Picture me) { /* * Find the clipboard and clear it. */ PasteboardRef clipboard = nullptr; PasteboardCreate (kPasteboardClipboard, & clipboard); PasteboardClear (clipboard); /* * Add a PDF flavour to the clipboard. */ static CGDataConsumerCallbacks callbacks = { appendBytes, nullptr }; CFDataRef data = CFDataCreateMutable (kCFAllocatorDefault, 0); CGDataConsumerRef consumer = CGDataConsumerCreate ((void *) data, & callbacks); int resolution = 600; CGRect rect = CGRectMake (0, 0, (my selx2 - my selx1) * resolution, (my sely1 - my sely2) * resolution); CGContextRef context = CGPDFContextCreate (consumer, & rect, nullptr); //my selx1 * RES, (12 - my sely2) * RES, my selx2 * RES, (12 - my sely1) * RES) {// scope autoGraphics graphics = Graphics_create_pdf (context, resolution, my selx1, my selx2, my sely1, my sely2); Graphics_play (my graphics.get(), graphics.get()); } PasteboardPutItemFlavor (clipboard, (PasteboardItemID) 1, kUTTypePDF, data, kPasteboardFlavorNoFlags); CFRelease (data); /* * Forget the clipboard. */ CFRelease (clipboard); }
static SkUniqueCFRef<CGDataConsumerRef> SkStreamToCGDataConsumer(SkWStream* stream) { CGDataConsumerCallbacks procs; procs.putBytes = consumer_put; procs.releaseConsumer = consumer_release; // we don't own/reference the stream, so it our consumer must not live // longer that our caller's ownership of the stream return SkUniqueCFRef<CGDataConsumerRef>(CGDataConsumerCreate(stream, &procs)); }
/* The idea of a scratch context comes from WebKit */ static CGContextRef CreateScratchContext() { CGDataConsumerCallbacks callbacks = {PutBytesNull, nullptr}; CGDataConsumerRef consumer = CGDataConsumerCreate(nullptr, &callbacks); CGContextRef cg = CGPDFContextCreate(consumer, nullptr, nullptr); CGDataConsumerRelease(consumer); return cg; }
static CGContextRef createScratchContext() { CGDataConsumerCallbacks callbacks = { putBytesNowhere, 0 }; RetainPtr<CGDataConsumerRef> consumer(AdoptCF, CGDataConsumerCreate(0, &callbacks)); CGContextRef context = CGPDFContextCreate(consumer.get(), 0, 0); CGFloat black[4] = { 0, 0, 0, 1 }; CGContextSetFillColor(context, black); CGContextSetStrokeColor(context, black); return context; }
err_t MacCGEncoder::writeImage(const Image& image) { Image tmp; if (image.isEmpty()) return ERR_IMAGE_INVALID_SIZE; err_t err = ERR_OK; CGDataConsumerRef cgConsumer = NULL; CGImageDestinationRef cgDestination = NULL; CGImageRef cgImage = NULL; cgConsumer = CGDataConsumerCreate(this, &_consumerCallbacks); if (FOG_IS_NULL(cgConsumer)) { err = ERR_RT_OUT_OF_MEMORY; goto _End; } cgDestination = CGImageDestinationCreateWithDataConsumer(cgConsumer, static_cast<MacCGCodecProvider*>(_provider)->getUTType(), 1, NULL); CFRelease(cgConsumer); if (FOG_IS_NULL(cgDestination)) { err = ERR_RT_OUT_OF_MEMORY; goto _End; } if (image.getType() == IMAGE_TYPE_MAC_CG) cgImage = static_cast<CGImageRef>(const_cast<Image&>(image).getHandle()); if (FOG_IS_NULL(cgImage)) { err = image.toCGImage(&cgImage); if (FOG_IS_ERROR(err)) goto _End; } CGImageDestinationAddImage(cgDestination, cgImage, NULL); if (!CGImageDestinationFinalize(cgDestination)) { err = ERR_IO_CANT_WRITE; } _End: CFRelease(cgDestination); if (err == ERR_OK) updateProgress(1.0f); return err; }
static void quartzgen_end_job(GVJ_t *job) { CGContextRef context = (CGContextRef)job->context; if (!job->external_context) { switch (job->device.id) { case FORMAT_PDF: /* save the PDF */ CGPDFContextClose(context); break; case FORMAT_CGIMAGE: break; #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040 default: /* bitmap formats */ { /* create an image destination */ CGDataConsumerRef data_consumer = CGDataConsumerCreate(job, &device_data_consumer_callbacks); CGImageDestinationRef image_destination = CGImageDestinationCreateWithDataConsumer(data_consumer, format_uti[job->device.id], 1, NULL); /* add the bitmap image to the destination and save it */ CGImageRef image = CGBitmapContextCreateImage(context); CGImageDestinationAddImage(image_destination, image, NULL); CGImageDestinationFinalize(image_destination); /* clean up */ if (image_destination) CFRelease(image_destination); CGImageRelease(image); CGDataConsumerRelease(data_consumer); } break; #endif } CGContextRelease(context); } else if (job->device.id == FORMAT_CGIMAGE) { /* create an image and save it where the window field is, which was set to the passed-in context at begin job */ *((CGImageRef*)job->window) = CGBitmapContextCreateImage(context); #if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000 void* context_data = CGBitmapContextGetData(context); size_t context_datalen = CGBitmapContextGetBytesPerRow(context) * CGBitmapContextGetHeight(context); #endif CGContextRelease(context); #if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000 munmap(context_data, context_datalen); #endif } }
int main(int argc, char** argv) { if (argc <= 1 || !*(argv[1]) || 0 == strcmp(argv[1], "-")) { fprintf(stderr, "usage:\n\t%s INPUT_PDF_FILE_PATH [OUTPUT_PNG_PATH]\n", argv[0]); return 1; } const char* output = argc > 2 ? argv[2] : nullptr; CGDataProviderRef data = CGDataProviderCreateWithFilename(argv[1]); ASSERT(data); CGPDFDocumentRef pdf = CGPDFDocumentCreateWithProvider(data); CGDataProviderRelease(data); ASSERT(pdf); CGPDFPageRef page = CGPDFDocumentGetPage(pdf, PAGE); ASSERT(page); CGRect bounds = CGPDFPageGetBoxRect(page, kCGPDFMediaBox); int w = (int)CGRectGetWidth(bounds); int h = (int)CGRectGetHeight(bounds); CGBitmapInfo info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast; CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); ASSERT(cs); std::unique_ptr<uint32_t[]> bitmap(new uint32_t[w * h]); memset(bitmap.get(), 0xFF, 4 * w * h); CGContextRef ctx = CGBitmapContextCreate(bitmap.get(), w, h, 8, w * 4, cs, info); ASSERT(ctx); CGContextDrawPDFPage(ctx, page); CGPDFDocumentRelease(pdf); CGImageRef image = CGBitmapContextCreateImage(ctx); ASSERT(image); CGDataConsumerCallbacks procs; procs.putBytes = [](void* f, const void* buf, size_t s) { return fwrite(buf, 1, s, (FILE*)f); }; procs.releaseConsumer = [](void* info) { fclose((FILE*)info); }; FILE* ofile = (!output || !output[0] || 0 == strcmp(output, "-")) ? stdout : fopen(output, "wb"); ASSERT(ofile); CGDataConsumerRef consumer = CGDataConsumerCreate(ofile, &procs); ASSERT(consumer); CGImageDestinationRef dst = CGImageDestinationCreateWithDataConsumer(consumer, kUTTypePNG, 1, nullptr); CFRelease(consumer); ASSERT(dst); CGImageDestinationAddImage(dst, image, nullptr); ASSERT(CGImageDestinationFinalize(dst)); CFRelease(dst); CGImageRelease(image); CGColorSpaceRelease(cs); CGContextRelease(ctx); return 0; }
static void quartzgen_begin_page(GVJ_t *job) { CGRect bounds = CGRectMake(0.0, 0.0, job->width, job->height); if (!job->context) { switch (job->device.id) { case FORMAT_PDF: { /* create the auxiliary info for PDF content, author and title */ CFStringRef auxiliaryKeys[] = { kCGPDFContextCreator, kCGPDFContextTitle }; CFStringRef auxiliaryValues[] = { CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s %s"), job->common->info[0], job->common->info[1]), job->obj->type == ROOTGRAPH_OBJTYPE ? CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)job->obj->u.g->name, strlen(job->obj->u.g->name), kCFStringEncodingUTF8, false, kCFAllocatorNull) : CFSTR("") }; CFDictionaryRef auxiliaryInfo = CFDictionaryCreate( kCFAllocatorDefault, (const void **)&auxiliaryKeys, (const void **)&auxiliaryValues, sizeof(auxiliaryValues)/sizeof(auxiliaryValues[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); /* create a PDF for drawing into */ CGDataConsumerRef data_consumer = CGDataConsumerCreate(job, &device_data_consumer_callbacks); job->context = CGPDFContextCreate(data_consumer, &bounds, auxiliaryInfo); /* clean up */ CGDataConsumerRelease(data_consumer); CFRelease(auxiliaryInfo); int i; for (i = 0; i < sizeof(auxiliaryValues)/sizeof(auxiliaryValues[0]); ++i) CFRelease(auxiliaryValues[i]); } break; default: /* bitmap formats */ { size_t bytes_per_row = (job->width * BYTES_PER_PIXEL + BYTE_ALIGN) & ~BYTE_ALIGN; void* buffer = NULL; #if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000 /* iPhoneOS has no swap files for memory, so if we're short of memory we need to make our own temp scratch file to back it */ size_t buffer_size = job->height * bytes_per_row; mach_msg_type_number_t vm_info_size = HOST_VM_INFO_COUNT; vm_statistics_data_t vm_info; if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_info, &vm_info_size) != KERN_SUCCESS || buffer_size * 2 > vm_info.free_count * vm_page_size) { FILE* temp_file = tmpfile(); if (temp_file) { int temp_file_descriptor = fileno(temp_file); if (temp_file_descriptor >= 0 && ftruncate(temp_file_descriptor, buffer_size) == 0) { buffer = mmap( NULL, buffer_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, temp_file_descriptor, 0); if (buffer == (void*)-1) buffer = NULL; } fclose(temp_file); } } if (!buffer) buffer = mmap( NULL, buffer_size, PROT_READ | PROT_WRITE, MAP_ANON| MAP_SHARED, -1, 0); #endif /* create a true color bitmap for drawing into */ CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB(); job->context = CGBitmapContextCreate( buffer, /* data: MacOSX lets system allocate, iPhoneOS use manual memory mapping */ job->width, /* width in pixels */ job->height, /* height in pixels */ BITS_PER_COMPONENT, /* bits per component */ bytes_per_row, /* bytes per row: align to 16 byte boundary */ color_space, /* color space: device RGB */ kCGImageAlphaPremultipliedFirst /* bitmap info: premul ARGB has best support in OS X */ ); job->imagedata = CGBitmapContextGetData((CGContextRef)job->context); /* clean up */ CGColorSpaceRelease(color_space); } break; } } /* start the page (if this is a paged context) and graphics state */ CGContextRef context = (CGContextRef)job->context; CGContextBeginPage(context, &bounds); CGContextSaveGState(context); CGContextSetMiterLimit(context, 1.0); CGContextSetLineJoin(context, kCGLineJoinRound); /* set up the context transformation */ CGContextScaleCTM(context, job->scale.x, job->scale.y); CGContextRotateCTM(context, -job->rotation * M_PI / 180.0); CGContextTranslateCTM(context, job->translation.x, job->translation.y); }