mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-20 04:08:15 +02:00
977 lines
25 KiB
PHP
977 lines
25 KiB
PHP
{%MainUnit ../osprinters.pas}
|
|
{**************************************************************
|
|
Implementation for carbonprinter
|
|
***************************************************************}
|
|
uses InterfaceBase, LCLIntf, LCLProc, CocoaPrnDelegate;
|
|
|
|
const
|
|
CleanPMRect: PMRect = (top: 0; left: 0; bottom: 0; right: 0);
|
|
//CleanPMOrientation: PMOrientation = 0;
|
|
|
|
{ TCocoaPrinterCanvas }
|
|
|
|
procedure ReleaseMemoryStream(info: UnivPtr; data: UnivPtr; size: size_t); mwpascal;
|
|
begin
|
|
TMemoryStream(info).free;
|
|
end;
|
|
|
|
function TCocoaPrinterCanvas.GetCGContext: CGContextRef;
|
|
begin
|
|
result := TCocoaContext(Handle).CGContext;
|
|
end;
|
|
|
|
procedure TCocoaPrinterCanvas.DoEllipse(const Bounds: TRect);
|
|
var
|
|
R: CGRect;
|
|
begin
|
|
R := CGRectMake(bounds.left, bounds.top, bounds.Width, bounds.Height);
|
|
CGContextFillEllipseInRect(CGContext, R);
|
|
end;
|
|
|
|
procedure TCocoaPrinterCanvas.DoEllipseFill(const Bounds: TRect);
|
|
var
|
|
R: CGRect;
|
|
begin
|
|
R := CGRectMake(bounds.left, bounds.top, bounds.Width, bounds.Height);
|
|
CGContextStrokeEllipseInRect(CGContext, R);
|
|
end;
|
|
|
|
procedure TCocoaPrinterCanvas.DoEllipseAndFill(const Bounds: TRect);
|
|
var
|
|
R: CGRect;
|
|
begin
|
|
R := CGRectMake(bounds.left, bounds.top, bounds.Width, bounds.Height);
|
|
CGContextFillEllipseInRect(CGContext, R);
|
|
CGContextStrokeEllipseInRect(CGContext, R);
|
|
end;
|
|
|
|
{ TPrinterEnumerator }
|
|
|
|
constructor TPrinterEnumerator.Create(objType: TObjType; aPrinterRef: PMPrinter);
|
|
begin
|
|
inherited create;
|
|
fArray := nil;
|
|
fObjType := objType;
|
|
fIndex := -1;
|
|
fPrinterRef := aPrinterRef;
|
|
end;
|
|
|
|
destructor TPrinterEnumerator.Destroy;
|
|
begin
|
|
if (fObjType=otPrinters) and (fArray<>nil) then
|
|
CFRelease(fArray);
|
|
inherited destroy;
|
|
end;
|
|
|
|
function TPrinterEnumerator.MoveNext: boolean;
|
|
var
|
|
res: OSStatus;
|
|
begin
|
|
|
|
if fIndex<0 then
|
|
begin
|
|
|
|
case fObjType of
|
|
otPrinters:
|
|
res := PMServerCreatePrinterList(kPMServerLocal, fArray);
|
|
|
|
otPapers:
|
|
res := PMPrinterGetPaperList(fPrinterRef, fArray);
|
|
end;
|
|
|
|
result := (res=noErr) and (fArray<>nil);
|
|
if not result then
|
|
exit;
|
|
end;
|
|
|
|
inc(fIndex);
|
|
result := fIndex<CFArrayGetCount(fArray);
|
|
if result then
|
|
fCurrent := CFArrayGetValueAtIndex(fArray, fIndex);
|
|
end;
|
|
|
|
function TPrinterEnumerator.GetEnumerator: TPrinterEnumerator;
|
|
begin
|
|
result := self;
|
|
end;
|
|
|
|
{ TCocoaPrinterView }
|
|
|
|
procedure TCocoaPrinterView.drawRect(dirtyRect: NSRect);
|
|
var
|
|
Context: NSGraphicsContext;
|
|
begin
|
|
Context := NSGraphicsContext.currentContext;
|
|
|
|
CGContextDrawPDFDocument(context.lclCGContext, CGRect(dirtyRect), doc, pageNum);
|
|
end;
|
|
|
|
// Return the number of pages available for printing
|
|
function TCocoaPrinterView.knowsPageRange(range: NSRangePointer): LCLObjCBoolean;
|
|
begin
|
|
range^.location := 1;
|
|
range^.length := CGPDFDocumentGetNumberOfPages(doc);
|
|
Result := True;
|
|
end;
|
|
|
|
function TCocoaPrinterView.rectForPage(page: NSInteger): NSRect;
|
|
var
|
|
aPage: CGPDFPageRef;
|
|
begin
|
|
pageNum := page;
|
|
aPage := CGPDFDocumentGetPage(Doc, pageNum);
|
|
result := NSRect(CGPDFPageGetBoxRect(aPage, kCGPDFMediaBox));
|
|
self.setBounds(result);
|
|
end;
|
|
|
|
function TCocoaPrinterView.isFlipped: LCLObjCBoolean;
|
|
begin
|
|
Result := true;
|
|
end;
|
|
|
|
|
|
{ TCocoaPrinter }
|
|
|
|
|
|
procedure TCocoaPrinter.ResetPapersList(aPrinter: PMPrinter);
|
|
var
|
|
aPaper: PMPaper;
|
|
aName: CFStringRef;
|
|
res: OSStatus;
|
|
pageFormat: PMPageFormat;
|
|
paperR, pageR: PMRect;
|
|
i: Integer;
|
|
aInfo: NSPrintInfo;
|
|
validationResult: Boolean;
|
|
pmOr: PMOrientation;
|
|
kx, ky: Double;
|
|
begin
|
|
|
|
kx := XDPI/72;
|
|
ky := YDPI/72;
|
|
|
|
aInfo := NSPrintInfo.sharedPrintInfo;
|
|
if aInfo.orientation=NSPortraitOrientation then
|
|
pmOr := kPMPortrait
|
|
else
|
|
pmOr := kPMLandscape;
|
|
|
|
SetLength(fPapersList, 0);
|
|
for aPaper in self.GetPMPrinterEnumerator(otPapers, aPrinter) do
|
|
begin
|
|
|
|
aName := nil;
|
|
pageFormat := nil;
|
|
res := PMPaperCreateLocalizedName(aPaper, aPrinter, aName);
|
|
if res<>noErr then continue;
|
|
|
|
if res<>noErr then continue;
|
|
res := PMCreatePageFormatWithPMPaper(pageFormat, aPaper);
|
|
if res<>noErr then continue;
|
|
res := PMSetOrientation(pageFormat, pmOr, false);
|
|
if res<>noErr then continue;
|
|
|
|
res := PMSessionValidatePageFormat(aInfo.PMPrintSession, pageFormat, @validationResult);
|
|
if res<>noErr then continue;
|
|
|
|
paperR:=CleanPMRect;
|
|
res := PMGetAdjustedPaperRect(pageFormat, paperR);
|
|
if res<>noErr then begin PMRelease(pageFormat); continue; end;
|
|
|
|
pageR:=CleanPMRect;
|
|
res := PMGetAdjustedPageRect(pageFormat, pageR);
|
|
PMRelease(pageFormat);
|
|
if res<>noErr then continue;
|
|
|
|
i:= Length(fPapersList);
|
|
SetLength(fPapersList, i+1);
|
|
|
|
with fPapersList[i] do
|
|
begin
|
|
PaperName := CFStringToString(aName);
|
|
CFRelease(aName);
|
|
|
|
PaperRect.PhysicalRect.Left := 0;
|
|
PaperRect.PhysicalRect.Top := 0;
|
|
PaperRect.PhysicalRect.Right := Round((paperR.right - paperR.left)*kx);
|
|
PaperRect.PhysicalRect.Bottom := Round((paperR.bottom - paperR.top)*ky);
|
|
|
|
PaperRect.WorkRect.Left := Round(-paperR.left*kx);
|
|
PaperRect.WorkRect.Top := Round(-paperR.top*ky);
|
|
PaperRect.WorkRect.Right := Round((pageR.right - pageR.left - paperR.left)*kx);
|
|
PaperRect.WorkRect.Bottom := Round((pageR.bottom - pageR.top - paperR.top)*ky);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TCocoaPrinter.GetDefaultPaperFromPPDFile: string;
|
|
var
|
|
pInfo: NSPrintInfo;
|
|
aStatus: NSPrinterTableStatus;
|
|
aValue: NSString;
|
|
begin
|
|
result := '';
|
|
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
aStatus := pInfo.printer.statusForTable(NSSTR('PPD'));
|
|
if aStatus=NSPrinterTableOK then
|
|
begin
|
|
// it is a shame that the NSPrinter functions available for querying
|
|
// PPD key and values are deprecated (except by StatusForTable)
|
|
// if using deprecated functions hurt too much we can always parse the
|
|
// ppd file directly as done in the the carbon printer.
|
|
aValue := pInfo.printer.stringForKey_inTable(NSSTR('DefaultPageSize'), NSSTR('PPD'));
|
|
if aValue<>nil then
|
|
result := aValue.UTF8String;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TCocoaPrinter.GetCurrentPrinterName: string;
|
|
var
|
|
aInfo: NSPrintInfo;
|
|
begin
|
|
aInfo := NSPrintInfo.sharedPrintInfo;
|
|
result := aInfo.printer.name.UTF8String;
|
|
end;
|
|
|
|
function TCocoaPrinter.GetCurrentPrinter: PMPrinter;
|
|
var
|
|
pInfo: NSPrintInfo;
|
|
begin
|
|
Result := nil;
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
if PMSessionGetCurrentPrinter(pInfo.PMPrintSession, Result) <> noErr then Exit;
|
|
end;
|
|
|
|
function TCocoaPrinter.GetPMPrinterEnumerator(objType: TObjType;
|
|
printerRef: PMPrinter): TPrinterEnumerator;
|
|
begin
|
|
result := TPrinterEnumerator.create(objType, printerRef);
|
|
end;
|
|
|
|
procedure TCocoaPrinter.FindDefaultPrinter;
|
|
var
|
|
aPrinter: PMPrinter;
|
|
begin
|
|
FDefaultPrinter := '';
|
|
|
|
for aPrinter in GetPMPrinterEnumerator(otPrinters) do
|
|
begin
|
|
if PMPrinterIsDefault(aPrinter) then
|
|
begin
|
|
FDefaultPrinter := CFStringToStr(PMPrinterGetName(aPrinter));
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
constructor TCocoaPrinter.Create;
|
|
begin
|
|
inherited Create;
|
|
|
|
CanvasClass := TCocoaPrinterCanvas;
|
|
|
|
FindDefaultPrinter;
|
|
UpdatePrinter;
|
|
Validate;
|
|
end;
|
|
|
|
procedure TCocoaPrinter.DoDestroy;
|
|
begin
|
|
inherited DoDestroy;
|
|
end;
|
|
|
|
function TCocoaPrinter.Write(const Buffer; Count: Integer; out Written: Integer): Boolean;
|
|
begin
|
|
Result := False;
|
|
CheckRawMode(True);
|
|
Written := FStream.Write(buffer, count);
|
|
result := (Written=Count);
|
|
end;
|
|
|
|
procedure TCocoaPrinter.CheckPrinterList;
|
|
var
|
|
orgList,curList: TStringList;
|
|
begin
|
|
orgList := TStringList.create;
|
|
curList := TStringList.create;
|
|
try
|
|
orgList.Assign(Printers);
|
|
DoEnumPrinters(curList);
|
|
orgList.Sort;
|
|
curList.Sort;
|
|
if not curList.Equals(orgList) then
|
|
Refresh;
|
|
finally
|
|
curList.Free;
|
|
orgList.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TCocoaPrinter.RawModeChanging;
|
|
begin
|
|
//
|
|
end;
|
|
|
|
procedure TCocoaPrinter.Validate;
|
|
var
|
|
P: String;
|
|
aPrinter: PMPrinter;
|
|
aPaper: PMPaper;
|
|
aPaperName: CFStringRef;
|
|
papersList: TStrings;
|
|
found: Boolean;
|
|
begin
|
|
aPrinter := GetCurrentPrinter;
|
|
ResetPapersList(aPrinter);
|
|
PaperSize.SupportedPapers.Clear; // refill on next query, ie. next line
|
|
|
|
papersList := PaperSize.SupportedPapers;
|
|
|
|
// if target paper is not supported, use the default
|
|
P := DoGetPaperName();
|
|
if papersList.IndexOf(P) = -1 then
|
|
begin
|
|
P := DoGetDefaultPaperName();
|
|
if papersList.IndexOf(P) < 0 then
|
|
begin
|
|
// neither the current paper or the default one exists in the supported
|
|
// list of papers, instead of randomly choose one, let's try a bit harder
|
|
// as some printer ppd files have a hint about the default paper.
|
|
found := false;
|
|
P := GetDefaultPaperFromPPDFile;
|
|
if p<>'' then
|
|
begin
|
|
for aPaper in GetPMPrinterEnumerator(otPapers, aPrinter) do
|
|
begin
|
|
aPaperName := nil;
|
|
PMPaperGetPPDPaperName(aPaper, aPaperName);
|
|
if (aPapername<>nil) and (CFStringToString(aPaperName)=P) then
|
|
begin
|
|
aPaperName := nil;
|
|
PMPaperCreateLocalizedName(aPaper, aPrinter, aPapername);
|
|
if aPaperName<>nil then
|
|
begin
|
|
P := CFStringToString(aPaperName);
|
|
CFRelease(aPapername);
|
|
found := (papersList.IndexOf(P)>=0);
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if not found then
|
|
p := papersList[0];
|
|
|
|
end;
|
|
DoSetPaperName(P);
|
|
end;
|
|
end;
|
|
|
|
procedure TCocoaPrinter.UpdatePrinter;
|
|
var
|
|
s: string;
|
|
pInfo: NSPrintInfo;
|
|
begin
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
s := pInfo.printer.name.UTF8String;
|
|
if trim(s) = '' then // Observed if Default printer set to "Use last printer", and no printing done
|
|
s := '*'; // so select lcl default
|
|
SetPrinter(s);
|
|
end;
|
|
|
|
function TCocoaPrinter.GetOutputResolution: PMResolution;
|
|
var
|
|
pInfo: NSPrintInfo;
|
|
prn : PMPrinter;
|
|
cnt : UInt32;
|
|
i : UInt32;
|
|
rs : PMResolution;
|
|
begin
|
|
// JRA: This method should return the user desired output resolution, and not the higher
|
|
// resolution that the printer can handle. In fact, it seems that the old method of
|
|
// setting up some output resolution is now deprecated in cocoa. Drawing at
|
|
// "high resolution" should be now made through setting up some transformation
|
|
// matrix. That is a TODO. At the moment, some printing, even if it is a lower
|
|
// lower resolution, is better than no printing at all.
|
|
{
|
|
Result.vRes := 0;
|
|
Result.hRes := 0;
|
|
cnt := 0;
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
prn := GetCurrentPrinter();
|
|
// todo: the code has been changed to mirror Carbon implementation
|
|
// for some drivers PMPrinterGetOutputResolution() returns failure at all times
|
|
// (even if printer dialog has been called).
|
|
// Enumeration of resolution doesn't return all possible values either.
|
|
// (i.e. Brother MFC 7860DW only gives 300x300 resolution
|
|
// while it actually supports 300, 600 and HQ1200 (2400x600) dpis)
|
|
// CUPS properties do indicate the actual resoltuion, BUT there's no standard
|
|
// way of reading the resolution.
|
|
// (i.e. the same Brother printer reports via "lpoptions -l":
|
|
// BRResolution/Resolution: 300dpi *600dpi 2400x600dpi)
|
|
//
|
|
if (PMPrinterGetOutputResolution(prn, pInfo.PMPrintSettings, rs{%H-}) = noErr) then
|
|
Result := rs
|
|
else if PMPrinterGetPrinterResolutionCount(prn, cnt) = noErr then
|
|
begin
|
|
for i:=1 to cnt do
|
|
begin
|
|
if (PMPrinterGetIndexedPrinterResolution(prn, i, rs) = noErr)
|
|
and ((rs.vRes > Result.vRes) or (rs.hRes > Result.hRes)) then
|
|
Result := rs;
|
|
end;
|
|
end;
|
|
if (Result.vRes = 0) or (Result.hRes = 0) then
|
|
begin
|
|
}
|
|
Result.vRes := 72;
|
|
Result.hRes := 72;
|
|
//end;
|
|
end;
|
|
|
|
function TCocoaPrinter.GetXDPI: Integer;
|
|
var
|
|
dpi: PMResolution;
|
|
begin
|
|
dpi := GetOutputResolution;
|
|
result := round(dpi.hRes);
|
|
end;
|
|
|
|
function TCocoaPrinter.GetYDPI: Integer;
|
|
var
|
|
dpi: PMResolution;
|
|
begin
|
|
dpi := GetOutputResolution;
|
|
result := round(dpi.hRes);
|
|
end;
|
|
|
|
{$define ToPrinter}
|
|
|
|
procedure TCocoaPrinter.DoBeginDoc;
|
|
var
|
|
//pInfo: NSPrintInfo;
|
|
consumer: CGDataConsumerRef;
|
|
gr: NSGraphicsContext;
|
|
//path: CStringPtr;
|
|
//url: CFUrlRef;
|
|
R: TRect;
|
|
begin
|
|
|
|
fDocStarted := true;
|
|
if RawMode then
|
|
begin
|
|
|
|
fStream := TMemoryStream.create;
|
|
|
|
end else
|
|
begin
|
|
|
|
// TODO: margins ???
|
|
//
|
|
// Initially NSPrintInfo do not carry the printer real margins
|
|
// (from the imageable area) set up in the printer ppd file but some
|
|
// standard defined (undocumented but I guess they corresponds
|
|
// to the "Any Printer" printer). It is even documented somewhere
|
|
// that in order to use the real printer margins one have to
|
|
// run the PageLayout dialog and choose the real printer instead
|
|
// of the "Any Printer" and this way the margins will match the
|
|
// real printer ones. Check later this stuff...
|
|
//
|
|
// * We don't use margins in the calc of the mediabox because
|
|
// Apple doesn't implement a custom margins dialog and ...
|
|
// * In order to implement custom margins we have to probably
|
|
// add some accessory panel, but as we currently don't do that
|
|
// it makes no sense to use them.
|
|
//
|
|
//pInfo := NSPrintInfo.sharedPrintInfo;
|
|
//pInfo.setLeftMargin(0);
|
|
//pInfo.setTopMargin(0);
|
|
//pInfo.setRightMargin(0);
|
|
//pInfo.setBottomMargin(0);
|
|
|
|
R := PaperSize.PaperRect.WorkRect;
|
|
pdfMediaBox := CGRectMake(0, 0, r.Width, r.Height);
|
|
|
|
{$ifdef ToPrinter}
|
|
if pdfData<>nil then
|
|
CFRelease(pdfData);
|
|
pdfData := CFDataCreateMutable(nil, 0);
|
|
consumer := CGDataConsumerCreateWithCFData(pdfData);
|
|
{$else}
|
|
path := 'salida.pdf';
|
|
url := CFURLCreateFromFileSystemRepresentation(nil, path, length(path), false);
|
|
consumer := CGDataConsumerCreateWithURL(url);
|
|
CFRelease(url);
|
|
{$endif}
|
|
pdfContext := CGPDFContextCreate(consumer, pdfMediabox, nil);
|
|
CGDataConsumerRelease(consumer);
|
|
|
|
gr := NSGraphicsContext.graphicsContextWithGraphicsPort_flipped(pdfContext, false);
|
|
FPrinterContext := TCocoaContext.Create(gr);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TCocoaPrinter.DoBeginPage;
|
|
var
|
|
mediaBox: CGRect;
|
|
R: TRect;
|
|
rgn: TCocoaRegion;
|
|
begin
|
|
|
|
if RawMode then
|
|
exit;
|
|
|
|
R := PaperSize.PaperRect.WorkRect;
|
|
mediaBox := CGRectMake(0, 0, r.Width, r.Height);
|
|
|
|
//CGPDFContextBeginPage(pdfContext, nil);
|
|
CGContextBeginPage(pdfContext, mediabox);
|
|
CGContextSaveGState(pdfContext);
|
|
|
|
if Assigned(Canvas) then
|
|
Canvas.Handle := HDC(FPrinterContext);
|
|
|
|
rgn := TCocoaRegion.Create(0, 0, r.Width, r.height);
|
|
FPrinterContext.SetClipRegion(Rgn, cc_Copy);
|
|
rgn.Free;
|
|
end;
|
|
|
|
procedure TCocoaPrinter.DoEndPage;
|
|
|
|
procedure ResetCanvasHandle;
|
|
begin
|
|
if Assigned(Canvas) then
|
|
Canvas.Handle := HDC(0);
|
|
end;
|
|
|
|
begin
|
|
|
|
if RawMode then
|
|
exit;
|
|
|
|
if not fDocStarted then
|
|
begin
|
|
ResetcanvasHandle;
|
|
exit;
|
|
end;
|
|
|
|
if Aborted then
|
|
begin
|
|
ResetcanvasHandle;
|
|
exit;
|
|
end;
|
|
|
|
CGContextRestoreGState(pdfContext);
|
|
CGContextEndPage(pdfContext);
|
|
|
|
ResetCanvasHandle;
|
|
|
|
end;
|
|
|
|
// starts a raw mode print job
|
|
procedure TCocoaPrinter.StartRawModePrintJob(Sender: TObject);
|
|
var
|
|
pInfo: NSPrintInfo;
|
|
printDestination: PMDestinationType;
|
|
aPrinter: PMPrinter;
|
|
mimeType: CFStringRef;
|
|
mimeTypes: CFArrayRef;
|
|
arrayCount: CFIndex;
|
|
provider: CGDataProviderRef;
|
|
status: OSStatus;
|
|
|
|
procedure Error(s:string);
|
|
begin
|
|
//DebugLn(s);
|
|
try
|
|
fStream.free;
|
|
except
|
|
// DebugLn
|
|
end;
|
|
fStream := nil;
|
|
raise Exception.Create(s);
|
|
end;
|
|
|
|
begin
|
|
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
printDestination := kPMDestinationInvalid;
|
|
|
|
if PMSessionGetDestinationType(pInfo.PMPrintSession, pInfo.PMPrintSettings, printDestination)=noErr then
|
|
begin
|
|
if printDestination=kPMDestinationPrinter then
|
|
begin
|
|
aPrinter := GetCurrentPrinter;
|
|
if aPrinter<>nil then
|
|
begin
|
|
status := PMPrinterGetMimeTypes(aPrinter, pInfo.PMPrintSettings, mimeTypes);
|
|
if (status=noErr) and (mimeTypes<>nil) then
|
|
begin
|
|
mimeType := CFSTR('application/vnd.cups-raw');
|
|
arrayCount := CFArrayGetCount(mimeTypes);
|
|
if CFArrayContainsValue(mimeTypes, CFRangeMake(0, arrayCount), mimeType) then
|
|
begin
|
|
provider := CGDataProviderCreateWithData(fStream, fStream.Memory, fStream.Size, @ReleaseMemoryStream);
|
|
status := PMPrinterPrintWithProvider(aPrinter, pInfo.PMPrintSettings, pInfo.PMPageFormat, mimeType, provider);
|
|
CGDataProviderRelease(provider);
|
|
if status<>noErr then
|
|
Error('Error '+IntToStr(status)+'while raw printing')
|
|
else
|
|
fStream := nil;
|
|
end else
|
|
Error('Printer do not support raw printing');
|
|
end else
|
|
Error('Error while getting supported mime types');
|
|
end else
|
|
Error('Error, couldn''t get the current printer');
|
|
end else
|
|
Error('Error, destination is not printer');
|
|
end else
|
|
Error('Error on getting DestinationType');
|
|
end;
|
|
|
|
procedure TCocoaPrinter.DoEndDoc(aAborted: Boolean);
|
|
var
|
|
preview: TCocoaPrinterView;
|
|
op: NSPrintOperation;
|
|
provider: CGDataProviderRef;
|
|
pInfo: NSPrintInfo;
|
|
begin
|
|
|
|
if not fDocStarted then
|
|
exit;
|
|
|
|
if aAborted then
|
|
begin
|
|
// TODO: check leaks ...
|
|
end;
|
|
|
|
try
|
|
|
|
pInfo := NSPrintInfo.SharedPrintInfo;
|
|
if not RawMode then
|
|
begin
|
|
FPrinterContext.Free;
|
|
FPrinterContext := nil;
|
|
CGPDFContextClose(pdfContext);
|
|
//path := 'salida2.pdf';
|
|
//url := CFURLCreateFromFileSystemRepresentation(nil, path, length(path), false);
|
|
//if not CFURLWriteDataAndPropertiesToResource(url, pdfData, nil, err) then
|
|
// WriteLn('Error al guardar pdfdata: ', err)
|
|
//else
|
|
// WriteLn('pdf data guardado exitosamente');
|
|
preview := TCocoaPrinterView.alloc.initWithFrame(NSRect(pdfMediabox));
|
|
provider := CGDataProviderCreateWithCFData(pdfData);
|
|
preview.Doc := CGPDFDocumentCreateWithProvider(provider);
|
|
CGDataProviderRelease(provider);
|
|
end;
|
|
// here for
|
|
// rawmode: we have a fStream with data ready to print
|
|
// not rawmode: we have a view that can render pdf content
|
|
//
|
|
// check if we want to print directly or through a print dialog.
|
|
if printDelegate<>nil then
|
|
begin
|
|
|
|
printDelegate.sender := self;
|
|
printDelegate.OnStartJob := nil;
|
|
printDelegate.renderView := nil;
|
|
if RawMode then
|
|
printDelegate.OnStartJob := @StartRawModePrintJob
|
|
else
|
|
printDelegate.renderView := preview;
|
|
|
|
try
|
|
printDelegate.RunPrintJob;
|
|
finally
|
|
printDelegate := nil;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
|
|
if RawMode then
|
|
StartRawModePrintJob(self)
|
|
else
|
|
begin
|
|
// run print operation without print dialog
|
|
op := NSPrintOperation.printOperationWithView_printInfo(preview, pInfo);
|
|
op.setShowsPrintPanel(false);
|
|
op.runOperation;
|
|
end;
|
|
|
|
end;
|
|
|
|
finally
|
|
fDocStarted := false;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TCocoaPrinter.DoAbort;
|
|
begin
|
|
inherited DoAbort;
|
|
|
|
//OSError(PMSessionSetError(PrintSession, kPMCancel), Self, 'DoAbort', 'PMSessionSetError');
|
|
end;
|
|
|
|
//Enum all defined printers. First printer it's default
|
|
procedure TCocoaPrinter.DoEnumPrinters(Lst: TStrings);
|
|
var
|
|
aName: String;
|
|
aPrinter: PMPrinter;
|
|
begin
|
|
Lst.Clear;
|
|
for aprinter in GetPMPrinterEnumerator(otPrinters) do
|
|
begin
|
|
aName := CFStringToStr(PMPrinterGetName(aPrinter));
|
|
if aName=FDefaultPrinter then begin
|
|
Lst.Insert(0, aName);
|
|
end
|
|
else
|
|
Lst.Add(aName);
|
|
end;
|
|
end;
|
|
|
|
procedure TCocoaPrinter.DoResetPrintersList;
|
|
begin
|
|
inherited DoResetPrintersList;
|
|
end;
|
|
|
|
// We need to use Core Printing here, see:
|
|
// http://lists.apple.com/archives/cocoa-dev/2005/Nov/msg01227.html
|
|
// See Also "Using Cocoa and Core Printing Together"
|
|
// https://developer.apple.com/library/mac/technotes/tn2248/_index.html
|
|
procedure TCocoaPrinter.DoEnumPapers(Lst: TStrings);
|
|
var
|
|
aPaper: PMPaper;
|
|
CFString: CFStringRef;
|
|
aPrinter: PMPrinter;
|
|
locName: string;
|
|
begin
|
|
aPrinter := GetCurrentPrinter;
|
|
for aPaper in GetPMPrinterEnumerator(otPapers, aPrinter) do
|
|
begin
|
|
CFString := nil;
|
|
PMPaperCreateLocalizedName(aPaper, aPrinter, CFString);
|
|
if CFString<>nil then
|
|
begin
|
|
locName := CFStringToStr(CFString);
|
|
CFRelease(CFString);
|
|
CFString := nil;
|
|
Lst.Add(locName);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaPrinter.DoGetPaperName(): string;
|
|
var
|
|
pInfo: NSPrintInfo;
|
|
begin
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
result := NSStringToString(pInfo.localizedPaperName);
|
|
end;
|
|
|
|
function TCocoaPrinter.DoGetDefaultPaperName: string;
|
|
var
|
|
pageFormat: PMPageFormat = nil;
|
|
pInfo: NSPrintInfo;
|
|
aPaper: PMPaper = nil;
|
|
aPapername: CFStringRef = nil;
|
|
begin
|
|
Result := '';
|
|
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
|
|
if PMCreatePageFormat(pageFormat) <> noErr then exit;
|
|
try
|
|
if PMSessionDefaultPageFormat(pInfo.PMPrintSession, pageFormat) <> noErr then exit;
|
|
if PMGetPageFormatPaper(pageFormat, aPaper) <> noErr then exit;
|
|
if PMPaperCreateLocalizedName(aPaper, GetCurrentPrinter, aPapername) <> noErr then exit;
|
|
result := CFStringToString(aPapername);
|
|
finally
|
|
PMRelease(pageFormat);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TCocoaPrinter.DoSetPaperName(aName: string);
|
|
var
|
|
anOrientation: TPrinterOrientation;
|
|
aPrinter: PMPrinter;
|
|
aPaper: PMPaper;
|
|
orgFormat: PMPageFormat;
|
|
pageFormat: PMPageFormat = nil;
|
|
aPapername: CFStringRef;
|
|
pInfo: NSPrintInfo;
|
|
curName: String;
|
|
begin
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
anOrientation := DoGetOrientation();
|
|
aPrinter := GetCurrentPrinter;
|
|
for aPaper in Self.GetPMPrinterEnumerator(otPapers, aPrinter) do
|
|
begin
|
|
aPapername := nil;
|
|
PMPaperCreateLocalizedName(aPaper, aPrinter, aPaperName);
|
|
if aPapername<>nil then
|
|
begin
|
|
curName := CFStringToString(aPapername);
|
|
CFRelease(aPapername);
|
|
if curName=aName then
|
|
begin
|
|
PMCreatePageFormatWithPMPaper(pageFormat, aPaper);
|
|
orgFormat := pInfo.PMPageFormat;
|
|
PMCopyPageFormat(pageFormat, orgFormat);
|
|
pInfo.updateFromPMPageFormat;
|
|
PMRelease(pageFormat);
|
|
DoSetOrientation(anOrientation);
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaPrinter.DoGetPaperRect(aName: string; var aPaperRc: TPaperRect
|
|
): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := -1;
|
|
for i:=0 to Length(fPapersList)-1 do
|
|
begin
|
|
if aName=fPapersList[i].PaperName then
|
|
begin
|
|
aPaperRc := fPapersList[i].PaperRect;
|
|
result := i;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaPrinter.DoSetPrinter(aName: string): Integer;
|
|
var
|
|
aPrinter: PMPrinter;
|
|
curName: String;
|
|
pInfo: NSPrintInfo;
|
|
begin
|
|
|
|
result := -1;
|
|
for aPrinter in Self.GetPMPrinterEnumerator(otPrinters) do
|
|
begin
|
|
curName := CFStringToStr(PMPrinterGetName(aPrinter));
|
|
if curName=aName then
|
|
begin
|
|
result := Printers.IndexOf(aName);
|
|
//
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
PMSessionSetCurrentPMPrinter( pInfo.PMPrintSession, aPrinter);
|
|
|
|
ResetPapersList(aPrinter);
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TCocoaPrinter.DoGetCopies: Integer;
|
|
var
|
|
NumCopies: UInt32;
|
|
pInfo: NSPrintInfo;
|
|
begin
|
|
Result := 1;
|
|
NumCopies := 0;
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
if PMGetCopies(pInfo.PMPrintSettings, NumCopies) <> noErr then Exit;
|
|
Result := NumCopies;
|
|
end;
|
|
|
|
procedure TCocoaPrinter.DoSetCopies(aValue: Integer);
|
|
var
|
|
pInfo: NSPrintInfo;
|
|
begin
|
|
pInfo := NSPrintInfo.sharedPrintInfo;
|
|
if PMSetCopies(pInfo.PMPrintSettings, AValue, False) <> noErr then
|
|
Exit;
|
|
pInfo.updateFromPMPrintSettings();
|
|
end;
|
|
|
|
function TCocoaPrinter.DoGetOrientation: TPrinterOrientation;
|
|
var
|
|
info: NSPrintInfo;
|
|
begin
|
|
info := NSPrintInfo.sharedPrintInfo;
|
|
if info.orientation=NSPortraitOrientation then
|
|
result := poPortrait
|
|
else
|
|
result := poLandscape;
|
|
end;
|
|
|
|
procedure TCocoaPrinter.DoSetOrientation(aValue: TPrinterOrientation);
|
|
var
|
|
info: NSPrintInfo;
|
|
oldValue: NSPrintingOrientation;
|
|
begin
|
|
|
|
info := NSPrintInfo.sharedPrintInfo;
|
|
oldValue := info.orientation;
|
|
case aValue of
|
|
poPortrait, poReversePortrait:
|
|
info.setOrientation(NSPortraitOrientation);
|
|
else
|
|
info.setOrientation(NSLandscapeOrientation);
|
|
end;
|
|
if oldValue<>info.orientation then
|
|
ResetPapersList(GetCurrentPrinter);
|
|
end;
|
|
|
|
function TCocoaPrinter.GetPrinterType: TPrinterType;
|
|
var
|
|
IsRemote: Boolean;
|
|
begin
|
|
Result := ptLocal;
|
|
IsRemote := false;
|
|
if PMPrinterIsRemote(GetCurrentPrinter(), IsRemote) <> noErr then Exit;
|
|
if IsRemote then Result := ptNetwork;
|
|
end;
|
|
|
|
|
|
function TCocoaPrinter.DoGetPrinterState: TPrinterState;
|
|
var
|
|
State: PMPrinterState;
|
|
begin
|
|
Result := psNoDefine;
|
|
|
|
State:=0;
|
|
if PMPrinterGetState(GetCurrentPrinter(), State) <> noErr then Exit;
|
|
|
|
case State of
|
|
kPMPrinterIdle: Result := psReady;
|
|
kPMPrinterProcessing: Result := psPrinting;
|
|
kPMPrinterStopped: Result := psStopped;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaPrinter.GetCanPrint: Boolean;
|
|
begin
|
|
Result := (DoGetPrinterState() <> psStopped);
|
|
end;
|
|
|
|
function TCocoaPrinter.GetCanRenderCopies: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
initialization
|
|
|
|
Printer := TCocoaPrinter.Create;
|
|
|
|
finalization
|
|
|
|
FreeAndNil(Printer);
|