JohnBeckett (talk | contribs) (→Comments: thanks) |
(Change <tt> to <code>, perhaps also minor tweak.) |
||
(17 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{TipNew |
||
− | {{TipProposed |
||
− | |id= |
+ | |id=1629 |
− | |previous= |
+ | |previous=1628 |
− | |next= |
+ | |next=1630 |
− | |created= |
+ | |created=2009 |
|complexity=basic |
|complexity=basic |
||
|author=Michael.Eriksson |
|author=Michael.Eriksson |
||
Line 11: | Line 11: | ||
|category2= |
|category2= |
||
}} |
}} |
||
+ | Why use an image editor when you can create a [[wikipedia:Favicon|favicon]] using Vim ''and'' have WYSIWYG editing? This tip shows a Vim script to generate a [[wikipedia:Netpbm format|portable pixmap format (PPM)]] text file that can be used to create an icon using a tool such as [[wikipedia:Netpbm|Netpbm]]. In addition, syntax commands are provided that highlight the source text file to give WYSIWYG editing (the screen shows how the icon will appear while the text is edited). |
||
− | I recently found myself in want of a favicon. Not wanting to mess around with typical WYSIWYG editors, I wrote a Bash script that generated a PPM file based on a data matrix corresponding to the individual pixels of the eventual favicon. By applying syntax highlightning to the data matrix, I effectively had a WYSIWYG display of the eventual image within Vim. |
||
+ | ==Procedure== |
||
− | The true favicon was a five color, 32x32 matrix, mixing the Swedish and German flags (that I indeed did some extensive editing on, trying a number of variations). The below gives a simplified version using a 7x5 Swedish flag with two colors. |
||
+ | As a simple example, an icon for a Swedish flag will be created. Make a file called <code>flag.txt</code> containing the following (the letters following "data" define the colors, other lines are ignored; <code>B</code> = blue and <code>Y</code> = yellow): |
||
+ | <pre> |
||
+ | Sample data for a 16x10 flag of Sweden. |
||
+ | data B B B B B Y Y B B B B B B B B B |
||
− | ==Bash script== |
||
+ | data B B B B B Y Y B B B B B B B B B |
||
− | (output to be directed into a .ppm file): |
||
+ | data B B B B B Y Y B B B B B B B B B |
||
+ | data B B B B B Y Y B B B B B B B B B |
||
+ | data Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y |
||
+ | data Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y |
||
+ | data B B B B B Y Y B B B B B B B B B |
||
+ | data B B B B B Y Y B B B B B B B B B |
||
+ | data B B B B B Y Y B B B B B B B B B |
||
+ | data B B B B B Y Y B B B B B B B B B |
||
+ | </pre> |
||
+ | Make a file called <code>append-colors.vim</code> containing this Vim script: |
||
<pre> |
<pre> |
||
+ | " Basic colors from $VIMRUNTIME/rgb.txt |
||
− | #!/bin/bash -u |
||
− | + | let colors = { |
|
− | k |
+ | \ 'k' : '0 0 0', |
− | b |
+ | \ 'b' : '0 0 139', |
− | g |
+ | \ 'g' : '0 100 0', |
− | c |
+ | \ 'c' : '0 139 139', |
− | r |
+ | \ 'r' : '139 0 0', |
− | m |
+ | \ 'm' : '139 0 139', |
− | y |
+ | \ 'y' : '165 42 42', |
− | w |
+ | \ 'w' : '211 211 211', |
− | K |
+ | \ 'K' : '169 169 169', |
− | B |
+ | \ 'B' : '0 0 255', |
− | G |
+ | \ 'G' : '0 255 0', |
− | C |
+ | \ 'C' : '0 255 255', |
− | R |
+ | \ 'R' : '255 0 0', |
− | M |
+ | \ 'M' : '255 0 255', |
− | Y |
+ | \ 'Y' : '255 255 0', |
− | W |
+ | \ 'W' : '255 255 255'} |
+ | " Append lines to current buffer consisting of header (three lines): |
||
− | function outputLine() { |
||
− | + | " 'P3' = PPM (full color; numbers in ASCII decimal) |
|
+ | " width height (two numbers) |
||
− | do |
||
+ | " color_depth (one number) |
||
− | eval echo "\$$color" |
||
+ | " then lines from translating each input letter to its color triple. |
||
− | done |
||
+ | " We translate only the letters that follow "data" at the start of a line. |
||
− | } |
||
+ | " Width = number of letters in first data item; height = number data items. |
||
+ | function! AppendColors(data_file) abort |
||
+ | let data = readfile(a:data_file) |
||
+ | call filter(data, 'v:val=~#''^data\s''') |
||
+ | call map(data, 'split(v:val)[1:]') |
||
+ | let width_height = printf('%d %d', len(data[0]), len(data)) |
||
+ | call append(line('$'), ['P3', width_height, '255']) |
||
+ | for columns in data |
||
+ | call map(columns, 'g:colors[v:val]') |
||
+ | call append(line('$'), columns) |
||
+ | endfor |
||
+ | endfunction |
||
+ | command! -nargs=1 -complete=file AppendColors call AppendColors('<args>') |
||
+ | </pre> |
||
+ | In Vim, enter the following commands to generate the output file: |
||
− | # PNM header |
||
+ | <pre> |
||
− | # P1=PBM (B&W) P2=PGM (greyscale) P3=PMM (full-color) P4-P7=binary |
||
+ | :so append-colors.vim |
||
− | echo 'P3' |
||
+ | :new |
||
− | # width / height |
||
+ | :AppendColors flag.txt |
||
− | echo '7 5' |
||
+ | :w flag.ppm |
||
− | # color depth |
||
+ | </pre> |
||
− | echo '255' |
||
+ | The above commands creates file <code>flag.ppm</code> by translating the letters in <code>flag.txt</code> to the color code numbers defined in the <code>colors</code> dictionary in the script. The script reads the file into a list called <code>data</code>, then filters the list, keeping only the lines that start with "data" followed by a space or a tab character. Each element in the list (a data line) is then split into a list of whitespace-separated words, but the first word ("data") is omitted. The width and height of the icon are then determined from the number of columns and rows in the data. Then the ppm output data is appended to the current buffer. |
||
− | # The below is the colored matrix. (Could be in a separate file.) |
||
+ | |||
− | outputLine B B Y B B B B |
||
+ | With the Netpbm tools installed, you can create an icon file (say <code>flag.ico</code>) using: |
||
− | outputLine B B Y B B B B |
||
+ | <pre> |
||
− | outputLine Y Y Y Y Y Y Y |
||
+ | ppmtowinicon -output=flag.ico flag.ppm |
||
− | outputLine B B Y B B B B |
||
− | outputLine B B Y B B B B |
||
</pre> |
</pre> |
||
+ | ==WYSIWYG editing== |
||
− | ==Vim syntax script== |
||
+ | Edit file <code>flag.txt</code> and enter the following commands: |
||
− | to apply to bash scripts such as the above |
||
+ | <pre> |
||
+ | :syntax clear |
||
+ | :syntax match Yellow " Y" |
||
+ | :syntax match Blue " B" |
||
+ | :highlight Yellow guibg=#FFFF00 guifg=#FFFF00 |
||
+ | :highlight Blue guibg=#006FFD guifg=#006FFD |
||
+ | </pre> |
||
+ | That will highlight "<code> Y</code>" (space then <code>Y</code>) in yellow, and "<code> B</code>" (space then <code>B</code>) in blue. The colors are solid (foreground = background). |
||
+ | An easy way to enter the commands would be to save the above lines in file <code>flag-syntax.vim</code>, then edit <code>flag.txt</code> and enter the command: |
||
+ | <pre> |
||
+ | :so flag-syntax.vim |
||
+ | </pre> |
||
+ | |||
+ | To clear the highlighting, enter: |
||
+ | <pre> |
||
+ | :syntax clear |
||
+ | </pre> |
||
+ | |||
+ | ==WYSIWYG editing with full-featured syntax file== |
||
+ | An alternative to the above simple syntax commands would be to source the following syntax script while editing <code>flag.txt</code>: |
||
<pre> |
<pre> |
||
if version < 600 |
if version < 600 |
||
syntax clear |
syntax clear |
||
− | elseif exists(b:current_syntax) |
+ | elseif exists('b:current_syntax') |
finish |
finish |
||
endif |
endif |
||
+ | runtime! syntax/sh.vim |
||
⚫ | |||
+ | unlet b:current_syntax |
||
+ | |||
⚫ | |||
\ matchgroup=ppmKeyword |
\ matchgroup=ppmKeyword |
||
\ keepend |
\ keepend |
||
− | \ start=/^ |
+ | \ start=/^data\>/ |
\ end=/$/ |
\ end=/$/ |
||
\ contains=ppmBlack,ppmDarkblue,ppmDarkgreen,ppmDarkcyan,ppmDarkred,ppmDarkmagenta, |
\ contains=ppmBlack,ppmDarkblue,ppmDarkgreen,ppmDarkcyan,ppmDarkred,ppmDarkmagenta, |
||
Line 97: | Line 146: | ||
syn match ppmWhite /\C W/ contained |
syn match ppmWhite /\C W/ contained |
||
+ | if version >= 508 || !exists('did_ppm_syntax_inits') |
||
⚫ | |||
+ | if version < 508 |
||
⚫ | |||
+ | let did_ppm_syntax_inits = 1 |
||
⚫ | |||
+ | command -nargs=+ HiSet hi <args> |
||
⚫ | |||
+ | else |
||
⚫ | |||
+ | command -nargs=+ HiSet hi def <args> |
||
− | hi def ppmDarkmagenta ctermbg=DarkMagenta ctermfg=LightGrey guibg=darkmagenta guifg=white |
||
+ | endif |
||
⚫ | |||
− | + | HiSet ppmBlack ctermbg=Black ctermfg=LightGrey guibg=black guifg=white |
|
− | + | HiSet ppmDarkblue ctermbg=DarkBlue ctermfg=LightGrey guibg=darkblue guifg=white |
|
− | + | HiSet ppmDarkGreen ctermbg=DarkGreen ctermfg=LightGrey guibg=darkgreen guifg=white |
|
− | + | HiSet ppmDarkCyan ctermbg=DarkCyan ctermfg=LightGrey guibg=darkcyan guifg=white |
|
− | + | HiSet ppmDarkRed ctermbg=DarkRed ctermfg=LightGrey guibg=darkred guifg=white |
|
− | + | HiSet ppmDarkmagenta ctermbg=DarkMagenta ctermfg=LightGrey guibg=darkmagenta guifg=white |
|
− | + | HiSet ppmBrown ctermbg=Brown ctermfg=LightGrey guibg=brown guifg=white |
|
− | + | HiSet ppmLightgrey ctermbg=LightGrey ctermfg=Black guibg=lightgrey guifg=black |
|
⚫ | |||
⚫ | |||
⚫ | |||
+ | HiSet ppmRed ctermbg=Red ctermfg=White guibg=red guifg=black |
||
⚫ | |||
⚫ | |||
⚫ | |||
− | + | HiSet link ppmKeyword Keyword |
|
+ | delcommand HiSet |
||
+ | endif |
||
+ | let b:current_syntax = "ppm" |
||
</pre> |
</pre> |
||
− | |||
− | A [http://www.aswedeingermany.de/50MetaInformation/50Favicon.html much larger write-up] with the full examples and some screen-shots is available. (I hope that the size justifies the external link.) The above should suffice to reproduce everything, however. |
||
− | |||
− | ==Notes== |
||
− | The above can be adapted (trivially) to PBM which has only black and white pixels, and (easily) to PGM greyscale where each pixel is defined by one number (a grey value on a linear scale) |
||
==See also== |
==See also== |
||
+ | *[http://www.aswedeingermany.de/50MetaInformation/50Favicon.html Larger example] using a bash script, with screen shots |
||
− | * [http://en.wikipedia.org/wiki/Netpbm Netpbm] (Wikipedia) |
||
− | * [http://en.wikipedia.org/wiki/Netpbm_format Netpbm format] (Wikipedia) |
||
==Comments== |
==Comments== |
||
− | '''TODO:''' |
||
− | * Include "sh" syntax for lines other than "outputline" |
||
− | * Foreground: same as bg (for solid colors) or distinct from bg (to facilitate editing)? |
||
− | ---- |
||
− | Due to my editing, this "tip" has become a "software package" with a bash script and a Vim syntax script. Maybe move to a subpage? --[[User:Tonymec|Tonymec]] 07:37, 27 August 2009 (UTC) |
||
− | :Thanks Tony, that's great. I think a few tricky and long tips are fine, so I would not put this on a subpage. I might reword the introduction so the big picture is somewhat clearer, and perhaps start with a very simple example, before any scripting is shown. We would just have a table of letters and the original :syntax statements, so people could easily see (in Vim) how a simple flag appears. |
||
− | :Can you please add a few words (here or in the tip) saying what your tricky syntax code achieves, compared with the original (bearing in mind that I know almost nothing about syntax files). We should not try to explain the details here, but roughly, what is being achieved with the "syn region..." and "contained" stuff? |
||
− | :It occurs to me that we could eliminate the bash script with some creative Vim coding ... not very important, but it might be interesting. [[User:JohnBeckett|JohnBeckett]] 08:53, 27 August 2009 (UTC) |
Latest revision as of 06:40, 13 July 2012
created 2009 · complexity basic · author Michael.Eriksson · version 7.0
Why use an image editor when you can create a favicon using Vim and have WYSIWYG editing? This tip shows a Vim script to generate a portable pixmap format (PPM) text file that can be used to create an icon using a tool such as Netpbm. In addition, syntax commands are provided that highlight the source text file to give WYSIWYG editing (the screen shows how the icon will appear while the text is edited).
Procedure[]
As a simple example, an icon for a Swedish flag will be created. Make a file called flag.txt
containing the following (the letters following "data" define the colors, other lines are ignored; B
= blue and Y
= yellow):
Sample data for a 16x10 flag of Sweden. data B B B B B Y Y B B B B B B B B B data B B B B B Y Y B B B B B B B B B data B B B B B Y Y B B B B B B B B B data B B B B B Y Y B B B B B B B B B data Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y data Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y data B B B B B Y Y B B B B B B B B B data B B B B B Y Y B B B B B B B B B data B B B B B Y Y B B B B B B B B B data B B B B B Y Y B B B B B B B B B
Make a file called append-colors.vim
containing this Vim script:
" Basic colors from $VIMRUNTIME/rgb.txt let colors = { \ 'k' : '0 0 0', \ 'b' : '0 0 139', \ 'g' : '0 100 0', \ 'c' : '0 139 139', \ 'r' : '139 0 0', \ 'm' : '139 0 139', \ 'y' : '165 42 42', \ 'w' : '211 211 211', \ 'K' : '169 169 169', \ 'B' : '0 0 255', \ 'G' : '0 255 0', \ 'C' : '0 255 255', \ 'R' : '255 0 0', \ 'M' : '255 0 255', \ 'Y' : '255 255 0', \ 'W' : '255 255 255'} " Append lines to current buffer consisting of header (three lines): " 'P3' = PPM (full color; numbers in ASCII decimal) " width height (two numbers) " color_depth (one number) " then lines from translating each input letter to its color triple. " We translate only the letters that follow "data" at the start of a line. " Width = number of letters in first data item; height = number data items. function! AppendColors(data_file) abort let data = readfile(a:data_file) call filter(data, 'v:val=~#''^data\s''') call map(data, 'split(v:val)[1:]') let width_height = printf('%d %d', len(data[0]), len(data)) call append(line('$'), ['P3', width_height, '255']) for columns in data call map(columns, 'g:colors[v:val]') call append(line('$'), columns) endfor endfunction command! -nargs=1 -complete=file AppendColors call AppendColors('<args>')
In Vim, enter the following commands to generate the output file:
:so append-colors.vim :new :AppendColors flag.txt :w flag.ppm
The above commands creates file flag.ppm
by translating the letters in flag.txt
to the color code numbers defined in the colors
dictionary in the script. The script reads the file into a list called data
, then filters the list, keeping only the lines that start with "data" followed by a space or a tab character. Each element in the list (a data line) is then split into a list of whitespace-separated words, but the first word ("data") is omitted. The width and height of the icon are then determined from the number of columns and rows in the data. Then the ppm output data is appended to the current buffer.
With the Netpbm tools installed, you can create an icon file (say flag.ico
) using:
ppmtowinicon -output=flag.ico flag.ppm
WYSIWYG editing[]
Edit file flag.txt
and enter the following commands:
:syntax clear :syntax match Yellow " Y" :syntax match Blue " B" :highlight Yellow guibg=#FFFF00 guifg=#FFFF00 :highlight Blue guibg=#006FFD guifg=#006FFD
That will highlight " Y
" (space then Y
) in yellow, and " B
" (space then B
) in blue. The colors are solid (foreground = background).
An easy way to enter the commands would be to save the above lines in file flag-syntax.vim
, then edit flag.txt
and enter the command:
:so flag-syntax.vim
To clear the highlighting, enter:
:syntax clear
WYSIWYG editing with full-featured syntax file[]
An alternative to the above simple syntax commands would be to source the following syntax script while editing flag.txt
:
if version < 600 syntax clear elseif exists('b:current_syntax') finish endif runtime! syntax/sh.vim unlet b:current_syntax syn region ppmData \ matchgroup=ppmKeyword \ keepend \ start=/^data\>/ \ end=/$/ \ contains=ppmBlack,ppmDarkblue,ppmDarkgreen,ppmDarkcyan,ppmDarkred,ppmDarkmagenta, \ppmBrown,ppmLightgrey,ppmDarkgrey,ppmBlue,ppmGreen,ppmCyan,ppmRed,ppmMagenta, \ppmYellow,ppmWhite syn match ppmBlack /\C k/ contained syn match ppmDarkblue /\C b/ contained syn match ppmDarkgreen /\C g/ contained syn match ppmDarkcyan /\C c/ contained syn match ppmDarkred /\C r/ contained syn match ppmDarkmagenta /\C m/ contained syn match ppmBrown /\C y/ contained syn match ppmLightgrey /\C w/ contained syn match ppmDarkgrey /\C K/ contained syn match ppmBlue /\C B/ contained syn match ppmGreen /\C G/ contained syn match ppmRed /\C R/ contained syn match ppmMagenta /\C M/ contained syn match ppmYellow /\C Y/ contained syn match ppmWhite /\C W/ contained if version >= 508 || !exists('did_ppm_syntax_inits') if version < 508 let did_ppm_syntax_inits = 1 command -nargs=+ HiSet hi <args> else command -nargs=+ HiSet hi def <args> endif HiSet ppmBlack ctermbg=Black ctermfg=LightGrey guibg=black guifg=white HiSet ppmDarkblue ctermbg=DarkBlue ctermfg=LightGrey guibg=darkblue guifg=white HiSet ppmDarkGreen ctermbg=DarkGreen ctermfg=LightGrey guibg=darkgreen guifg=white HiSet ppmDarkCyan ctermbg=DarkCyan ctermfg=LightGrey guibg=darkcyan guifg=white HiSet ppmDarkRed ctermbg=DarkRed ctermfg=LightGrey guibg=darkred guifg=white HiSet ppmDarkmagenta ctermbg=DarkMagenta ctermfg=LightGrey guibg=darkmagenta guifg=white HiSet ppmBrown ctermbg=Brown ctermfg=LightGrey guibg=brown guifg=white HiSet ppmLightgrey ctermbg=LightGrey ctermfg=Black guibg=lightgrey guifg=black HiSet ppmDarkgrey ctermbg=DarkGrey ctermfg=White guibg=darkgrey guifg=white HiSet ppmBlue ctermbg=Blue ctermfg=White guibg=blue guifg=white HiSet ppmCyan ctermbg=Cyan ctermfg=DarkGrey guibg=cyan guifg=white HiSet ppmRed ctermbg=Red ctermfg=White guibg=red guifg=black HiSet ppmMagenta ctermbg=Magenta ctermfg=White guibg=magenta guifg=black HiSet ppmYellow ctermbg=Yellow ctermfg=DarkGrey guibg=yellow guifg=black HiSet ppmWhite ctermbg=White ctermfg=DarkGrey guibg=white guifg=black HiSet link ppmKeyword Keyword delcommand HiSet endif let b:current_syntax = "ppm"
See also[]
- Larger example using a bash script, with screen shots