git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/barcode/scaledbarcode.go (about) 1 package barcode 2 3 import ( 4 "errors" 5 "fmt" 6 "image" 7 "image/color" 8 "math" 9 ) 10 11 type wrapFunc func(x, y int) color.Color 12 13 type scaledBarcode struct { 14 wrapped Barcode 15 wrapperFunc wrapFunc 16 rect image.Rectangle 17 } 18 19 type intCSscaledBC struct { 20 scaledBarcode 21 } 22 23 func (bc *scaledBarcode) Content() string { 24 return bc.wrapped.Content() 25 } 26 27 func (bc *scaledBarcode) Metadata() Metadata { 28 return bc.wrapped.Metadata() 29 } 30 31 func (bc *scaledBarcode) ColorModel() color.Model { 32 return bc.wrapped.ColorModel() 33 } 34 35 func (bc *scaledBarcode) Bounds() image.Rectangle { 36 return bc.rect 37 } 38 39 func (bc *scaledBarcode) At(x, y int) color.Color { 40 return bc.wrapperFunc(x, y) 41 } 42 43 func (bc *intCSscaledBC) CheckSum() int { 44 if cs, ok := bc.wrapped.(BarcodeIntCS); ok { 45 return cs.CheckSum() 46 } 47 return 0 48 } 49 50 // Scale returns a resized barcode with the given width and height. 51 func Scale(bc Barcode, width, height int) (Barcode, error) { 52 switch bc.Metadata().Dimensions { 53 case 1: 54 return scale1DCode(bc, width, height) 55 case 2: 56 return scale2DCode(bc, width, height) 57 } 58 59 return nil, errors.New("unsupported barcode format") 60 } 61 62 func newScaledBC(wrapped Barcode, wrapperFunc wrapFunc, rect image.Rectangle) Barcode { 63 result := &scaledBarcode{ 64 wrapped: wrapped, 65 wrapperFunc: wrapperFunc, 66 rect: rect, 67 } 68 69 if _, ok := wrapped.(BarcodeIntCS); ok { 70 return &intCSscaledBC{*result} 71 } 72 return result 73 } 74 75 func scale2DCode(bc Barcode, width, height int) (Barcode, error) { 76 orgBounds := bc.Bounds() 77 orgWidth := orgBounds.Max.X - orgBounds.Min.X 78 orgHeight := orgBounds.Max.Y - orgBounds.Min.Y 79 80 factor := int(math.Min(float64(width)/float64(orgWidth), float64(height)/float64(orgHeight))) 81 if factor <= 0 { 82 return nil, fmt.Errorf("can not scale barcode to an image smaller than %dx%d", orgWidth, orgHeight) 83 } 84 85 offsetX := (width - (orgWidth * factor)) / 2 86 offsetY := (height - (orgHeight * factor)) / 2 87 88 wrap := func(x, y int) color.Color { 89 if x < offsetX || y < offsetY { 90 return color.White 91 } 92 x = (x - offsetX) / factor 93 y = (y - offsetY) / factor 94 if x >= orgWidth || y >= orgHeight { 95 return color.White 96 } 97 return bc.At(x, y) 98 } 99 100 return newScaledBC( 101 bc, 102 wrap, 103 image.Rect(0, 0, width, height), 104 ), nil 105 } 106 107 func scale1DCode(bc Barcode, width, height int) (Barcode, error) { 108 orgBounds := bc.Bounds() 109 orgWidth := orgBounds.Max.X - orgBounds.Min.X 110 factor := int(float64(width) / float64(orgWidth)) 111 112 if factor <= 0 { 113 return nil, fmt.Errorf("can not scale barcode to an image smaller than %dx1", orgWidth) 114 } 115 offsetX := (width - (orgWidth * factor)) / 2 116 117 wrap := func(x, y int) color.Color { 118 if x < offsetX { 119 return color.White 120 } 121 x = (x - offsetX) / factor 122 123 if x >= orgWidth { 124 return color.White 125 } 126 return bc.At(x, 0) 127 } 128 129 return newScaledBC( 130 bc, 131 wrap, 132 image.Rect(0, 0, width, height), 133 ), nil 134 }