helpers_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. package imaging
  2. import (
  3. "bytes"
  4. "errors"
  5. "image"
  6. "image/color"
  7. "image/color/palette"
  8. "image/draw"
  9. "image/png"
  10. "io"
  11. "io/ioutil"
  12. "os"
  13. "path/filepath"
  14. "testing"
  15. )
  16. var (
  17. errCreate = errors.New("failed to create file")
  18. errClose = errors.New("failed to close file")
  19. errOpen = errors.New("failed to open file")
  20. )
  21. type badFS struct{}
  22. func (badFS) Create(name string) (io.WriteCloser, error) {
  23. if name == "badFile.jpg" {
  24. return badFile{ioutil.Discard}, nil
  25. }
  26. return nil, errCreate
  27. }
  28. func (badFS) Open(name string) (io.ReadCloser, error) {
  29. return nil, errOpen
  30. }
  31. type badFile struct {
  32. io.Writer
  33. }
  34. func (badFile) Close() error {
  35. return errClose
  36. }
  37. type quantizer struct {
  38. palette []color.Color
  39. }
  40. func (q quantizer) Quantize(p color.Palette, m image.Image) color.Palette {
  41. pal := make([]color.Color, len(p), cap(p))
  42. copy(pal, p)
  43. n := cap(p) - len(p)
  44. if n > len(q.palette) {
  45. n = len(q.palette)
  46. }
  47. for i := 0; i < n; i++ {
  48. pal = append(pal, q.palette[i])
  49. }
  50. return pal
  51. }
  52. func TestOpenSave(t *testing.T) {
  53. imgWithoutAlpha := image.NewNRGBA(image.Rect(0, 0, 4, 6))
  54. imgWithoutAlpha.Pix = []uint8{
  55. 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  56. 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  57. 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
  58. 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
  59. 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x88, 0x88, 0x88, 0xff, 0x88, 0x88, 0x88, 0xff,
  60. 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x88, 0x88, 0x88, 0xff, 0x88, 0x88, 0x88, 0xff,
  61. }
  62. imgWithAlpha := image.NewNRGBA(image.Rect(0, 0, 4, 6))
  63. imgWithAlpha.Pix = []uint8{
  64. 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  65. 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  66. 0xff, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0x00, 0xff, 0x00, 0x80, 0x00, 0xff, 0x00, 0x80,
  67. 0xff, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0x00, 0xff, 0x00, 0x80, 0x00, 0xff, 0x00, 0x80,
  68. 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x88, 0x88, 0x88, 0x00, 0x88, 0x88, 0x88, 0x00,
  69. 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x88, 0x88, 0x88, 0x00, 0x88, 0x88, 0x88, 0x00,
  70. }
  71. options := [][]EncodeOption{
  72. {
  73. JPEGQuality(100),
  74. },
  75. {
  76. JPEGQuality(99),
  77. GIFDrawer(draw.FloydSteinberg),
  78. GIFNumColors(256),
  79. GIFQuantizer(quantizer{palette.Plan9}),
  80. PNGCompressionLevel(png.BestSpeed),
  81. },
  82. }
  83. dir, err := ioutil.TempDir("", "imaging")
  84. if err != nil {
  85. t.Fatalf("failed to create temporary directory: %v", err)
  86. }
  87. defer os.RemoveAll(dir)
  88. for _, ext := range []string{"jpg", "jpeg", "png", "gif", "bmp", "tif", "tiff"} {
  89. filename := filepath.Join(dir, "test."+ext)
  90. img := imgWithoutAlpha
  91. if ext == "png" {
  92. img = imgWithAlpha
  93. }
  94. for _, opts := range options {
  95. err := Save(img, filename, opts...)
  96. if err != nil {
  97. t.Fatalf("failed to save image (%q): %v", filename, err)
  98. }
  99. img2, err := Open(filename)
  100. if err != nil {
  101. t.Fatalf("failed to open image (%q): %v", filename, err)
  102. }
  103. got := Clone(img2)
  104. delta := 0
  105. if ext == "jpg" || ext == "jpeg" || ext == "gif" {
  106. delta = 3
  107. }
  108. if !compareNRGBA(got, img, delta) {
  109. t.Fatalf("bad encode-decode result (ext=%q): got %#v want %#v", ext, got, img)
  110. }
  111. }
  112. }
  113. buf := &bytes.Buffer{}
  114. err = Encode(buf, imgWithAlpha, JPEG)
  115. if err != nil {
  116. t.Fatalf("failed to encode alpha to JPEG: %v", err)
  117. }
  118. buf = &bytes.Buffer{}
  119. err = Encode(buf, imgWithAlpha, Format(100))
  120. if err != ErrUnsupportedFormat {
  121. t.Fatalf("got %v want ErrUnsupportedFormat", err)
  122. }
  123. buf = bytes.NewBuffer([]byte("bad data"))
  124. _, err = Decode(buf)
  125. if err == nil {
  126. t.Fatalf("decoding bad data: expected error got nil")
  127. }
  128. err = Save(imgWithAlpha, filepath.Join(dir, "test.unknown"))
  129. if err != ErrUnsupportedFormat {
  130. t.Fatalf("got %v want ErrUnsupportedFormat", err)
  131. }
  132. prevFS := fs
  133. fs = badFS{}
  134. defer func() { fs = prevFS }()
  135. err = Save(imgWithAlpha, "test.jpg")
  136. if err != errCreate {
  137. t.Fatalf("got error %v want errCreate", err)
  138. }
  139. err = Save(imgWithAlpha, "badFile.jpg")
  140. if err != errClose {
  141. t.Fatalf("got error %v want errClose", err)
  142. }
  143. _, err = Open("test.jpg")
  144. if err != errOpen {
  145. t.Fatalf("got error %v want errOpen", err)
  146. }
  147. }
  148. func TestNew(t *testing.T) {
  149. testCases := []struct {
  150. name string
  151. w, h int
  152. c color.Color
  153. dstBounds image.Rectangle
  154. dstPix []uint8
  155. }{
  156. {
  157. "New 1x1 transparent",
  158. 1, 1,
  159. color.Transparent,
  160. image.Rect(0, 0, 1, 1),
  161. []uint8{0x00, 0x00, 0x00, 0x00},
  162. },
  163. {
  164. "New 1x2 red",
  165. 1, 2,
  166. color.RGBA{255, 0, 0, 255},
  167. image.Rect(0, 0, 1, 2),
  168. []uint8{0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff},
  169. },
  170. {
  171. "New 2x1 white",
  172. 2, 1,
  173. color.White,
  174. image.Rect(0, 0, 2, 1),
  175. []uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  176. },
  177. {
  178. "New 3x3 with alpha",
  179. 3, 3,
  180. color.NRGBA{0x01, 0x23, 0x45, 0x67},
  181. image.Rect(0, 0, 3, 3),
  182. []uint8{
  183. 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67,
  184. 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67,
  185. 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67,
  186. },
  187. },
  188. {
  189. "New 0x0 white",
  190. 0, 0,
  191. color.White,
  192. image.Rect(0, 0, 0, 0),
  193. nil,
  194. },
  195. {
  196. "New 800x600 custom",
  197. 800, 600,
  198. color.NRGBA{1, 2, 3, 4},
  199. image.Rect(0, 0, 800, 600),
  200. bytes.Repeat([]byte{1, 2, 3, 4}, 800*600),
  201. },
  202. }
  203. for _, tc := range testCases {
  204. t.Run(tc.name, func(t *testing.T) {
  205. got := New(tc.w, tc.h, tc.c)
  206. want := image.NewNRGBA(tc.dstBounds)
  207. want.Pix = tc.dstPix
  208. if !compareNRGBA(got, want, 0) {
  209. t.Fatalf("got result %#v want %#v", got, want)
  210. }
  211. })
  212. }
  213. }
  214. func BenchmarkNew(b *testing.B) {
  215. b.ReportAllocs()
  216. for i := 0; i < b.N; i++ {
  217. New(1024, 1024, color.White)
  218. }
  219. }
  220. func TestFormats(t *testing.T) {
  221. formatNames := map[Format]string{
  222. JPEG: "JPEG",
  223. PNG: "PNG",
  224. GIF: "GIF",
  225. BMP: "BMP",
  226. TIFF: "TIFF",
  227. Format(-1): "Unsupported",
  228. }
  229. for format, name := range formatNames {
  230. got := format.String()
  231. if got != name {
  232. t.Fatalf("got format name %q want %q", got, name)
  233. }
  234. }
  235. }
  236. func TestClone(t *testing.T) {
  237. testCases := []struct {
  238. name string
  239. src image.Image
  240. want *image.NRGBA
  241. }{
  242. {
  243. "Clone NRGBA",
  244. &image.NRGBA{
  245. Rect: image.Rect(-1, -1, 0, 1),
  246. Stride: 1 * 4,
  247. Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
  248. },
  249. &image.NRGBA{
  250. Rect: image.Rect(0, 0, 1, 2),
  251. Stride: 1 * 4,
  252. Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
  253. },
  254. },
  255. {
  256. "Clone NRGBA64",
  257. &image.NRGBA64{
  258. Rect: image.Rect(-1, -1, 0, 1),
  259. Stride: 1 * 8,
  260. Pix: []uint8{
  261. 0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
  262. 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
  263. },
  264. },
  265. &image.NRGBA{
  266. Rect: image.Rect(0, 0, 1, 2),
  267. Stride: 1 * 4,
  268. Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
  269. },
  270. },
  271. {
  272. "Clone RGBA",
  273. &image.RGBA{
  274. Rect: image.Rect(-1, -1, 0, 2),
  275. Stride: 1 * 4,
  276. Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
  277. },
  278. &image.NRGBA{
  279. Rect: image.Rect(0, 0, 1, 3),
  280. Stride: 1 * 4,
  281. Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
  282. },
  283. },
  284. {
  285. "Clone RGBA64",
  286. &image.RGBA64{
  287. Rect: image.Rect(-1, -1, 0, 2),
  288. Stride: 1 * 8,
  289. Pix: []uint8{
  290. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  291. 0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
  292. 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
  293. },
  294. },
  295. &image.NRGBA{
  296. Rect: image.Rect(0, 0, 1, 3),
  297. Stride: 1 * 4,
  298. Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
  299. },
  300. },
  301. {
  302. "Clone Gray",
  303. &image.Gray{
  304. Rect: image.Rect(-1, -1, 0, 1),
  305. Stride: 1 * 1,
  306. Pix: []uint8{0x11, 0xee},
  307. },
  308. &image.NRGBA{
  309. Rect: image.Rect(0, 0, 1, 2),
  310. Stride: 1 * 4,
  311. Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
  312. },
  313. },
  314. {
  315. "Clone Gray16",
  316. &image.Gray16{
  317. Rect: image.Rect(-1, -1, 0, 1),
  318. Stride: 1 * 2,
  319. Pix: []uint8{0x11, 0x11, 0xee, 0xee},
  320. },
  321. &image.NRGBA{
  322. Rect: image.Rect(0, 0, 1, 2),
  323. Stride: 1 * 4,
  324. Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
  325. },
  326. },
  327. {
  328. "Clone Alpha",
  329. &image.Alpha{
  330. Rect: image.Rect(-1, -1, 0, 1),
  331. Stride: 1 * 1,
  332. Pix: []uint8{0x11, 0xee},
  333. },
  334. &image.NRGBA{
  335. Rect: image.Rect(0, 0, 1, 2),
  336. Stride: 1 * 4,
  337. Pix: []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
  338. },
  339. },
  340. {
  341. "Clone YCbCr",
  342. &image.YCbCr{
  343. Rect: image.Rect(-1, -1, 5, 0),
  344. SubsampleRatio: image.YCbCrSubsampleRatio444,
  345. YStride: 6,
  346. CStride: 6,
  347. Y: []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
  348. Cb: []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
  349. Cr: []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
  350. },
  351. &image.NRGBA{
  352. Rect: image.Rect(0, 0, 6, 1),
  353. Stride: 6 * 4,
  354. Pix: []uint8{
  355. 0x00, 0x00, 0x00, 0xff,
  356. 0xff, 0xff, 0xff, 0xff,
  357. 0x7f, 0x7f, 0x7f, 0xff,
  358. 0x7f, 0x00, 0x00, 0xff,
  359. 0x00, 0x7f, 0x00, 0xff,
  360. 0x00, 0x00, 0x7f, 0xff,
  361. },
  362. },
  363. },
  364. {
  365. "Clone YCbCr 444",
  366. &image.YCbCr{
  367. Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
  368. Cb: []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
  369. Cr: []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
  370. YStride: 4,
  371. CStride: 4,
  372. SubsampleRatio: image.YCbCrSubsampleRatio444,
  373. Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
  374. },
  375. &image.NRGBA{
  376. Pix: []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
  377. Stride: 16,
  378. Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
  379. },
  380. },
  381. {
  382. "Clone YCbCr 440",
  383. &image.YCbCr{
  384. Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
  385. Cb: []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
  386. Cr: []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
  387. YStride: 4,
  388. CStride: 4,
  389. SubsampleRatio: image.YCbCrSubsampleRatio440,
  390. Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
  391. },
  392. &image.NRGBA{
  393. Pix: []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
  394. Stride: 16,
  395. Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
  396. },
  397. },
  398. {
  399. "Clone YCbCr 422",
  400. &image.YCbCr{
  401. Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
  402. Cb: []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
  403. Cr: []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
  404. YStride: 4,
  405. CStride: 2,
  406. SubsampleRatio: image.YCbCrSubsampleRatio422,
  407. Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
  408. },
  409. &image.NRGBA{
  410. Pix: []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
  411. Stride: 16,
  412. Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
  413. },
  414. },
  415. {
  416. "Clone YCbCr 420",
  417. &image.YCbCr{
  418. Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
  419. Cb: []uint8{0x01, 0xaa, 0x80, 0x80},
  420. Cr: []uint8{0x95, 0xb5, 0x80, 0x80},
  421. YStride: 4, CStride: 2,
  422. SubsampleRatio: image.YCbCrSubsampleRatio420,
  423. Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
  424. },
  425. &image.NRGBA{
  426. Pix: []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
  427. Stride: 16,
  428. Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
  429. },
  430. },
  431. {
  432. "Clone Paletted",
  433. &image.Paletted{
  434. Rect: image.Rect(-1, -1, 5, 0),
  435. Stride: 6 * 1,
  436. Palette: color.Palette{
  437. color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
  438. color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
  439. color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
  440. color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
  441. color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
  442. color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
  443. },
  444. Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
  445. },
  446. &image.NRGBA{
  447. Rect: image.Rect(0, 0, 6, 1),
  448. Stride: 6 * 4,
  449. Pix: []uint8{
  450. 0x00, 0x00, 0x00, 0xff,
  451. 0xff, 0xff, 0xff, 0xff,
  452. 0x7f, 0x7f, 0x7f, 0xff,
  453. 0x7f, 0x00, 0x00, 0xff,
  454. 0x00, 0x7f, 0x00, 0xff,
  455. 0x00, 0x00, 0x7f, 0xff,
  456. },
  457. },
  458. },
  459. }
  460. for _, tc := range testCases {
  461. t.Run(tc.name, func(t *testing.T) {
  462. got := Clone(tc.src)
  463. delta := 0
  464. if _, ok := tc.src.(*image.YCbCr); ok {
  465. delta = 1
  466. }
  467. if !compareNRGBA(got, tc.want, delta) {
  468. t.Fatalf("got result %#v want %#v", got, tc.want)
  469. }
  470. })
  471. }
  472. }
  473. func TestFormatFromExtension(t *testing.T) {
  474. testCases := []struct {
  475. name string
  476. ext string
  477. want Format
  478. err error
  479. }{
  480. {
  481. name: "jpg without leading dot",
  482. ext: "jpg",
  483. want: JPEG,
  484. },
  485. {
  486. name: "jpg with leading dot",
  487. ext: ".jpg",
  488. want: JPEG,
  489. },
  490. {
  491. name: "jpg uppercase",
  492. ext: ".JPG",
  493. want: JPEG,
  494. },
  495. {
  496. name: "unsupported",
  497. ext: ".unsupportedextension",
  498. want: -1,
  499. err: ErrUnsupportedFormat,
  500. },
  501. }
  502. for _, tc := range testCases {
  503. t.Run(tc.name, func(t *testing.T) {
  504. got, err := FormatFromExtension(tc.ext)
  505. if err != tc.err {
  506. t.Errorf("got error %#v want %#v", err, tc.err)
  507. }
  508. if got != tc.want {
  509. t.Errorf("got result %#v want %#v", got, tc.want)
  510. }
  511. })
  512. }
  513. }