Skip to content

Commit

Permalink
Merge pull request #19 from DarrenN/ui
Browse files Browse the repository at this point in the history
1.0.0 Release
  • Loading branch information
DarrenN committed Oct 5, 2015
2 parents 8287142 + 20a8a11 commit 6d7c876
Show file tree
Hide file tree
Showing 7 changed files with 407 additions and 125 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [1.0.0] - 2015-10-04
### Changed
- Significant changes to API for `identikon`. Please see updated documentation. Related to [#16](https://github.com/DarrenN/identikon/issues/16)
- Two new functions provided: `save-identikon`, `identikon->string`. Related to [#15](https://github.com/DarrenN/identikon/issues/15)
- `identikon` can now take a file as input via the `#:filename` flag.
- Added tests, dealt with weird errors in test submod w/ quickcheck
- Updated documentation

### Fixed
- [#18](https://github.com/DarrenN/identikon/issues/18) Contract-violation when saving identikon to file
2 changes: 1 addition & 1 deletion info.rkt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#lang info
(define collection "identikon")
(define version "0.2")
(define version "1.0.0")
(define scribblings '(("scribblings/identikon.scrbl" ())))
(define deps '("base"
"sugar"
Expand Down
193 changes: 116 additions & 77 deletions main.rkt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#lang racket/base

; Identikon - parses username into a sha1-based identifier list and
; interfaces with rule-sets to create identicon image
;; Identikon - parses username into a sha1-based identifier list and
;; interfaces with rule-sets to create identicon image

(require racket/date
racket/list
Expand All @@ -11,26 +11,33 @@
openssl/sha1
2htdp/image
sugar
identikon/utils)
identikon/utils
identikon/transforms)

(provide (contract-out [identikon (->* (exact-positive-integer?
exact-positive-integer?
any/c)
(string?
(or/c boolean? string?))
image?)]))

; ———————————
; implementation

; Identifier we overwrite dynamically with module functions
((or/c string? symbol?)
#:filename boolean?)
image?)]
[save-identikon (->* (string?
(or/c symbol? string?)
image?)
(#:quality number?)
boolean?)]
[identikon->string (->* (image?
(or/c symbol? string?))
(#:quality number?)
string?)]))

;; Identifier we overwrite dynamically with module functions
(define draw-rules null)

(define-namespace-anchor a)

(define-runtime-path RULES-DIR "rules")

; Dynamically load in a rules file
;; Dynamically load in a rules file
(define (load-plug-in file)
(let ([ns (make-base-empty-namespace)]
[filename (build-path RULES-DIR file)])
Expand All @@ -40,76 +47,95 @@
(parameterize ([current-namespace ns])
(dynamic-require filename 'draw-rules))))

; Create a filename and check if the file already exists, if so
; append a timestamp
;; Create a filename and check if the file already exists, if so
;; append a timestamp
(define (make-filename name size extension)
(let* ([ext (string-join (list "." extension) "")]
[sizename (string-join (list name (number->string size)) "_")]
(let* ([ext (format ".~a" (->string extension))]
[sizename (format "~a_~a" (->string name) (number->string size))]
[filename (string-join (list sizename ext) "")])
(if (file-exists? filename)
(string-join (list sizename "_" (number->string (date->seconds (current-date))) ext) "")
(string-join
(list sizename "_"
(number->string (date->seconds (current-date))) ext) "")
filename)))

; Save the file based on type - png or svg
(define (save-identicon filename type rendered)
(cond
[(string=? "svg" type) (save-svg-image rendered filename)]
[(string=? "png" type) (save-image rendered filename)]
[else (error 'save-identicon "failed because could not not save file type of ~a" type)]))

; Turn a SHA1 hash into a list of 20 base 10 numbers
(define (process-user user)
(let [(str (if (string? user)
user
(->string user)))]
(map (λ (x) (string->number x 16))
(string-pairs (sha1 (open-input-bytes (string->bytes/utf-8 str)))))))

; Identikon - build an identicon of a specific size based on username and
; using a rule-set. Will automatically drop the identicon in the repl unless
; you tell it to save
;
; ex: ;(identikon 300 300 "dfsdf")
;
(define (identikon width height username [rules "default"] [type #f])
(let* ([processed-user (process-user username)]
[rule-file (string-join (list rules "rkt") ".")])

; Load rules file if provided
;; Save the file based on type - png, jpeg or svg
(define (save-identikon filename type image #:quality [quality 75])
(let* ([ext (->string type)]
[path (make-filename filename (image-width image) ext)])
(cond
[(string=? "svg" ext) (save-svg image path)]
[(string=? "png" ext) (save-bitmap image path)]
[(string=? "jpeg" ext) (save-bitmap image path 'jpeg #:quality quality)]
[else (error 'save-identicon
"failed because could not not save file type of ~a" type)])))

;; Output the image as a string representation
;; (svg as xml, png/jpeg as base64 bytes)
(define (identikon->string type image #:quality [quality 75])
(let* ([ext (->string type)])
(cond
[(string=? "svg" ext) (image->svg-string image)]
[(or (string=? "png" ext) (string=? "jpeg" ext))
(image->bitmap-string image type quality)]
[else (error 'identikon->string "~a is not a valid image type" ext)])))

;; Convert a symbol or string into a rules filename
(define (create-rules-filename rules)
(let ([root (if (string? rules)
rules
(->string rules))])
(format "~a.rkt" rules)))

#|
Identikon - build an identicon of a specific size based on username and
using a rule-set. Will automatically drop the identicon in the repl unless
you tell it to save
ex: (identikon 300 300 "dfsdf")
(identikon 300 300 'dfsdf 'qbert)
|#
(define (identikon width height input
[rules "default"] #:filename [filename #f])
(let* ([processed-input (if filename
(file->numberlist input)
(string->numberlist input))]
[rule-file (create-rules-filename rules)])

;; Load rules file if provided
(set! draw-rules (load-plug-in rule-file))

; Create identicon
(define rendered (draw-rules width height processed-user))
;; Create identicon
(define rendered (draw-rules width height processed-input))

; Either save the identicon or output to REPL
(if type
(save-identicon (make-filename username width type) type rendered)
rendered)))
;; Return identikon (image)
rendered))

(module+ test
(require quickcheck
(require rackunit
sugar
2htdp/image)

; Ensure we get a list of 20 values
(define process-user-lengths-agree
(property ([val (choose-mixed (list (choose-integer 1 (random 10000)) (choose-string choose-printable-ascii-char (random 100))))])
(= 20 (length (process-user val)))))
(test-case
"create-rules-filename will append .rkt to anything that can be stringed"
(check-regexp-match ".rkt" (create-rules-filename "rza"))
(check-regexp-match ".rkt" (create-rules-filename 'wutang))
(check-regexp-match ".rkt" (create-rules-filename 187)))

(quickcheck process-user-lengths-agree)
(test-case
"identikon returns an image"
(check-pred image? (identikon 100 100 'rza)))

; Ensure identikon returns images
; !! Warning: this is computationally expensive as it generates 100
; !! identicons
(define identikon-images-agree
(property ([dim arbitrary-natural]
[str arbitrary-printable-ascii-string])
(image? (identikon dim dim str))))

(quickcheck identikon-images-agree))
(test-case
"identikon->string returns a string"
(check-pred string? (identikon->string 'jpeg (identikon 100 100 'rza)))
(check-pred string? (identikon->string 'png (identikon 100 100 'rza)))
(check-pred string? (identikon->string 'svg (identikon 100 100 'rza)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command line handling for Identikon
;; Command line handling for Identikon
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(module+ main
Expand All @@ -118,16 +144,21 @@

(define size-flags (make-parameter null))
(define rules-set (make-parameter '("default")))
(define name (make-parameter null))
(define input-str (make-parameter null))
(define file-name (make-parameter null))
(define ext (make-parameter "png"))

(define make-identikon
(command-line
#:program "identikon"
#:once-each
[("-n" "--name") nm
"Username to convert to identikon"
(name nm)]
[("-i" "--input-str") in
"String input-str to convert to identikon"
(input-str in)]

[("-f" "--file") fl
"File or input stream used to generate identikon"
(file-name fl)]

[("-t" "--type") ty
"File type: png or svg"
Expand All @@ -139,16 +170,24 @@

#:multi
[("-s" "--size") sz
"Add a square size to generate"
"Add a square size(s) to generate. You can create multiple sizes."
(size-flags (cons sz (size-flags)))]))

(cond
[(and (empty? (size-flags)) (empty? (name))) (printf "No information provided ~n")]
[(and (empty? (size-flags))
(empty? (input-str))) (printf "No information provided ~n")]
[(empty? (size-flags)) (printf "No sizes were provided, -s ~n")]
[(empty? (name)) (printf "No name provided to process, -n ~n")]
[(empty? (input-str)) (printf "No input provided to process, -i ~n")]
[(not (empty? (file-name))) (for ([s (size-flags)])
(save-identikon (file-name) (ext) (identikon (string->number s)
(string->number s)
(file-name)
(first (rules-set))
#:filename #t))
(printf "Saved ~apx identicon for ~a ~n" s (file-name)))]
[else (for ([s (size-flags)])
(identikon (string->number s)
(string->number s)
(name)
(first (rules-set)) (ext))
(printf "Saved ~apx identicon for ~a ~n" s (name)))]))
(save-identikon (input-str) (ext) (identikon (string->number s)
(string->number s)
(input-str)
(first (rules-set))))
(printf "Saved ~apx identicon for ~a ~n" s (input-str)))]))
8 changes: 4 additions & 4 deletions rules/default.rkt
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#lang racket/base

(require racket/list
2htdp/image
identikon/utils)

; Default rule-set for identikon.
; All rule-sets must provide a single function, draw-rules
; which is called by identikon. This function should always
Expand All @@ -10,10 +14,6 @@
; ———————————
; implementation

(require racket/list
2htdp/image
identikon/utils)

; Constants
(define BORDER-MAX 20)

Expand Down
Loading

0 comments on commit 6d7c876

Please sign in to comment.