scaledbarcode.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package barcode
  2. import (
  3. "errors"
  4. "fmt"
  5. "image"
  6. "image/color"
  7. "math"
  8. )
  9. type wrapFunc func(x, y int) color.Color
  10. type scaledBarcode struct {
  11. wrapped Barcode
  12. wrapperFunc wrapFunc
  13. rect image.Rectangle
  14. }
  15. func (bc *scaledBarcode) Content() string {
  16. return bc.wrapped.Content()
  17. }
  18. func (bc *scaledBarcode) Metadata() Metadata {
  19. return bc.wrapped.Metadata()
  20. }
  21. func (bc *scaledBarcode) ColorModel() color.Model {
  22. return bc.wrapped.ColorModel()
  23. }
  24. func (bc *scaledBarcode) Bounds() image.Rectangle {
  25. return bc.rect
  26. }
  27. func (bc *scaledBarcode) At(x, y int) color.Color {
  28. return bc.wrapperFunc(x, y)
  29. }
  30. // returns a resized barcode with the given width and height.
  31. func Scale(bc Barcode, width, height int) (Barcode, error) {
  32. switch bc.Metadata().Dimensions {
  33. case 1:
  34. return scale1DCode(bc, width, height)
  35. case 2:
  36. return scale2DCode(bc, width, height)
  37. }
  38. return nil, errors.New("unsupported barcode format")
  39. }
  40. func scale2DCode(bc Barcode, width, height int) (Barcode, error) {
  41. orgBounds := bc.Bounds()
  42. orgWidth := orgBounds.Max.X - orgBounds.Min.X
  43. orgHeight := orgBounds.Max.Y - orgBounds.Min.Y
  44. factor := int(math.Min(float64(width)/float64(orgWidth), float64(height)/float64(orgHeight)))
  45. if factor <= 0 {
  46. return nil, fmt.Errorf("can not scale barcode to an image smaller then %dx%d", orgWidth, orgHeight)
  47. }
  48. offsetX := (width - (orgWidth * factor)) / 2
  49. offsetY := (height - (orgHeight * factor)) / 2
  50. wrap := func(x, y int) color.Color {
  51. if x < offsetX || y < offsetY {
  52. return color.White
  53. }
  54. x = (x - offsetX) / factor
  55. y = (y - offsetY) / factor
  56. if x >= orgWidth || y >= orgHeight {
  57. return color.White
  58. }
  59. return bc.At(x, y)
  60. }
  61. return &scaledBarcode{
  62. bc,
  63. wrap,
  64. image.Rect(0, 0, width, height),
  65. }, nil
  66. }
  67. func scale1DCode(bc Barcode, width, height int) (Barcode, error) {
  68. orgBounds := bc.Bounds()
  69. orgWidth := orgBounds.Max.X - orgBounds.Min.X
  70. factor := int(float64(width) / float64(orgWidth))
  71. if factor <= 0 {
  72. return nil, fmt.Errorf("can not scale barcode to an image smaller then %dx1", orgWidth)
  73. }
  74. offsetX := (width - (orgWidth * factor)) / 2
  75. wrap := func(x, y int) color.Color {
  76. if x < offsetX {
  77. return color.White
  78. }
  79. x = (x - offsetX) / factor
  80. if x >= orgWidth {
  81. return color.White
  82. }
  83. return bc.At(x, 0)
  84. }
  85. return &scaledBarcode{
  86. bc,
  87. wrap,
  88. image.Rect(0, 0, width, height),
  89. }, nil
  90. }