mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 08:46:55 +08:00
1 parent
b85b3bc27d
commit
bbc8d59bdb
11 files changed
+165
-39
No files matched your search
+20
-2
@@ -4996,6 +4996,13 @@ function destinationPoint(page, x, y) {
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
function sourcePoint(page, x, y) {
|
||||
if (state.rotation === 90) return { x: y, y: page.height - x };
|
||||
if (state.rotation === 180) return { x: page.width - x, y: page.height - y };
|
||||
if (state.rotation === 270) return { x: page.width - y, y: x };
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
async function navigateDestination(dest) {
|
||||
if (document.body.hasAttribute("aria-busy")) return;
|
||||
const index = state.doc.pages.findIndex(page => page.id === dest.pageID);
|
||||
@@ -5008,11 +5015,22 @@ async function navigateDestination(dest) {
|
||||
return;
|
||||
}
|
||||
const seq = state.openSeq, scale = state.scale;
|
||||
let retained = null;
|
||||
if (dest.omitLeft || dest.omitTop) {
|
||||
const current = state.doc.pages[state.pageIndex], shell = pageShell(state.pageIndex)?.getBoundingClientRect();
|
||||
if (current && shell) {
|
||||
const viewer = el.viewerPanel.getBoundingClientRect();
|
||||
retained = sourcePoint(current,
|
||||
(viewer.left + pageSpace() - shell.left) / (MM_TO_PX * scale),
|
||||
(viewer.top + pageBlockSpace() - shell.top) / (MM_TO_PX * scale));
|
||||
}
|
||||
}
|
||||
await renderPage(index, { fit: false, scroll: false });
|
||||
if (seq !== state.openSeq || state.pageIndex !== index) return;
|
||||
const page = state.doc.pages[index], size = pageViewSize(page), space = pageSpace();
|
||||
const width = el.viewerPanel.clientWidth - space * 2, height = el.viewerPanel.clientHeight - space * 2;
|
||||
let left = dest.left, top = dest.top;
|
||||
let left = dest.omitLeft && retained ? retained.x : dest.left;
|
||||
let top = dest.omitTop && retained ? retained.y : dest.top;
|
||||
if (dest.type === "Fit") {
|
||||
fitHeight(false);
|
||||
scrollToPage(index);
|
||||
@@ -5028,7 +5046,7 @@ async function navigateDestination(dest) {
|
||||
if (dest.right <= dest.left || dest.bottom <= dest.top) return;
|
||||
setScale(Math.min(width / Math.abs(b.x - a.x), height / Math.abs(b.y - a.y)) / MM_TO_PX, false);
|
||||
} else {
|
||||
setScale(dest.zoom > 0 ? dest.zoom : scale, false);
|
||||
setScale(!dest.omitZoom && dest.zoom > 0 ? dest.zoom : scale, false);
|
||||
}
|
||||
const point = destinationPoint(page, left, top);
|
||||
if (dest.type === "FitR") {
|
||||
|
||||
@@ -9,7 +9,7 @@ require (
|
||||
github.com/tdewolff/canvas v0.0.0-20260923214215-09804640d00c
|
||||
github.com/tdewolff/font v0.0.0-20260913163313-54f98bb59ee6
|
||||
github.com/xiaoqidun/jbig2 v1.1.1
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20260924162208-698614ef984e
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20260925061819-c89bfccf349d
|
||||
golang.org/x/crypto v0.57.0
|
||||
golang.org/x/image v0.46.0
|
||||
golang.org/x/text v0.42.0
|
||||
|
||||
@@ -60,8 +60,8 @@ github.com/tdewolff/test v1.0.12 h1:7F21DqIajswxuche0geHdrUZRCWE4oko4b7bcmkkrxk=
|
||||
github.com/tdewolff/test v1.0.12/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
||||
github.com/xiaoqidun/jbig2 v1.1.1 h1:SjliS9ZO0e9HX5oYUfBuXrfFsXhWricrSz+XY4zORDI=
|
||||
github.com/xiaoqidun/jbig2 v1.1.1/go.mod h1:8QonVWtENmh2kc6l+leqeGl7psb79DWlHDkCpdChjfQ=
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20260924162208-698614ef984e h1:17a5JOpYM6gwXZnhapgrXA6H7LhtGVrF0rpeiEORYUA=
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20260924162208-698614ef984e/go.mod h1:/D0XHgfZ7xNhix95swpNaThpuqoJjVR5wIadogtR5pI=
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20260925061819-c89bfccf349d h1:hjdo01d4EsiNe9l0JNyc+Bqfrvdj9XGG786EYxAx3yw=
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20260925061819-c89bfccf349d/go.mod h1:/D0XHgfZ7xNhix95swpNaThpuqoJjVR5wIadogtR5pI=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/yuin/goldmark v1.8.5 h1:r6N5afV5qj/5S4UTch8agZHJ8UxNCMwX7WjkkJam2NA=
|
||||
|
||||
@@ -529,7 +529,8 @@ func renderPage(args []js.Value) (any, error) {
|
||||
}
|
||||
if dest := link.Dest; dest != nil {
|
||||
item["dest"] = map[string]any{"type": dest.Type, "pageID": dest.PageID, "left": dest.Left, "top": dest.Top,
|
||||
"right": dest.Right, "bottom": dest.Bottom, "zoom": dest.Zoom}
|
||||
"right": dest.Right, "bottom": dest.Bottom, "zoom": dest.Zoom,
|
||||
"omitLeft": dest.OmitLeft, "omitTop": dest.OmitTop, "omitZoom": dest.OmitZoom}
|
||||
}
|
||||
links[i] = item
|
||||
}
|
||||
|
||||
+24
-7
@@ -39,13 +39,16 @@ type Goto struct {
|
||||
|
||||
// Dest 文档内跳转目标
|
||||
type Dest struct {
|
||||
Type string `xml:"Type,attr"`
|
||||
PageID string `xml:"PageID,attr"`
|
||||
Left float64 `xml:"Left"`
|
||||
Right float64 `xml:"Right"`
|
||||
Top float64 `xml:"Top"`
|
||||
Bottom float64 `xml:"Bottom"`
|
||||
Zoom float64 `xml:"Zoom"`
|
||||
Type string `xml:"Type,attr"`
|
||||
PageID string `xml:"PageID,attr"`
|
||||
Left float64 `xml:"Left"`
|
||||
Right float64 `xml:"Right"`
|
||||
Top float64 `xml:"Top"`
|
||||
Bottom float64 `xml:"Bottom"`
|
||||
Zoom float64 `xml:"Zoom"`
|
||||
OmitLeft bool `xml:"-"`
|
||||
OmitTop bool `xml:"-"`
|
||||
OmitZoom bool `xml:"-"`
|
||||
}
|
||||
|
||||
// GotoBookmark 书签跳转目标
|
||||
@@ -151,6 +154,17 @@ func (dest *Dest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
}
|
||||
dest.Type = attrValue(start, "Type")
|
||||
dest.PageID = attrValue(start, "PageID")
|
||||
dest.OmitLeft, dest.OmitTop, dest.OmitZoom = true, true, true
|
||||
for _, attr := range start.Attr {
|
||||
switch attr.Name.Local {
|
||||
case "Left":
|
||||
dest.OmitLeft = false
|
||||
case "Top":
|
||||
dest.OmitTop = false
|
||||
case "Zoom":
|
||||
dest.OmitZoom = false
|
||||
}
|
||||
}
|
||||
dest.Left = actionFloatAttr(start, "Left")
|
||||
dest.Right = actionFloatAttr(start, "Right")
|
||||
dest.Top = actionFloatAttr(start, "Top")
|
||||
@@ -161,18 +175,21 @@ func (dest *Dest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
}
|
||||
if value.Left != nil {
|
||||
dest.Left = *value.Left
|
||||
dest.OmitLeft = false
|
||||
}
|
||||
if value.Right != nil {
|
||||
dest.Right = *value.Right
|
||||
}
|
||||
if value.Top != nil {
|
||||
dest.Top = *value.Top
|
||||
dest.OmitTop = false
|
||||
}
|
||||
if value.Bottom != nil {
|
||||
dest.Bottom = *value.Bottom
|
||||
}
|
||||
if value.Zoom != nil {
|
||||
dest.Zoom = *value.Zoom
|
||||
dest.OmitZoom = false
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -372,6 +372,12 @@ func annotationLinkXML(target AnnotationLink) ([]byte, error) {
|
||||
if !finite(value.value) {
|
||||
return nil, fmt.Errorf("destination coordinates must be finite")
|
||||
}
|
||||
omit := dest.Type == "XYZ" && (value.name == "Left" && dest.OmitLeft || value.name == "Top" && dest.OmitTop || value.name == "Zoom" && dest.OmitZoom)
|
||||
omit = omit || dest.Type == "FitH" && value.name == "Top" && dest.OmitTop
|
||||
omit = omit || dest.Type == "FitV" && value.name == "Left" && dest.OmitLeft
|
||||
if omit {
|
||||
continue
|
||||
}
|
||||
if dest.Type == "XYZ" && slices.Contains([]string{"Left", "Top", "Zoom"}, value.name) || dest.Type == "FitH" && value.name == "Top" || dest.Type == "FitV" && value.name == "Left" || dest.Type == "FitR" && value.name != "Zoom" {
|
||||
attrs.add(value.name, ofdNumber(value.value))
|
||||
}
|
||||
|
||||
+23
-4
@@ -378,8 +378,8 @@ func (p *pdfImporter) appendPath(mark pdfgo.PathMark) error {
|
||||
margin := mark.Style.LineWidth * scale / 2 * math.Max(1, mark.Style.MiterLimit)
|
||||
box = Box{box.X - margin, box.Y - margin, box.W + 2*margin, box.H + 2*margin}
|
||||
}
|
||||
strokeColor := StrokeColor(*p.pathColor(mark.Style.Stroke, box))
|
||||
object := PathObject{Boundary: pdfBoundary(box), AbbreviatedData: p.pathData(mark.Path, box), Fill: &mark.Fill, Stroke: &mark.Stroke, FillColor: p.pathColor(mark.Style.Fill, box), StrokeColor: &strokeColor, LineWidth: mark.Style.LineWidth * scale, Cap: []string{"Butt", "Round", "Square"}[mark.Style.Cap], Join: []string{"Miter", "Round", "Bevel"}[mark.Style.Join], MiterLimit: mark.Style.MiterLimit, Clips: p.clips(mark.Style.Clips, box)}
|
||||
strokeColor := StrokeColor(*p.paintColor(mark.Style.Stroke, box))
|
||||
object := PathObject{Boundary: pdfBoundary(box), AbbreviatedData: p.pathData(mark.Path, box), Fill: &mark.Fill, Stroke: &mark.Stroke, FillColor: p.paintColor(mark.Style.Fill, box), StrokeColor: &strokeColor, LineWidth: mark.Style.LineWidth * scale, Cap: []string{"Butt", "Round", "Square"}[mark.Style.Cap], Join: []string{"Miter", "Round", "Bevel"}[mark.Style.Join], MiterLimit: mark.Style.MiterLimit, Clips: p.clips(mark.Style.Clips, box)}
|
||||
object.LineWidthSet = object.LineWidth == 0
|
||||
if mark.Path.EvenOdd {
|
||||
object.Rule = "Even-Odd"
|
||||
@@ -398,11 +398,30 @@ func (p *pdfImporter) appendPath(mark pdfgo.PathMark) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// pathColor 将页面渐变轴转换为对象局部坐标
|
||||
// paintColor 将页面渐变转换为对象局部坐标
|
||||
// 入参: paint PDF画刷, box 对象边界
|
||||
// 返回: *FillColor OFD颜色或渐变
|
||||
func (p *pdfImporter) pathColor(paint pdfgo.Paint, box Box) *FillColor {
|
||||
func (p *pdfImporter) paintColor(paint pdfgo.Paint, box Box) *FillColor {
|
||||
color := p.color(paint)
|
||||
if paint.Radial != nil {
|
||||
gradient := paint.Radial
|
||||
start, end := p.matrix.Apply(gradient.Start), p.matrix.Apply(gradient.End)
|
||||
scale := math.Hypot(p.matrix[0], p.matrix[1])
|
||||
extend := 0
|
||||
if gradient.Extend[0] {
|
||||
extend |= 1
|
||||
}
|
||||
if gradient.Extend[1] {
|
||||
extend |= 2
|
||||
}
|
||||
shading := &RadialShd{StartPoint: pdfNumbers(start.X-box.X, start.Y-box.Y), EndPoint: pdfNumbers(end.X-box.X, end.Y-box.Y), StartRadius: gradient.StartRadius * scale, EndRadius: gradient.EndRadius * scale, Extend: strconv.Itoa(extend)}
|
||||
for _, stop := range gradient.Stops {
|
||||
shading.Segment = append(shading.Segment, ShdSegment{Position: stop.Position, Color: ShdColor{Value: pdfNumbers(math.Round(stop.RGB[0]*255), math.Round(stop.RGB[1]*255), math.Round(stop.RGB[2]*255))}})
|
||||
}
|
||||
color.Value = ""
|
||||
color.RadialShd = shading
|
||||
return color
|
||||
}
|
||||
if paint.Axial == nil {
|
||||
return color
|
||||
}
|
||||
|
||||
+2
-2
@@ -72,7 +72,7 @@ func (p *pdfImporter) group(mark pdfgo.GroupMark, walk func(pdfgo.Visitor) error
|
||||
if stroke {
|
||||
color, overprint = path.Style.Stroke, path.Style.StrokeOverprint
|
||||
}
|
||||
if color.Alpha != 1 || color.Axial != nil || overprint && pdfOverprintNeedsSeparation(color) {
|
||||
if color.Alpha != 1 || color.Axial != nil || color.Radial != nil || overprint && pdfOverprintNeedsSeparation(color) {
|
||||
return &pdfgo.UnsupportedError{Feature: "transparent or overprinted group content"}
|
||||
}
|
||||
if paint == nil {
|
||||
@@ -230,7 +230,7 @@ func (p *pdfImporter) maskClip(mask *pdfgo.SoftMask) (pdfgo.Path, error) {
|
||||
}
|
||||
visitor.Path = func(mark pdfgo.PathMark) error {
|
||||
paint := mark.Style.Fill
|
||||
if !mark.Fill || mark.Stroke || paint.Alpha != 1 || paint.CMYK != nil || paint.Axial != nil || paint.RGB[0] != paint.RGB[1] || paint.RGB[1] != paint.RGB[2] || mark.Style.SoftMask != nil {
|
||||
if !mark.Fill || mark.Stroke || paint.Alpha != 1 || paint.CMYK != nil || paint.Axial != nil || paint.Radial != nil || paint.RGB[0] != paint.RGB[1] || paint.RGB[1] != paint.RGB[2] || mark.Style.SoftMask != nil {
|
||||
return &pdfgo.UnsupportedError{Feature: "nonbinary mask graphic"}
|
||||
}
|
||||
visible, err := opacity(paint.RGB[0])
|
||||
|
||||
+58
-4
@@ -41,7 +41,7 @@ func (p *pdfImporter) annotations(ctx context.Context, page *pdfgo.Page, strict
|
||||
if annotation.Subtype != "Link" {
|
||||
return &pdfgo.UnsupportedError{Feature: "annotation " + string(annotation.Subtype)}
|
||||
}
|
||||
for _, key := range []pdfgo.Name{"AP", "AA", "BS", "QuadPoints", "OC"} {
|
||||
for _, key := range []pdfgo.Name{"AP", "AA", "BS", "OC"} {
|
||||
if dict[key] != nil {
|
||||
return &pdfgo.UnsupportedError{Feature: fmt.Sprintf("link annotation field %q", key)}
|
||||
}
|
||||
@@ -127,6 +127,7 @@ func (p *pdfImporter) annotations(ctx context.Context, page *pdfgo.Page, strict
|
||||
dest := &Dest{Type: string(destination.Mode), PageID: p.pageIDs[destination.Page]}
|
||||
if destination.Mode == "XYZ" {
|
||||
values := [3]float64{}
|
||||
retained := [3]bool{}
|
||||
for n, v := range destination.Parameters {
|
||||
switch v := v.(type) {
|
||||
case pdfgo.Integer:
|
||||
@@ -134,13 +135,16 @@ func (p *pdfImporter) annotations(ctx context.Context, page *pdfgo.Page, strict
|
||||
case pdfgo.Real:
|
||||
values[n] = float64(v)
|
||||
case nil:
|
||||
if n < 2 {
|
||||
return &pdfgo.UnsupportedError{Feature: "retained destination coordinates"}
|
||||
}
|
||||
retained[n] = true
|
||||
}
|
||||
}
|
||||
point := matrix.Apply(pdfgo.Point{X: values[0], Y: values[1]})
|
||||
dest.Left, dest.Top, dest.Zoom = point.X, point.Y, values[2]
|
||||
dest.OmitLeft, dest.OmitTop = retained[0], retained[1]
|
||||
if targetPage.Rotation == 90 || targetPage.Rotation == 270 {
|
||||
dest.OmitLeft, dest.OmitTop = retained[1], retained[0]
|
||||
}
|
||||
dest.OmitZoom = retained[2] || values[2] == 0
|
||||
} else if destination.Mode != "Fit" {
|
||||
return &pdfgo.UnsupportedError{Feature: "destination mode " + string(destination.Mode)}
|
||||
}
|
||||
@@ -154,9 +158,59 @@ func (p *pdfImporter) annotations(ctx context.Context, page *pdfgo.Page, strict
|
||||
}
|
||||
no := false
|
||||
object.Fill, object.Stroke = &no, &no
|
||||
action.Region, err = p.linkRegion(annotation, box)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
object.Actions = []Action{action}
|
||||
p.objects = append(p.objects, GraphicObject{Type: "PathObject", PathObject: object})
|
||||
p.report.Links++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// linkRegion 将PDF链接四边形映射为OFD动作区域,越出注解矩形时使用矩形
|
||||
// 入参: annotation PDF链接注解, box OFD对象边界
|
||||
// 返回: *Region 点击区域, error 解析错误
|
||||
func (p *pdfImporter) linkRegion(annotation pdfgo.Annotation, box Box) (*Region, error) {
|
||||
value, err := p.reader.Resolve(annotation.Dictionary["QuadPoints"])
|
||||
if err != nil || value == nil {
|
||||
return nil, err
|
||||
}
|
||||
array, ok := value.(pdfgo.Array)
|
||||
if !ok || len(array) == 0 || len(array)%8 != 0 {
|
||||
return nil, nil
|
||||
}
|
||||
region := &Region{Area: make([]RegionArea, 0, len(array)/8)}
|
||||
for start := 0; start < len(array); start += 8 {
|
||||
var points [4]pdfgo.Point
|
||||
for index := range points {
|
||||
coordinates := [2]float64{}
|
||||
for axis := range coordinates {
|
||||
resolved, err := p.reader.Resolve(array[start+index*2+axis])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch number := resolved.(type) {
|
||||
case pdfgo.Integer:
|
||||
coordinates[axis] = float64(number)
|
||||
case pdfgo.Real:
|
||||
coordinates[axis] = float64(number)
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
x, y := coordinates[0], coordinates[1]
|
||||
if !finite(x) || !finite(y) || x < annotation.Rect.XMin || x > annotation.Rect.XMax || y < annotation.Rect.YMin || y > annotation.Rect.YMax {
|
||||
return nil, nil
|
||||
}
|
||||
points[index] = p.matrix.Apply(pdfgo.Point{X: x, Y: y})
|
||||
}
|
||||
area := RegionArea{Start: pdfNumbers(points[0].X-box.X, points[0].Y-box.Y)}
|
||||
for _, point := range points[1:] {
|
||||
area.Command = append(area.Command, RegionCommand{Type: "Line", Point1: pdfNumbers(point.X-box.X, point.Y-box.Y)})
|
||||
}
|
||||
region.Area = append(region.Area, area)
|
||||
}
|
||||
return region, nil
|
||||
}
|
||||
+12
-11
@@ -39,7 +39,7 @@ func (p *pdfImporter) image(mark pdfgo.ImageMark) error {
|
||||
if err := p.flushPath(); err != nil {
|
||||
return err
|
||||
}
|
||||
if mark.Image.ImageMask && mark.Style.Fill.Axial != nil {
|
||||
if mark.Image.ImageMask && (mark.Style.Fill.Axial != nil || mark.Style.Fill.Radial != nil) {
|
||||
return &pdfgo.UnsupportedError{Feature: "gradient stencil image"}
|
||||
}
|
||||
var err error
|
||||
@@ -147,9 +147,6 @@ func (p *pdfImporter) text(mark pdfgo.TextMark) error {
|
||||
if err := p.flushPath(); err != nil {
|
||||
return err
|
||||
}
|
||||
if mark.Style.Fill.Axial != nil || mark.Style.Stroke.Axial != nil {
|
||||
return &pdfgo.UnsupportedError{Feature: "gradient text paint"}
|
||||
}
|
||||
var err error
|
||||
mark.Style, err = p.maskStyle(mark.Style)
|
||||
if err != nil {
|
||||
@@ -167,7 +164,8 @@ func (p *pdfImporter) text(mark pdfgo.TextMark) error {
|
||||
if id == "" {
|
||||
var err error
|
||||
if embedded {
|
||||
program, err := pdfFontProgram(font)
|
||||
var program []byte
|
||||
program, err = pdfFontProgram(font)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -225,7 +223,7 @@ func (p *pdfImporter) text(mark pdfgo.TextMark) error {
|
||||
}
|
||||
}
|
||||
if embedded && gid >= metrics.NumGlyphs() {
|
||||
return fmt.Errorf("PDF glyph index outside embedded font")
|
||||
return fmt.Errorf("PDF glyph index %d outside embedded font %s (%d glyphs)", gid, font.Name, metrics.NumGlyphs())
|
||||
}
|
||||
if !embedded && glyph.Text == "" {
|
||||
return &pdfgo.UnsupportedError{Feature: "unmapped external font character"}
|
||||
@@ -263,8 +261,6 @@ func (p *pdfImporter) text(mark pdfgo.TextMark) error {
|
||||
}
|
||||
margin := mark.Style.LineWidth * unit / 2 * math.Max(1, mark.Style.MiterLimit)
|
||||
box = Box{box.X - margin, box.Y - margin, box.W + 2*margin, box.H + 2*margin}
|
||||
color := StrokeColor(*p.color(mark.Style.Stroke))
|
||||
object.StrokeColor = &color
|
||||
object.LineWidth = mark.Style.LineWidth * unit / scale
|
||||
object.LineWidthSet = object.LineWidth == 0
|
||||
object.Join = []string{"Miter", "Round", "Bevel"}[mark.Style.Join]
|
||||
@@ -274,6 +270,10 @@ func (p *pdfImporter) text(mark pdfgo.TextMark) error {
|
||||
}
|
||||
}
|
||||
object.Boundary = pdfBoundary(box)
|
||||
if stroke {
|
||||
color := StrokeColor(*p.paintColor(mark.Style.Stroke, box))
|
||||
object.StrokeColor = &color
|
||||
}
|
||||
if box.X >= p.pageWidth || box.Y >= p.pageHeight || box.X+box.W <= 0 || box.Y+box.H <= 0 {
|
||||
visible = false
|
||||
}
|
||||
@@ -281,7 +281,7 @@ func (p *pdfImporter) text(mark pdfgo.TextMark) error {
|
||||
object.Fill = &fill
|
||||
object.Stroke = &stroke
|
||||
object.Visible = &visible
|
||||
object.FillColor = p.color(mark.Style.Fill)
|
||||
object.FillColor = p.paintColor(mark.Style.Fill, box)
|
||||
object.Clips = p.clips(mark.Style.Clips, box)
|
||||
p.objects = append(p.objects, GraphicObject{Type: "TextObject", TextObject: object})
|
||||
p.report.TextObjects++
|
||||
@@ -293,7 +293,8 @@ func (p *pdfImporter) text(mark pdfgo.TextMark) error {
|
||||
// 返回: []byte 封装后的字体数据, error 错误信息
|
||||
func pdfFontProgram(source *pdfgo.Font) ([]byte, error) {
|
||||
program := source.Program
|
||||
if source.ProgramType == "Type1C" || source.ProgramType == "CIDFontType0C" {
|
||||
bareCFF := len(program) >= 4 && program[0] == 1 && program[1] == 0 && program[2] >= 4 && program[3] >= 1 && program[3] <= 4
|
||||
if source.ProgramType == "Type1C" || source.ProgramType == "CIDFontType0C" || bareCFF {
|
||||
var err error
|
||||
program, _, err = wrapCFFToOTF(source.Program)
|
||||
if err != nil {
|
||||
@@ -377,7 +378,7 @@ func pdfFontProgram(source *pdfgo.Font) ([]byte, error) {
|
||||
tables["OS/2"] = buildOS2TableWithMetrics(int16(binary.BigEndian.Uint16(hhea[4:6])), int16(binary.BigEndian.Uint16(hhea[6:8])))
|
||||
changed = true
|
||||
}
|
||||
if !changed {
|
||||
if !changed && len(program)%4 == 0 {
|
||||
return program, nil
|
||||
}
|
||||
return serializeOTF(tables)
|
||||
|
||||
+15
-5
@@ -961,13 +961,23 @@ func (x *ofdXML) actions(actions []Action) {
|
||||
attrs := ofdAttrs{{Name: xml.Name{Local: "Type"}, Value: dest.Type}, {Name: xml.Name{Local: "PageID"}, Value: dest.PageID}}
|
||||
switch dest.Type {
|
||||
case "XYZ":
|
||||
attrs.add("Left", ofdNumber(dest.Left))
|
||||
attrs.add("Top", ofdNumber(dest.Top))
|
||||
attrs.add("Zoom", ofdNumber(dest.Zoom))
|
||||
if !dest.OmitLeft {
|
||||
attrs.add("Left", ofdNumber(dest.Left))
|
||||
}
|
||||
if !dest.OmitTop {
|
||||
attrs.add("Top", ofdNumber(dest.Top))
|
||||
}
|
||||
if !dest.OmitZoom {
|
||||
attrs.add("Zoom", ofdNumber(dest.Zoom))
|
||||
}
|
||||
case "FitH":
|
||||
attrs.add("Top", ofdNumber(dest.Top))
|
||||
if !dest.OmitTop {
|
||||
attrs.add("Top", ofdNumber(dest.Top))
|
||||
}
|
||||
case "FitV":
|
||||
attrs.add("Left", ofdNumber(dest.Left))
|
||||
if !dest.OmitLeft {
|
||||
attrs.add("Left", ofdNumber(dest.Left))
|
||||
}
|
||||
case "FitR":
|
||||
attrs.add("Left", ofdNumber(dest.Left))
|
||||
attrs.add("Right", ofdNumber(dest.Right))
|
||||
|
||||
Reference in new issue
Block a user