~dricottone/image2ascii

eaef718c089518f5a3ba874b4770edbcd77cf20e — qeesung 6 years ago e8d148c
Fixed the high cyclomatic complexity issue
2 files changed, 91 insertions(+), 46 deletions(-)

M convert/resize.go
M convert/resize_test.go
M convert/resize.go => convert/resize.go +89 -46
@@ 9,9 9,76 @@ import (

// NewResizeHandler create a new resize handler
func NewResizeHandler() ResizeHandler {
	return &ImageResizeHandler{
	handler := &ImageResizeHandler{
		terminal: terminal.NewTerminalAccessor(),
	}

	initResizeResolver(handler)
	return handler
}

// initResizeResolver register the size resolvers
func initResizeResolver(handler *ImageResizeHandler) {
	sizeResolvers := make([]imageSizeResolver, 0, 5)
	// fixed height or width resolver
	sizeResolvers = append(sizeResolvers, imageSizeResolver{
		match: func(options *Options) bool {
			return options.FixedWidth != -1 || options.FixedHeight != -1
		},
		compute: func(sz image.Rectangle, options *Options, handler *ImageResizeHandler) (width, height int, err error) {
			height = sz.Max.Y
			width = sz.Max.X
			if options.FixedWidth != -1 {
				width = options.FixedWidth
			}

			if options.FixedHeight != -1 {
				height = options.FixedHeight
			}
			return
		},
	})
	// scaled by ratio
	sizeResolvers = append(sizeResolvers, imageSizeResolver{
		match: func(options *Options) bool {
			return options.Ratio != 1
		},
		compute: func(sz image.Rectangle, options *Options, handler *ImageResizeHandler) (width, height int, err error) {
			ratio := options.Ratio
			width = handler.ScaleWidthByRatio(float64(sz.Max.X), ratio)
			height = handler.ScaleHeightByRatio(float64(sz.Max.Y), ratio)
			return
		},
	})
	// scaled by stretched screen
	sizeResolvers = append(sizeResolvers, imageSizeResolver{
		match: func(options *Options) bool {
			return options.StretchedScreen
		},
		compute: func(sz image.Rectangle, options *Options, handler *ImageResizeHandler) (width, height int, err error) {
			return handler.terminal.ScreenSize()
		},
	})
	// scaled by fit the screen
	sizeResolvers = append(sizeResolvers, imageSizeResolver{
		match: func(options *Options) bool {
			return options.FitScreen
		},
		compute: func(sz image.Rectangle, options *Options, handler *ImageResizeHandler) (width, height int, err error) {
			return handler.CalcProportionalFittingScreenSize(sz)
		},
	})
	// default size
	sizeResolvers = append(sizeResolvers, imageSizeResolver{
		match: func(options *Options) bool {
			return true
		},
		compute: func(sz image.Rectangle, options *Options, handler *ImageResizeHandler) (width, height int, err error) {
			return sz.Max.X, sz.Max.Y, nil
		},
	})

	handler.imageSizeResolvers = sizeResolvers
}

// ResizeHandler define the operation to resize a image


@@ 22,69 89,45 @@ type ResizeHandler interface {
// ImageResizeHandler implement the ResizeHandler interface and
// responsible for image resizing
type ImageResizeHandler struct {
	terminal terminal.Terminal
	terminal           terminal.Terminal
	imageSizeResolvers []imageSizeResolver
}

// imageSizeResolver to resolve the image size from the options
type imageSizeResolver struct {
	match   func(options *Options) bool
	compute func(sz image.Rectangle, options *Options, handler *ImageResizeHandler) (width, height int, err error)
}

// ScaleImage resize the convert to expected size base on the convert options
func (handler *ImageResizeHandler) ScaleImage(image image.Image, options *Options) (newImage image.Image) {
	sz := image.Bounds()
	ratio := options.Ratio
	newHeight := sz.Max.Y
	newWidth := sz.Max.X

	if options.FixedWidth != -1 {
		newWidth = options.FixedWidth
	}

	if options.FixedHeight != -1 {
		newHeight = options.FixedHeight
	}

	// use the ratio the scale the image
	if options.FixedHeight == -1 && options.FixedWidth == -1 && ratio != 1 {
		newWidth = handler.ScaleWidthByRatio(float64(sz.Max.X), ratio)
		newHeight = handler.ScaleHeightByRatio(float64(sz.Max.Y), ratio)
	newWidth, newHeight, err := handler.resolveSize(sz, options)
	if err != nil {
		log.Fatal(err)
	}

	//Stretch the picture to overspread the terminal
	if ratio == 1 &&
		options.FixedWidth == -1 &&
		options.FixedHeight == -1 &&
		options.StretchedScreen {
		screenWidth, screenHeight, err := handler.terminal.ScreenSize()
		if err != nil {
			log.Fatal(err)
		}
		newWidth = int(screenWidth)
		newHeight = int(screenHeight)
	}
	newImage = resize.Resize(uint(newWidth), uint(newHeight), image, resize.Lanczos3)
	return
}

	// fit the screen
	if ratio == 1 &&
		options.FixedWidth == -1 &&
		options.FixedHeight == -1 &&
		options.FitScreen &&
		!options.StretchedScreen {
		fitWidth, fitHeight, err := handler.CalcProportionalFittingScreenSize(image)
		if err != nil {
			log.Fatal(err)
// resolveSize resolve the image size
func (handler *ImageResizeHandler) resolveSize(sz image.Rectangle, options *Options) (width, height int, err error) {
	for _, resolver := range handler.imageSizeResolvers {
		if resolver.match(options) {
			return resolver.compute(sz, options, handler)
		}
		newWidth = int(fitWidth)
		newHeight = int(fitHeight)
	}

	newImage = resize.Resize(uint(newWidth), uint(newHeight), image, resize.Lanczos3)
	return
	return sz.Max.X, sz.Max.Y, nil
}

// CalcProportionalFittingScreenSize proportional scale the image
// so that the terminal can just show the picture.
func (handler *ImageResizeHandler) CalcProportionalFittingScreenSize(image image.Image) (newWidth, newHeight int, err error) {
func (handler *ImageResizeHandler) CalcProportionalFittingScreenSize(sz image.Rectangle) (newWidth, newHeight int, err error) {
	screenWidth, screenHeight, err := handler.terminal.ScreenSize()
	if err != nil {
		log.Fatal(nil)
	}
	sz := image.Bounds()
	newWidth, newHeight = handler.CalcFitSize(
		float64(screenWidth),
		float64(screenHeight),

M convert/resize_test.go => convert/resize_test.go +2 -0
@@ 136,6 136,7 @@ func TestFitTheTerminalScreenSize(t *testing.T) {
	handler := ImageResizeHandler{
		terminal: &terminalMock,
	}
	initResizeResolver(&handler)

	imageFilePath := "testdata/cat_2000x1500.jpg"
	img, err := OpenImageFile(imageFilePath)


@@ 169,6 170,7 @@ func TestStretchTheTerminalScreenSize(t *testing.T) {
	handler := ImageResizeHandler{
		terminal: &terminalMock,
	}
	initResizeResolver(&handler)

	imageFilePath := "testdata/cat_2000x1500.jpg"
	img, err := OpenImageFile(imageFilePath)