Mac OS X: ¿Cómo dibujar múltiples NSViews en un nuevo PDF de varias páginas?

Tengo una aplicación de Mac basada en documentos relacionada con gráficos. Los documentos de mi aplicación pueden tener varias "páginas". Cada página tiene un NSView objeto "lienzo".

Mi aplicación tiene varias opciones de exportación que se implementan como métodos que devuelven un NSData objeto (que luego se escribe en el disco).

Me gustaría implementar una opción de exportación de PDF en un método que:

  1. Crea un PDF en memoria
  2. recorre las vistas de lienzo de mi documento y representa cada una en una nueva página en el PDF en memoria
  3. devuelve el PDF de varias páginas en memoria como un NSData

El siguiente código es lo que estoy intentando actualmente.

Cada página de mi documento tiene 800 x 600 píxeles.

Cuando escribo el resultado NSData objeto en el disco, la operación de escritura tiene éxito, pero el archivo en el disco está dañado de alguna manera. El archivo no se puede abrir en Vista previa ni en ninguna otra aplicación que haya probado.

¿Qué estoy haciendo mal?

NSMutableData *data = [NSMutableData data];
CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)data);

CGRect mediaBox = CGRectMake(0.0, 0.0, 800.0, 600.0);
CGContextRef ctx = CGPDFContextCreate(consumer, &mediaBox, NULL);
CFRelease(consumer);

NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:NO];

for (NSView *canvas in myCanvases) {
    CGContextBeginPage(ctx, &mediaBox);
    CGContextSaveGState(ctx);

    [canvas displayRectIgnoringOpacity:mediaBox inContext:gc];

    CGContextRestoreGState(ctx);
    CGContextEndPage(ctx);
}

CGPDFContextClose(ctx); // UPDATE: this line was originally missing. see answer below
CGContextRelease(ctx);

...

NSError *err = nil;
if (![data writeToFile:s options:NSDataWritingAtomic error:&err]) {
    if (err) {
        NSLog(@"%@", err);
    }
}

preguntado el 03 de mayo de 12 a las 20:05

¿Puede publicar un volcado hexadecimal de quizás el primer kilobyte de datos? -

¿Por qué está exportando a un objeto de datos en la memoria? ¿Por qué no exportar directamente al archivo? -

Me gustaría saber si podrías darme alguna información sobre esto: stackoverflow.com/questions/10621858/… ¡Gracias! -

2 Respuestas

OP aquí. He resuelto el problema. Me faltaba una última llamada para CGPDFContextClose().

Así que antes de soltar el contexto...

CGPDFContextClose(ctx);
CGContextRelease(ctx);

Respondido el 31 de enero de 16 a las 01:01

No puedo creer que fuera tan simple, gracias! Perdí horas en esto, ya que el error solo ocurría cuando comencé a mezclar el dibujo de NSString (a través de las extensiones de AppKit) en OS 10.10, pero no en OS 10.9, así que estaba buscando algo mucho más complicado. ¡Y había funcionado antes sin cerrar el contexto, durante meses! - Charles

Encontré esta una respuesta muy útil (¡y pude votar el OP tanto en la pregunta como en la respuesta!). Hubo algunos contratiempos al traducirlo a Swift 3, pero esto funciona de maravilla, y funcionará en iOS...

let data = NSMutableData()
guard let consumer = CGDataConsumer(data: data) else { Swift.print("Aargh - no CGDataConsumer"); return }
var mediaBox = CGRect(x: 0, y: 0, width: 800, height: 600)
guard let ctx = CGContext(consumer: consumer, mediaBox: &mediaBox, nil) else { Swift.print("Aargh - no CGContext"); return }

//let gc = NSGraphicsContext(cgContext: ctx, flipped: false) 
//I don't need the NS context, as my drawing routines just use CGContext

for page in self.pages { // Array of page models
    ctx.beginPage(mediaBox: &mediaBox)
    ctx.saveGState()
    myDraw(page, context: ctx, options: []) // My routine
    ctx.restoreGState()
    ctx.endPage()
}
ctx.closePDF()
do {
    try data.write(toFile: "/Users/grimxn/Test.pdf", options: .atomic)
} catch {
    Swift.print("Aargh - failed to write output file")
}

Respondido 13 Abr '17, 09:04

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.