You are not logged in.
Pages: 1
Okay. I'm not sure anymore if mapping from/to records is popular or not.
But this (with the option ^), and the fact, that the parser didn't throw any feedback on type mismatch (record field vs. json),
just returns with false, make the things very complicated and fragile.
Should I move to classes any way?
Would that solve my problems? I mean that the parser either won't die on the first missing field or on type mismatch?
Or at least gives me a verbose feedback?
Yes, it returns with false as the record type is not yet registered.
Hi all,
How can I set soReadIgnoreUnknownFields option for RecordLoadJSON or global?
I'm not using RegisterCustomJSONSerializerFromText nor do I want to register custom serializers, I just want to use the default one based on RTTI.
Regards
Hi all,
How can I ignore some record fields on RecordSaveJSON ?
I'd like to mark some fields not to serialize into the json.
Regards
Looks like a windows bug?
https://stackoverflow.com/questions/303 … dimensions
No.
I don't know what TGDIPages nor ForceScreenResolution is.
SynPDF.pas
I'm trying to draw metafiles with "PlayEnhMetaFile" on SynPDF's VCLCanvas and somehow the images in my metafile are not drawn if they are vertically below the displays Y resolution. For example, the A4 page has at 96 DPI a height of 1124, the display has a height of 768 or 800 pixels, the metafile should be drawn at 770 in a height of 120, the images are missing from the result. Textst are drawn but "EMR_STRETCHDIBITS" won't be called in the GDI Enum.
On Printer Canvas no problems, on bigger display with bigger resolution the same code is working.
Any help/hint would be greatly appreciated.
Regards
Demo code:
obPDF := TPdfDocumentGDI.Create;
try
obPDF.UseOptionalContent := True;
obNonPrintableLayer := obPDF.CreateOptionalContentGroup(nil, 'Non-Printable', True, False);
try
obPDF.AddPage;
obPDF.VCLCanvasBeginMarkedContent(obNonPrintableLayer);
c := obPDF.VCLCanvas;
c.Font.Name := 'Times new roman';
c.Font.Size := 32;
c.Font.Style := [fsBold, fsItalic];
c.Font.Color := clNavy;
c.TextOut(100, 100, 'Hello 1');
obPDF.VclCanvasEndMarkedContent;
c.TextOut(40, 40, 'Hello 2');
obPDF.SaveToFile(ChangeFileExt(ExeVersion.ProgramFileName, '.pdf'));
finally
obPDF.Free;
end;
I've no better idea for these two methods then vclcanvas is not our class.
(Are the RawUTF8() casts okay?)
procedure TPdfDocumentGDI.VclCanvasBeginMarkedContent(Group: TPdfOptionalContentGroup);
var
Resources, Properties: TPdfDictionary;
ID: PDFString;
begin
if not UseOptionalContent then
exit;
if Group <> nil then
begin
ID := 'oc' + UInt32ToPDFString(Group.ObjectNumber);
// register Group in page resources properties
Resources := Canvas.FPage.PdfDictionaryByName('Resources');
if Resources <> nil then
begin
Properties := Resources.PdfDictionaryByName('Properties');
if Properties = nil then
begin
Properties := TPdfDictionary.Create(Canvas.fDoc.FXRef);
Resources.AddItem('Properties', Properties);
end;
if Properties <> nil then
Properties.AddItem(ID, Group);
end;
GDICommentCustomCode(VCLCanvas.Handle, RawUTF8('/OC /' + ID + ' BDC'#10));
end
else
GDICommentCustomCode(VCLCanvas.Handle, RawUTF8('/OC BMC'#10));
end;
procedure TPdfDocumentGDI.VclCanvasEndMarkedContent;
begin
if UseOptionalContent then
GDICommentCustomCode(VCLCanvas.Handle, RawUTF8('EMC'#10));
end;
I made it general, instead of two messages with begin/end content.
procedure GDICommentCustomCode(MetaHandle: HDC; const aCustomCode: RawUTF8);
var
Data: RawByteString;
d: PAnsiChar;
L: integer;
begin // high(TPdfGDIComment)<$47 so it will never begin with GDICOMMENT_IDENTIFIER
L := length(aCustomCode);
SetLength(Data, L + 1);
d := Pointer(Data);
d^ := AnsiChar(pgCustomCode);
Move(Pointer(aCustomCode)^, d[1], L);
Windows.GdiComment(MetaHandle, L + 1, d);
end;
some changes:
TPdfGDIComment = (pgcOutline, pgcBookmark, pgcLink, pgCustomCode);
procedure TPdfEnum.HandleComment(Kind: TPdfGDIComment; P: PAnsiChar; Len: integer);
.
.
.
pgCustomCode:
if Len > 0 then
begin
SetString(Text, P, Len);
Canvas.Contents.Writer.Add(Text);
end;
Solved with GDIComment. Phew, I'm supporting myself very good. This is awesome, I'm wondering if anyone anytime implements this.
Does not work with VCLCanvas
How to flush VCLCanvas' buffer before 'EMC'?
Ok, I've zero knowledge about pdf and SynPDF, so do not expect much from me.
Here is a very rough implementation, main goal was to achieve it quickly, it would be nice if Arnaud would implement it _nicely_.
And here comes the beauty (Test it with "05 - Report created from code" / SynPdfLayers.dpr):
function TPdfDocument.CreateOptionalContentGroup(ParentContentGroup: TPdfOptionalContentGroup; const Title: string; Visible: boolean; PrintLayer: boolean = True): TPdfOptionalContentGroup;
var
Dico, DicoD, DicU, DicASEntry, DicPr: TPdfDictionary;
Arr, ArrOCGs, ArrAS: TPdfArray;
i: integer;
function FindParentContentGroupArray(Current: TPdfArray): TPdfArray;
var
i: integer;
begin
Result := nil;
if Current = nil then
exit;
for i := 0 to Current.ItemCount - 1 do
if Current.Items[i] = ParentContentGroup then
begin
if (i < Current.ItemCount - 1) and Current.Items[i + 1].InheritsFrom(TPdfArray) then
Result := TPdfArray(Current.Items[i + 1])
else
begin
Result := TPdfArray.Create(FXRef);
Current.InsertItem(i + 1, Result);
end;
exit;
end;
for i := 0 to Current.ItemCount - 1 do
if Current.Items[i].InheritsFrom(TPdfArray) then
begin
Result := FindParentContentGroupArray(TPdfArray(Current.Items[i]));
if Result <> nil then
exit;
end;
end;
begin
if FUseOptionalContent then
begin
Result := TPdfOptionalContentGroup.Create(FXRef);
FXRef.AddObject(Result);
Result.AddItem('Type', 'OCG');
Result.AddItemTextString('Name', Title);
Dico := FRoot.Data.PdfDictionaryByName('OCProperties');
if not PrintLayer then
begin
DicU := TPdfDictionary.Create(FXRef);
DicPr := TPdfDictionary.Create(FXRef);
DicPr.AddItem('PrintState', 'OFF');
DicU.AddItem('Print', DicPr);
Result.AddItem('Usage', DicU);
end;
if Dico <> nil then
begin
DicoD := Dico.PdfDictionaryByName('D');
if DicoD <> nil then
begin
Arr := DicoD.PdfArrayByName('Order');
if ParentContentGroup <> nil then
Arr := FindParentContentGroupArray(Arr);
if Arr <> nil then
Arr.AddItem(Result);
if not Visible then
begin
Arr := DicoD.PdfArrayByName('OFF');
if Arr <> nil then
Arr.AddItem(Result);
end;
if not PrintLayer then
begin
ArrAS := DicoD.PdfArrayByName('AS');
if ArrAS = nil then
begin
ArrAS := TPdfArray.Create(FXRef);
DicASEntry := TPdfDictionary.Create(FXRef);
DicASEntry.AddItem('Event', 'Print');
DicASEntry.AddItem('Category', TPdfArray.CreateNames(FXRef, ['Print']));
ArrOCGs := TPdfArray.Create(FXRef);
ArrOCGs.AddItem(Result);
DicASEntry.AddItem('OCGs', ArrOCGs);
ArrAS.AddItem(DicASEntry);
DicoD.AddItem('AS', ArrAS);
end
else
begin
for i := 0 to ArrAS.ItemCount - 1 do
begin
if TPdfName(TPdfDictionaryElement(TPdfDictionary(ArrAS.Items[i]).ValueByName('Event'))).Value = 'Print' then
begin
ArrOCGs := TPdfArray(TPdfDictionary(ArrAS.Items[i]).ValueByName('OCGs'));
if ArrOCGs <> nil then
ArrOCGs.AddItem(Result);
end;
end;
end;
end;
Arr := Dico.PdfArrayByName('OCGs');
if Arr <> nil then
Arr.AddItem(Result);
end;
end;
end
else
Result := nil;
end;
Hi there,
I'm wondering if there is an option for setting some elements in the generated PDF as non-printable?
Edit: looks like layers are supported, have to find out how to set it's property and what property to what
Regards,
Pages: 1