github.com/pdfcpu/pdfcpu@v0.11.1/pkg/api/test/create_test.go (about)

     1  /*
     2  Copyright 2019 The pdf Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package test
    18  
    19  import (
    20  	"bytes"
    21  	"path/filepath"
    22  	"testing"
    23  
    24  	"github.com/pdfcpu/pdfcpu/pkg/api"
    25  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu"
    26  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/color"
    27  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/draw"
    28  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
    29  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
    30  )
    31  
    32  var sampleText string = `MOST of the adventures recorded in this book really occurred; one or
    33  two were experiences of my own, the rest those of boys who were
    34  schoolmates of mine. Huck Finn is drawn from life; Tom Sawyer also, but
    35  not from an individual--he is a combination of the characteristics of
    36  three boys whom I knew, and therefore belongs to the composite order of
    37  architecture.
    38  
    39  The odd superstitions touched upon were all prevalent among children
    40  and slaves in the West at the period of this story--that is to say,
    41  thirty or forty years ago.
    42  
    43  Although my book is intended mainly for the entertainment of boys and
    44  girls, I hope it will not be shunned by men and women on that account,
    45  for part of my plan has been to try to pleasantly remind adults of what
    46  they once were themselves, and of how they felt and thought and talked,
    47  and what queer enterprises they sometimes engaged in.`
    48  
    49  var sampleTextArabic = `حدثت بالفعل معظم المغامرات المسجلة في هذا الكتاب ؛ واحد أو
    50  كانت اثنتان من تجربتي الخاصة ، والباقي تجارب الأولاد الذين كانوا كذلك
    51  زملائي في المدرسة. هاك فين مستوحى من الحياة ؛ توم سوير أيضا ولكن
    52  ليس من فرد - إنه مزيج من خصائص
    53  ثلاثة أولاد أعرفهم ، وبالتالي ينتمون إلى الترتيب المركب لـ
    54  هندسة معمارية.
    55  
    56  كانت الخرافات الغريبة التي تم التطرق إليها سائدة بين الأطفال
    57  والعبيد في الغرب في فترة هذه القصة - أي
    58  قبل ثلاثين أو أربعين سنة.
    59  
    60  على الرغم من أن كتابي مخصص بشكل أساسي للترفيه عن الأولاد و
    61  الفتيات ، أتمنى ألا يتجنب الرجال والنساء ذلك الحساب ،
    62  جزء من خطتي كان محاولة تذكير البالغين بما يحدث
    63  كانوا أنفسهم ذات مرة ، وكيف شعروا وفكروا وتحدثوا ،
    64  وما هي المؤسسات الكويرية التي شاركوا فيها أحيانًا.`
    65  
    66  var sampleTextHebrew = `רוב ההרפתקאות שתועדו בספר זה באמת התרחשו; אחד או
    67  שתיים היו חוויות משלי, והשאר אלה של בנים שהיו
    68  חברי לבית הספר שלי. האק פין נשאב מהחיים; גם טום סוייר, אבל
    69  לא מאדם - הוא שילוב של המאפיינים של
    70  שלושה בנים שהכרתי ולכן שייכים לסדר המורכב של
    71  ארכיטקטורה.
    72  
    73  האמונות הטפלות המוזרות בהן נגעו היו כולן רווחות בקרב ילדים
    74  ועבדים במערב בתקופת הסיפור הזה - כלומר,
    75  לפני שלושים או ארבעים שנה.
    76  
    77  למרות שהספר שלי מיועד בעיקר לבידור של בנים ו
    78  בנות, אני מקווה שזה לא יימנע מגברים ונשים בגלל זה,
    79  חלק מהתוכנית שלי הייתה לנסות להזכיר למבוגרים בנעימות מה
    80  פעם הם היו עצמם, ועל איך שהם הרגישו וחשבו ודיברו,
    81  ובאילו מפעלים מוזרים הם עסקו לפעמים.`
    82  
    83  var sampleTextPersian = `بیشتر ماجراهای ثبت شده در این کتاب واقعاً اتفاق افتاده است. یکی یا
    84  دو مورد از تجربه های خودم بود ، بقیه از پسران بودند
    85  هم مدرسه ای های من. هاک فین از زندگی کشیده شده است. تام سویر نیز ، اما
    86  نه از یک فرد - او ترکیبی از ویژگی های است
    87  سه پسر که من آنها را می شناختم و بنابراین به ترتیب مرکب تعلق دارند
    88  معماری.
    89  
    90  خرافات عجیب و غریب لمس شده همه در میان کودکان شایع بود
    91  و بردگان در غرب این دوره از داستان - یعنی اینکه ،
    92  سی چهل سال پیش
    93  
    94  اگرچه کتاب من عمدتا برای سرگرمی پسران و
    95  دختران ، امیدوارم با این حساب مردان و زنان از آن اجتناب نکنند ،
    96  زیرا بخشی از برنامه من این بوده است که سعی کنم چه چیزی را به بزرگسالان یادآوری کنم
    97  آنها یک بار خودشان بودند ، و از احساس و تفکر و صحبت کردن ،
    98  و بعضی اوقات چه کارهایی را انجام می دادند`
    99  
   100  var sampleTextUrdu = `اس کتاب میں درج کی گئی زیادہ تر مہم جوئی واقعتا؛ پیش آئی ہے۔ ایک یا
   101  دو میرے اپنے تجربات تھے ، باقی جو لڑکے تھے
   102  میرے اسکول کے ساتھیوں. ہک فن زندگی سے نکالا گیا ہے۔ ٹام ساویر بھی ، لیکن
   103  کسی فرد سے نہیں - وہ کی خصوصیات کا ایک مجموعہ ہے
   104  تین لڑکے جن کو میں جانتا تھا ، اور اس وجہ سے یہ جامع ترتیب سے ہے
   105  فن تعمیر
   106  
   107  بچوں میں عجیب و غریب اندوشواس کا اثر تمام تھا
   108  اور اس کہانی کے دور میں مغرب میں غلام۔
   109  تیس یا چالیس سال پہلے کی بات ہے۔
   110  
   111  اگرچہ میری کتاب بنیادی طور پر لڑکوں اور تفریح ​​کے لئے ہے
   112  لڑکیاں ، مجھے امید ہے کہ اس وجہ سے مرد اور خواتین اس سے باز نہیں آئیں گے ،
   113  میرے منصوبے کا ایک حص adultsہ یہ رہا ہے کہ بالغوں کو خوشی سے اس کی یاد دلانے کی کیا کوشش کی جائے
   114  وہ ایک بار خود تھے ، اور یہ کہ وہ کیسے محسوس کرتے ہیں ، سوچتے اور بات کرتے ہیں ،
   115  اور کن کن کن کاروباری اداروں میں وہ کبھی کبھی مشغول رہتے ہیں۔`
   116  
   117  var sampleTextRTL = map[string]string{
   118  	"Arabic":  sampleTextArabic,
   119  	"Hebrew":  sampleTextHebrew,
   120  	"Persian": sampleTextPersian,
   121  	"Urdu":    sampleTextUrdu,
   122  }
   123  
   124  var sampleText2 = `THE two boys flew on and on, toward the village, speechless with
   125  horror. They glanced backward over their shoulders from time to time,
   126  apprehensively, as if they feared they might be followed. Every stump
   127  that started up in their path seemed a man and an enemy, and made them
   128  catch their breath; and as they sped by some outlying cottages that lay
   129  near the village, the barking of the aroused watch-dogs seemed to give
   130  wings to their feet.
   131  
   132  "If we can only get to the old tannery before we break down!"
   133  whispered Tom, in short catches between breaths. "I can't stand it much
   134  longer."
   135  
   136  Huckleberry's hard pantings were his only reply, and the boys fixed
   137  their eyes on the goal of their hopes and bent to their work to win it.
   138  They gained steadily on it, and at last, breast to breast, they burst
   139  through the open door and fell grateful and exhausted in the sheltering
   140  shadows beyond. By and by their pulses slowed down, and Tom whispered:
   141  
   142  "Huckleberry, what do you reckon'll come of this?"`
   143  
   144  var sampleText3 = `Even the Glorious Fourth was in some sense a failure, for it rained
   145  hard, there was no procession in consequence, and the greatest man in
   146  the world (as Tom supposed), Mr. Benton, an actual United States
   147  Senator, proved an overwhelming disappointment--for he was not
   148  twenty-five feet high, nor even anywhere in the neighborhood of it.
   149  
   150  A circus came. The boys played circus for three days afterward in
   151  tents made of rag carpeting--admission, three pins for boys, two for
   152  girls--and then circusing was abandoned.
   153  
   154  A phrenologist and a mesmerizer came--and went again and left the
   155  village duller and drearier than ever.
   156  
   157  There were some boys-and-girls' parties, but they were so few and so
   158  delightful that they only made the aching voids between ache the harder.
   159  
   160  Becky Thatcher was gone to her Constantinople home to stay with her
   161  parents during vacation--so there was no bright side to life anywhere.`
   162  
   163  func createAndValidate(t *testing.T, xRefTable *model.XRefTable, outFile, msg string) {
   164  	t.Helper()
   165  	outDir := "../../samples/basic"
   166  	outFile = filepath.Join(outDir, outFile)
   167  	if err := api.CreatePDFFile(xRefTable, outFile, nil); err != nil {
   168  		t.Fatalf("%s: %v\n", msg, err)
   169  	}
   170  	if err := api.ValidateFile(outFile, nil); err != nil {
   171  		t.Fatalf("%s: %v\n", msg, err)
   172  	}
   173  }
   174  
   175  func TestCreateDemoPDF(t *testing.T) {
   176  	msg := "TestCreateDemoPDF"
   177  	mediaBox := types.RectForFormat("A4")
   178  	p := model.Page{MediaBox: mediaBox, Fm: model.FontMap{}, Buf: new(bytes.Buffer)}
   179  	pdfcpu.CreateTestPageContent(p)
   180  	xRefTable, err := pdfcpu.CreateDemoXRef()
   181  	if err != nil {
   182  		t.Fatalf("%s: %v\n", msg, err)
   183  	}
   184  	rootDict, err := xRefTable.Catalog()
   185  	if err != nil {
   186  		t.Fatalf("%s: %v\n", msg, err)
   187  	}
   188  	if err = pdfcpu.AddPageTreeWithSamplePage(xRefTable, rootDict, p); err != nil {
   189  		t.Fatalf("%s: %v\n", msg, err)
   190  	}
   191  	createAndValidate(t, xRefTable, "Test.pdf", msg)
   192  }
   193  
   194  func TestResourceDictInheritanceDemoPDF(t *testing.T) {
   195  	// Create a test page proofing resource inheritance.
   196  	// Resources may be inherited from ANY parent node.
   197  	// Case in point: fonts
   198  	msg := "TestResourceDictInheritanceDemoPDF"
   199  	xRefTable, err := pdfcpu.CreateResourceDictInheritanceDemoXRef()
   200  	if err != nil {
   201  		t.Fatalf("%s: %v\n", msg, err)
   202  	}
   203  	createAndValidate(t, xRefTable, "ResourceDictInheritanceDemo.pdf", msg)
   204  }
   205  
   206  func TestAnnotationDemoPDF(t *testing.T) {
   207  	msg := "TestAnnotationDemoPDF"
   208  	xRefTable, err := pdfcpu.CreateAnnotationDemoXRef()
   209  	if err != nil {
   210  		t.Fatalf("%s: %v\n", msg, err)
   211  	}
   212  	createAndValidate(t, xRefTable, "AnnotationDemo.pdf", msg)
   213  }
   214  
   215  func writeTextDemoAlignedWidthAndMargin(
   216  	xRefTable *model.XRefTable,
   217  	p model.Page,
   218  	region *types.Rectangle,
   219  	hAlign types.HAlignment,
   220  	w, mLeft, mRight, mTop, mBot float64) {
   221  
   222  	buf := p.Buf
   223  	mediaBox := p.MediaBox
   224  
   225  	mediaBB := true
   226  
   227  	var cr, cg, cb float32
   228  	cr, cg, cb = .5, .75, 1.
   229  	r := mediaBox
   230  	if region != nil {
   231  		r = region
   232  		cr, cg, cb = .75, .75, 1
   233  	}
   234  	if mediaBB {
   235  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
   236  	}
   237  
   238  	fontName := "Helvetica"
   239  	k := p.Fm.EnsureKey(fontName)
   240  
   241  	td := model.TextDescriptor{
   242  		FontName:       fontName,
   243  		Embed:          true,
   244  		FontKey:        k,
   245  		FontSize:       24,
   246  		ShowMargins:    true,
   247  		MLeft:          mLeft,
   248  		MRight:         mRight,
   249  		MTop:           mTop,
   250  		MBot:           mBot,
   251  		Scale:          1.,
   252  		ScaleAbs:       true,
   253  		HAlign:         hAlign,
   254  		RMode:          draw.RMFill,
   255  		StrokeCol:      color.Black,
   256  		FillCol:        color.Black,
   257  		ShowBackground: true,
   258  		BackgroundCol:  color.SimpleColor{R: 1., G: .98, B: .77},
   259  		ShowBorder:     true,
   260  		ShowLineBB:     true,
   261  		ShowTextBB:     true,
   262  		HairCross:      true,
   263  	}
   264  
   265  	td.VAlign, td.X, td.Y, td.Text = types.AlignBaseline, -1, r.Height()*.75, "M\\u(lti\nline\n\nwith empty line"
   266  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   267  
   268  	td.VAlign, td.X, td.Y, td.Text = types.AlignBaseline, r.Width()*.75, r.Height()*.25, "Arbitrary\ntext\nlines"
   269  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   270  
   271  	// Multilines along the top of the page:
   272  	td.VAlign, td.X, td.Y, td.Text = types.AlignTop, 0, r.Height(), "0,h (topleft)\nand line2"
   273  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   274  
   275  	td.VAlign, td.X, td.Y, td.Text = types.AlignTop, -1, r.Height(), "-1,h (topcenter)\nand line2"
   276  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   277  
   278  	td.VAlign, td.X, td.Y, td.Text = types.AlignTop, r.Width(), r.Height(), "w,h (topright)\nand line2"
   279  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   280  
   281  	// Multilines along the center of the page:
   282  	// x = 0 centers the position of multilines horizontally
   283  	// y = 0 centers the position of multilines vertically and enforces alignMiddle
   284  	td.VAlign, td.X, td.Y, td.Text = types.AlignBaseline, 0, -1, "0,-1 (left)\nand line2"
   285  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   286  
   287  	td.VAlign, td.X, td.Y, td.Text = types.AlignMiddle, -1, -1, "-1,-1 (center)\nand line2"
   288  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   289  
   290  	td.VAlign, td.X, td.Y, td.Text = types.AlignBaseline, r.Width(), -1, "w,-1 (right)\nand line2"
   291  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   292  
   293  	// Multilines along the bottom of the page:
   294  	td.VAlign, td.X, td.Y, td.Text = types.AlignBottom, 0, 0, "0,0 (botleft)\nand line2"
   295  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   296  
   297  	td.VAlign, td.X, td.Y, td.Text = types.AlignBottom, -1, 0, "-1,0 (botcenter)\nand line2"
   298  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   299  
   300  	td.VAlign, td.X, td.Y, td.Text = types.AlignBottom, r.Width(), 0, "w,0 (botright)\nand line2"
   301  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, w)
   302  
   303  	draw.DrawHairCross(buf, 0, 0, r)
   304  }
   305  
   306  func createTextDemoAlignedWidthAndMargin(xRefTable *model.XRefTable, mediaBox *types.Rectangle, hAlign types.HAlignment, w, mLeft, mRight, mTop, mBot float64) model.Page {
   307  	p := model.NewPage(mediaBox, nil)
   308  	var region *types.Rectangle
   309  	writeTextDemoAlignedWidthAndMargin(xRefTable, p, region, hAlign, w, mLeft, mRight, mTop, mBot)
   310  	region = types.RectForWidthAndHeight(50, 70, 200, 200)
   311  	writeTextDemoAlignedWidthAndMargin(xRefTable, p, region, hAlign, w, mLeft, mRight, mTop, mBot)
   312  	return p
   313  }
   314  
   315  func createTextDemoAlignLeft(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   316  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignLeft, 0, 0, 0, 0, 0)
   317  }
   318  
   319  func createTextDemoAlignLeftMargin(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   320  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignLeft, 0, 5, 10, 15, 20)
   321  }
   322  
   323  func createTextDemoAlignRight(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   324  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignRight, 0, 0, 0, 0, 0)
   325  }
   326  
   327  func createTextDemoAlignRightMargin(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   328  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignRight, 0, 5, 10, 15, 20)
   329  }
   330  
   331  func createTextDemoAlignCenter(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   332  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignCenter, 0, 0, 0, 0, 0)
   333  }
   334  
   335  func createTextDemoAlignCenterMargin(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   336  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignCenter, 0, 5, 10, 15, 20)
   337  }
   338  
   339  func createTextDemoAlignJustify(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   340  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignJustify, 0, 0, 0, 0, 0)
   341  }
   342  
   343  func createTextDemoAlignJustifyMargin(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   344  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignJustify, 0, 5, 10, 15, 20)
   345  }
   346  
   347  func createTextDemoAlignLeftWidth(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   348  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignLeft, 250, 0, 0, 0, 0)
   349  }
   350  
   351  func createTextDemoAlignLeftWidthAndMargin(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   352  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignLeft, 250, 5, 10, 15, 20)
   353  }
   354  
   355  func createTextDemoAlignRightWidth(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   356  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignRight, 250, 0, 0, 0, 0)
   357  }
   358  
   359  func createTextDemoAlignRightWidthAndMargin(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   360  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignRight, 250, 5, 10, 15, 20)
   361  }
   362  
   363  func createTextDemoAlignCenterWidth(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   364  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignCenter, 250, 0, 0, 0, 0)
   365  }
   366  
   367  func createTextDemoAlignCenterWidthAndMargin(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   368  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignCenter, 250, 5, 40, 15, 20)
   369  }
   370  
   371  func createTextDemoAlignJustifyWidth(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   372  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignJustify, 250, 0, 0, 0, 0)
   373  }
   374  
   375  func createTextDemoAlignJustifyWidthAndMargin(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   376  	return createTextDemoAlignedWidthAndMargin(xRefTable, mediaBox, types.AlignJustify, 250, 5, 10, 15, 20)
   377  }
   378  
   379  func writeTextAlignJustifyDemo(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle, fontName string) {
   380  	mediaBox := p.MediaBox
   381  	buf := p.Buf
   382  
   383  	mediaBB := true
   384  
   385  	var cr, cg, cb float32
   386  	cr, cg, cb = .5, .75, 1.
   387  	r := mediaBox
   388  	if region != nil {
   389  		r = region
   390  		cr, cg, cb = .75, .75, 1
   391  	}
   392  	if mediaBB {
   393  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
   394  	}
   395  
   396  	k := p.Fm.EnsureKey(fontName)
   397  
   398  	td := model.TextDescriptor{
   399  		Text:           sampleText,
   400  		FontName:       fontName,
   401  		Embed:          true,
   402  		FontKey:        k,
   403  		FontSize:       12,
   404  		MLeft:          5,
   405  		MRight:         5,
   406  		MTop:           5,
   407  		MBot:           5,
   408  		X:              -1,
   409  		Y:              -1,
   410  		Scale:          1.,
   411  		ScaleAbs:       true,
   412  		HAlign:         types.AlignJustify,
   413  		VAlign:         types.AlignMiddle,
   414  		RMode:          draw.RMFill,
   415  		StrokeCol:      color.NewSimpleColor(0x206A29),
   416  		FillCol:        color.NewSimpleColor(0x206A29),
   417  		ShowBackground: true,
   418  		BackgroundCol:  color.SimpleColor{R: 1., G: .98, B: .77},
   419  		ShowBorder:     true,
   420  		ShowLineBB:     false,
   421  		ShowTextBB:     true,
   422  		HairCross:      false,
   423  	}
   424  
   425  	model.WriteMultiLine(xRefTable, buf, mediaBox, region, td)
   426  
   427  	draw.DrawHairCross(p.Buf, 0, 0, mediaBox)
   428  }
   429  
   430  func writeTextAlignJustifyColumnDemo(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle) {
   431  	mediaBox := p.MediaBox
   432  	buf := p.Buf
   433  
   434  	mediaBB := true
   435  
   436  	var cr, cg, cb float32
   437  	cr, cg, cb = .5, .75, 1.
   438  	r := mediaBox
   439  	if region != nil {
   440  		r = region
   441  		cr, cg, cb = .75, .75, 1
   442  	}
   443  	if mediaBB {
   444  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
   445  	}
   446  
   447  	fontName := "Times-Roman"
   448  	fontName2 := "Helvetica"
   449  	k1 := p.Fm.EnsureKey(fontName)
   450  	k2 := p.Fm.EnsureKey(fontName2)
   451  
   452  	td := model.TextDescriptor{
   453  		Text:           sampleText,
   454  		Embed:          true,
   455  		MLeft:          5,
   456  		MRight:         5,
   457  		MTop:           5,
   458  		MBot:           5,
   459  		Scale:          1.,
   460  		ScaleAbs:       true,
   461  		HAlign:         types.AlignJustify,
   462  		RMode:          draw.RMFill,
   463  		StrokeCol:      color.Black,
   464  		FillCol:        color.Black,
   465  		ShowBackground: true,
   466  		BackgroundCol:  color.SimpleColor{R: 1., G: .98, B: .77},
   467  		ShowBorder:     true,
   468  		ShowLineBB:     false,
   469  		ShowTextBB:     true,
   470  		HairCross:      false,
   471  	}
   472  
   473  	td.BackgroundCol = color.White
   474  	td.FillCol = color.Black
   475  	td.FontName, td.FontKey, td.FontSize = fontName, k1, 9
   476  	td.ParIndent = true
   477  	td.VAlign, td.X, td.Y, td.Dx, td.Dy = types.AlignTop, 0, r.Height(), 5, -5
   478  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, 150)
   479  
   480  	td.BackgroundCol = color.Black
   481  	td.FillCol = color.White
   482  	td.FontName, td.FontKey, td.FontSize = fontName2, k2, 12
   483  	td.ParIndent = true
   484  	td.VAlign, td.X, td.Y, td.Dx, td.Dy = types.AlignTop, -1, -1, 0, 0
   485  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, 290)
   486  
   487  	draw.DrawHairCross(p.Buf, 0, 0, mediaBox)
   488  }
   489  
   490  func createTextAlignJustifyDemo(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   491  	p := model.NewPage(mediaBox, nil)
   492  	var region *types.Rectangle
   493  	fontName := "Times-Roman"
   494  	writeTextAlignJustifyDemo(xRefTable, p, region, fontName)
   495  	region = types.RectForWidthAndHeight(0, 0, 200, 200)
   496  	writeTextAlignJustifyDemo(xRefTable, p, region, fontName)
   497  	return p
   498  }
   499  
   500  func createTextAlignJustifyColumnDemo(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   501  	p := model.NewPage(mediaBox, nil)
   502  	var region *types.Rectangle
   503  	writeTextAlignJustifyColumnDemo(xRefTable, p, region)
   504  	region = types.RectForWidthAndHeight(0, 0, 200, 200)
   505  	writeTextAlignJustifyColumnDemo(xRefTable, p, region)
   506  	return p
   507  }
   508  
   509  func writeTextDemoAnchorsWithOffset(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle, dx, dy float64) {
   510  	mediaBox := p.MediaBox
   511  	buf := p.Buf
   512  
   513  	mediaBB := true
   514  
   515  	var cr, cg, cb float32
   516  	cr, cg, cb = .5, .75, 1.
   517  	r := mediaBox
   518  	if region != nil {
   519  		r = region
   520  		cr, cg, cb = .75, .75, 1
   521  	}
   522  	if mediaBB {
   523  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
   524  	}
   525  
   526  	fontName := "Helvetica"
   527  	k := p.Fm.EnsureKey(fontName)
   528  
   529  	td := model.TextDescriptor{
   530  		FontName:       fontName,
   531  		Embed:          true,
   532  		FontKey:        k,
   533  		FontSize:       24,
   534  		MLeft:          10,
   535  		MRight:         10,
   536  		MTop:           10,
   537  		MBot:           10,
   538  		Scale:          1.,
   539  		ScaleAbs:       true,
   540  		RMode:          draw.RMFill,
   541  		StrokeCol:      color.Black,
   542  		FillCol:        color.Black,
   543  		ShowBackground: true,
   544  		BackgroundCol:  color.SimpleColor{R: 1., G: .98, B: .77},
   545  		ShowBorder:     true,
   546  		ShowLineBB:     true,
   547  		ShowTextBB:     true,
   548  		HairCross:      false,
   549  	}
   550  
   551  	td.Dx, td.Dy, td.Text = dx, -dy, "topleft\nandLine2"
   552  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopLeft)
   553  
   554  	td.Dx, td.Dy, td.Text = 0, -dy, "topcenter\nandLine2"
   555  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopCenter)
   556  
   557  	td.Dx, td.Dy, td.Text = -dx, -dy, "topright\nandLine2"
   558  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopRight)
   559  
   560  	td.Dx, td.Dy, td.Text = dx, 0, "left\nandline2"
   561  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Left)
   562  
   563  	td.Dx, td.Dy, td.Text = 0, 0, "center\nandLine2"
   564  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Center)
   565  
   566  	td.Dx, td.Dy, td.Text = -dx, 0, "right\nandLine2"
   567  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Right)
   568  
   569  	td.Dx, td.Dy, td.Text = dx, dy, "botleft\nandLine2"
   570  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomLeft)
   571  
   572  	td.Dx, td.Dy, td.Text = 0, dy, "botcenter\nandLine2"
   573  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomCenter)
   574  
   575  	td.Dx, td.Dy, td.Text = -dx, dy, "botright\nandLine2"
   576  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomRight)
   577  
   578  	draw.DrawHairCross(buf, 0, 0, r)
   579  }
   580  
   581  func writeTextDemoAnchors(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle) {
   582  	writeTextDemoAnchorsWithOffset(xRefTable, p, region, 0, 0)
   583  }
   584  
   585  func createTextDemoAnchors(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   586  	p := model.NewPage(mediaBox, nil)
   587  	var region *types.Rectangle
   588  	writeTextDemoAnchors(xRefTable, p, region)
   589  	region = types.RectForWidthAndHeight(50, 70, 200, 200)
   590  	writeTextDemoAnchors(xRefTable, p, region)
   591  	return p
   592  }
   593  
   594  func createTextDemoAnchorsWithOffset(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   595  	p := model.NewPage(mediaBox, nil)
   596  	dx, dy := 20., 20.
   597  	var region *types.Rectangle
   598  	writeTextDemoAnchorsWithOffset(xRefTable, p, region, dx, dy)
   599  	region = types.RectForWidthAndHeight(50, 70, 200, 200)
   600  	writeTextDemoAnchorsWithOffset(xRefTable, p, region, dx, dy)
   601  	return p
   602  }
   603  
   604  func writeTextDemoColumnAnchoredWithOffset(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle, dx, dy float64) {
   605  	mediaBox := p.MediaBox
   606  	buf := p.Buf
   607  
   608  	mediaBB := true
   609  
   610  	var cr, cg, cb float32
   611  	cr, cg, cb = .5, .75, 1.
   612  	r := mediaBox
   613  	if region != nil {
   614  		r = region
   615  		cr, cg, cb = .75, .75, 1
   616  	}
   617  	if mediaBB {
   618  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
   619  	}
   620  
   621  	wSmall := 100.
   622  	wBig := 300.
   623  
   624  	fontName := "Helvetica"
   625  	k := p.Fm.EnsureKey(fontName)
   626  
   627  	td := model.TextDescriptor{
   628  		Text:           sampleText,
   629  		FontName:       fontName,
   630  		Embed:          true,
   631  		FontKey:        k,
   632  		FontSize:       6,
   633  		MLeft:          5,
   634  		MRight:         5,
   635  		MTop:           5,
   636  		MBot:           5,
   637  		Scale:          1.,
   638  		ScaleAbs:       true,
   639  		RMode:          draw.RMFill,
   640  		StrokeCol:      color.Black,
   641  		FillCol:        color.Black,
   642  		ShowBackground: true,
   643  		BackgroundCol:  color.SimpleColor{R: 1., G: .98, B: .77},
   644  		ShowBorder:     true,
   645  		ShowLineBB:     false,
   646  		ShowTextBB:     true,
   647  		HairCross:      false,
   648  	}
   649  
   650  	td.Dx, td.Dy = dx, -dy
   651  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.TopLeft, wSmall)
   652  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.TopLeft, 0)
   653  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.TopLeft, wBig)
   654  
   655  	td.Dx, td.Dy = 0, -dy
   656  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.TopCenter, wSmall)
   657  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.TopCenter, 0)
   658  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.TopCenter, wBig)
   659  
   660  	td.Dx, td.Dy = -dx, -dy
   661  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.TopRight, wSmall)
   662  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.TopRight, 0)
   663  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.TopRight, wBig)
   664  
   665  	td.Dx, td.Dy = dx, 0
   666  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.Left, wSmall)
   667  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.Left, 0)
   668  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.Left, wBig)
   669  
   670  	td.Dx, td.Dy = 0, 0
   671  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.Center, wSmall)
   672  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.Center, 0)
   673  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.Center, wBig)
   674  
   675  	td.Dx, td.Dy = -dx, 0
   676  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.Right, wSmall)
   677  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.Right, 0)
   678  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.Right, wBig)
   679  
   680  	td.Dx, td.Dy = dx, dy
   681  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.BottomLeft, wSmall)
   682  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.BottomLeft, 0)
   683  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.BottomLeft, wBig)
   684  
   685  	td.Dx, td.Dy = 0, dy
   686  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.BottomCenter, wSmall)
   687  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.BottomCenter, 0)
   688  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.BottomCenter, wBig)
   689  
   690  	td.Dx, td.Dy = -dx, dy
   691  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.BottomRight, wSmall)
   692  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.BottomRight, 0)
   693  	model.WriteColumnAnchored(xRefTable, buf, mediaBox, region, td, types.BottomRight, wBig)
   694  
   695  	draw.DrawHairCross(buf, 0, 0, mediaBox)
   696  }
   697  
   698  func writeTextDemoColumnAnchored(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle) {
   699  	writeTextDemoColumnAnchoredWithOffset(xRefTable, p, region, 0, 0)
   700  }
   701  
   702  func createTextDemoColumnAnchored(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   703  	p := model.NewPage(mediaBox, nil)
   704  	var region *types.Rectangle
   705  	writeTextDemoColumnAnchored(xRefTable, p, region)
   706  	region = types.RectForWidthAndHeight(50, 70, 400, 400)
   707  	writeTextDemoColumnAnchored(xRefTable, p, region)
   708  	return p
   709  }
   710  
   711  func createTextDemoColumnAnchoredWithOffset(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   712  	p := model.NewPage(mediaBox, nil)
   713  	var region *types.Rectangle
   714  	dx, dy := 20., 20.
   715  	writeTextDemoColumnAnchoredWithOffset(xRefTable, p, region, dx, dy)
   716  	region = types.RectForWidthAndHeight(50, 70, 400, 400)
   717  	writeTextDemoColumnAnchoredWithOffset(xRefTable, p, region, dx, dy)
   718  	return p
   719  }
   720  
   721  func writeTextRotateDemoWithOffset(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle, dx, dy float64) {
   722  	mediaBox := p.MediaBox
   723  	buf := p.Buf
   724  
   725  	mediaBB := true
   726  
   727  	var cr, cg, cb float32
   728  	cr, cg, cb = .5, .75, 1.
   729  	r := mediaBox
   730  	if region != nil {
   731  		r = region
   732  		cr, cg, cb = .75, .75, 1
   733  	}
   734  	if mediaBB {
   735  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
   736  		draw.DrawHairCross(buf, 0, 0, r)
   737  	}
   738  
   739  	fillCol := color.Black
   740  
   741  	fontName := "Helvetica"
   742  	k := p.Fm.EnsureKey(fontName)
   743  
   744  	td := model.TextDescriptor{
   745  		Text:           "Hello Gopher!\nLine 2",
   746  		FontName:       fontName,
   747  		Embed:          true,
   748  		FontKey:        k,
   749  		FontSize:       24,
   750  		MLeft:          10,
   751  		MRight:         10,
   752  		MTop:           10,
   753  		MBot:           10,
   754  		Scale:          1.,
   755  		ScaleAbs:       true,
   756  		RMode:          draw.RMFill,
   757  		StrokeCol:      color.Black,
   758  		ShowBackground: true,
   759  		BackgroundCol:  color.SimpleColor{R: 1., G: .98, B: .77},
   760  		ShowBorder:     true,
   761  		ShowLineBB:     false,
   762  		ShowTextBB:     true,
   763  		HairCross:      false,
   764  	}
   765  
   766  	td.Dx, td.Dy = dx, -dy
   767  	td.Rotation, td.FillCol = 0, fillCol
   768  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopLeft)
   769  	td.Rotation, td.FillCol = 45, color.SimpleColor{R: 1}
   770  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopLeft)
   771  	td.Rotation, td.FillCol = 90, color.SimpleColor{R: .5}
   772  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopLeft)
   773  
   774  	td.Dx, td.Dy = 0, -dy
   775  	td.Rotation, td.FillCol = 0, fillCol
   776  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopCenter)
   777  	td.Rotation, td.FillCol = 45, color.SimpleColor{G: 1}
   778  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopCenter)
   779  	td.Rotation, td.FillCol = 90, color.SimpleColor{G: .5}
   780  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopCenter)
   781  
   782  	td.Dx, td.Dy = -dx, -dy
   783  	td.Rotation, td.FillCol = 0, fillCol
   784  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopRight)
   785  	td.Rotation, td.FillCol = 45, color.SimpleColor{B: 1}
   786  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopRight)
   787  	td.Rotation, td.FillCol = 90, color.SimpleColor{B: .5}
   788  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopRight)
   789  
   790  	td.Dx, td.Dy = dx, 0
   791  	td.Rotation, td.FillCol = 0, fillCol
   792  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Left)
   793  	td.Rotation, td.FillCol = 45, color.SimpleColor{R: 1}
   794  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Left)
   795  	td.Rotation, td.FillCol = 90, color.SimpleColor{R: .5}
   796  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Left)
   797  
   798  	td.Dx, td.Dy = 0, 0
   799  	td.Rotation, td.FillCol = 0, fillCol
   800  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Center)
   801  	td.Rotation, td.FillCol = 45, color.SimpleColor{G: 1}
   802  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Center)
   803  	td.Rotation, td.FillCol = 90, color.SimpleColor{G: .5}
   804  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Center)
   805  
   806  	td.Dx, td.Dy = -dx, 0
   807  	td.Rotation, td.FillCol = 0, fillCol
   808  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Right)
   809  	td.Rotation, td.FillCol = 45, color.SimpleColor{B: 1}
   810  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Right)
   811  	td.Rotation, td.FillCol = 90, color.SimpleColor{B: .5}
   812  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Right)
   813  
   814  	td.Dx, td.Dy = dx, dy
   815  	td.Rotation, td.FillCol = 0, fillCol
   816  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomLeft)
   817  	td.Rotation, td.FillCol = 45, color.SimpleColor{R: 1}
   818  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomLeft)
   819  	td.Rotation, td.FillCol = 90, color.SimpleColor{R: .5}
   820  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomLeft)
   821  
   822  	td.Dx, td.Dy = 0, dy
   823  	td.Rotation, td.FillCol = 0, fillCol
   824  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomCenter)
   825  	td.Rotation, td.FillCol = 45, color.SimpleColor{G: 1}
   826  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomCenter)
   827  	td.Rotation, td.FillCol = 90, color.SimpleColor{G: .5}
   828  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomCenter)
   829  
   830  	td.Dx, td.Dy = -dx, dy
   831  	td.Rotation, td.FillCol = 0, fillCol
   832  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomRight)
   833  	td.Rotation, td.FillCol = 45, color.SimpleColor{B: 1}
   834  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomRight)
   835  	td.Rotation, td.FillCol = 90, color.SimpleColor{B: .5}
   836  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomRight)
   837  }
   838  
   839  func writeTextRotateDemo(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle) {
   840  	writeTextRotateDemoWithOffset(xRefTable, p, region, 0, 0)
   841  }
   842  
   843  func createTextRotateDemo(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   844  	p := model.NewPage(mediaBox, nil)
   845  	var region *types.Rectangle
   846  	writeTextRotateDemo(xRefTable, p, region)
   847  	region = types.RectForWidthAndHeight(150, 150, 300, 300)
   848  	writeTextRotateDemo(xRefTable, p, region)
   849  	return p
   850  }
   851  
   852  func createTextRotateDemoWithOffset(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
   853  	p := model.NewPage(mediaBox, nil)
   854  	var region *types.Rectangle
   855  	dx, dy := 20., 20.
   856  	writeTextRotateDemoWithOffset(xRefTable, p, region, dx, dy)
   857  	region = types.RectForWidthAndHeight(150, 150, 300, 300)
   858  	writeTextRotateDemoWithOffset(xRefTable, p, region, dx, dy)
   859  	return p
   860  }
   861  
   862  func writeTextScaleAbsoluteDemoWithOffset(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle, dx, dy float64) {
   863  	mediaBox := p.MediaBox
   864  	buf := p.Buf
   865  
   866  	mediaBB := true
   867  
   868  	var cr, cg, cb float32
   869  	cr, cg, cb = .5, .75, 1.
   870  	r := mediaBox
   871  	if region != nil {
   872  		r = region
   873  		cr, cg, cb = .75, .75, 1
   874  	}
   875  	if mediaBB {
   876  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
   877  	}
   878  
   879  	fillCol := color.Black
   880  	bgCol := color.SimpleColor{R: 1., G: .98, B: .77}
   881  
   882  	fontName := "Helvetica"
   883  	k := p.Fm.EnsureKey(fontName)
   884  
   885  	td := model.TextDescriptor{
   886  		Text:           sampleText,
   887  		FontName:       fontName,
   888  		Embed:          true,
   889  		FontKey:        k,
   890  		FontSize:       18,
   891  		MLeft:          5,
   892  		MRight:         5,
   893  		MTop:           5,
   894  		MBot:           5,
   895  		ScaleAbs:       true,
   896  		RMode:          draw.RMFill,
   897  		StrokeCol:      color.Black,
   898  		ShowBackground: true,
   899  		BackgroundCol:  bgCol,
   900  		ShowBorder:     true,
   901  		ShowLineBB:     false,
   902  		ShowTextBB:     true,
   903  		HairCross:      false,
   904  	}
   905  
   906  	td.HAlign, td.VAlign, td.X, td.Y, td.FontSize = types.AlignJustify, types.AlignMiddle, -1, r.Height()*.72, 9
   907  	td.Scale, td.FillCol = 1, fillCol
   908  	model.WriteMultiLine(xRefTable, buf, mediaBox, region, td)
   909  	td.Scale, td.FillCol = 1.5, color.SimpleColor{R: 1}
   910  	model.WriteMultiLine(xRefTable, buf, mediaBox, region, td)
   911  	td.Scale, td.FillCol = 2, color.SimpleColor{R: .5}
   912  	model.WriteMultiLine(xRefTable, buf, mediaBox, region, td)
   913  
   914  	width := 130.
   915  
   916  	td.HAlign, td.VAlign, td.X = types.AlignJustify, types.AlignMiddle, r.Width()*.75
   917  	td.FillCol, td.Text = fillCol, "Justified column\nWidth=130"
   918  
   919  	td.FontSize, td.Y = 24, r.Height()*.35
   920  	td.Scale = 1
   921  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, width)
   922  	td.Scale = 1.5
   923  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, width)
   924  
   925  	td.FontSize, td.Y = 12, r.Height()*.22
   926  	td.Scale = 1
   927  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, width)
   928  	td.Scale = 1.5
   929  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, width)
   930  
   931  	td.FontSize = 9
   932  	td.Scale, td.Y = 1, r.Height()*.15
   933  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, width)
   934  	td.Scale, td.Y = 1.5, r.Height()*.13
   935  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, width)
   936  
   937  	td = model.TextDescriptor{
   938  		FontName:       fontName,
   939  		Embed:          true,
   940  		FontKey:        k,
   941  		FontSize:       12,
   942  		MLeft:          5,
   943  		MRight:         5,
   944  		MTop:           5,
   945  		MBot:           5,
   946  		ScaleAbs:       true,
   947  		RMode:          draw.RMFill,
   948  		StrokeCol:      color.Black,
   949  		ShowBackground: true,
   950  		BackgroundCol:  bgCol,
   951  		ShowBorder:     true,
   952  		ShowLineBB:     false,
   953  		ShowTextBB:     true,
   954  		HairCross:      false,
   955  	}
   956  
   957  	text15 := "Hello Gopher!\nAbsolute Width=1.5"
   958  	text1 := "Hello Gopher!\nAbsolute Width=1"
   959  	text5 := "Hello Gopher!\nAbsolute Width=.5"
   960  
   961  	td.Dx, td.Dy = dx, -dy
   962  	td.Scale, td.FillCol, td.Text = 1.5, fillCol, text15
   963  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopLeft)
   964  	td.Scale, td.FillCol, td.Text = 1, color.SimpleColor{R: 1}, text1
   965  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopLeft)
   966  	td.Scale, td.FillCol, td.Text = .5, color.SimpleColor{R: .5}, text5
   967  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopLeft)
   968  
   969  	td.Dx, td.Dy = 0, -dy
   970  	td.Scale, td.FillCol, td.Text = 1.5, fillCol, text15
   971  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopCenter)
   972  	td.Scale, td.FillCol, td.Text = 1, color.SimpleColor{G: 1}, text1
   973  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopCenter)
   974  	td.Scale, td.FillCol, td.Text = .5, color.SimpleColor{G: .5}, text5
   975  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopCenter)
   976  
   977  	td.Dx, td.Dy = -dx, -dy
   978  	td.Scale, td.FillCol, td.Text = 1.5, fillCol, text15
   979  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopRight)
   980  	td.Scale, td.FillCol, td.Text = 1, color.SimpleColor{B: 1}, text1
   981  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopRight)
   982  	td.Scale, td.FillCol, td.Text = .5, color.SimpleColor{B: .5}, text5
   983  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.TopRight)
   984  
   985  	td.Dx, td.Dy = dx, 0
   986  	td.Scale, td.FillCol, td.Text = 1.5, fillCol, text15
   987  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Left)
   988  	td.Scale, td.FillCol, td.Text = 1, color.SimpleColor{R: 1}, text1
   989  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Left)
   990  	td.Scale, td.FillCol = .5, color.SimpleColor{R: .5}
   991  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Left)
   992  
   993  	td.Dx, td.Dy = 0, 0
   994  	td.Scale, td.FillCol, td.Text = 1.5, fillCol, text15
   995  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Center)
   996  	td.Scale, td.FillCol, td.Text = 1, color.SimpleColor{G: 1}, text1
   997  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Center)
   998  	td.Scale, td.FillCol, td.Text = .5, color.SimpleColor{G: .5}, text5
   999  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Center)
  1000  
  1001  	td.Dx, td.Dy = -dx, 0
  1002  	td.Scale, td.FillCol, td.Text = 1.5, fillCol, text15
  1003  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Right)
  1004  	td.Scale, td.FillCol, td.Text = 1, color.SimpleColor{B: 1}, text1
  1005  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Right)
  1006  	td.Scale, td.FillCol, td.Text = .5, color.SimpleColor{B: .5}, text5
  1007  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.Right)
  1008  
  1009  	td.Dx, td.Dy = dx, dy
  1010  	td.Scale, td.FillCol, td.Text = 1.5, fillCol, text15
  1011  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomLeft)
  1012  	td.Scale, td.FillCol, td.Text = 1, color.SimpleColor{R: 1}, text1
  1013  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomLeft)
  1014  	td.Scale, td.FillCol = .5, color.SimpleColor{R: .5}
  1015  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomLeft)
  1016  
  1017  	td.Dx, td.Dy = 0, dy
  1018  	td.Scale, td.FillCol, td.Text = 1.5, fillCol, text15
  1019  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomCenter)
  1020  	td.Scale, td.FillCol, td.Text = 1, color.SimpleColor{G: 1}, text1
  1021  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomCenter)
  1022  	td.Scale, td.FillCol, td.Text = .5, color.SimpleColor{G: .5}, text5
  1023  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomCenter)
  1024  
  1025  	td.Dx, td.Dy = -dx, +dy
  1026  	td.Scale, td.FillCol, td.Text = 1.5, fillCol, text15
  1027  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomRight)
  1028  	td.Scale, td.FillCol, td.Text = 1, color.SimpleColor{B: 1}, text1
  1029  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomRight)
  1030  	td.Scale, td.FillCol, td.Text = .5, color.SimpleColor{B: .5}, text5
  1031  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, r, td, types.BottomRight)
  1032  
  1033  	draw.DrawHairCross(buf, 0, 0, r)
  1034  }
  1035  
  1036  func writeTextScaleAbsoluteDemo(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle) {
  1037  	writeTextScaleAbsoluteDemoWithOffset(xRefTable, p, region, 0, 0)
  1038  }
  1039  
  1040  func createTextScaleAbsoluteDemo(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1041  	p := model.NewPage(mediaBox, nil)
  1042  	var region *types.Rectangle
  1043  	writeTextScaleAbsoluteDemo(xRefTable, p, region)
  1044  	region = types.RectForWidthAndHeight(20, 70, 180, 180)
  1045  	writeTextScaleAbsoluteDemo(xRefTable, p, region)
  1046  	return p
  1047  }
  1048  
  1049  func createTextScaleAbsoluteDemoWithOffset(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1050  	p := model.NewPage(mediaBox, nil)
  1051  	dx, dy := 20., 20.
  1052  	var region *types.Rectangle
  1053  	writeTextScaleAbsoluteDemoWithOffset(xRefTable, p, region, dx, dy)
  1054  	region = types.RectForWidthAndHeight(20, 70, 180, 180)
  1055  	writeTextScaleAbsoluteDemoWithOffset(xRefTable, p, region, dx, dy)
  1056  	return p
  1057  }
  1058  
  1059  func writeTextScaleRelativeDemoWithOffset(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle, dx, dy float64) {
  1060  	mediaBox := p.MediaBox
  1061  	buf := p.Buf
  1062  
  1063  	mediaBB := true
  1064  
  1065  	var cr, cg, cb float32
  1066  	cr, cg, cb = .5, .75, 1.
  1067  	r := mediaBox
  1068  	if region != nil {
  1069  		r = region
  1070  		cr, cg, cb = .75, .75, 1
  1071  	}
  1072  	if mediaBB {
  1073  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
  1074  	}
  1075  
  1076  	fillCol := color.Black
  1077  	bgCol := color.SimpleColor{R: 1., G: .98, B: .77}
  1078  
  1079  	fontName := "Helvetica"
  1080  	k := p.Fm.EnsureKey(fontName)
  1081  
  1082  	td := model.TextDescriptor{
  1083  		Text:           sampleText,
  1084  		FontName:       fontName,
  1085  		Embed:          true,
  1086  		FontKey:        k,
  1087  		FontSize:       18,
  1088  		MLeft:          5,
  1089  		MRight:         5,
  1090  		MTop:           5,
  1091  		MBot:           5,
  1092  		HAlign:         types.AlignJustify,
  1093  		VAlign:         types.AlignMiddle,
  1094  		X:              -1,
  1095  		Y:              r.Height() * .73,
  1096  		ScaleAbs:       false,
  1097  		RMode:          draw.RMFill,
  1098  		StrokeCol:      color.Black,
  1099  		ShowBackground: true,
  1100  		BackgroundCol:  bgCol,
  1101  		ShowBorder:     true,
  1102  		ShowLineBB:     false,
  1103  		ShowTextBB:     true,
  1104  		HairCross:      false,
  1105  	}
  1106  
  1107  	td.FontSize, td.Scale, td.FillCol = 9, .4, fillCol
  1108  	model.WriteMultiLine(xRefTable, buf, mediaBox, region, td)
  1109  	td.FontSize, td.Scale, td.FillCol = 9, .6, color.SimpleColor{R: 1}
  1110  	model.WriteMultiLine(xRefTable, buf, mediaBox, region, td)
  1111  	td.FontSize, td.Scale, td.FillCol = 9, .8, color.SimpleColor{R: .5}
  1112  	model.WriteMultiLine(xRefTable, buf, mediaBox, region, td)
  1113  
  1114  	width := 130.
  1115  
  1116  	td = model.TextDescriptor{
  1117  		Text:           "Justified column\nWidth=130",
  1118  		FontName:       fontName,
  1119  		Embed:          true,
  1120  		FontKey:        k,
  1121  		FontSize:       18,
  1122  		MLeft:          5,
  1123  		MRight:         5,
  1124  		MTop:           5,
  1125  		MBot:           5,
  1126  		HAlign:         types.AlignJustify,
  1127  		VAlign:         types.AlignMiddle,
  1128  		X:              r.Width() * .75,
  1129  		Y:              r.Height() * .25,
  1130  		ScaleAbs:       false,
  1131  		RMode:          draw.RMFill,
  1132  		StrokeCol:      color.Black,
  1133  		ShowBackground: true,
  1134  		BackgroundCol:  bgCol,
  1135  		ShowBorder:     true,
  1136  		ShowLineBB:     false,
  1137  		ShowTextBB:     true,
  1138  		HairCross:      false,
  1139  	}
  1140  	td.Scale, td.FillCol = .5, fillCol
  1141  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, width)
  1142  	td.Scale, td.FillCol = .3, color.SimpleColor{G: 1}
  1143  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, width)
  1144  	td.Scale, td.FillCol = .20, color.SimpleColor{G: .5}
  1145  	model.WriteColumn(xRefTable, buf, mediaBox, region, td, width)
  1146  
  1147  	td = model.TextDescriptor{
  1148  		FontName:       fontName,
  1149  		Embed:          true,
  1150  		FontKey:        k,
  1151  		FontSize:       18,
  1152  		MLeft:          5,
  1153  		MRight:         5,
  1154  		MTop:           5,
  1155  		MBot:           5,
  1156  		HAlign:         types.AlignJustify,
  1157  		VAlign:         types.AlignMiddle,
  1158  		X:              r.Width() * .75,
  1159  		Y:              r.Height() * .25,
  1160  		ScaleAbs:       false,
  1161  		RMode:          draw.RMFill,
  1162  		StrokeCol:      color.Black,
  1163  		ShowBackground: true,
  1164  		BackgroundCol:  bgCol,
  1165  		ShowBorder:     true,
  1166  		ShowLineBB:     false,
  1167  		ShowTextBB:     true,
  1168  		HairCross:      false,
  1169  	}
  1170  
  1171  	text10 := "Hello Gopher!\nRelative Width=10%"
  1172  	text20 := "Hello Gopher!\nRelative Width=20%"
  1173  	text30 := "Hello Gopher!\nRelative Width=30%"
  1174  
  1175  	td.Dx, td.Dy = dx, -dy
  1176  	td.Scale, td.FillCol, td.Text = .3, fillCol, text30
  1177  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopLeft)
  1178  	td.Scale, td.FillCol, td.Text = .2, color.SimpleColor{R: 1}, text20
  1179  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopLeft)
  1180  	td.Scale, td.FillCol, td.Text = .1, color.SimpleColor{R: .5}, text10
  1181  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopLeft)
  1182  
  1183  	td.Dx, td.Dy = 0, -dy
  1184  	td.Scale, td.FillCol, td.Text = .3, fillCol, text30
  1185  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopCenter)
  1186  	td.Scale, td.FillCol, td.Text = .2, color.SimpleColor{G: 1}, text20
  1187  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopCenter)
  1188  	td.Scale, td.FillCol, td.Text = .1, color.SimpleColor{G: .5}, text10
  1189  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopCenter)
  1190  
  1191  	td.Dx, td.Dy = -dx, -dy
  1192  	td.Scale, td.FillCol, td.Text = .3, fillCol, text30
  1193  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopRight)
  1194  	td.Scale, td.FillCol, td.Text = .2, color.SimpleColor{B: 1}, text20
  1195  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopRight)
  1196  	td.Scale, td.FillCol, td.Text = .1, color.SimpleColor{B: .5}, text10
  1197  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.TopRight)
  1198  
  1199  	td.Dx, td.Dy = dx, 0
  1200  	td.Scale, td.FillCol, td.Text = .3, fillCol, text30
  1201  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Left)
  1202  	td.Scale, td.FillCol, td.Text = .2, color.SimpleColor{R: 1}, text20
  1203  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Left)
  1204  	td.Scale, td.FillCol, td.Text = .1, color.SimpleColor{R: .5}, text10
  1205  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Left)
  1206  
  1207  	td.Dx, td.Dy = 0, 0
  1208  	td.Scale, td.FillCol, td.Text = .3, fillCol, text30
  1209  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Center)
  1210  	td.Scale, td.FillCol, td.Text = .2, color.SimpleColor{G: 1}, text20
  1211  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Center)
  1212  	td.Scale, td.FillCol, td.Text = .1, color.SimpleColor{G: .5}, text10
  1213  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Center)
  1214  
  1215  	td.Dx, td.Dy = -dx, 0
  1216  	td.Scale, td.FillCol, td.Text = .3, fillCol, text30
  1217  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Right)
  1218  	td.Scale, td.FillCol, td.Text = .2, color.SimpleColor{B: 1}, text20
  1219  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Right)
  1220  	td.Scale, td.FillCol, td.Text = .1, color.SimpleColor{B: .5}, text10
  1221  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.Right)
  1222  
  1223  	td.Dx, td.Dy = dx, dy
  1224  	td.Scale, td.FillCol, td.Text = .3, fillCol, text30
  1225  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomLeft)
  1226  	td.Scale, td.FillCol, td.Text = .2, color.SimpleColor{R: 1}, text20
  1227  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomLeft)
  1228  	td.Scale, td.FillCol, td.Text = .1, color.SimpleColor{R: .5}, text10
  1229  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomLeft)
  1230  
  1231  	td.Dx, td.Dy = 0, dy
  1232  	td.Scale, td.FillCol, td.Text = .3, fillCol, text30
  1233  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomCenter)
  1234  	td.Scale, td.FillCol, td.Text = .2, color.SimpleColor{G: 1}, text20
  1235  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomCenter)
  1236  	td.Scale, td.FillCol, td.Text = .1, color.SimpleColor{G: .5}, text10
  1237  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomCenter)
  1238  
  1239  	td.Dx, td.Dy = -dx, dy
  1240  	td.Scale, td.FillCol, td.Text = .3, fillCol, text30
  1241  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomRight)
  1242  	td.Scale, td.FillCol, td.Text = .2, color.SimpleColor{B: 1}, text20
  1243  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomRight)
  1244  	td.Scale, td.FillCol, td.Text = .1, color.SimpleColor{B: .5}, text10
  1245  	model.WriteMultiLineAnchored(xRefTable, buf, mediaBox, region, td, types.BottomRight)
  1246  
  1247  	draw.DrawHairCross(buf, 0, 0, r)
  1248  }
  1249  
  1250  func writeTextScaleRelativeDemo(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle) {
  1251  	writeTextScaleRelativeDemoWithOffset(xRefTable, p, region, 0, 0)
  1252  }
  1253  
  1254  func createTextScaleRelativeDemo(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1255  	p := model.NewPage(mediaBox, nil)
  1256  	var region *types.Rectangle
  1257  	writeTextScaleRelativeDemo(xRefTable, p, region)
  1258  	region = types.RectForWidthAndHeight(50, 70, 200, 200)
  1259  	writeTextScaleRelativeDemo(xRefTable, p, region)
  1260  	return p
  1261  }
  1262  
  1263  func createTextScaleRelativeDemoWithOffset(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1264  	p := model.NewPage(mediaBox, nil)
  1265  	var region *types.Rectangle
  1266  	dx, dy := 20., 20.
  1267  	writeTextScaleRelativeDemoWithOffset(xRefTable, p, region, dx, dy)
  1268  	region = types.RectForWidthAndHeight(50, 70, 200, 200)
  1269  	writeTextScaleRelativeDemoWithOffset(xRefTable, p, region, dx, dy)
  1270  	return p
  1271  }
  1272  
  1273  func createTextDemoColumns(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1274  	p := model.NewPageWithBg(mediaBox, color.NewSimpleColor(0xbeded9))
  1275  	fontName := "Times-Roman"
  1276  	k := p.Fm.EnsureKey(fontName)
  1277  	td := model.TextDescriptor{
  1278  		FontName:       fontName,
  1279  		Embed:          true,
  1280  		FontKey:        k,
  1281  		FontSize:       9,
  1282  		MLeft:          10,
  1283  		MRight:         10,
  1284  		MTop:           10,
  1285  		MBot:           10,
  1286  		Scale:          1.,
  1287  		ScaleAbs:       true,
  1288  		RMode:          draw.RMFill,
  1289  		StrokeCol:      color.Black,
  1290  		ShowBackground: true,
  1291  		BorderWidth:    3,
  1292  	}
  1293  
  1294  	// 1st row: 3 side by side columns using anchors, width and a background color.
  1295  
  1296  	width := mediaBox.Width() / 3
  1297  	td.MinHeight = mediaBox.Height() / 2
  1298  
  1299  	// Render left column.
  1300  	// Draw the bounding box with rounded corners but no borders.
  1301  	td.Text = sampleText
  1302  	td.ShowTextBB, td.ShowBorder = true, false
  1303  	td.BackgroundCol = color.SimpleColor{R: .4, G: .98, B: .77}
  1304  	td.BorderStyle = types.LJRound
  1305  	model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, nil, td, types.TopLeft, width)
  1306  
  1307  	// Render middle column.
  1308  	// Draw the bounding box with regular corners but no border.
  1309  	td.Text = sampleText2
  1310  	td.Dx = -width / 2
  1311  	td.ShowTextBB, td.ShowBorder = true, false
  1312  	td.BackgroundCol = color.SimpleColor{R: .6, G: .98, B: .77}
  1313  	td.BorderStyle = types.LJMiter
  1314  	model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, nil, td, types.TopCenter, width)
  1315  
  1316  	// Render right column.
  1317  	// Draw bounding box and a border with rounded corners.
  1318  
  1319  	td.Text = sampleText3
  1320  	td.Dx = 0
  1321  	td.ShowTextBB, td.ShowBorder = true, true
  1322  	td.BackgroundCol = color.SimpleColor{R: 1., G: .98, B: .77}
  1323  	td.BorderCol = color.SimpleColor{R: .2, G: .5, B: .2}
  1324  	td.BorderStyle = types.LJRound
  1325  	model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, nil, td, types.TopRight, width)
  1326  
  1327  	// 2nd row: 3 side by side columns below using relative scaling,
  1328  	// Indent paragraph beginnings and don't draw the background.
  1329  	relScaleFactor := .334
  1330  	td.Dy = mediaBox.Height() / 2
  1331  	td.Scale = relScaleFactor
  1332  	td.ScaleAbs = false
  1333  	td.ParIndent = true
  1334  	td.ShowBackground, td.ShowBorder = false, true
  1335  	td.HAlign, td.VAlign = types.AlignJustify, types.AlignTop
  1336  
  1337  	// Render left column.
  1338  	td.Text = sampleText
  1339  	td.X = 0
  1340  	td.ShowTextBB = true
  1341  	td.BorderStyle = types.LJBevel
  1342  	model.WriteMultiLine(xRefTable, p.Buf, mediaBox, nil, td)
  1343  
  1344  	// Render middle column.
  1345  	td.Text = sampleText2
  1346  	td.X = mediaBox.Width() / 2
  1347  	td.Dx = -width / 2
  1348  	td.ShowTextBB = false
  1349  	model.WriteMultiLine(xRefTable, p.Buf, mediaBox, nil, td)
  1350  
  1351  	// Render right column.
  1352  	td.Text = sampleText3
  1353  	td.X = mediaBox.Width()
  1354  	td.Dx = 0
  1355  	td.ShowTextBB = true
  1356  	td.BorderStyle = types.LJMiter
  1357  	model.WriteMultiLine(xRefTable, p.Buf, mediaBox, nil, td)
  1358  
  1359  	draw.DrawHairCross(p.Buf, 0, 0, mediaBox)
  1360  
  1361  	return p
  1362  }
  1363  
  1364  func writeTextBorderTest(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle) model.Page {
  1365  	mediaBox := p.MediaBox
  1366  	buf := p.Buf
  1367  
  1368  	mediaBB := true
  1369  
  1370  	var cr, cg, cb float32
  1371  	cr, cg, cb = .5, .75, 1.
  1372  	r := mediaBox
  1373  	if region != nil {
  1374  		r = region
  1375  		cr, cg, cb = .75, .75, 1
  1376  	}
  1377  	if mediaBB {
  1378  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
  1379  	}
  1380  
  1381  	fontName := "Times-Roman"
  1382  	k := p.Fm.EnsureKey(fontName)
  1383  	td := model.TextDescriptor{
  1384  		FontName:   fontName,
  1385  		Embed:      true,
  1386  		FontKey:    k,
  1387  		FontSize:   7,
  1388  		MLeft:      10,
  1389  		MRight:     10,
  1390  		MTop:       10,
  1391  		MBot:       10,
  1392  		Scale:      1.,
  1393  		ScaleAbs:   true,
  1394  		RMode:      draw.RMFill,
  1395  		BorderCol:  color.NewSimpleColor(0xabe003),
  1396  		ShowTextBB: true,
  1397  	}
  1398  
  1399  	w := mediaBox.Width() / 2
  1400  
  1401  	// no background, no margin, no border
  1402  	td.Text = sampleText2
  1403  	td.ShowBackground, td.ShowBorder, td.ShowMargins = false, false, false
  1404  	td.MBot, td.MTop, td.MLeft, td.MRight = 0, 0, 0, 0
  1405  	td.BorderWidth = 0
  1406  	td.BackgroundCol = color.SimpleColor{R: .6, G: .98, B: .77}
  1407  	td.BorderStyle = types.LJMiter
  1408  	model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, region, td, types.TopLeft, w)
  1409  
  1410  	// with background, no margin, no border
  1411  	td.Text = sampleText2
  1412  	td.ShowBackground, td.ShowBorder, td.ShowMargins = true, false, false
  1413  	td.MBot, td.MTop, td.MLeft, td.MRight = 0, 0, 0, 0
  1414  	td.BorderWidth = 0
  1415  	td.BackgroundCol = color.SimpleColor{R: .6, G: .98, B: .77}
  1416  	model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, region, td, types.TopCenter, w)
  1417  
  1418  	// with background, with margins, no border
  1419  	td.Text = sampleText2
  1420  	td.ShowBackground, td.ShowBorder, td.ShowMargins = true, false, false
  1421  	td.MBot, td.MTop, td.MLeft, td.MRight = 10, 10, 10, 10
  1422  	td.BackgroundCol = color.SimpleColor{R: .6, G: .98, B: .77}
  1423  	td.Dy = 100
  1424  	model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, region, td, types.Left, w)
  1425  
  1426  	// with background, with margins, show margins, no border
  1427  	td.Text = sampleText2
  1428  	td.ShowBackground, td.ShowBorder, td.ShowMargins = true, false, true
  1429  	td.MBot, td.MTop, td.MLeft, td.MRight = 10, 10, 10, 10
  1430  	td.BackgroundCol = color.SimpleColor{R: .6, G: .98, B: .77}
  1431  	td.BorderStyle = types.LJMiter
  1432  	td.Dy = 100
  1433  	bb := model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, region, td, types.Center, w)
  1434  
  1435  	// with background, no margin, with border, without border background
  1436  	td.Text = sampleText2
  1437  	td.ShowBackground, td.ShowBorder, td.ShowMargins = true, false, false
  1438  	td.BorderWidth = 5
  1439  	td.MBot, td.MTop, td.MLeft, td.MRight = 0, 0, 0, 0
  1440  	td.BackgroundCol = color.SimpleColor{R: .6, G: .98, B: .77}
  1441  	td.BorderStyle = types.LJRound
  1442  	td.Dy = -bb.Height() / 2
  1443  	model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, region, td, types.Left, w)
  1444  
  1445  	// with background, no margin, with border, with border background
  1446  	td.Text = sampleText2
  1447  	td.ShowBackground, td.ShowBorder, td.ShowMargins = true, true, false
  1448  	td.BorderWidth = 5
  1449  	td.MBot, td.MTop, td.MLeft, td.MRight = 0, 0, 0, 0
  1450  	td.BackgroundCol = color.SimpleColor{R: .6, G: .98, B: .77}
  1451  	td.BorderStyle = types.LJRound
  1452  	td.Dy = -bb.Height() / 2
  1453  	model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, region, td, types.Center, w)
  1454  
  1455  	// with background, with margins, with border, with border background
  1456  	td.Text = sampleText2
  1457  	td.ShowBackground, td.ShowBorder, td.ShowMargins = true, true, false
  1458  	td.BorderWidth = 5
  1459  	td.MBot, td.MTop, td.MLeft, td.MRight = 10, 10, 10, 10
  1460  	td.BackgroundCol = color.SimpleColor{R: .6, G: .98, B: .77}
  1461  	td.BorderStyle = types.LJRound
  1462  	td.Dy = 0
  1463  	model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, region, td, types.BottomLeft, w)
  1464  
  1465  	// with background, with margins, show margins, with border, with border background
  1466  	td.Text = sampleText2
  1467  	td.ShowBackground, td.ShowBorder, td.ShowMargins = true, true, true
  1468  	td.BorderWidth = 5
  1469  	td.MBot, td.MTop, td.MLeft, td.MRight = 10, 10, 10, 10
  1470  	td.BackgroundCol = color.SimpleColor{R: .6, G: .98, B: .77}
  1471  	td.BorderStyle = types.LJRound
  1472  	td.Dy = 0
  1473  	model.WriteColumnAnchored(xRefTable, p.Buf, mediaBox, region, td, types.BottomCenter, w)
  1474  
  1475  	draw.DrawHairCross(p.Buf, 0, 0, r)
  1476  
  1477  	return p
  1478  }
  1479  
  1480  func createTextBorderTest(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1481  	p := model.NewPageWithBg(mediaBox, color.NewSimpleColor(0xbeded9))
  1482  	var region *types.Rectangle
  1483  	writeTextBorderTest(xRefTable, p, region)
  1484  	region = types.RectForWidthAndHeight(70, 200, 200, 200)
  1485  	writeTextBorderTest(xRefTable, p, region)
  1486  	return p
  1487  }
  1488  
  1489  func createTextBorderNoMarginAlignLeftTest(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1490  	p := model.NewPageWithBg(mediaBox, color.NewSimpleColor(0xbeded9))
  1491  	fontName := "Times-Roman"
  1492  	k := p.Fm.EnsureKey(fontName)
  1493  	td := model.TextDescriptor{
  1494  		Text:           sampleText2,
  1495  		FontName:       fontName,
  1496  		Embed:          true,
  1497  		FontKey:        k,
  1498  		FontSize:       12,
  1499  		Scale:          1.,
  1500  		ScaleAbs:       true,
  1501  		RMode:          draw.RMFill,
  1502  		ShowBackground: true,
  1503  		BackgroundCol:  color.SimpleColor{R: .6, G: .98, B: .77},
  1504  		ShowBorder:     true,
  1505  		BorderWidth:    10,
  1506  		ShowMargins:    true,
  1507  		MLeft:          10,
  1508  		MRight:         10,
  1509  		MTop:           10,
  1510  		MBot:           10,
  1511  		BorderCol:      color.NewSimpleColor(0xabe003),
  1512  		ShowTextBB:     true,
  1513  	}
  1514  
  1515  	td.X, td.Y, td.HAlign, td.VAlign = 100, 450, types.AlignLeft, types.AlignTop
  1516  	td.MinHeight = 300
  1517  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 400)
  1518  
  1519  	draw.SetLineWidth(p.Buf, 0)
  1520  	draw.SetStrokeColor(p.Buf, color.Black)
  1521  	draw.DrawLineSimple(p.Buf, 100, 0, 100, 600)
  1522  	draw.DrawLineSimple(p.Buf, 500, 0, 500, 600)
  1523  	draw.DrawLineSimple(p.Buf, 110, 0, 110, 600)
  1524  	draw.DrawLineSimple(p.Buf, 490, 0, 490, 600)
  1525  	draw.DrawLineSimple(p.Buf, 0, 150, 600, 150)
  1526  	draw.DrawLineSimple(p.Buf, 0, 450, 600, 450)
  1527  	draw.DrawLineSimple(p.Buf, 0, 160, 600, 160)
  1528  	draw.DrawLineSimple(p.Buf, 0, 440, 600, 440)
  1529  	//pdf.DrawHairCross(p.Buf, 0, 0, mediaBox)
  1530  	return p
  1531  }
  1532  
  1533  func createTextBorderNoMarginAlignRightTest(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1534  	p := model.NewPageWithBg(mediaBox, color.NewSimpleColor(0xbeded9))
  1535  	fontName := "Times-Roman"
  1536  	k := p.Fm.EnsureKey(fontName)
  1537  	td := model.TextDescriptor{
  1538  		Text:           sampleText2,
  1539  		FontName:       fontName,
  1540  		Embed:          true,
  1541  		FontKey:        k,
  1542  		FontSize:       12,
  1543  		Scale:          1.,
  1544  		ScaleAbs:       true,
  1545  		RMode:          draw.RMFill,
  1546  		ShowBackground: true,
  1547  		BackgroundCol:  color.SimpleColor{R: .6, G: .98, B: .77},
  1548  		ShowBorder:     true,
  1549  		BorderWidth:    10,
  1550  		ShowMargins:    true,
  1551  		MLeft:          10,
  1552  		MRight:         10,
  1553  		MTop:           10,
  1554  		MBot:           10,
  1555  		BorderCol:      color.NewSimpleColor(0xabe003),
  1556  		ShowTextBB:     true,
  1557  	}
  1558  
  1559  	td.X, td.Y, td.HAlign, td.VAlign = 500, 450, types.AlignRight, types.AlignTop
  1560  	td.MinHeight = 300
  1561  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 400)
  1562  
  1563  	draw.SetLineWidth(p.Buf, 0)
  1564  	draw.SetStrokeColor(p.Buf, color.Black)
  1565  	draw.DrawLineSimple(p.Buf, 100, 0, 100, 600)
  1566  	draw.DrawLineSimple(p.Buf, 500, 0, 500, 600)
  1567  	draw.DrawLineSimple(p.Buf, 110, 0, 110, 600)
  1568  	draw.DrawLineSimple(p.Buf, 490, 0, 490, 600)
  1569  	draw.DrawLineSimple(p.Buf, 0, 150, 600, 150)
  1570  	draw.DrawLineSimple(p.Buf, 0, 450, 600, 450)
  1571  	draw.DrawLineSimple(p.Buf, 0, 160, 600, 160)
  1572  	draw.DrawLineSimple(p.Buf, 0, 440, 600, 440)
  1573  	//pdf.DrawHairCross(p.Buf, 0, 0, mediaBox)
  1574  	return p
  1575  }
  1576  
  1577  func createTextBorderNoMarginAlignCenterTest(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1578  	p := model.NewPageWithBg(mediaBox, color.NewSimpleColor(0xbeded9))
  1579  	fontName := "Times-Roman"
  1580  	k := p.Fm.EnsureKey(fontName)
  1581  	td := model.TextDescriptor{
  1582  		Text:           sampleText2,
  1583  		FontName:       fontName,
  1584  		Embed:          true,
  1585  		FontKey:        k,
  1586  		FontSize:       12,
  1587  		Scale:          1.,
  1588  		ScaleAbs:       true,
  1589  		RMode:          draw.RMFill,
  1590  		ShowBackground: true,
  1591  		BackgroundCol:  color.SimpleColor{R: .6, G: .98, B: .77},
  1592  		ShowBorder:     true,
  1593  		BorderWidth:    10,
  1594  		BorderCol:      color.NewSimpleColor(0xabe003),
  1595  		ShowMargins:    true,
  1596  		MLeft:          10,
  1597  		MRight:         10,
  1598  		MTop:           10,
  1599  		MBot:           10,
  1600  		ShowTextBB:     true,
  1601  	}
  1602  
  1603  	td.X, td.Y, td.HAlign, td.VAlign = 300, 450, types.AlignCenter, types.AlignTop
  1604  	td.MinHeight = 300
  1605  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 400)
  1606  
  1607  	draw.SetLineWidth(p.Buf, 0)
  1608  	draw.SetStrokeColor(p.Buf, color.Black)
  1609  	draw.DrawLineSimple(p.Buf, 100, 0, 100, 600)
  1610  	draw.DrawLineSimple(p.Buf, 500, 0, 500, 600)
  1611  	draw.DrawLineSimple(p.Buf, 110, 0, 110, 600)
  1612  	draw.DrawLineSimple(p.Buf, 490, 0, 490, 600)
  1613  	draw.DrawLineSimple(p.Buf, 0, 150, 600, 150)
  1614  	draw.DrawLineSimple(p.Buf, 0, 450, 600, 450)
  1615  	draw.DrawLineSimple(p.Buf, 0, 440, 600, 440)
  1616  	//pdf.DrawHairCross(p.Buf, 0, 0, mediaBox)
  1617  	return p
  1618  }
  1619  
  1620  func createTextBorderNoMarginAlignJustifyTest(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1621  	p := model.NewPageWithBg(mediaBox, color.NewSimpleColor(0xbeded9))
  1622  	fontName := "Times-Roman"
  1623  	k := p.Fm.EnsureKey(fontName)
  1624  	td := model.TextDescriptor{
  1625  		Text:           sampleText2,
  1626  		FontName:       fontName,
  1627  		Embed:          true,
  1628  		FontKey:        k,
  1629  		FontSize:       12,
  1630  		Scale:          1.,
  1631  		ScaleAbs:       true,
  1632  		RMode:          draw.RMFill,
  1633  		ShowBackground: true,
  1634  		BackgroundCol:  color.SimpleColor{R: .6, G: .98, B: .77},
  1635  		ShowBorder:     true,
  1636  		BorderWidth:    10,
  1637  		BorderCol:      color.NewSimpleColor(0xabe003),
  1638  		ShowTextBB:     true,
  1639  		ShowMargins:    true,
  1640  		MLeft:          10,
  1641  		MRight:         10,
  1642  		MTop:           10,
  1643  		MBot:           10,
  1644  	}
  1645  
  1646  	td.X, td.Y, td.HAlign, td.VAlign = 100, 450, types.AlignJustify, types.AlignTop
  1647  	td.MinHeight = 300
  1648  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 400)
  1649  
  1650  	draw.SetLineWidth(p.Buf, 0)
  1651  	draw.SetStrokeColor(p.Buf, color.Black)
  1652  	draw.DrawLineSimple(p.Buf, 100, 0, 100, 600)
  1653  	draw.DrawLineSimple(p.Buf, 500, 0, 500, 600)
  1654  	draw.DrawLineSimple(p.Buf, 110, 0, 110, 600)
  1655  	draw.DrawLineSimple(p.Buf, 490, 0, 490, 600)
  1656  	draw.DrawLineSimple(p.Buf, 0, 150, 600, 150)
  1657  	draw.DrawLineSimple(p.Buf, 0, 450, 600, 450)
  1658  	draw.DrawLineSimple(p.Buf, 0, 160, 600, 160)
  1659  	draw.DrawLineSimple(p.Buf, 0, 440, 600, 440)
  1660  	//pdf.DrawHairCross(p.Buf, 0, 0, mediaBox)
  1661  	return p
  1662  }
  1663  
  1664  func createXRefAndWritePDF(t *testing.T, msg, fileName string, mediaBox *types.Rectangle, f func(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page) {
  1665  	t.Helper()
  1666  	xRefTable, err := pdfcpu.CreateDemoXRef()
  1667  	if err != nil {
  1668  		t.Fatalf("%s: %v\n", msg, err)
  1669  	}
  1670  
  1671  	p := f(xRefTable, mediaBox)
  1672  
  1673  	rootDict, err := xRefTable.Catalog()
  1674  	if err != nil {
  1675  		t.Fatalf("%s: %v\n", msg, err)
  1676  	}
  1677  	if err = pdfcpu.AddPageTreeWithSamplePage(xRefTable, rootDict, p); err != nil {
  1678  		t.Fatalf("%s: %v\n", msg, err)
  1679  	}
  1680  
  1681  	outDir := filepath.Join("..", "..", "samples", "basic")
  1682  	outFile := filepath.Join(outDir, fileName+".pdf")
  1683  	createAndValidate(t, xRefTable, outFile, msg)
  1684  }
  1685  
  1686  func testTextDemoPDF(t *testing.T, msg, fileName string, w, h int, hAlign types.HAlignment) {
  1687  	t.Helper()
  1688  
  1689  	var f1, f2, f3, f4 func(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page
  1690  
  1691  	switch hAlign {
  1692  	case types.AlignLeft:
  1693  		f1 = createTextDemoAlignLeft
  1694  		f2 = createTextDemoAlignLeftMargin
  1695  		f3 = createTextDemoAlignLeftWidth
  1696  		f4 = createTextDemoAlignLeftWidthAndMargin
  1697  	case types.AlignCenter:
  1698  		f1 = createTextDemoAlignCenter
  1699  		f2 = createTextDemoAlignCenterMargin
  1700  		f3 = createTextDemoAlignCenterWidth
  1701  		f4 = createTextDemoAlignCenterWidthAndMargin
  1702  	case types.AlignRight:
  1703  		f1 = createTextDemoAlignRight
  1704  		f2 = createTextDemoAlignRightMargin
  1705  		f3 = createTextDemoAlignRightWidth
  1706  		f4 = createTextDemoAlignRightWidthAndMargin
  1707  	case types.AlignJustify:
  1708  		f1 = createTextDemoAlignJustify
  1709  		f2 = createTextDemoAlignJustifyMargin
  1710  		f3 = createTextDemoAlignJustifyWidth
  1711  		f4 = createTextDemoAlignJustifyWidthAndMargin
  1712  	}
  1713  
  1714  	mediaBox := types.RectForDim(float64(w), float64(h))
  1715  	createXRefAndWritePDF(t, msg, "TextDemo"+fileName, mediaBox, f1)
  1716  	createXRefAndWritePDF(t, msg, "TextDemo"+fileName+"Margin", mediaBox, f2)
  1717  	createXRefAndWritePDF(t, msg, "TextDemo"+fileName+"Width", mediaBox, f3)
  1718  	createXRefAndWritePDF(t, msg, "TextDemo"+fileName+"WidthAndMargin", mediaBox, f4)
  1719  }
  1720  
  1721  func TestTextDemoPDF(t *testing.T) {
  1722  	msg := "TestTextDemoPDF"
  1723  	w, h := 600, 600
  1724  
  1725  	for _, tt := range []struct {
  1726  		fileName string
  1727  		w, h     int
  1728  		hAlign   types.HAlignment
  1729  	}{
  1730  		{"AlignLeft", w, h, types.AlignLeft},
  1731  		{"AlignCenter", w, h, types.AlignCenter},
  1732  		{"AlignRight", w, h, types.AlignRight},
  1733  		{"AlignJustify", w, h, types.AlignJustify},
  1734  	} {
  1735  		testTextDemoPDF(t, msg, tt.fileName, tt.w, tt.h, tt.hAlign)
  1736  	}
  1737  }
  1738  
  1739  func TestColumnDemoPDF(t *testing.T) {
  1740  	msg := "TestColumnDemoPDF"
  1741  
  1742  	for _, tt := range []struct {
  1743  		fileName string
  1744  		w, h     int
  1745  		f        func(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page
  1746  	}{
  1747  		{"TestTextAlignJustifyDemo", 600, 600, createTextAlignJustifyDemo},
  1748  		{"TestTextAlignJustifyColumnDemo", 600, 600, createTextAlignJustifyColumnDemo},
  1749  		{"TextDemoAnchors", 600, 600, createTextDemoAnchors},
  1750  		{"TextDemoAnchorsWithOffset", 600, 600, createTextDemoAnchorsWithOffset},
  1751  		{"TextDemoColumnAnchored", 1200, 1200, createTextDemoColumnAnchored},
  1752  		{"TextDemoColumnAnchoredWithOffset", 1200, 1200, createTextDemoColumnAnchoredWithOffset},
  1753  		{"TextRotateDemo", 1200, 1200, createTextRotateDemo},
  1754  		{"TextRotateDemoWithOffset", 1200, 1200, createTextRotateDemoWithOffset},
  1755  		{"TextScaleAbsoluteDemo", 600, 600, createTextScaleAbsoluteDemo},
  1756  		{"TextScaleAbsoluteDemoWithOffset", 600, 600, createTextScaleAbsoluteDemoWithOffset},
  1757  		{"TextScaleRelativeDemo", 600, 600, createTextScaleRelativeDemo},
  1758  		{"TextScaleRelativeDemoWithOffset", 600, 600, createTextScaleRelativeDemoWithOffset},
  1759  		{"TextDemoColumns", 600, 600, createTextDemoColumns},
  1760  		{"TextBorderTest", 600, 600, createTextBorderTest},
  1761  		{"TextBorderNoMarginAlignLeftTest", 600, 600, createTextBorderNoMarginAlignLeftTest},
  1762  		{"TextBorderNoMarginAlignRightTest", 600, 600, createTextBorderNoMarginAlignRightTest},
  1763  		{"TextBorderNoMarginAlignCenterTest", 600, 600, createTextBorderNoMarginAlignCenterTest},
  1764  		{"TextBorderNoMarginAlignJustifyTest", 600, 600, createTextBorderNoMarginAlignJustifyTest},
  1765  	} {
  1766  		mediaBox := types.RectForDim(float64(tt.w), float64(tt.h))
  1767  		createXRefAndWritePDF(t, msg, tt.fileName, mediaBox, tt.f)
  1768  	}
  1769  }
  1770  
  1771  func writecreateTestRTLUserFont(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle, fontName, s string) {
  1772  	mediaBox := p.MediaBox
  1773  	buf := p.Buf
  1774  
  1775  	mediaBB := true
  1776  
  1777  	var cr, cg, cb float32
  1778  	cr, cg, cb = .5, .75, 1.
  1779  	r := mediaBox
  1780  	if region != nil {
  1781  		r = region
  1782  		cr, cg, cb = .75, .75, 1
  1783  	}
  1784  	if mediaBB {
  1785  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
  1786  	}
  1787  
  1788  	k := p.Fm.EnsureKey(fontName)
  1789  
  1790  	td := model.TextDescriptor{
  1791  		Text:           s,
  1792  		FontName:       fontName,
  1793  		Embed:          true,
  1794  		FontKey:        k,
  1795  		FontSize:       12,
  1796  		RTL:            true,
  1797  		MLeft:          5,
  1798  		MRight:         5,
  1799  		MTop:           5,
  1800  		MBot:           5,
  1801  		X:              mediaBox.Width(),
  1802  		Y:              -1,
  1803  		Scale:          1.,
  1804  		ScaleAbs:       true,
  1805  		HAlign:         types.AlignRight,
  1806  		VAlign:         types.AlignMiddle,
  1807  		RMode:          draw.RMFill,
  1808  		StrokeCol:      color.NewSimpleColor(0x206A29),
  1809  		FillCol:        color.NewSimpleColor(0x206A29),
  1810  		ShowBackground: true,
  1811  		BackgroundCol:  color.SimpleColor{R: 1., G: .98, B: .77},
  1812  		ShowBorder:     true,
  1813  		ShowLineBB:     false,
  1814  		ShowTextBB:     true,
  1815  		HairCross:      false,
  1816  	}
  1817  
  1818  	model.WriteMultiLine(xRefTable, buf, mediaBox, region, td)
  1819  
  1820  	draw.DrawHairCross(p.Buf, 0, 0, mediaBox)
  1821  }
  1822  
  1823  func createTestRTLUserFont(xRefTable *model.XRefTable, mediaBox *types.Rectangle, language, fontName string) model.Page {
  1824  	p := model.NewPage(mediaBox, nil)
  1825  	var region *types.Rectangle
  1826  	text := sampleTextRTL[language]
  1827  	writecreateTestRTLUserFont(xRefTable, p, region, fontName, text)
  1828  	region = types.RectForWidthAndHeight(10, 10, mediaBox.Width()/4, mediaBox.Height()/4)
  1829  	writecreateTestRTLUserFont(xRefTable, p, region, fontName, text)
  1830  	return p
  1831  }
  1832  
  1833  func writecreateTestUserFontJustified(xRefTable *model.XRefTable, p model.Page, region *types.Rectangle, rtl bool) {
  1834  	mediaBox := p.MediaBox
  1835  	buf := p.Buf
  1836  
  1837  	mediaBB := true
  1838  
  1839  	var cr, cg, cb float32
  1840  	cr, cg, cb = .5, .75, 1.
  1841  	r := mediaBox
  1842  	if region != nil {
  1843  		r = region
  1844  		cr, cg, cb = .75, .75, 1
  1845  	}
  1846  	if mediaBB {
  1847  		draw.FillRectNoBorder(buf, r, color.SimpleColor{R: cr, G: cg, B: cb})
  1848  	}
  1849  
  1850  	fontName := "Roboto-Regular"
  1851  	k := p.Fm.EnsureKey(fontName)
  1852  
  1853  	td := model.TextDescriptor{
  1854  		Text:           sampleText,
  1855  		FontName:       fontName,
  1856  		Embed:          true,
  1857  		FontKey:        k,
  1858  		FontSize:       12,
  1859  		RTL:            rtl,
  1860  		MLeft:          5,
  1861  		MRight:         5,
  1862  		MTop:           5,
  1863  		MBot:           5,
  1864  		X:              -1,
  1865  		Y:              -1,
  1866  		Scale:          1.,
  1867  		ScaleAbs:       true,
  1868  		HAlign:         types.AlignJustify,
  1869  		VAlign:         types.AlignMiddle,
  1870  		RMode:          draw.RMFill,
  1871  		StrokeCol:      color.NewSimpleColor(0x206A29),
  1872  		FillCol:        color.NewSimpleColor(0x206A29),
  1873  		ShowBackground: true,
  1874  		BackgroundCol:  color.SimpleColor{R: 1., G: .98, B: .77},
  1875  		ShowBorder:     true,
  1876  		ShowLineBB:     false,
  1877  		ShowTextBB:     true,
  1878  		HairCross:      false,
  1879  	}
  1880  
  1881  	model.WriteMultiLine(xRefTable, buf, mediaBox, region, td)
  1882  
  1883  	draw.DrawHairCross(p.Buf, 0, 0, mediaBox)
  1884  }
  1885  
  1886  func createTestUserFontJustified(xRefTable *model.XRefTable, mediaBox *types.Rectangle, rtl bool) model.Page {
  1887  	p := model.NewPage(mediaBox, nil)
  1888  	var region *types.Rectangle
  1889  	writecreateTestUserFontJustified(xRefTable, p, region, rtl)
  1890  	return p
  1891  }
  1892  
  1893  func createXRefAndWriteJustifiedPDF(t *testing.T, msg, fileName string, mediaBox *types.Rectangle, rtl bool) {
  1894  	t.Helper()
  1895  	xRefTable, err := pdfcpu.CreateDemoXRef()
  1896  	if err != nil {
  1897  		t.Fatalf("%s: %v\n", msg, err)
  1898  	}
  1899  
  1900  	p := createTestUserFontJustified(xRefTable, mediaBox, rtl)
  1901  
  1902  	rootDict, err := xRefTable.Catalog()
  1903  	if err != nil {
  1904  		t.Fatalf("%s: %v\n", msg, err)
  1905  	}
  1906  	if err = pdfcpu.AddPageTreeWithSamplePage(xRefTable, rootDict, p); err != nil {
  1907  		t.Fatalf("%s: %v\n", msg, err)
  1908  	}
  1909  
  1910  	outDir := filepath.Join("..", "..", "samples", "basic")
  1911  	outFile := filepath.Join(outDir, fileName+".pdf")
  1912  	createAndValidate(t, xRefTable, outFile, msg)
  1913  }
  1914  
  1915  func TestUserFontJustified(t *testing.T) {
  1916  	msg := "TestUserFontJustified"
  1917  	mediaBox := types.RectForDim(600, 600)
  1918  	createXRefAndWriteJustifiedPDF(t, msg, "UserFont_Justified", mediaBox, false)
  1919  	createXRefAndWriteJustifiedPDF(t, msg, "UserFont_JustifiedRightToLeft", mediaBox, true)
  1920  }
  1921  
  1922  func createXRefAndWriteRTLPDF(t *testing.T,
  1923  	msg, fileName string,
  1924  	mediaBox *types.Rectangle,
  1925  	language, fontName string,
  1926  	f func(xRefTable *model.XRefTable, mediaBox *types.Rectangle, language, fontName string) model.Page) {
  1927  	t.Helper()
  1928  
  1929  	xRefTable, err := pdfcpu.CreateDemoXRef()
  1930  	if err != nil {
  1931  		t.Fatalf("%s: %v\n", msg, err)
  1932  	}
  1933  
  1934  	p := f(xRefTable, mediaBox, language, fontName)
  1935  
  1936  	rootDict, err := xRefTable.Catalog()
  1937  	if err != nil {
  1938  		t.Fatalf("%s: %v\n", msg, err)
  1939  	}
  1940  	if err = pdfcpu.AddPageTreeWithSamplePage(xRefTable, rootDict, p); err != nil {
  1941  		t.Fatalf("%s: %v\n", msg, err)
  1942  	}
  1943  	outDir := filepath.Join("..", "..", "samples", "basic")
  1944  	outFile := filepath.Join(outDir, fileName+".pdf")
  1945  	createAndValidate(t, xRefTable, outFile, msg)
  1946  }
  1947  
  1948  func TestUserFontRTL(t *testing.T) {
  1949  	msg := "TestUserFontRTL"
  1950  	f := createTestRTLUserFont
  1951  	mediaBox := types.RectForDim(600, 600)
  1952  
  1953  	for _, tt := range []struct {
  1954  		fileName string
  1955  		language string
  1956  		fontName string
  1957  	}{
  1958  		{"UserFont_Arabic", "Arabic", "UnifontMedium"},
  1959  		{"UserFont_Hebrew", "Hebrew", "UnifontMedium"},
  1960  		{"UserFont_Persian", "Persian", "UnifontMedium"},
  1961  		{"UserFont_Urdu", "Urdu", "UnifontMedium"},
  1962  	} {
  1963  		createXRefAndWriteRTLPDF(t, msg, tt.fileName, mediaBox, tt.language, tt.fontName, f)
  1964  	}
  1965  }
  1966  
  1967  func createCJKVDemo(xRefTable *model.XRefTable, mediaBox *types.Rectangle) model.Page {
  1968  	p := model.NewPage(mediaBox, nil)
  1969  	mb := p.MediaBox
  1970  
  1971  	textEnglish := `pdfcpu
  1972  Instant PDF processing for all your needs.
  1973  Now supporting CJKV!`
  1974  
  1975  	textChineseSimple := `pdfcpu
  1976  即时处理PDF,满足您的所有需求。
  1977  现在支持CJKV字体!`
  1978  
  1979  	textJapanese := `pdfcpu
  1980  すべてのニーズに対応するインスタントPDF処理。
  1981  CJKVフォントがサポートされるようになりました!`
  1982  
  1983  	textKorean := `pdfcpu
  1984  모든 요구 사항에 맞는 즉각적인 PDF 처리.
  1985  이제 CJKV 글꼴을 지원합니다!`
  1986  
  1987  	textVietnamese := `pdfcpu
  1988  Xử lý PDF tức thì cho mọi nhu cầu của bạn.
  1989  Bây giờ với sự hỗ trợ cho các phông chữ CJKV!`
  1990  
  1991  	td := model.TextDescriptor{
  1992  		FontSize:       24,
  1993  		Embed:          true,
  1994  		MLeft:          5,
  1995  		MRight:         5,
  1996  		MTop:           5,
  1997  		MBot:           5,
  1998  		Scale:          1,
  1999  		ScaleAbs:       true,
  2000  		HAlign:         types.AlignLeft,
  2001  		VAlign:         types.AlignMiddle,
  2002  		RMode:          draw.RMFill,
  2003  		StrokeCol:      color.NewSimpleColor(0x206A29),
  2004  		FillCol:        color.NewSimpleColor(0x206A29),
  2005  		ShowBackground: true,
  2006  		BackgroundCol:  color.SimpleColor{R: 1., G: .98, B: .77},
  2007  		ShowBorder:     true,
  2008  		ShowLineBB:     false,
  2009  		ShowTextBB:     true,
  2010  		HairCross:      false,
  2011  	}
  2012  
  2013  	td.Text, td.FontName, td.FontKey = textChineseSimple, "UnifontMedium", p.Fm.EnsureKey("UnifontMedium")
  2014  	td.X, td.Y = 0, mb.Height()
  2015  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 3*mb.Width()/4)
  2016  
  2017  	td.Text, td.FontName, td.FontKey = textJapanese, "Unifont-JPMedium", p.Fm.EnsureKey("Unifont-JPMedium")
  2018  	td.X, td.Y = mb.Width(), 2*mb.Height()/3
  2019  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 3*mb.Width()/4)
  2020  
  2021  	td.Text, td.FontName, td.FontKey = textKorean, "UnifontMedium", p.Fm.EnsureKey("UnifontMedium")
  2022  	td.X, td.Y = 0, mb.Height()/3
  2023  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 3*mb.Width()/4)
  2024  
  2025  	td.Text, td.FontName, td.FontKey = textVietnamese, "Roboto-Regular", p.Fm.EnsureKey("Roboto-Regular")
  2026  	td.X, td.Y = mb.Width(), 0
  2027  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 3*mb.Width()/4)
  2028  
  2029  	td.Text, td.FontSize, td.ShowTextBB = textEnglish, 24, false
  2030  	td.X, td.Y, td.HAlign = -1, -1, types.AlignCenter
  2031  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 0)
  2032  
  2033  	td.FontSize = 80
  2034  	td.Text, td.HAlign, td.X, td.Y = "C", types.AlignRight, mb.Width(), mb.Height()
  2035  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 0)
  2036  
  2037  	td.Text, td.HAlign, td.X, td.Y = "J", types.AlignLeft, 0, 2*mb.Height()/3
  2038  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 0)
  2039  
  2040  	td.Text, td.HAlign, td.X, td.Y = "K", types.AlignRight, mb.Width(), mb.Height()/3
  2041  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 0)
  2042  
  2043  	td.Text, td.HAlign, td.X, td.Y = "V", types.AlignLeft, 0, 0
  2044  	model.WriteColumn(xRefTable, p.Buf, mediaBox, nil, td, 0)
  2045  
  2046  	return p
  2047  }
  2048  
  2049  func TestCJKV(t *testing.T) {
  2050  	msg := "TestCJKV"
  2051  	mediaBox := types.RectForDim(600, 600)
  2052  	xRefTable, err := pdfcpu.CreateDemoXRef()
  2053  	if err != nil {
  2054  		t.Fatalf("%s: %v\n", msg, err)
  2055  	}
  2056  
  2057  	p := createCJKVDemo(xRefTable, mediaBox)
  2058  
  2059  	rootDict, err := xRefTable.Catalog()
  2060  	if err != nil {
  2061  		t.Fatalf("%s: %v\n", msg, err)
  2062  	}
  2063  	if err = pdfcpu.AddPageTreeWithSamplePage(xRefTable, rootDict, p); err != nil {
  2064  		t.Fatalf("%s: %v\n", msg, err)
  2065  	}
  2066  	outDir := filepath.Join("..", "..", "samples", "basic")
  2067  	outFile := filepath.Join(outDir, "UserFont_CJKV.pdf")
  2068  	createAndValidate(t, xRefTable, outFile, msg)
  2069  }