You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
2.4 KiB

  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. func (bc *scaledBarcode) CheckSum() int {
  31. return bc.wrapped.CheckSum()
  32. }
  33. // Scale returns a resized barcode with the given width and height.
  34. func Scale(bc Barcode, width, height int) (Barcode, error) {
  35. switch bc.Metadata().Dimensions {
  36. case 1:
  37. return scale1DCode(bc, width, height)
  38. case 2:
  39. return scale2DCode(bc, width, height)
  40. }
  41. return nil, errors.New("unsupported barcode format")
  42. }
  43. func scale2DCode(bc Barcode, width, height int) (Barcode, error) {
  44. orgBounds := bc.Bounds()
  45. orgWidth := orgBounds.Max.X - orgBounds.Min.X
  46. orgHeight := orgBounds.Max.Y - orgBounds.Min.Y
  47. factor := int(math.Min(float64(width)/float64(orgWidth), float64(height)/float64(orgHeight)))
  48. if factor <= 0 {
  49. return nil, fmt.Errorf("can not scale barcode to an image smaller then %dx%d", orgWidth, orgHeight)
  50. }
  51. offsetX := (width - (orgWidth * factor)) / 2
  52. offsetY := (height - (orgHeight * factor)) / 2
  53. wrap := func(x, y int) color.Color {
  54. if x < offsetX || y < offsetY {
  55. return color.White
  56. }
  57. x = (x - offsetX) / factor
  58. y = (y - offsetY) / factor
  59. if x >= orgWidth || y >= orgHeight {
  60. return color.White
  61. }
  62. return bc.At(x, y)
  63. }
  64. return &scaledBarcode{
  65. bc,
  66. wrap,
  67. image.Rect(0, 0, width, height),
  68. }, nil
  69. }
  70. func scale1DCode(bc Barcode, width, height int) (Barcode, error) {
  71. orgBounds := bc.Bounds()
  72. orgWidth := orgBounds.Max.X - orgBounds.Min.X
  73. factor := int(float64(width) / float64(orgWidth))
  74. if factor <= 0 {
  75. return nil, fmt.Errorf("can not scale barcode to an image smaller then %dx1", orgWidth)
  76. }
  77. offsetX := (width - (orgWidth * factor)) / 2
  78. wrap := func(x, y int) color.Color {
  79. if x < offsetX {
  80. return color.White
  81. }
  82. x = (x - offsetX) / factor
  83. if x >= orgWidth {
  84. return color.White
  85. }
  86. return bc.At(x, 0)
  87. }
  88. return &scaledBarcode{
  89. bc,
  90. wrap,
  91. image.Rect(0, 0, width, height),
  92. }, nil
  93. }