github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/convert/convert.go (about)

     1  // Copyright 2014 <chaishushan{AT}gmail.com>. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package convert implements some image convert functions.
     6  package convert
     7  
     8  import (
     9  	"fmt"
    10  	"image"
    11  	"image/color"
    12  
    13  	image_ext "github.com/chai2010/gopkg/image"
    14  	color_ext "github.com/chai2010/gopkg/image/color"
    15  )
    16  
    17  func ColorModel(m image.Image, model color.Model) image.Image {
    18  	if model == nil {
    19  		return m
    20  	}
    21  	switch model {
    22  	case color.GrayModel:
    23  		return Gray(m)
    24  	case color.Gray16Model:
    25  		return Gray16(m)
    26  	case color_ext.Gray32fModel:
    27  		return Gray32f(m)
    28  	case color_ext.RGBModel:
    29  		return RGB(m)
    30  	case color_ext.RGB48Model:
    31  		return RGB48(m)
    32  	case color_ext.RGB96fModel:
    33  		return RGB96f(m)
    34  	case color.RGBAModel:
    35  		return RGBA(m)
    36  	case color.RGBA64Model:
    37  		return RGBA64(m)
    38  	case color_ext.RGBA128fModel:
    39  		return RGBA128f(m)
    40  	}
    41  	panic(fmt.Sprintf("image/convert: unsupport colorModel %T", model))
    42  }
    43  
    44  func Color(m image.Image, isColor bool) image.Image {
    45  	if isColor {
    46  		return convertToColor(m)
    47  	} else {
    48  		return convertToGray(m)
    49  	}
    50  }
    51  
    52  func Gray(m image.Image) *image.Gray {
    53  	if gray, ok := m.(*image.Gray); ok {
    54  		return gray
    55  	}
    56  	b := m.Bounds()
    57  	gray := image.NewGray(b)
    58  	switch m := m.(type) {
    59  	case *image.Gray16:
    60  		for y := b.Min.Y; y < b.Max.Y; y++ {
    61  			for x := b.Min.X; x < b.Max.X; x++ {
    62  				v := m.Gray16At(x, y)
    63  				gray.SetGray(x, y, color.Gray{uint8(v.Y >> 8)})
    64  			}
    65  		}
    66  	case *image.RGBA:
    67  		for y := b.Min.Y; y < b.Max.Y; y++ {
    68  			for x := b.Min.X; x < b.Max.X; x++ {
    69  				gray.SetGray(x, y, color.GrayModel.Convert(m.RGBAAt(x, y)).(color.Gray))
    70  			}
    71  		}
    72  	case *image.RGBA64:
    73  		for y := b.Min.Y; y < b.Max.Y; y++ {
    74  			for x := b.Min.X; x < b.Max.X; x++ {
    75  				gray.SetGray(x, y, color.GrayModel.Convert(m.RGBA64At(x, y)).(color.Gray))
    76  			}
    77  		}
    78  	case *image.YCbCr:
    79  		for y := b.Min.Y; y < b.Max.Y; y++ {
    80  			copy(
    81  				gray.Pix[y*gray.Stride:][:gray.Stride],
    82  				m.Y[y*m.YStride:][:m.YStride],
    83  			)
    84  		}
    85  	default:
    86  		for y := b.Min.Y; y < b.Max.Y; y++ {
    87  			for x := b.Min.X; x < b.Max.X; x++ {
    88  				gray.Set(x, y, m.At(x, y))
    89  			}
    90  		}
    91  	}
    92  	return gray
    93  }
    94  
    95  func Gray16(m image.Image) *image.Gray16 {
    96  	if gray16, ok := m.(*image.Gray16); ok {
    97  		return gray16
    98  	}
    99  	b := m.Bounds()
   100  	gray16 := image.NewGray16(b)
   101  	switch m := m.(type) {
   102  	case *image.Gray:
   103  		for y := b.Min.Y; y < b.Max.Y; y++ {
   104  			for x := b.Min.X; x < b.Max.X; x++ {
   105  				v := m.GrayAt(x, y)
   106  				gray16.SetGray16(x, y, color.Gray16{uint16(v.Y) << 8})
   107  			}
   108  		}
   109  	case *image.RGBA:
   110  		for y := b.Min.Y; y < b.Max.Y; y++ {
   111  			for x := b.Min.X; x < b.Max.X; x++ {
   112  				gray16.SetGray16(x, y,
   113  					color.Gray16Model.Convert(m.RGBAAt(x, y)).(color.Gray16),
   114  				)
   115  			}
   116  		}
   117  	case *image.RGBA64:
   118  		for y := b.Min.Y; y < b.Max.Y; y++ {
   119  			for x := b.Min.X; x < b.Max.X; x++ {
   120  				gray16.SetGray16(x, y,
   121  					color.Gray16Model.Convert(m.RGBA64At(x, y)).(color.Gray16),
   122  				)
   123  			}
   124  		}
   125  	case *image.YCbCr:
   126  		for y := b.Min.Y; y < b.Max.Y; y++ {
   127  			for x := b.Min.X; x < b.Max.X; x++ {
   128  				v := m.Y[m.YOffset(x, y)]
   129  				gray16.SetGray16(x, y, color.Gray16{uint16(v) << 8})
   130  			}
   131  		}
   132  	default:
   133  		for y := b.Min.Y; y < b.Max.Y; y++ {
   134  			for x := b.Min.X; x < b.Max.X; x++ {
   135  				gray16.Set(x, y, m.At(x, y))
   136  			}
   137  		}
   138  	}
   139  	return gray16
   140  }
   141  
   142  func Gray32f(m image.Image) *image_ext.Gray32f {
   143  	if gray32f, ok := m.(*image_ext.Gray32f); ok {
   144  		return gray32f
   145  	}
   146  	b := m.Bounds()
   147  	gray32f := image_ext.NewGray32f(b)
   148  	for y := b.Min.Y; y < b.Max.Y; y++ {
   149  		for x := b.Min.X; x < b.Max.X; x++ {
   150  			gray32f.Set(x, y, m.At(x, y))
   151  		}
   152  	}
   153  	return gray32f
   154  }
   155  
   156  func RGB(m image.Image) *image_ext.RGB {
   157  	if rgb, ok := m.(*image_ext.RGB); ok {
   158  		return rgb
   159  	}
   160  	b := m.Bounds()
   161  	rgb := image_ext.NewRGB(b)
   162  	switch m := m.(type) {
   163  	case *image.Gray:
   164  		for y := b.Min.Y; y < b.Max.Y; y++ {
   165  			for x := b.Min.X; x < b.Max.X; x++ {
   166  				v := m.GrayAt(x, y)
   167  				rgb.SetRGB(x, y, color_ext.RGB{
   168  					R: v.Y,
   169  					G: v.Y,
   170  					B: v.Y,
   171  				})
   172  			}
   173  		}
   174  	case *image.Gray16:
   175  		for y := b.Min.Y; y < b.Max.Y; y++ {
   176  			for x := b.Min.X; x < b.Max.X; x++ {
   177  				v := m.Gray16At(x, y)
   178  				rgb.SetRGB(x, y, color_ext.RGB{
   179  					R: uint8(v.Y >> 8),
   180  					G: uint8(v.Y >> 8),
   181  					B: uint8(v.Y >> 8),
   182  				})
   183  			}
   184  		}
   185  	default:
   186  		for y := b.Min.Y; y < b.Max.Y; y++ {
   187  			for x := b.Min.X; x < b.Max.X; x++ {
   188  				rgb.Set(x, y, m.At(x, y))
   189  			}
   190  		}
   191  	}
   192  	return rgb
   193  }
   194  
   195  func RGB48(m image.Image) *image_ext.RGB48 {
   196  	if rgb48, ok := m.(*image_ext.RGB48); ok {
   197  		return rgb48
   198  	}
   199  	b := m.Bounds()
   200  	rgb48 := image_ext.NewRGB48(b)
   201  	switch m := m.(type) {
   202  	case *image.Gray:
   203  		for y := b.Min.Y; y < b.Max.Y; y++ {
   204  			for x := b.Min.X; x < b.Max.X; x++ {
   205  				v := m.GrayAt(x, y)
   206  				rgb48.SetRGB48(x, y, color_ext.RGB48{
   207  					R: uint16(v.Y) >> 8,
   208  					G: uint16(v.Y) >> 8,
   209  					B: uint16(v.Y) >> 8,
   210  				})
   211  			}
   212  		}
   213  	case *image.Gray16:
   214  		for y := b.Min.Y; y < b.Max.Y; y++ {
   215  			for x := b.Min.X; x < b.Max.X; x++ {
   216  				v := m.Gray16At(x, y)
   217  				rgb48.SetRGB48(x, y, color_ext.RGB48{
   218  					R: v.Y,
   219  					G: v.Y,
   220  					B: v.Y,
   221  				})
   222  			}
   223  		}
   224  	default:
   225  		for y := b.Min.Y; y < b.Max.Y; y++ {
   226  			for x := b.Min.X; x < b.Max.X; x++ {
   227  				rgb48.Set(x, y, m.At(x, y))
   228  			}
   229  		}
   230  	}
   231  	return rgb48
   232  }
   233  
   234  func RGB96f(m image.Image) *image_ext.RGB96f {
   235  	if rgb96f, ok := m.(*image_ext.RGB96f); ok {
   236  		return rgb96f
   237  	}
   238  	b := m.Bounds()
   239  	rgb96f := image_ext.NewRGB96f(b)
   240  	switch m := m.(type) {
   241  	case *image.Gray:
   242  		for y := b.Min.Y; y < b.Max.Y; y++ {
   243  			for x := b.Min.X; x < b.Max.X; x++ {
   244  				v := m.GrayAt(x, y)
   245  				rgb96f.SetRGB96f(x, y, color_ext.RGB96f{
   246  					R: float32(uint16(v.Y) >> 8),
   247  					G: float32(uint16(v.Y) >> 8),
   248  					B: float32(uint16(v.Y) >> 8),
   249  				})
   250  			}
   251  		}
   252  	case *image.Gray16:
   253  		for y := b.Min.Y; y < b.Max.Y; y++ {
   254  			for x := b.Min.X; x < b.Max.X; x++ {
   255  				v := m.Gray16At(x, y)
   256  				rgb96f.SetRGB96f(x, y, color_ext.RGB96f{
   257  					R: float32(v.Y),
   258  					G: float32(v.Y),
   259  					B: float32(v.Y),
   260  				})
   261  			}
   262  		}
   263  	default:
   264  		for y := b.Min.Y; y < b.Max.Y; y++ {
   265  			for x := b.Min.X; x < b.Max.X; x++ {
   266  				rgb96f.Set(x, y, m.At(x, y))
   267  			}
   268  		}
   269  	}
   270  	return rgb96f
   271  }
   272  
   273  func RGBA(m image.Image) *image.RGBA {
   274  	if rgba, ok := m.(*image.RGBA); ok {
   275  		return rgba
   276  	}
   277  	b := m.Bounds()
   278  	rgba := image.NewRGBA(b)
   279  	switch m := m.(type) {
   280  	case *image.Gray:
   281  		for y := b.Min.Y; y < b.Max.Y; y++ {
   282  			for x := b.Min.X; x < b.Max.X; x++ {
   283  				v := m.GrayAt(x, y)
   284  				rgba.SetRGBA(x, y, color.RGBA{
   285  					R: v.Y,
   286  					G: v.Y,
   287  					B: v.Y,
   288  					A: 0xFF,
   289  				})
   290  			}
   291  		}
   292  	case *image.Gray16:
   293  		for y := b.Min.Y; y < b.Max.Y; y++ {
   294  			for x := b.Min.X; x < b.Max.X; x++ {
   295  				v := m.Gray16At(x, y)
   296  				rgba.SetRGBA(x, y, color.RGBA{
   297  					R: uint8(v.Y >> 8),
   298  					G: uint8(v.Y >> 8),
   299  					B: uint8(v.Y >> 8),
   300  					A: 0xFF,
   301  				})
   302  			}
   303  		}
   304  	default:
   305  		for y := b.Min.Y; y < b.Max.Y; y++ {
   306  			for x := b.Min.X; x < b.Max.X; x++ {
   307  				rgba.Set(x, y, m.At(x, y))
   308  			}
   309  		}
   310  	}
   311  	return rgba
   312  }
   313  
   314  func RGBA64(m image.Image) *image.RGBA64 {
   315  	if rgba64, ok := m.(*image.RGBA64); ok {
   316  		return rgba64
   317  	}
   318  	b := m.Bounds()
   319  	rgba64 := image.NewRGBA64(b)
   320  	switch m := m.(type) {
   321  	case *image.Gray:
   322  		for y := b.Min.Y; y < b.Max.Y; y++ {
   323  			for x := b.Min.X; x < b.Max.X; x++ {
   324  				v := m.GrayAt(x, y)
   325  				rgba64.SetRGBA64(x, y, color.RGBA64{
   326  					R: uint16(v.Y) >> 8,
   327  					G: uint16(v.Y) >> 8,
   328  					B: uint16(v.Y) >> 8,
   329  					A: 0xFFFF,
   330  				})
   331  			}
   332  		}
   333  	case *image.Gray16:
   334  		for y := b.Min.Y; y < b.Max.Y; y++ {
   335  			for x := b.Min.X; x < b.Max.X; x++ {
   336  				v := m.Gray16At(x, y)
   337  				rgba64.SetRGBA64(x, y, color.RGBA64{
   338  					R: v.Y,
   339  					G: v.Y,
   340  					B: v.Y,
   341  					A: 0xFFFF,
   342  				})
   343  			}
   344  		}
   345  	case *image.RGBA:
   346  		for y := b.Min.Y; y < b.Max.Y; y++ {
   347  			for x := b.Min.X; x < b.Max.X; x++ {
   348  				v := m.RGBAAt(x, y)
   349  				rgba64.SetRGBA64(x, y, color.RGBA64{
   350  					R: uint16(v.R) >> 8,
   351  					G: uint16(v.G) >> 8,
   352  					B: uint16(v.B) >> 8,
   353  					A: uint16(v.A) >> 8,
   354  				})
   355  			}
   356  		}
   357  	default:
   358  		for y := b.Min.Y; y < b.Max.Y; y++ {
   359  			for x := b.Min.X; x < b.Max.X; x++ {
   360  				rgba64.Set(x, y, m.At(x, y))
   361  			}
   362  		}
   363  	}
   364  	return rgba64
   365  }
   366  
   367  func RGBA128f(m image.Image) *image_ext.RGBA128f {
   368  	if rgba128f, ok := m.(*image_ext.RGBA128f); ok {
   369  		return rgba128f
   370  	}
   371  	b := m.Bounds()
   372  	rgba128f := image_ext.NewRGBA128f(b)
   373  	switch m := m.(type) {
   374  	case *image.Gray:
   375  		for y := b.Min.Y; y < b.Max.Y; y++ {
   376  			for x := b.Min.X; x < b.Max.X; x++ {
   377  				v := m.GrayAt(x, y)
   378  				rgba128f.SetRGBA128f(x, y, color_ext.RGBA128f{
   379  					R: float32(uint16(v.Y) >> 8),
   380  					G: float32(uint16(v.Y) >> 8),
   381  					B: float32(uint16(v.Y) >> 8),
   382  					A: 0xFFFF,
   383  				})
   384  			}
   385  		}
   386  	case *image.Gray16:
   387  		for y := b.Min.Y; y < b.Max.Y; y++ {
   388  			for x := b.Min.X; x < b.Max.X; x++ {
   389  				v := m.Gray16At(x, y)
   390  				rgba128f.SetRGBA128f(x, y, color_ext.RGBA128f{
   391  					R: float32(v.Y),
   392  					G: float32(v.Y),
   393  					B: float32(v.Y),
   394  					A: 0xFFFF,
   395  				})
   396  			}
   397  		}
   398  	case *image.RGBA:
   399  		for y := b.Min.Y; y < b.Max.Y; y++ {
   400  			for x := b.Min.X; x < b.Max.X; x++ {
   401  				v := m.RGBAAt(x, y)
   402  				rgba128f.SetRGBA128f(x, y, color_ext.RGBA128f{
   403  					R: float32(uint16(v.R) >> 8),
   404  					G: float32(uint16(v.G) >> 8),
   405  					B: float32(uint16(v.B) >> 8),
   406  					A: float32(uint16(v.A) >> 8),
   407  				})
   408  			}
   409  		}
   410  	default:
   411  		for y := b.Min.Y; y < b.Max.Y; y++ {
   412  			for x := b.Min.X; x < b.Max.X; x++ {
   413  				rgba128f.Set(x, y, m.At(x, y))
   414  			}
   415  		}
   416  	}
   417  	return rgba128f
   418  }
   419  
   420  func Paletted(m image.Image, p color.Palette) *image.Paletted {
   421  	if m, ok := m.(*image.Paletted); ok {
   422  		if len(m.Palette) == len(p) {
   423  			if &m.Palette[0] == &p[0] {
   424  				return m
   425  			}
   426  			isEqual := true
   427  			for i, c := range m.Palette {
   428  				r0, g0, b0, a0 := c.RGBA()
   429  				r1, g1, b1, a1 := p[i].RGBA()
   430  				if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
   431  					isEqual = false
   432  					break
   433  				}
   434  			}
   435  			if isEqual {
   436  				return m
   437  			}
   438  		}
   439  	}
   440  	b := m.Bounds()
   441  	paletted := image.NewPaletted(b, p)
   442  	for y := b.Min.Y; y < b.Max.Y; y++ {
   443  		for x := b.Min.X; x < b.Max.X; x++ {
   444  			paletted.Set(x, y, m.At(x, y))
   445  		}
   446  	}
   447  	return paletted
   448  }
   449  
   450  func YCbCr(m image.Image, subsampleRatio image.YCbCrSubsampleRatio) *image.YCbCr {
   451  	if m, ok := m.(*image.YCbCr); ok {
   452  		if m.SubsampleRatio == subsampleRatio {
   453  			return m
   454  		}
   455  	}
   456  	b := m.Bounds()
   457  	yCbCr := image_ext.NewYCbCr(b, subsampleRatio)
   458  	for y := b.Min.Y; y < b.Max.Y; y++ {
   459  		for x := b.Min.X; x < b.Max.X; x++ {
   460  			yCbCr.Set(x, y, m.At(x, y))
   461  		}
   462  	}
   463  	return (*image.YCbCr)(yCbCr)
   464  }
   465  
   466  func convertToColor(m image.Image) image.Image {
   467  	switch m := m.(type) {
   468  	case *image.Gray:
   469  		b := m.Bounds()
   470  		rgb := image_ext.NewRGB(b)
   471  		for y := b.Min.Y; y < b.Max.Y; y++ {
   472  			for x := b.Min.X; x < b.Max.X; x++ {
   473  				v := m.GrayAt(x, y)
   474  				rgb.SetRGB(x, y, color_ext.RGB{
   475  					R: v.Y,
   476  					G: v.Y,
   477  					B: v.Y,
   478  				})
   479  			}
   480  		}
   481  		return rgb
   482  	case *image.Gray16:
   483  		b := m.Bounds()
   484  		rgb48 := image_ext.NewRGB48(b)
   485  		for y := b.Min.Y; y < b.Max.Y; y++ {
   486  			for x := b.Min.X; x < b.Max.X; x++ {
   487  				v := m.Gray16At(x, y)
   488  				rgb48.SetRGB48(x, y, color_ext.RGB48{
   489  					R: v.Y,
   490  					G: v.Y,
   491  					B: v.Y,
   492  				})
   493  			}
   494  		}
   495  		return rgb48
   496  	case *image_ext.Gray32f:
   497  		b := m.Bounds()
   498  		rgb96f := image_ext.NewRGB96f(b)
   499  		for y := b.Min.Y; y < b.Max.Y; y++ {
   500  			for x := b.Min.X; x < b.Max.X; x++ {
   501  				v := m.Gray32fAt(x, y)
   502  				rgb96f.SetRGB96f(x, y, color_ext.RGB96f{
   503  					R: v.Y,
   504  					G: v.Y,
   505  					B: v.Y,
   506  				})
   507  			}
   508  		}
   509  		return rgb96f
   510  	case *image.YCbCr:
   511  		b := m.Bounds()
   512  		rgb := image_ext.NewRGB(b)
   513  		for y := b.Min.Y; y < b.Max.Y; y++ {
   514  			for x := b.Min.X; x < b.Max.X; x++ {
   515  				v := m.YCbCrAt(x, y)
   516  				rr, gg, bb := color.YCbCrToRGB(v.Y, v.Cb, v.Cr)
   517  				rgb.SetRGB(x, y, color_ext.RGB{
   518  					R: rr,
   519  					G: gg,
   520  					B: bb,
   521  				})
   522  			}
   523  		}
   524  		return rgb
   525  	case *image.Paletted:
   526  		switch m.Palette[0].(type) {
   527  		case color.Gray:
   528  			b := m.Bounds()
   529  			rgb := image_ext.NewRGB(b)
   530  			for y := b.Min.Y; y < b.Max.Y; y++ {
   531  				for x := b.Min.X; x < b.Max.X; x++ {
   532  					v := m.At(x, y).(color.Gray)
   533  					rgb.SetRGB(x, y, color_ext.RGB{
   534  						R: v.Y,
   535  						G: v.Y,
   536  						B: v.Y,
   537  					})
   538  				}
   539  			}
   540  			return rgb
   541  		case color.Gray16:
   542  			b := m.Bounds()
   543  			rgb48 := image_ext.NewRGB48(b)
   544  			for y := b.Min.Y; y < b.Max.Y; y++ {
   545  				for x := b.Min.X; x < b.Max.X; x++ {
   546  					v := m.At(x, y).(color.Gray16)
   547  					rgb48.SetRGB48(x, y, color_ext.RGB48{
   548  						R: v.Y,
   549  						G: v.Y,
   550  						B: v.Y,
   551  					})
   552  				}
   553  			}
   554  			return rgb48
   555  		case color_ext.Gray32f:
   556  			b := m.Bounds()
   557  			rgb96f := image_ext.NewRGB96f(b)
   558  			for y := b.Min.Y; y < b.Max.Y; y++ {
   559  				for x := b.Min.X; x < b.Max.X; x++ {
   560  					v := m.At(x, y).(color_ext.Gray32f)
   561  					rgb96f.SetRGB96f(x, y, color_ext.RGB96f{
   562  						R: v.Y,
   563  						G: v.Y,
   564  						B: v.Y,
   565  					})
   566  				}
   567  			}
   568  			return rgb96f
   569  		case color.YCbCr:
   570  			b := m.Bounds()
   571  			rgb := image_ext.NewRGB(b)
   572  			for y := b.Min.Y; y < b.Max.Y; y++ {
   573  				for x := b.Min.X; x < b.Max.X; x++ {
   574  					v := m.At(x, y).(color.YCbCr)
   575  					rr, gg, bb := color.YCbCrToRGB(v.Y, v.Cb, v.Cr)
   576  					rgb.SetRGB(x, y, color_ext.RGB{
   577  						R: rr,
   578  						G: gg,
   579  						B: bb,
   580  					})
   581  				}
   582  			}
   583  			return rgb
   584  		}
   585  	}
   586  	return m
   587  }
   588  
   589  func convertToGray(m image.Image) image.Image {
   590  	switch m := m.(type) {
   591  	case *image_ext.RGB:
   592  		b := m.Bounds()
   593  		gray := image.NewGray(b)
   594  		for y := b.Min.Y; y < b.Max.Y; y++ {
   595  			for x := b.Min.X; x < b.Max.X; x++ {
   596  				gray.SetGray(x, y,
   597  					color.GrayModel.Convert(m.RGBAt(x, y)).(color.Gray),
   598  				)
   599  			}
   600  		}
   601  		return gray
   602  	case *image_ext.RGB48:
   603  		b := m.Bounds()
   604  		gray16 := image.NewGray16(b)
   605  		for y := b.Min.Y; y < b.Max.Y; y++ {
   606  			for x := b.Min.X; x < b.Max.X; x++ {
   607  				gray16.SetGray16(x, y,
   608  					color.Gray16Model.Convert(m.RGB48At(x, y)).(color.Gray16),
   609  				)
   610  			}
   611  		}
   612  		return gray16
   613  	case *image_ext.RGB96f:
   614  		b := m.Bounds()
   615  		gray32f := image_ext.NewGray32f(b)
   616  		for y := b.Min.Y; y < b.Max.Y; y++ {
   617  			for x := b.Min.X; x < b.Max.X; x++ {
   618  				gray32f.SetGray32f(x, y,
   619  					color_ext.Gray32fModel.Convert(m.RGB96fAt(x, y)).(color_ext.Gray32f),
   620  				)
   621  			}
   622  		}
   623  		return gray32f
   624  	case *image.RGBA:
   625  		b := m.Bounds()
   626  		gray := image.NewGray(b)
   627  		for y := b.Min.Y; y < b.Max.Y; y++ {
   628  			for x := b.Min.X; x < b.Max.X; x++ {
   629  				gray.SetGray(x, y,
   630  					color.RGBAModel.Convert(m.RGBAAt(x, y)).(color.Gray),
   631  				)
   632  			}
   633  		}
   634  		return gray
   635  	case *image.RGBA64:
   636  		b := m.Bounds()
   637  		gray16 := image.NewGray16(b)
   638  		for y := b.Min.Y; y < b.Max.Y; y++ {
   639  			for x := b.Min.X; x < b.Max.X; x++ {
   640  				gray16.SetGray16(x, y,
   641  					color.Gray16Model.Convert(m.RGBA64At(x, y)).(color.Gray16),
   642  				)
   643  			}
   644  		}
   645  		return gray16
   646  	case *image_ext.RGBA128f:
   647  		b := m.Bounds()
   648  		gray32f := image_ext.NewGray32f(b)
   649  		for y := b.Min.Y; y < b.Max.Y; y++ {
   650  			for x := b.Min.X; x < b.Max.X; x++ {
   651  				gray32f.SetGray32f(x, y,
   652  					color_ext.Gray32fModel.Convert(m.RGBA128fAt(x, y)).(color_ext.Gray32f),
   653  				)
   654  			}
   655  		}
   656  		return gray32f
   657  	case *image.YCbCr:
   658  		b := m.Bounds()
   659  		gray := image.NewGray(b)
   660  		for y := b.Min.Y; y < b.Max.Y; y++ {
   661  			copy(gray.Pix[y*gray.Stride:][:b.Dx()], m.Y[y*m.YStride:])
   662  		}
   663  		return gray
   664  	case *image.Paletted:
   665  		switch m.Palette[0].(type) {
   666  		case color_ext.RGB, color.RGBA, color.YCbCr:
   667  			b := m.Bounds()
   668  			gray := image.NewGray(b)
   669  			for y := b.Min.Y; y < b.Max.Y; y++ {
   670  				for x := b.Min.X; x < b.Max.X; x++ {
   671  					gray.SetGray(x, y,
   672  						color.GrayModel.Convert(m.At(x, y)).(color.Gray),
   673  					)
   674  				}
   675  			}
   676  			return gray
   677  		case color_ext.RGB48, color.RGBA64:
   678  			b := m.Bounds()
   679  			gray16 := image.NewGray16(b)
   680  			for y := b.Min.Y; y < b.Max.Y; y++ {
   681  				for x := b.Min.X; x < b.Max.X; x++ {
   682  					gray16.SetGray16(x, y,
   683  						color.Gray16Model.Convert(m.At(x, y)).(color.Gray16),
   684  					)
   685  				}
   686  			}
   687  			return gray16
   688  		case color_ext.RGB96f, color_ext.RGBA128f:
   689  			b := m.Bounds()
   690  			gray32f := image_ext.NewGray32f(b)
   691  			for y := b.Min.Y; y < b.Max.Y; y++ {
   692  				for x := b.Min.X; x < b.Max.X; x++ {
   693  					gray32f.SetGray32f(x, y,
   694  						color_ext.Gray32fModel.Convert(m.At(x, y)).(color_ext.Gray32f),
   695  					)
   696  				}
   697  			}
   698  			return gray32f
   699  		}
   700  	}
   701  	return m
   702  }