Commit 1b51eed04dcd7aaa90727f3586530ec57f1d2843
1 parent
b80ee4b2bc
Exists in
master
pdf helper
Showing
7 changed files
with
352 additions
and
2 deletions
Show diff stats
date_util.go
... | ... | @@ -2,6 +2,7 @@ package webutility |
2 | 2 | |
3 | 3 | import ( |
4 | 4 | "fmt" |
5 | + "strings" | |
5 | 6 | "time" |
6 | 7 | ) |
7 | 8 | |
... | ... | @@ -23,6 +24,11 @@ const ( |
23 | 24 | DDMMYYYY_HHMMSS_dt = "02.01.2006. 15:04:05" |
24 | 25 | ) |
25 | 26 | |
27 | +var ( | |
28 | + regularYear = [12]int64{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} | |
29 | + leapYear = [12]int64{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} | |
30 | +) | |
31 | + | |
26 | 32 | func Systime() int64 { |
27 | 33 | return time.Now().Unix() |
28 | 34 | } |
... | ... | @@ -39,3 +45,26 @@ func DateToEpoch(date, format string) int64 { |
39 | 45 | func EpochToDate(e int64, format string) string { |
40 | 46 | return time.Unix(e, 0).Format(format) |
41 | 47 | } |
48 | + | |
49 | +func EpochToDayMonthYear(timestamp int64) (d, m, y int64) { | |
50 | + datestring := EpochToDate(timestamp, DDMMYYYY_sl) | |
51 | + parts := strings.Split(datestring, "/") | |
52 | + d = StringToInt64(parts[0]) | |
53 | + m = StringToInt64(parts[1]) | |
54 | + y = StringToInt64(parts[2]) | |
55 | + return d, m, y | |
56 | +} | |
57 | + | |
58 | +func DaysInMonth(year, month int64) int64 { | |
59 | + if month < 1 || month > 12 { | |
60 | + return 0 | |
61 | + } | |
62 | + if IsLeapYear(year) { | |
63 | + return leapYear[month-1] | |
64 | + } | |
65 | + return regularYear[month-1] | |
66 | +} | |
67 | + | |
68 | +func IsLeapYear(year int64) bool { | |
69 | + return year%4 == 0 && !((year%100 == 0) && (year%400 != 0)) | |
70 | +} | ... | ... |
float_util.go
... | ... | @@ -57,3 +57,10 @@ func BFtoFloat(f *big.Float) float64 { |
57 | 57 | func Float64ToString(f float64) string { |
58 | 58 | return fmt.Sprintf("%.2f", f) |
59 | 59 | } |
60 | + | |
61 | +func Float64PtrToString(f *float64) string { | |
62 | + if f == nil { | |
63 | + return "" | |
64 | + } | |
65 | + return fmt.Sprintf("%.2f", *f) | |
66 | +} | ... | ... |
guid.go
1 | 1 | package webutility |
2 | 2 | |
3 | 3 | import ( |
4 | - "crypto/rand" | |
5 | 4 | "fmt" |
5 | + "math/rand" | |
6 | 6 | ) |
7 | 7 | |
8 | +func SeedGUID(seed int64) { | |
9 | + rand.Seed(seed) | |
10 | +} | |
11 | + | |
8 | 12 | // GUID ... |
9 | 13 | func GUID() (string, error) { |
10 | 14 | b := make([]byte, 16) |
... | ... | @@ -15,3 +19,8 @@ func GUID() (string, error) { |
15 | 19 | id := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) |
16 | 20 | return id, nil |
17 | 21 | } |
22 | + | |
23 | +func NewGUID() string { | |
24 | + id, _ := GUID() | |
25 | + return id | |
26 | +} | ... | ... |
http.go
... | ... | @@ -168,6 +168,6 @@ func GetHeader(r *http.Request, key string) string { |
168 | 168 | return r.Header.Get(key) |
169 | 169 | } |
170 | 170 | |
171 | -func GetClientAgentUTCOffset(req *http.Request) int64 { | |
171 | +func ClientUTCOffset(req *http.Request) int64 { | |
172 | 172 | return StringToInt64(GetHeader(req, "X-Timezone-Offset")) |
173 | 173 | } | ... | ... |
int_util.go
... | ... | @@ -25,6 +25,14 @@ func Int64ToString(i int64) string { |
25 | 25 | return fmt.Sprintf("%d", i) |
26 | 26 | } |
27 | 27 | |
28 | +// Int64PtrToString ... | |
29 | +func Int64PtrToString(i *int64) string { | |
30 | + if i == nil { | |
31 | + return "" | |
32 | + } | |
33 | + return fmt.Sprintf("%d", *i) | |
34 | +} | |
35 | + | |
28 | 36 | // BoolToInt64 ... |
29 | 37 | func BoolToInt64(b bool) int64 { |
30 | 38 | if b { |
... | ... | @@ -39,6 +47,7 @@ func Int64ToBool(i int64) bool { |
39 | 47 | } |
40 | 48 | |
41 | 49 | func MaxInt(vars ...int) (max int) { |
50 | + max = vars[0] | |
42 | 51 | for _, v := range vars { |
43 | 52 | if v > max { |
44 | 53 | max = v |
... | ... | @@ -46,3 +55,13 @@ func MaxInt(vars ...int) (max int) { |
46 | 55 | } |
47 | 56 | return max |
48 | 57 | } |
58 | + | |
59 | +func MinInt64(vars ...int64) (min int64) { | |
60 | + min = vars[0] | |
61 | + for _, v := range vars { | |
62 | + if v < min { | |
63 | + min = v | |
64 | + } | |
65 | + } | |
66 | + return min | |
67 | +} | ... | ... |
nullables.go
... | ... | @@ -139,6 +139,21 @@ func (ni *NullInt64) Value() (driver.Value, error) { |
139 | 139 | return ni.Int64, nil |
140 | 140 | } |
141 | 141 | |
142 | +func (ni *NullInt64) Val() int64 { | |
143 | + return ni.Int64 | |
144 | +} | |
145 | + | |
146 | +// Add | |
147 | +func (ni *NullInt64) Add(i NullInt64) { | |
148 | + ni.Valid = true | |
149 | + ni.Int64 += i.Int64 | |
150 | +} | |
151 | + | |
152 | +func (ni *NullInt64) Set(i int64) { | |
153 | + ni.Valid = true | |
154 | + ni.Int64 = i | |
155 | +} | |
156 | + | |
142 | 157 | // MarshalJSON ... |
143 | 158 | func (ni NullInt64) MarshalJSON() ([]byte, error) { |
144 | 159 | if ni.Valid { |
... | ... | @@ -197,6 +212,22 @@ func (nf *NullFloat64) Value() (driver.Value, error) { |
197 | 212 | return nf.Float64, nil |
198 | 213 | } |
199 | 214 | |
215 | +// Val ... | |
216 | +func (nf *NullFloat64) Val() float64 { | |
217 | + return nf.Float64 | |
218 | +} | |
219 | + | |
220 | +// Add ... | |
221 | +func (nf *NullFloat64) Add(f NullFloat64) { | |
222 | + nf.Valid = true | |
223 | + nf.Float64 += f.Float64 | |
224 | +} | |
225 | + | |
226 | +func (nf *NullFloat64) Set(f float64) { | |
227 | + nf.Valid = true | |
228 | + nf.Float64 = f | |
229 | +} | |
230 | + | |
200 | 231 | // MarshalJSON ... |
201 | 232 | func (nf NullFloat64) MarshalJSON() ([]byte, error) { |
202 | 233 | if nf.Valid { | ... | ... |
pdfhelper/pdf.go
... | ... | @@ -0,0 +1,255 @@ |
1 | +package pdfhelper | |
2 | + | |
3 | +import ( | |
4 | + "fmt" | |
5 | + "strings" | |
6 | + | |
7 | + "git.to-net.rs/marko.tikvic/gofpdf" | |
8 | +) | |
9 | + | |
10 | +// Block ... | |
11 | +const ( | |
12 | + CENTER = "C" | |
13 | + LEFT = "L" | |
14 | + RIGHT = "R" | |
15 | + TOP = "T" | |
16 | + BOTTOM = "B" | |
17 | + FULL = "1" | |
18 | + NOBORDER = "" | |
19 | +) | |
20 | + | |
21 | +const ( | |
22 | + CONTINUE = 0 | |
23 | + NEWLINE = 1 | |
24 | + BELLOW = 2 | |
25 | +) | |
26 | + | |
27 | +const ( | |
28 | + cyrillicEncoding = "cp1251" | |
29 | + latinEncoding = "cp1250" | |
30 | +) | |
31 | + | |
32 | +// Helper ... | |
33 | +type Helper struct { | |
34 | + *gofpdf.Fpdf | |
35 | + translators map[string]func(string) string | |
36 | +} | |
37 | + | |
38 | +// New ... | |
39 | +func New(ori, unit, size string) *Helper { | |
40 | + helper := &Helper{ | |
41 | + Fpdf: gofpdf.New(ori, unit, size, ""), | |
42 | + } | |
43 | + | |
44 | + return helper | |
45 | +} | |
46 | + | |
47 | +func (pdf *Helper) LoadTranslators() { | |
48 | + pdf.translators = make(map[string]func(string) string) | |
49 | + pdf.translators[latinEncoding] = pdf.UnicodeTranslatorFromDescriptor(latinEncoding) | |
50 | + pdf.translators[cyrillicEncoding] = pdf.UnicodeTranslatorFromDescriptor(cyrillicEncoding) | |
51 | +} | |
52 | + | |
53 | +// InsertTab ... | |
54 | +func (pdf *Helper) InsertTab(count int, w, h float64) { | |
55 | + for i := 0; i < count; i++ { | |
56 | + pdf.Cell(w, h, "") | |
57 | + } | |
58 | +} | |
59 | + | |
60 | +// CellWithBox ... | |
61 | +func (pdf *Helper) CellWithBox(w, h float64, text, align string) { | |
62 | + //pdf.drawCellMargins(w, h) | |
63 | + //pdf.Cell(w, h, text) | |
64 | + pdf.CellFormat(w, h, pdf.ToUTF8(text), FULL, CONTINUE, align, false, 0, "") | |
65 | +} | |
66 | + | |
67 | +func (pdf *Helper) CellWithMargins(w, h float64, text, align string, index, of int) { | |
68 | + len := of - 1 | |
69 | + border := "" | |
70 | + | |
71 | + // if top cell | |
72 | + if index == 0 { | |
73 | + border += "T" | |
74 | + } | |
75 | + | |
76 | + border += "LR" // always draw these | |
77 | + | |
78 | + // if bottom cell | |
79 | + if index == len { | |
80 | + border += "B" | |
81 | + } | |
82 | + | |
83 | + pdf.CellFormat(w, h, pdf.ToUTF8(text), border, CONTINUE, align, false, 0, "") | |
84 | +} | |
85 | + | |
86 | +// MultiRowCellWithBox ... | |
87 | +func (pdf *Helper) MultiRowCellWithBox(w, h float64, text []string, align string) { | |
88 | + pdf.drawCellMargins(w, h*float64(len(text))) | |
89 | + for i := range text { | |
90 | + pdf.CellFormat(w, h, pdf.ToUTF8(text[i]), "", BELLOW, align, false, 0, "") | |
91 | + } | |
92 | +} | |
93 | + | |
94 | +// CellFormat(w, h, text, borders, newLine, fill) | |
95 | + | |
96 | +type FormatedCell struct { | |
97 | + W, H float64 | |
98 | + Text string | |
99 | + Font, FontStyle string | |
100 | + FontSize float64 | |
101 | + Border string | |
102 | + Alignment string | |
103 | +} | |
104 | + | |
105 | +func (pdf *Helper) Column(x, y float64, cells []FormatedCell) { | |
106 | + pdf.SetXY(x, y) | |
107 | + for _, c := range cells { | |
108 | + pdf.SetFont(c.Font, c.FontStyle, c.FontSize) | |
109 | + pdf.CellFormat(c.W, c.H, pdf.ToUTF8(c.Text), c.Border, BELLOW, c.Alignment, false, 0, "") | |
110 | + //pdf.CellFormat(c.w, c.h, c.text, c.border, BELLOW, align, false, 0, "") | |
111 | + } | |
112 | +} | |
113 | + | |
114 | +// NewLine ... | |
115 | +func (pdf *Helper) NewLine(h float64) { | |
116 | + pdf.Ln(h) | |
117 | +} | |
118 | + | |
119 | +// WriteColumns ... | |
120 | +func (pdf *Helper) WriteColumns(align string, cols []PDFCell) { | |
121 | + for _, c := range cols { | |
122 | + pdf.CellFormat(c.width, c.height, pdf.ToUTF8(c.data), "", CONTINUE, align, false, 0, "") | |
123 | + } | |
124 | +} | |
125 | + | |
126 | +func (pdf *Helper) Row(x, y float64, cells []FormatedCell) { | |
127 | + pdf.SetXY(x, y) | |
128 | + for _, c := range cells { | |
129 | + pdf.SetFont(c.Font, c.FontStyle, c.FontSize) | |
130 | + pdf.CellFormat(c.W, c.H, pdf.ToUTF8(c.Text), c.Border, CONTINUE, c.Alignment, false, 0, "") | |
131 | + } | |
132 | +} | |
133 | + | |
134 | +const threeDots = "\u2056\u2056\u2056" | |
135 | + | |
136 | +// WriteColumnsWithAlignment ... | |
137 | +func (pdf *Helper) WriteColumnsWithAlignment(cols []PDFCellAligned) { | |
138 | + for _, c := range cols { | |
139 | + lines := pdf.SplitText(c.data, c.width) | |
140 | + if len(lines) == 1 { | |
141 | + pdf.CellFormat(c.width, c.height, pdf.ToUTF8(lines[0]), "", CONTINUE, c.alignment, false, 0, "") | |
142 | + } else { | |
143 | + pdf.CellFormat(c.width, c.height, pdf.ToUTF8(lines[0]+threeDots), "", CONTINUE, c.alignment, false, 0, "") | |
144 | + } | |
145 | + } | |
146 | + | |
147 | +} | |
148 | + | |
149 | +func (pdf *Helper) LimitText(text, limiter string, maxWidth float64) string { | |
150 | + parts := pdf.Fpdf.SplitText(text, maxWidth) | |
151 | + if len(parts) > 1 { | |
152 | + return parts[0] + limiter | |
153 | + } | |
154 | + | |
155 | + return text | |
156 | +} | |
157 | + | |
158 | +// InsertImage ... | |
159 | +func (pdf *Helper) InsertImage(img string, x, y, w, h float64) { | |
160 | + imgType := "" | |
161 | + if parts := strings.Split(img, "."); len(parts) >= 2 { | |
162 | + imgType = parts[len(parts)-1] | |
163 | + } | |
164 | + opt := gofpdf.ImageOptions{ | |
165 | + ImageType: imgType, | |
166 | + ReadDpi: false, | |
167 | + AllowNegativePosition: false, | |
168 | + } | |
169 | + autoBreak := false // if it's not false then you can't draw the image at an arbitrary height (y position) | |
170 | + pdf.ImageOptions(img, x, y, w, h, autoBreak, opt, 0, "") | |
171 | +} | |
172 | + | |
173 | +// PDFCell ... | |
174 | +type PDFCell struct { | |
175 | + data string | |
176 | + height, width float64 | |
177 | +} | |
178 | + | |
179 | +// PDFCellAligned ... | |
180 | +type PDFCellAligned struct { | |
181 | + alignment string | |
182 | + data string | |
183 | + height, width float64 | |
184 | +} | |
185 | + | |
186 | +func (pdf *Helper) TextLength(txt, family, style string, size float64) float64 { | |
187 | + family, _, _, _ = pdf.setCorrectFontFamily(txt) | |
188 | + return pdf.Fpdf.TextLength(txt, family, style, size) | |
189 | +} | |
190 | + | |
191 | +// ToUTF8 ... | |
192 | +func (pdf *Helper) ToUTF8(s string) string { | |
193 | + encoding := latinEncoding | |
194 | + runes := []rune(s) | |
195 | + for _, r := range runes { | |
196 | + if uint64(r) >= 0x0402 && uint64(r) <= 0x044f { | |
197 | + encoding = cyrillicEncoding | |
198 | + break | |
199 | + } | |
200 | + } | |
201 | + pdf.setCorrectFontFamily(encoding) | |
202 | + translator, ok := pdf.translators[encoding] | |
203 | + if !ok { | |
204 | + return "" | |
205 | + } | |
206 | + return translator(s) | |
207 | +} | |
208 | + | |
209 | +func (pdf *Helper) setCorrectFontFamily(enc string) (family, style string, ptSize, unitSize float64) { | |
210 | + family, style, ptSize, unitSize = pdf.GetFontInfo() | |
211 | + if enc == cyrillicEncoding { | |
212 | + if !strings.HasSuffix(family, "Cyrillic") { | |
213 | + family += "Cyrillic" | |
214 | + } | |
215 | + } else { | |
216 | + if strings.HasSuffix(family, "Cyrillic") { | |
217 | + family = strings.TrimSuffix(family, "Cyrillic") | |
218 | + } | |
219 | + } | |
220 | + pdf.SetFont(family, style, ptSize) | |
221 | + return family, style, ptSize, unitSize | |
222 | +} | |
223 | + | |
224 | +func (pdf *Helper) PageHasSpace(requiredHeight float64) bool { | |
225 | + _, h := pdf.GetPageSize() | |
226 | + _, _, _, bot := pdf.GetMargins() | |
227 | + return (h - bot - pdf.GetY()) > requiredHeight | |
228 | +} | |
229 | + | |
230 | +func (pdf *Helper) imageCenterOffset(w, h float64) (x, y float64) { | |
231 | + pageW, pageH := pdf.GetPageSize() | |
232 | + x = pageW/2.0 - w/2.0 | |
233 | + y = pageH/2.0 - h/2.0 | |
234 | + return x, y | |
235 | +} | |
236 | + | |
237 | +// call before drawing the cell | |
238 | +func (pdf *Helper) drawCellMargins(cw, ch float64) { | |
239 | + x0, y0 := pdf.GetX(), pdf.GetY() | |
240 | + pdf.DrawBox(x0, y0, cw, ch) | |
241 | +} | |
242 | + | |
243 | +// DrawBox ... | |
244 | +func (pdf Helper) DrawBox(x0, y0, w, h float64) { | |
245 | + pdf.Line(x0, y0, x0+w, y0) | |
246 | + pdf.Line(x0+w, y0, x0+w, y0+h) | |
247 | + pdf.Line(x0+w, y0+h, x0, y0+h) | |
248 | + pdf.Line(x0, y0+h, x0, y0) | |
249 | +} | |
250 | + | |
251 | +// Strana %d/{TotalPages} | |
252 | +func (pdf *Helper) InsertPageNumber(x, y float64, format string) { | |
253 | + num := fmt.Sprintf(format, pdf.PageNo()) | |
254 | + pdf.Column(x, y, []FormatedCell{{10, 1, num, "DejaVuSans", "", 8, NOBORDER, LEFT}}) | |
255 | +} | ... | ... |