@@ -12,6 +12,7 @@ import (
1212 "io/ioutil"
1313 "os"
1414 "path/filepath"
15+ "strconv"
1516 "strings"
1617
1718 "github.com/alecthomas/chroma"
@@ -25,13 +26,21 @@ import (
2526 "golang.org/x/term"
2627)
2728
28- var version = "1.1 .0"
29+ var version = "1.2 .0"
2930
3031func exitErr (err error ) {
3132 fmt .Fprintln (os .Stderr , err )
3233 os .Exit (1 )
3334}
3435
36+ type options struct {
37+ useClipboard bool
38+ source string
39+ output string
40+ ext string
41+ theme string
42+ }
43+
3544func main () {
3645 name := "code2img"
3746 fs := flag .NewFlagSet (name , flag .ContinueOnError )
5059 -t color theme(default: solarized-dark)
5160 -o output file name(default: out.png)
5261 -c copy to clipboard
62+ -l print line
5363 -ext file extension
5464` , name , version )
5565 }
5868 ext := fs .String ("ext" , "" , "" )
5969 output := fs .String ("o" , "out.png" , "" )
6070 useClipboard := fs .Bool ("c" , false , "" )
71+ printLine := fs .Bool ("l" , false , "" )
6172
6273 if err := fs .Parse (os .Args [1 :]); err != nil {
6374 if err == flag .ErrHelp {
@@ -103,32 +114,52 @@ Usage:
103114 }
104115 source := buf .String ()
105116
106- w , h := getSize (source )
117+ fontSize := 20
118+ w , h , lw := getSize (* printLine , source , fontSize )
107119 formatters .Register ("png" , & pngFormat {
108- width : w ,
109- height : h ,
120+ width : w ,
121+ height : h ,
122+ lineWidth : lw ,
123+ fontSize : fontSize ,
124+ printLine : * printLine ,
110125 })
111126
112- if err := toImg (* useClipboard , source , * output , * ext , * theme ); err != nil {
127+ opts := options {
128+ useClipboard : * useClipboard ,
129+ source : source ,
130+ output : * output ,
131+ ext : * ext ,
132+ theme : * theme ,
133+ }
134+ if err := toImg (opts ); err != nil {
113135 exitErr (err )
114136 }
115137}
116138
117- func getSize (s string ) (int , int ) {
118- w , h := 0 , 0
119- for _ , s := range strings .Split (s , "\n " ) {
120- ww := len (s ) * 12
139+ func getSize (printLine bool , s string , fontSize int ) (w int , h int , lw int ) {
140+ lines := strings .Split (s , "\n " )
141+ ws := 12
142+ for _ , s := range lines {
143+ ww := len (s ) * ws
121144 if ww > w {
122145 w = ww
123146 }
124147 h ++
125148 }
126149 h = h + 2
127- return w , h * 20
150+
151+ if printLine {
152+ lw = len (strconv .Itoa (len (lines )))
153+ w = w + lw * ws
154+ }
155+ return w , h * fontSize , lw
128156}
129157
130158type pngFormat struct {
159+ fontSize int
131160 width , height int
161+ lineWidth int
162+ printLine bool
132163}
133164
134165func (p * pngFormat ) Format (w io.Writer , style * chroma.Style , iterator chroma.Iterator ) error {
@@ -146,7 +177,7 @@ func (p *pngFormat) Format(w io.Writer, style *chroma.Style, iterator chroma.Ite
146177 }
147178
148179 opt := truetype.Options {
149- Size : 20 ,
180+ Size : float64 ( p . fontSize ) ,
150181 }
151182 face := truetype .NewFace (ft , & opt )
152183
@@ -162,9 +193,33 @@ func (p *pngFormat) Format(w io.Writer, style *chroma.Style, iterator chroma.Ite
162193 Face : face ,
163194 }
164195
196+ // width, height padding
165197 padding := 2
166- x := fixed .Int26_6 (padding )
167- y := fixed .Int26_6 (2 )
198+
199+ // draw line
200+ if p .printLine {
201+ i := 1
202+ if bg .Brightness () < 0.5 {
203+ dr .Src = image .NewUniform (color .White )
204+ } else {
205+ dr .Src = image .NewUniform (color .Black )
206+ }
207+
208+ lx := fixed .Int26_6 (padding )
209+
210+ lm := p .height / p .fontSize - 2 // remove font size
211+ for i < lm {
212+ dr .Dot .X = fixed .I (10 ) * lx
213+ dr .Dot .Y = fixed .I (p .fontSize ) * fixed .Int26_6 (i + 1 )
214+ dr .DrawString (strconv .Itoa (i ))
215+ i ++
216+ }
217+ }
218+
219+ // draw source code
220+ ox := fixed .Int26_6 (p .lineWidth + 3 )
221+ x := ox
222+ y := fixed .Int26_6 (padding )
168223
169224 for _ , t := range iterator .Tokens () {
170225 s := style .Get (t .Type )
@@ -182,15 +237,15 @@ func (p *pngFormat) Format(w io.Writer, style *chroma.Style, iterator chroma.Ite
182237
183238 for _ , c := range t .String () {
184239 if c == '\n' {
185- x = fixed . Int26_6 ( padding )
240+ x = ox
186241 y ++
187242 continue
188243 } else if c == '\t' {
189- x += fixed .Int26_6 (padding )
244+ x += fixed .Int26_6 (4 )
190245 continue
191246 }
192247 dr .Dot .X = fixed .I (10 ) * x
193- dr .Dot .Y = fixed .I (20 ) * y
248+ dr .Dot .Y = fixed .I (p . fontSize ) * y
194249 s := fmt .Sprintf ("%c" , c )
195250 dr .DrawString (s )
196251
@@ -206,10 +261,10 @@ func (p *pngFormat) Format(w io.Writer, style *chroma.Style, iterator chroma.Ite
206261 return png .Encode (w , img )
207262}
208263
209- func toImg (useClipboard bool , source , outFile string , lexer , style string ) error {
210- l := lexers .Get (lexer )
264+ func toImg (opt options ) error {
265+ l := lexers .Get (opt . ext )
211266 if l == nil {
212- l = lexers .Analyse (source )
267+ l = lexers .Analyse (opt . source )
213268 }
214269 if l == nil {
215270 l = lexers .Fallback
@@ -221,12 +276,12 @@ func toImg(useClipboard bool, source, outFile string, lexer, style string) error
221276 f = formatters .Fallback
222277 }
223278
224- s := styles .Get (style )
279+ s := styles .Get (opt . theme )
225280 if s == nil {
226281 s = styles .Fallback
227282 }
228283
229- it , err := l .Tokenise (nil , source )
284+ it , err := l .Tokenise (nil , opt . source )
230285 if err != nil {
231286 return err
232287 }
@@ -237,7 +292,7 @@ func toImg(useClipboard bool, source, outFile string, lexer, style string) error
237292 return err
238293 }
239294
240- if useClipboard {
295+ if opt . useClipboard {
241296 return clipboard .CopyToClipboard (buf )
242297 }
243298
@@ -249,7 +304,7 @@ func toImg(useClipboard bool, source, outFile string, lexer, style string) error
249304 if _ , err := io .Copy (tmp , buf ); err != nil {
250305 return err
251306 }
252-
253307 tmp .Close ()
254- return os .Rename (tmp .Name (), outFile )
308+
309+ return os .Rename (tmp .Name (), opt .output )
255310}
0 commit comments