all repos — captcha @ 874a3063edcad5646202f788b87b3a2901c5ebd6

Go package captcha implements generation and verification of image and audio CAPTCHAs.

Rearrange code and fix docs.
Dmitry Chestnykh dmitry@codingrobots.com
Sat, 23 Apr 2011 21:20:12 +0200
commit

874a3063edcad5646202f788b87b3a2901c5ebd6

parent

8b932fcfbb9e93f8dbdef6b8f4eba58448af76c3

2 files changed, 95 insertions(+), 91 deletions(-)

jump to
M audio.goaudio.go

@@ -18,6 +18,89 @@ longestNumSndLen int

endingBeepSound []byte ) +func init() { + for _, v := range numberSounds { + if longestNumSndLen < len(v) { + longestNumSndLen = len(v) + } + } + endingBeepSound = changeSpeed(beepSound, 1.4) +} + +type Audio struct { + body *bytes.Buffer +} + +// NewImage returns a new audio captcha with the given slice of numbers, where +// each number must be in range 0-9. +func NewAudio(numbers []byte) *Audio { + numsnd := make([][]byte, len(numbers)) + nsdur := 0 + for i, n := range numbers { + snd := randomizedNumSound(n) + nsdur += len(snd) + numsnd[i] = snd + } + // Intervals between numbers (including beginning) + intervals := make([]int, len(numbers)+1) + intdur := 0 + for i := range intervals { + // 1 to 3 seconds + dur := rnd(sampleRate, sampleRate*3) + intdur += dur + intervals[i] = dur + } + // Background noise + bg := makeBackgroundSound(longestNumSndLen*len(numbers) + intdur) + // -- + a := new(Audio) + a.body = bytes.NewBuffer(nil) + // Prelude, three beeps + sil := makeSilence(sampleRate / 5) + a.body.Write(beepSound) + a.body.Write(sil) + a.body.Write(beepSound) + a.body.Write(sil) + a.body.Write(beepSound) + // Numbers + pos := intervals[0] + for i, v := range numsnd { + mixSound(bg[pos:], v) + pos += len(v) + intervals[i+1] + } + a.body.Write(bg) + // Ending + a.body.Write(endingBeepSound) + return a +} + +// NewRandomAudio generates a sequence of random numbers with the given length, +// and returns a new audio captcha with this numbers, and the sequence of +// numbers itself. +func NewRandomAudio(length int) (a *Audio, numbers []byte) { + numbers = randomNumbers(length) + a = NewAudio(numbers) + return +} + +// WriteTo writes captcha audio in WAVE format into the given io.Writer, and +// returns the number of bytes written and an error if any. +func (a *Audio) WriteTo(w io.Writer) (n int64, err os.Error) { + nn, err := w.Write(waveHeader) + n = int64(nn) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, uint32(a.body.Len())) + if err != nil { + return + } + nn += 4 + n, err = a.body.WriteTo(w) + n += int64(nn) + return +} + // mixSound mixes src into dst. Dst must have length equal to or greater than // src length. func mixSound(dst, src []byte) {

@@ -123,84 +206,3 @@ s := randomSpeed(numberSounds[n])

setSoundLevel(s, rndFloat64n(0.7, 1.3)) return s } - -func init() { - for _, v := range numberSounds { - if longestNumSndLen < len(v) { - longestNumSndLen = len(v) - } - } - endingBeepSound = changeSpeed(beepSound, 1.4) -} - -type Audio struct { - body *bytes.Buffer -} - -func NewAudio(numbers []byte) *Audio { - numsnd := make([][]byte, len(numbers)) - nsdur := 0 - for i, n := range numbers { - snd := randomizedNumSound(n) - nsdur += len(snd) - numsnd[i] = snd - } - // Intervals between numbers (including beginning) - intervals := make([]int, len(numbers)+1) - intdur := 0 - for i := range intervals { - // 1 to 3 seconds - dur := rnd(sampleRate, sampleRate*3) - intdur += dur - intervals[i] = dur - } - // Background noise - bg := makeBackgroundSound(longestNumSndLen*len(numbers) + intdur) - // -- - a := new(Audio) - a.body = bytes.NewBuffer(nil) - // Prelude, three beeps - sil := makeSilence(sampleRate / 5) - a.body.Write(beepSound) - a.body.Write(sil) - a.body.Write(beepSound) - a.body.Write(sil) - a.body.Write(beepSound) - // Numbers - pos := intervals[0] - for i, v := range numsnd { - mixSound(bg[pos:], v) - pos += len(v) + intervals[i+1] - } - a.body.Write(bg) - // Ending - a.body.Write(endingBeepSound) - return a -} - -// NewRandomAudio generates a sequence of random numbers with the given length, -// and returns a new audio captcha with this numbers, and the sequence of -// numbers itself. -func NewRandomAudio(length int) (a *Audio, numbers []byte) { - numbers = randomNumbers(length) - a = NewAudio(numbers) - return -} - -// WriteTo writes captcha audio in WAVE format into the given io.Writer, and -// returns the number of bytes written and an error if any. -func (a *Audio) WriteTo(w io.Writer) (n int64, err os.Error) { - nn, err := w.Write(waveHeader) - n = int64(nn) - if err != nil { - return - } - err = binary.Write(w, binary.LittleEndian, uint32(a.body.Len())) - if err != nil { - return - } - nn += 4 - n, err = a.body.WriteTo(w) - n += int64(nn) - return -}
M captcha.gocaptcha.go

@@ -34,21 +34,23 @@ globalStore.saveCaptcha(id, randomNumbers(length))

return } -// Reload generates new numbers for the given captcha id. This function does -// nothing if there is no captcha with the given id. +// Reload generates and remembers new numbers for the given captcha id. This +// function returns false if there is no captcha with the given id. // -// After calling this function, the image presented to a user must be refreshed -// to show the new captcha (WriteImage will write the new one). -func Reload(id string) { +// After calling this function, the image or audio presented to a user must be +// refreshed to show the new captcha representation (WriteImage and WriteAudio +// will write the new one). +func Reload(id string) bool { oldns := globalStore.getNumbers(id) if oldns == nil { - return + return false } globalStore.saveCaptcha(id, randomNumbers(len(oldns))) + return true } -// WriteImage writes PNG-encoded captcha image of the given width and height -// with the given captcha id into the io.Writer. +// WriteImage writes PNG-encoded image representation of the captcha with the +// given id. The image will have the given width and height. func WriteImage(w io.Writer, id string, width, height int) os.Error { ns := globalStore.getNumbers(id) if ns == nil {

@@ -58,8 +60,8 @@ _, err := NewImage(ns, width, height).WriteTo(w)

return err } -// WriteAudio writes WAV-encoded audio captcha with the given captcha id into -// the given io.Writer. +// WriteAudio writes WAV-encoded audio representation of the captcha with the +// given id. func WriteAudio(w io.Writer, id string) os.Error { ns := globalStore.getNumbers(id) if ns == nil {