gen.go 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403
  1. // Copyright 2015 The Go Authors. 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. // +build ignore
  5. package main
  6. import (
  7. "bytes"
  8. "flag"
  9. "fmt"
  10. "go/format"
  11. "io/ioutil"
  12. "log"
  13. "os"
  14. "strings"
  15. )
  16. var debug = flag.Bool("debug", false, "")
  17. func main() {
  18. flag.Parse()
  19. w := new(bytes.Buffer)
  20. w.WriteString("// generated by \"go run gen.go\". DO NOT EDIT.\n\n" +
  21. "package draw\n\nimport (\n" +
  22. "\"image\"\n" +
  23. "\"image/color\"\n" +
  24. "\"math\"\n" +
  25. "\n" +
  26. "\"golang.org/x/image/math/f64\"\n" +
  27. ")\n")
  28. gen(w, "nnInterpolator", codeNNScaleLeaf, codeNNTransformLeaf)
  29. gen(w, "ablInterpolator", codeABLScaleLeaf, codeABLTransformLeaf)
  30. genKernel(w)
  31. if *debug {
  32. os.Stdout.Write(w.Bytes())
  33. return
  34. }
  35. out, err := format.Source(w.Bytes())
  36. if err != nil {
  37. log.Fatal(err)
  38. }
  39. if err := ioutil.WriteFile("impl.go", out, 0660); err != nil {
  40. log.Fatal(err)
  41. }
  42. }
  43. var (
  44. // dsTypes are the (dst image type, src image type) pairs to generate
  45. // scale_DType_SType implementations for. The last element in the slice
  46. // should be the fallback pair ("Image", "image.Image").
  47. //
  48. // TODO: add *image.CMYK src type after Go 1.5 is released.
  49. // An *image.CMYK is also alwaysOpaque.
  50. dsTypes = []struct{ dType, sType string }{
  51. {"*image.RGBA", "*image.Gray"},
  52. {"*image.RGBA", "*image.NRGBA"},
  53. {"*image.RGBA", "*image.RGBA"},
  54. {"*image.RGBA", "*image.YCbCr"},
  55. {"*image.RGBA", "image.Image"},
  56. {"Image", "image.Image"},
  57. }
  58. dTypes, sTypes []string
  59. sTypesForDType = map[string][]string{}
  60. subsampleRatios = []string{
  61. "444",
  62. "422",
  63. "420",
  64. "440",
  65. }
  66. ops = []string{"Over", "Src"}
  67. // alwaysOpaque are those image.Image implementations that are always
  68. // opaque. For these types, Over is equivalent to the faster Src, in the
  69. // absence of a source mask.
  70. alwaysOpaque = map[string]bool{
  71. "*image.Gray": true,
  72. "*image.YCbCr": true,
  73. }
  74. )
  75. func init() {
  76. dTypesSeen := map[string]bool{}
  77. sTypesSeen := map[string]bool{}
  78. for _, t := range dsTypes {
  79. if !sTypesSeen[t.sType] {
  80. sTypesSeen[t.sType] = true
  81. sTypes = append(sTypes, t.sType)
  82. }
  83. if !dTypesSeen[t.dType] {
  84. dTypesSeen[t.dType] = true
  85. dTypes = append(dTypes, t.dType)
  86. }
  87. sTypesForDType[t.dType] = append(sTypesForDType[t.dType], t.sType)
  88. }
  89. sTypesForDType["anyDType"] = sTypes
  90. }
  91. type data struct {
  92. dType string
  93. sType string
  94. sratio string
  95. receiver string
  96. op string
  97. }
  98. func gen(w *bytes.Buffer, receiver string, codes ...string) {
  99. expn(w, codeRoot, &data{receiver: receiver})
  100. for _, code := range codes {
  101. for _, t := range dsTypes {
  102. for _, op := range ops {
  103. if op == "Over" && alwaysOpaque[t.sType] {
  104. continue
  105. }
  106. expn(w, code, &data{
  107. dType: t.dType,
  108. sType: t.sType,
  109. receiver: receiver,
  110. op: op,
  111. })
  112. }
  113. }
  114. }
  115. }
  116. func genKernel(w *bytes.Buffer) {
  117. expn(w, codeKernelRoot, &data{})
  118. for _, sType := range sTypes {
  119. expn(w, codeKernelScaleLeafX, &data{
  120. sType: sType,
  121. })
  122. }
  123. for _, dType := range dTypes {
  124. for _, op := range ops {
  125. expn(w, codeKernelScaleLeafY, &data{
  126. dType: dType,
  127. op: op,
  128. })
  129. }
  130. }
  131. for _, t := range dsTypes {
  132. for _, op := range ops {
  133. if op == "Over" && alwaysOpaque[t.sType] {
  134. continue
  135. }
  136. expn(w, codeKernelTransformLeaf, &data{
  137. dType: t.dType,
  138. sType: t.sType,
  139. op: op,
  140. })
  141. }
  142. }
  143. }
  144. func expn(w *bytes.Buffer, code string, d *data) {
  145. if d.sType == "*image.YCbCr" && d.sratio == "" {
  146. for _, sratio := range subsampleRatios {
  147. e := *d
  148. e.sratio = sratio
  149. expn(w, code, &e)
  150. }
  151. return
  152. }
  153. for _, line := range strings.Split(code, "\n") {
  154. line = expnLine(line, d)
  155. if line == ";" {
  156. continue
  157. }
  158. fmt.Fprintln(w, line)
  159. }
  160. }
  161. func expnLine(line string, d *data) string {
  162. for {
  163. i := strings.IndexByte(line, '$')
  164. if i < 0 {
  165. break
  166. }
  167. prefix, s := line[:i], line[i+1:]
  168. i = len(s)
  169. for j, c := range s {
  170. if !('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z') {
  171. i = j
  172. break
  173. }
  174. }
  175. dollar, suffix := s[:i], s[i:]
  176. e := expnDollar(prefix, dollar, suffix, d)
  177. if e == "" {
  178. log.Fatalf("couldn't expand %q", line)
  179. }
  180. line = e
  181. }
  182. return line
  183. }
  184. // expnDollar expands a "$foo" fragment in a line of generated code. It returns
  185. // the empty string if there was a problem. It returns ";" if the generated
  186. // code is a no-op.
  187. func expnDollar(prefix, dollar, suffix string, d *data) string {
  188. switch dollar {
  189. case "dType":
  190. return prefix + d.dType + suffix
  191. case "dTypeRN":
  192. return prefix + relName(d.dType) + suffix
  193. case "sratio":
  194. return prefix + d.sratio + suffix
  195. case "sType":
  196. return prefix + d.sType + suffix
  197. case "sTypeRN":
  198. return prefix + relName(d.sType) + suffix
  199. case "receiver":
  200. return prefix + d.receiver + suffix
  201. case "op":
  202. return prefix + d.op + suffix
  203. case "switch":
  204. return expnSwitch("", "", true, suffix)
  205. case "switchD":
  206. return expnSwitch("", "", false, suffix)
  207. case "switchS":
  208. return expnSwitch("", "anyDType", false, suffix)
  209. case "preOuter":
  210. switch d.dType {
  211. default:
  212. return ";"
  213. case "Image":
  214. s := ""
  215. if d.sType == "image.Image" {
  216. s = "srcMask, smp := opts.SrcMask, opts.SrcMaskP\n"
  217. }
  218. return s +
  219. "dstMask, dmp := opts.DstMask, opts.DstMaskP\n" +
  220. "dstColorRGBA64 := &color.RGBA64{}\n" +
  221. "dstColor := color.Color(dstColorRGBA64)"
  222. }
  223. case "preInner":
  224. switch d.dType {
  225. default:
  226. return ";"
  227. case "*image.RGBA":
  228. return "d := " + pixOffset("dst", "dr.Min.X+adr.Min.X", "dr.Min.Y+int(dy)", "*4", "*dst.Stride")
  229. }
  230. case "preKernelOuter":
  231. switch d.sType {
  232. default:
  233. return ";"
  234. case "image.Image":
  235. return "srcMask, smp := opts.SrcMask, opts.SrcMaskP"
  236. }
  237. case "preKernelInner":
  238. switch d.dType {
  239. default:
  240. return ";"
  241. case "*image.RGBA":
  242. return "d := " + pixOffset("dst", "dr.Min.X+int(dx)", "dr.Min.Y+adr.Min.Y", "*4", "*dst.Stride")
  243. }
  244. case "blend":
  245. args, _ := splitArgs(suffix)
  246. if len(args) != 4 {
  247. return ""
  248. }
  249. switch d.sType {
  250. default:
  251. return argf(args, ""+
  252. "$3r = $0*$1r + $2*$3r\n"+
  253. "$3g = $0*$1g + $2*$3g\n"+
  254. "$3b = $0*$1b + $2*$3b\n"+
  255. "$3a = $0*$1a + $2*$3a",
  256. )
  257. case "*image.Gray":
  258. return argf(args, ""+
  259. "$3r = $0*$1r + $2*$3r",
  260. )
  261. case "*image.YCbCr":
  262. return argf(args, ""+
  263. "$3r = $0*$1r + $2*$3r\n"+
  264. "$3g = $0*$1g + $2*$3g\n"+
  265. "$3b = $0*$1b + $2*$3b",
  266. )
  267. }
  268. case "clampToAlpha":
  269. if alwaysOpaque[d.sType] {
  270. return ";"
  271. }
  272. // Go uses alpha-premultiplied color. The naive computation can lead to
  273. // invalid colors, e.g. red > alpha, when some weights are negative.
  274. return `
  275. if pr > pa {
  276. pr = pa
  277. }
  278. if pg > pa {
  279. pg = pa
  280. }
  281. if pb > pa {
  282. pb = pa
  283. }
  284. `
  285. case "convFtou":
  286. args, _ := splitArgs(suffix)
  287. if len(args) != 2 {
  288. return ""
  289. }
  290. switch d.sType {
  291. default:
  292. return argf(args, ""+
  293. "$0r := uint32($1r)\n"+
  294. "$0g := uint32($1g)\n"+
  295. "$0b := uint32($1b)\n"+
  296. "$0a := uint32($1a)",
  297. )
  298. case "*image.Gray":
  299. return argf(args, ""+
  300. "$0r := uint32($1r)",
  301. )
  302. case "*image.YCbCr":
  303. return argf(args, ""+
  304. "$0r := uint32($1r)\n"+
  305. "$0g := uint32($1g)\n"+
  306. "$0b := uint32($1b)",
  307. )
  308. }
  309. case "outputu":
  310. args, _ := splitArgs(suffix)
  311. if len(args) != 3 {
  312. return ""
  313. }
  314. switch d.op {
  315. case "Over":
  316. switch d.dType {
  317. default:
  318. log.Fatalf("bad dType %q", d.dType)
  319. case "Image":
  320. return argf(args, ""+
  321. "qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
  322. "if dstMask != nil {\n"+
  323. " _, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
  324. " $2r = $2r * ma / 0xffff\n"+
  325. " $2g = $2g * ma / 0xffff\n"+
  326. " $2b = $2b * ma / 0xffff\n"+
  327. " $2a = $2a * ma / 0xffff\n"+
  328. "}\n"+
  329. "$2a1 := 0xffff - $2a\n"+
  330. "dstColorRGBA64.R = uint16(qr*$2a1/0xffff + $2r)\n"+
  331. "dstColorRGBA64.G = uint16(qg*$2a1/0xffff + $2g)\n"+
  332. "dstColorRGBA64.B = uint16(qb*$2a1/0xffff + $2b)\n"+
  333. "dstColorRGBA64.A = uint16(qa*$2a1/0xffff + $2a)\n"+
  334. "dst.Set($0, $1, dstColor)",
  335. )
  336. case "*image.RGBA":
  337. return argf(args, ""+
  338. "$2a1 := (0xffff - $2a) * 0x101\n"+
  339. "dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*$2a1/0xffff + $2r) >> 8)\n"+
  340. "dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*$2a1/0xffff + $2g) >> 8)\n"+
  341. "dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*$2a1/0xffff + $2b) >> 8)\n"+
  342. "dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*$2a1/0xffff + $2a) >> 8)",
  343. )
  344. }
  345. case "Src":
  346. switch d.dType {
  347. default:
  348. log.Fatalf("bad dType %q", d.dType)
  349. case "Image":
  350. return argf(args, ""+
  351. "if dstMask != nil {\n"+
  352. " qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
  353. " _, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
  354. " pr = pr * ma / 0xffff\n"+
  355. " pg = pg * ma / 0xffff\n"+
  356. " pb = pb * ma / 0xffff\n"+
  357. " pa = pa * ma / 0xffff\n"+
  358. " $2a1 := 0xffff - ma\n"+ // Note that this is ma, not $2a.
  359. " dstColorRGBA64.R = uint16(qr*$2a1/0xffff + $2r)\n"+
  360. " dstColorRGBA64.G = uint16(qg*$2a1/0xffff + $2g)\n"+
  361. " dstColorRGBA64.B = uint16(qb*$2a1/0xffff + $2b)\n"+
  362. " dstColorRGBA64.A = uint16(qa*$2a1/0xffff + $2a)\n"+
  363. " dst.Set($0, $1, dstColor)\n"+
  364. "} else {\n"+
  365. " dstColorRGBA64.R = uint16($2r)\n"+
  366. " dstColorRGBA64.G = uint16($2g)\n"+
  367. " dstColorRGBA64.B = uint16($2b)\n"+
  368. " dstColorRGBA64.A = uint16($2a)\n"+
  369. " dst.Set($0, $1, dstColor)\n"+
  370. "}",
  371. )
  372. case "*image.RGBA":
  373. switch d.sType {
  374. default:
  375. return argf(args, ""+
  376. "dst.Pix[d+0] = uint8($2r >> 8)\n"+
  377. "dst.Pix[d+1] = uint8($2g >> 8)\n"+
  378. "dst.Pix[d+2] = uint8($2b >> 8)\n"+
  379. "dst.Pix[d+3] = uint8($2a >> 8)",
  380. )
  381. case "*image.Gray":
  382. return argf(args, ""+
  383. "out := uint8($2r >> 8)\n"+
  384. "dst.Pix[d+0] = out\n"+
  385. "dst.Pix[d+1] = out\n"+
  386. "dst.Pix[d+2] = out\n"+
  387. "dst.Pix[d+3] = 0xff",
  388. )
  389. case "*image.YCbCr":
  390. return argf(args, ""+
  391. "dst.Pix[d+0] = uint8($2r >> 8)\n"+
  392. "dst.Pix[d+1] = uint8($2g >> 8)\n"+
  393. "dst.Pix[d+2] = uint8($2b >> 8)\n"+
  394. "dst.Pix[d+3] = 0xff",
  395. )
  396. }
  397. }
  398. }
  399. case "outputf":
  400. args, _ := splitArgs(suffix)
  401. if len(args) != 5 {
  402. return ""
  403. }
  404. ret := ""
  405. switch d.op {
  406. case "Over":
  407. switch d.dType {
  408. default:
  409. log.Fatalf("bad dType %q", d.dType)
  410. case "Image":
  411. ret = argf(args, ""+
  412. "qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
  413. "$3r0 := uint32($2($3r * $4))\n"+
  414. "$3g0 := uint32($2($3g * $4))\n"+
  415. "$3b0 := uint32($2($3b * $4))\n"+
  416. "$3a0 := uint32($2($3a * $4))\n"+
  417. "if dstMask != nil {\n"+
  418. " _, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
  419. " $3r0 = $3r0 * ma / 0xffff\n"+
  420. " $3g0 = $3g0 * ma / 0xffff\n"+
  421. " $3b0 = $3b0 * ma / 0xffff\n"+
  422. " $3a0 = $3a0 * ma / 0xffff\n"+
  423. "}\n"+
  424. "$3a1 := 0xffff - $3a0\n"+
  425. "dstColorRGBA64.R = uint16(qr*$3a1/0xffff + $3r0)\n"+
  426. "dstColorRGBA64.G = uint16(qg*$3a1/0xffff + $3g0)\n"+
  427. "dstColorRGBA64.B = uint16(qb*$3a1/0xffff + $3b0)\n"+
  428. "dstColorRGBA64.A = uint16(qa*$3a1/0xffff + $3a0)\n"+
  429. "dst.Set($0, $1, dstColor)",
  430. )
  431. case "*image.RGBA":
  432. ret = argf(args, ""+
  433. "$3r0 := uint32($2($3r * $4))\n"+
  434. "$3g0 := uint32($2($3g * $4))\n"+
  435. "$3b0 := uint32($2($3b * $4))\n"+
  436. "$3a0 := uint32($2($3a * $4))\n"+
  437. "$3a1 := (0xffff - uint32($3a0)) * 0x101\n"+
  438. "dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*$3a1/0xffff + $3r0) >> 8)\n"+
  439. "dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*$3a1/0xffff + $3g0) >> 8)\n"+
  440. "dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*$3a1/0xffff + $3b0) >> 8)\n"+
  441. "dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*$3a1/0xffff + $3a0) >> 8)",
  442. )
  443. }
  444. case "Src":
  445. switch d.dType {
  446. default:
  447. log.Fatalf("bad dType %q", d.dType)
  448. case "Image":
  449. ret = argf(args, ""+
  450. "if dstMask != nil {\n"+
  451. " qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
  452. " _, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
  453. " pr := uint32($2($3r * $4)) * ma / 0xffff\n"+
  454. " pg := uint32($2($3g * $4)) * ma / 0xffff\n"+
  455. " pb := uint32($2($3b * $4)) * ma / 0xffff\n"+
  456. " pa := uint32($2($3a * $4)) * ma / 0xffff\n"+
  457. " pa1 := 0xffff - ma\n"+ // Note that this is ma, not pa.
  458. " dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)\n"+
  459. " dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)\n"+
  460. " dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)\n"+
  461. " dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)\n"+
  462. " dst.Set($0, $1, dstColor)\n"+
  463. "} else {\n"+
  464. " dstColorRGBA64.R = $2($3r * $4)\n"+
  465. " dstColorRGBA64.G = $2($3g * $4)\n"+
  466. " dstColorRGBA64.B = $2($3b * $4)\n"+
  467. " dstColorRGBA64.A = $2($3a * $4)\n"+
  468. " dst.Set($0, $1, dstColor)\n"+
  469. "}",
  470. )
  471. case "*image.RGBA":
  472. switch d.sType {
  473. default:
  474. ret = argf(args, ""+
  475. "dst.Pix[d+0] = uint8($2($3r * $4) >> 8)\n"+
  476. "dst.Pix[d+1] = uint8($2($3g * $4) >> 8)\n"+
  477. "dst.Pix[d+2] = uint8($2($3b * $4) >> 8)\n"+
  478. "dst.Pix[d+3] = uint8($2($3a * $4) >> 8)",
  479. )
  480. case "*image.Gray":
  481. ret = argf(args, ""+
  482. "out := uint8($2($3r * $4) >> 8)\n"+
  483. "dst.Pix[d+0] = out\n"+
  484. "dst.Pix[d+1] = out\n"+
  485. "dst.Pix[d+2] = out\n"+
  486. "dst.Pix[d+3] = 0xff",
  487. )
  488. case "*image.YCbCr":
  489. ret = argf(args, ""+
  490. "dst.Pix[d+0] = uint8($2($3r * $4) >> 8)\n"+
  491. "dst.Pix[d+1] = uint8($2($3g * $4) >> 8)\n"+
  492. "dst.Pix[d+2] = uint8($2($3b * $4) >> 8)\n"+
  493. "dst.Pix[d+3] = 0xff",
  494. )
  495. }
  496. }
  497. }
  498. return strings.Replace(ret, " * 1)", ")", -1)
  499. case "srcf", "srcu":
  500. lhs, eqOp := splitEq(prefix)
  501. if lhs == "" {
  502. return ""
  503. }
  504. args, extra := splitArgs(suffix)
  505. if len(args) != 2 {
  506. return ""
  507. }
  508. tmp := ""
  509. if dollar == "srcf" {
  510. tmp = "u"
  511. }
  512. // TODO: there's no need to multiply by 0x101 in the switch below if
  513. // the next thing we're going to do is shift right by 8.
  514. buf := new(bytes.Buffer)
  515. switch d.sType {
  516. default:
  517. log.Fatalf("bad sType %q", d.sType)
  518. case "image.Image":
  519. fmt.Fprintf(buf, ""+
  520. "%sr%s, %sg%s, %sb%s, %sa%s := src.At(%s, %s).RGBA()\n",
  521. lhs, tmp, lhs, tmp, lhs, tmp, lhs, tmp, args[0], args[1],
  522. )
  523. if d.dType == "" || d.dType == "Image" {
  524. fmt.Fprintf(buf, ""+
  525. "if srcMask != nil {\n"+
  526. " _, _, _, ma := srcMask.At(smp.X+%s, smp.Y+%s).RGBA()\n"+
  527. " %sr%s = %sr%s * ma / 0xffff\n"+
  528. " %sg%s = %sg%s * ma / 0xffff\n"+
  529. " %sb%s = %sb%s * ma / 0xffff\n"+
  530. " %sa%s = %sa%s * ma / 0xffff\n"+
  531. "}\n",
  532. args[0], args[1],
  533. lhs, tmp, lhs, tmp,
  534. lhs, tmp, lhs, tmp,
  535. lhs, tmp, lhs, tmp,
  536. lhs, tmp, lhs, tmp,
  537. )
  538. }
  539. case "*image.Gray":
  540. fmt.Fprintf(buf, ""+
  541. "%si := %s\n"+
  542. "%sr%s := uint32(src.Pix[%si]) * 0x101\n",
  543. lhs, pixOffset("src", args[0], args[1], "", "*src.Stride"),
  544. lhs, tmp, lhs,
  545. )
  546. case "*image.NRGBA":
  547. fmt.Fprintf(buf, ""+
  548. "%si := %s\n"+
  549. "%sa%s := uint32(src.Pix[%si+3]) * 0x101\n"+
  550. "%sr%s := uint32(src.Pix[%si+0]) * %sa%s / 0xff\n"+
  551. "%sg%s := uint32(src.Pix[%si+1]) * %sa%s / 0xff\n"+
  552. "%sb%s := uint32(src.Pix[%si+2]) * %sa%s / 0xff\n",
  553. lhs, pixOffset("src", args[0], args[1], "*4", "*src.Stride"),
  554. lhs, tmp, lhs,
  555. lhs, tmp, lhs, lhs, tmp,
  556. lhs, tmp, lhs, lhs, tmp,
  557. lhs, tmp, lhs, lhs, tmp,
  558. )
  559. case "*image.RGBA":
  560. fmt.Fprintf(buf, ""+
  561. "%si := %s\n"+
  562. "%sr%s := uint32(src.Pix[%si+0]) * 0x101\n"+
  563. "%sg%s := uint32(src.Pix[%si+1]) * 0x101\n"+
  564. "%sb%s := uint32(src.Pix[%si+2]) * 0x101\n"+
  565. "%sa%s := uint32(src.Pix[%si+3]) * 0x101\n",
  566. lhs, pixOffset("src", args[0], args[1], "*4", "*src.Stride"),
  567. lhs, tmp, lhs,
  568. lhs, tmp, lhs,
  569. lhs, tmp, lhs,
  570. lhs, tmp, lhs,
  571. )
  572. case "*image.YCbCr":
  573. fmt.Fprintf(buf, ""+
  574. "%si := %s\n"+
  575. "%sj := %s\n"+
  576. "%s\n",
  577. lhs, pixOffset("src", args[0], args[1], "", "*src.YStride"),
  578. lhs, cOffset(args[0], args[1], d.sratio),
  579. ycbcrToRGB(lhs, tmp),
  580. )
  581. }
  582. if dollar == "srcf" {
  583. switch d.sType {
  584. default:
  585. fmt.Fprintf(buf, ""+
  586. "%sr %s float64(%sru)%s\n"+
  587. "%sg %s float64(%sgu)%s\n"+
  588. "%sb %s float64(%sbu)%s\n"+
  589. "%sa %s float64(%sau)%s\n",
  590. lhs, eqOp, lhs, extra,
  591. lhs, eqOp, lhs, extra,
  592. lhs, eqOp, lhs, extra,
  593. lhs, eqOp, lhs, extra,
  594. )
  595. case "*image.Gray":
  596. fmt.Fprintf(buf, ""+
  597. "%sr %s float64(%sru)%s\n",
  598. lhs, eqOp, lhs, extra,
  599. )
  600. case "*image.YCbCr":
  601. fmt.Fprintf(buf, ""+
  602. "%sr %s float64(%sru)%s\n"+
  603. "%sg %s float64(%sgu)%s\n"+
  604. "%sb %s float64(%sbu)%s\n",
  605. lhs, eqOp, lhs, extra,
  606. lhs, eqOp, lhs, extra,
  607. lhs, eqOp, lhs, extra,
  608. )
  609. }
  610. }
  611. return strings.TrimSpace(buf.String())
  612. case "tweakD":
  613. if d.dType == "*image.RGBA" {
  614. return "d += dst.Stride"
  615. }
  616. return ";"
  617. case "tweakDx":
  618. if d.dType == "*image.RGBA" {
  619. return strings.Replace(prefix, "dx++", "dx, d = dx+1, d+4", 1)
  620. }
  621. return prefix
  622. case "tweakDy":
  623. if d.dType == "*image.RGBA" {
  624. return strings.Replace(prefix, "for dy, s", "for _, s", 1)
  625. }
  626. return prefix
  627. case "tweakP":
  628. switch d.sType {
  629. case "*image.Gray":
  630. if strings.HasPrefix(strings.TrimSpace(prefix), "pa * ") {
  631. return "1,"
  632. }
  633. return "pr,"
  634. case "*image.YCbCr":
  635. if strings.HasPrefix(strings.TrimSpace(prefix), "pa * ") {
  636. return "1,"
  637. }
  638. }
  639. return prefix
  640. case "tweakPr":
  641. if d.sType == "*image.Gray" {
  642. return "pr *= s.invTotalWeightFFFF"
  643. }
  644. return ";"
  645. case "tweakVarP":
  646. switch d.sType {
  647. case "*image.Gray":
  648. return strings.Replace(prefix, "var pr, pg, pb, pa", "var pr", 1)
  649. case "*image.YCbCr":
  650. return strings.Replace(prefix, "var pr, pg, pb, pa", "var pr, pg, pb", 1)
  651. }
  652. return prefix
  653. }
  654. return ""
  655. }
  656. func expnSwitch(op, dType string, expandBoth bool, template string) string {
  657. if op == "" && dType != "anyDType" {
  658. lines := []string{"switch op {"}
  659. for _, op = range ops {
  660. lines = append(lines,
  661. fmt.Sprintf("case %s:", op),
  662. expnSwitch(op, dType, expandBoth, template),
  663. )
  664. }
  665. lines = append(lines, "}")
  666. return strings.Join(lines, "\n")
  667. }
  668. switchVar := "dst"
  669. if dType != "" {
  670. switchVar = "src"
  671. }
  672. lines := []string{fmt.Sprintf("switch %s := %s.(type) {", switchVar, switchVar)}
  673. fallback, values := "Image", dTypes
  674. if dType != "" {
  675. fallback, values = "image.Image", sTypesForDType[dType]
  676. }
  677. for _, v := range values {
  678. if dType != "" {
  679. // v is the sType. Skip those always-opaque sTypes, where Over is
  680. // equivalent to Src.
  681. if op == "Over" && alwaysOpaque[v] {
  682. continue
  683. }
  684. }
  685. if v == fallback {
  686. lines = append(lines, "default:")
  687. } else {
  688. lines = append(lines, fmt.Sprintf("case %s:", v))
  689. }
  690. if dType != "" {
  691. if v == "*image.YCbCr" {
  692. lines = append(lines, expnSwitchYCbCr(op, dType, template))
  693. } else {
  694. lines = append(lines, expnLine(template, &data{dType: dType, sType: v, op: op}))
  695. }
  696. } else if !expandBoth {
  697. lines = append(lines, expnLine(template, &data{dType: v, op: op}))
  698. } else {
  699. lines = append(lines, expnSwitch(op, v, false, template))
  700. }
  701. }
  702. lines = append(lines, "}")
  703. return strings.Join(lines, "\n")
  704. }
  705. func expnSwitchYCbCr(op, dType, template string) string {
  706. lines := []string{
  707. "switch src.SubsampleRatio {",
  708. "default:",
  709. expnLine(template, &data{dType: dType, sType: "image.Image", op: op}),
  710. }
  711. for _, sratio := range subsampleRatios {
  712. lines = append(lines,
  713. fmt.Sprintf("case image.YCbCrSubsampleRatio%s:", sratio),
  714. expnLine(template, &data{dType: dType, sType: "*image.YCbCr", sratio: sratio, op: op}),
  715. )
  716. }
  717. lines = append(lines, "}")
  718. return strings.Join(lines, "\n")
  719. }
  720. func argf(args []string, s string) string {
  721. if len(args) > 9 {
  722. panic("too many args")
  723. }
  724. for i, a := range args {
  725. old := fmt.Sprintf("$%d", i)
  726. s = strings.Replace(s, old, a, -1)
  727. }
  728. return s
  729. }
  730. func pixOffset(m, x, y, xstride, ystride string) string {
  731. return fmt.Sprintf("(%s-%s.Rect.Min.Y)%s + (%s-%s.Rect.Min.X)%s", y, m, ystride, x, m, xstride)
  732. }
  733. func cOffset(x, y, sratio string) string {
  734. switch sratio {
  735. case "444":
  736. return fmt.Sprintf("( %s - src.Rect.Min.Y )*src.CStride + ( %s - src.Rect.Min.X )", y, x)
  737. case "422":
  738. return fmt.Sprintf("( %s - src.Rect.Min.Y )*src.CStride + ((%s)/2 - src.Rect.Min.X/2)", y, x)
  739. case "420":
  740. return fmt.Sprintf("((%s)/2 - src.Rect.Min.Y/2)*src.CStride + ((%s)/2 - src.Rect.Min.X/2)", y, x)
  741. case "440":
  742. return fmt.Sprintf("((%s)/2 - src.Rect.Min.Y/2)*src.CStride + ( %s - src.Rect.Min.X )", y, x)
  743. }
  744. return fmt.Sprintf("unsupported sratio %q", sratio)
  745. }
  746. func ycbcrToRGB(lhs, tmp string) string {
  747. s := `
  748. // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
  749. $yy1 := int(src.Y[$i]) * 0x10101
  750. $cb1 := int(src.Cb[$j]) - 128
  751. $cr1 := int(src.Cr[$j]) - 128
  752. $r@ := ($yy1 + 91881*$cr1) >> 8
  753. $g@ := ($yy1 - 22554*$cb1 - 46802*$cr1) >> 8
  754. $b@ := ($yy1 + 116130*$cb1) >> 8
  755. if $r@ < 0 {
  756. $r@ = 0
  757. } else if $r@ > 0xffff {
  758. $r@ = 0xffff
  759. }
  760. if $g@ < 0 {
  761. $g@ = 0
  762. } else if $g@ > 0xffff {
  763. $g@ = 0xffff
  764. }
  765. if $b@ < 0 {
  766. $b@ = 0
  767. } else if $b@ > 0xffff {
  768. $b@ = 0xffff
  769. }
  770. `
  771. s = strings.Replace(s, "$", lhs, -1)
  772. s = strings.Replace(s, "@", tmp, -1)
  773. return s
  774. }
  775. func split(s, sep string) (string, string) {
  776. if i := strings.Index(s, sep); i >= 0 {
  777. return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):])
  778. }
  779. return "", ""
  780. }
  781. func splitEq(s string) (lhs, eqOp string) {
  782. s = strings.TrimSpace(s)
  783. if lhs, _ = split(s, ":="); lhs != "" {
  784. return lhs, ":="
  785. }
  786. if lhs, _ = split(s, "+="); lhs != "" {
  787. return lhs, "+="
  788. }
  789. return "", ""
  790. }
  791. func splitArgs(s string) (args []string, extra string) {
  792. s = strings.TrimSpace(s)
  793. if s == "" || s[0] != '[' {
  794. return nil, ""
  795. }
  796. s = s[1:]
  797. i := strings.IndexByte(s, ']')
  798. if i < 0 {
  799. return nil, ""
  800. }
  801. args, extra = strings.Split(s[:i], ","), s[i+1:]
  802. for i := range args {
  803. args[i] = strings.TrimSpace(args[i])
  804. }
  805. return args, extra
  806. }
  807. func relName(s string) string {
  808. if i := strings.LastIndex(s, "."); i >= 0 {
  809. return s[i+1:]
  810. }
  811. return s
  812. }
  813. const (
  814. codeRoot = `
  815. func (z $receiver) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
  816. // Try to simplify a Scale to a Copy.
  817. if dr.Size() == sr.Size() {
  818. Copy(dst, dr.Min, src, sr, op, opts)
  819. return
  820. }
  821. var o Options
  822. if opts != nil {
  823. o = *opts
  824. }
  825. // adr is the affected destination pixels.
  826. adr := dst.Bounds().Intersect(dr)
  827. adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
  828. if adr.Empty() || sr.Empty() {
  829. return
  830. }
  831. // Make adr relative to dr.Min.
  832. adr = adr.Sub(dr.Min)
  833. if op == Over && o.SrcMask == nil && opaque(src) {
  834. op = Src
  835. }
  836. // sr is the source pixels. If it extends beyond the src bounds,
  837. // we cannot use the type-specific fast paths, as they access
  838. // the Pix fields directly without bounds checking.
  839. //
  840. // Similarly, the fast paths assume that the masks are nil.
  841. if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
  842. switch op {
  843. case Over:
  844. z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
  845. case Src:
  846. z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
  847. }
  848. } else if _, ok := src.(*image.Uniform); ok {
  849. Draw(dst, dr, src, src.Bounds().Min, op)
  850. } else {
  851. $switch z.scale_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, src, sr, &o)
  852. }
  853. }
  854. func (z $receiver) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
  855. // Try to simplify a Transform to a Copy.
  856. if s2d[0] == 1 && s2d[1] == 0 && s2d[3] == 0 && s2d[4] == 1 {
  857. dx := int(s2d[2])
  858. dy := int(s2d[5])
  859. if float64(dx) == s2d[2] && float64(dy) == s2d[5] {
  860. Copy(dst, image.Point{X: sr.Min.X + dx, Y: sr.Min.X + dy}, src, sr, op, opts)
  861. return
  862. }
  863. }
  864. var o Options
  865. if opts != nil {
  866. o = *opts
  867. }
  868. dr := transformRect(&s2d, &sr)
  869. // adr is the affected destination pixels.
  870. adr := dst.Bounds().Intersect(dr)
  871. adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
  872. if adr.Empty() || sr.Empty() {
  873. return
  874. }
  875. if op == Over && o.SrcMask == nil && opaque(src) {
  876. op = Src
  877. }
  878. d2s := invert(&s2d)
  879. // bias is a translation of the mapping from dst coordinates to src
  880. // coordinates such that the latter temporarily have non-negative X
  881. // and Y coordinates. This allows us to write int(f) instead of
  882. // int(math.Floor(f)), since "round to zero" and "round down" are
  883. // equivalent when f >= 0, but the former is much cheaper. The X--
  884. // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
  885. // adjustment.
  886. bias := transformRect(&d2s, &adr).Min
  887. bias.X--
  888. bias.Y--
  889. d2s[2] -= float64(bias.X)
  890. d2s[5] -= float64(bias.Y)
  891. // Make adr relative to dr.Min.
  892. adr = adr.Sub(dr.Min)
  893. // sr is the source pixels. If it extends beyond the src bounds,
  894. // we cannot use the type-specific fast paths, as they access
  895. // the Pix fields directly without bounds checking.
  896. //
  897. // Similarly, the fast paths assume that the masks are nil.
  898. if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
  899. switch op {
  900. case Over:
  901. z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
  902. case Src:
  903. z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
  904. }
  905. } else if u, ok := src.(*image.Uniform); ok {
  906. transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
  907. } else {
  908. $switch z.transform_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, &d2s, src, sr, bias, &o)
  909. }
  910. }
  911. `
  912. codeNNScaleLeaf = `
  913. func (nnInterpolator) scale_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle, opts *Options) {
  914. dw2 := uint64(dr.Dx()) * 2
  915. dh2 := uint64(dr.Dy()) * 2
  916. sw := uint64(sr.Dx())
  917. sh := uint64(sr.Dy())
  918. $preOuter
  919. for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
  920. sy := (2*uint64(dy) + 1) * sh / dh2
  921. $preInner
  922. for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { $tweakDx
  923. sx := (2*uint64(dx) + 1) * sw / dw2
  924. p := $srcu[sr.Min.X + int(sx), sr.Min.Y + int(sy)]
  925. $outputu[dr.Min.X + int(dx), dr.Min.Y + int(dy), p]
  926. }
  927. }
  928. }
  929. `
  930. codeNNTransformLeaf = `
  931. func (nnInterpolator) transform_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point, opts *Options) {
  932. $preOuter
  933. for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
  934. dyf := float64(dr.Min.Y + int(dy)) + 0.5
  935. $preInner
  936. for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { $tweakDx
  937. dxf := float64(dr.Min.X + int(dx)) + 0.5
  938. sx0 := int(d2s[0]*dxf + d2s[1]*dyf + d2s[2]) + bias.X
  939. sy0 := int(d2s[3]*dxf + d2s[4]*dyf + d2s[5]) + bias.Y
  940. if !(image.Point{sx0, sy0}).In(sr) {
  941. continue
  942. }
  943. p := $srcu[sx0, sy0]
  944. $outputu[dr.Min.X + int(dx), dr.Min.Y + int(dy), p]
  945. }
  946. }
  947. }
  948. `
  949. codeABLScaleLeaf = `
  950. func (ablInterpolator) scale_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle, opts *Options) {
  951. sw := int32(sr.Dx())
  952. sh := int32(sr.Dy())
  953. yscale := float64(sh) / float64(dr.Dy())
  954. xscale := float64(sw) / float64(dr.Dx())
  955. swMinus1, shMinus1 := sw - 1, sh - 1
  956. $preOuter
  957. for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
  958. sy := (float64(dy)+0.5)*yscale - 0.5
  959. // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
  960. // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
  961. // sx, below.
  962. sy0 := int32(sy)
  963. yFrac0 := sy - float64(sy0)
  964. yFrac1 := 1 - yFrac0
  965. sy1 := sy0 + 1
  966. if sy < 0 {
  967. sy0, sy1 = 0, 0
  968. yFrac0, yFrac1 = 0, 1
  969. } else if sy1 > shMinus1 {
  970. sy0, sy1 = shMinus1, shMinus1
  971. yFrac0, yFrac1 = 1, 0
  972. }
  973. $preInner
  974. for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { $tweakDx
  975. sx := (float64(dx)+0.5)*xscale - 0.5
  976. sx0 := int32(sx)
  977. xFrac0 := sx - float64(sx0)
  978. xFrac1 := 1 - xFrac0
  979. sx1 := sx0 + 1
  980. if sx < 0 {
  981. sx0, sx1 = 0, 0
  982. xFrac0, xFrac1 = 0, 1
  983. } else if sx1 > swMinus1 {
  984. sx0, sx1 = swMinus1, swMinus1
  985. xFrac0, xFrac1 = 1, 0
  986. }
  987. s00 := $srcf[sr.Min.X + int(sx0), sr.Min.Y + int(sy0)]
  988. s10 := $srcf[sr.Min.X + int(sx1), sr.Min.Y + int(sy0)]
  989. $blend[xFrac1, s00, xFrac0, s10]
  990. s01 := $srcf[sr.Min.X + int(sx0), sr.Min.Y + int(sy1)]
  991. s11 := $srcf[sr.Min.X + int(sx1), sr.Min.Y + int(sy1)]
  992. $blend[xFrac1, s01, xFrac0, s11]
  993. $blend[yFrac1, s10, yFrac0, s11]
  994. $convFtou[p, s11]
  995. $outputu[dr.Min.X + int(dx), dr.Min.Y + int(dy), p]
  996. }
  997. }
  998. }
  999. `
  1000. codeABLTransformLeaf = `
  1001. func (ablInterpolator) transform_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point, opts *Options) {
  1002. $preOuter
  1003. for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
  1004. dyf := float64(dr.Min.Y + int(dy)) + 0.5
  1005. $preInner
  1006. for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { $tweakDx
  1007. dxf := float64(dr.Min.X + int(dx)) + 0.5
  1008. sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
  1009. sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
  1010. if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
  1011. continue
  1012. }
  1013. sx -= 0.5
  1014. sx0 := int(sx)
  1015. xFrac0 := sx - float64(sx0)
  1016. xFrac1 := 1 - xFrac0
  1017. sx0 += bias.X
  1018. sx1 := sx0 + 1
  1019. if sx0 < sr.Min.X {
  1020. sx0, sx1 = sr.Min.X, sr.Min.X
  1021. xFrac0, xFrac1 = 0, 1
  1022. } else if sx1 >= sr.Max.X {
  1023. sx0, sx1 = sr.Max.X-1, sr.Max.X-1
  1024. xFrac0, xFrac1 = 1, 0
  1025. }
  1026. sy -= 0.5
  1027. sy0 := int(sy)
  1028. yFrac0 := sy - float64(sy0)
  1029. yFrac1 := 1 - yFrac0
  1030. sy0 += bias.Y
  1031. sy1 := sy0 + 1
  1032. if sy0 < sr.Min.Y {
  1033. sy0, sy1 = sr.Min.Y, sr.Min.Y
  1034. yFrac0, yFrac1 = 0, 1
  1035. } else if sy1 >= sr.Max.Y {
  1036. sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
  1037. yFrac0, yFrac1 = 1, 0
  1038. }
  1039. s00 := $srcf[sx0, sy0]
  1040. s10 := $srcf[sx1, sy0]
  1041. $blend[xFrac1, s00, xFrac0, s10]
  1042. s01 := $srcf[sx0, sy1]
  1043. s11 := $srcf[sx1, sy1]
  1044. $blend[xFrac1, s01, xFrac0, s11]
  1045. $blend[yFrac1, s10, yFrac0, s11]
  1046. $convFtou[p, s11]
  1047. $outputu[dr.Min.X + int(dx), dr.Min.Y + int(dy), p]
  1048. }
  1049. }
  1050. }
  1051. `
  1052. codeKernelRoot = `
  1053. func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
  1054. if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
  1055. z.kernel.Scale(dst, dr, src, sr, op, opts)
  1056. return
  1057. }
  1058. var o Options
  1059. if opts != nil {
  1060. o = *opts
  1061. }
  1062. // adr is the affected destination pixels.
  1063. adr := dst.Bounds().Intersect(dr)
  1064. adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
  1065. if adr.Empty() || sr.Empty() {
  1066. return
  1067. }
  1068. // Make adr relative to dr.Min.
  1069. adr = adr.Sub(dr.Min)
  1070. if op == Over && o.SrcMask == nil && opaque(src) {
  1071. op = Src
  1072. }
  1073. if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
  1074. Draw(dst, dr, src, src.Bounds().Min, op)
  1075. return
  1076. }
  1077. // Create a temporary buffer:
  1078. // scaleX distributes the source image's columns over the temporary image.
  1079. // scaleY distributes the temporary image's rows over the destination image.
  1080. var tmp [][4]float64
  1081. if z.pool.New != nil {
  1082. tmpp := z.pool.Get().(*[][4]float64)
  1083. defer z.pool.Put(tmpp)
  1084. tmp = *tmpp
  1085. } else {
  1086. tmp = z.makeTmpBuf()
  1087. }
  1088. // sr is the source pixels. If it extends beyond the src bounds,
  1089. // we cannot use the type-specific fast paths, as they access
  1090. // the Pix fields directly without bounds checking.
  1091. //
  1092. // Similarly, the fast paths assume that the masks are nil.
  1093. if o.SrcMask != nil || !sr.In(src.Bounds()) {
  1094. z.scaleX_Image(tmp, src, sr, &o)
  1095. } else {
  1096. $switchS z.scaleX_$sTypeRN$sratio(tmp, src, sr, &o)
  1097. }
  1098. if o.DstMask != nil {
  1099. switch op {
  1100. case Over:
  1101. z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
  1102. case Src:
  1103. z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
  1104. }
  1105. } else {
  1106. $switchD z.scaleY_$dTypeRN_$op(dst, dr, adr, tmp, &o)
  1107. }
  1108. }
  1109. func (q *Kernel) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
  1110. var o Options
  1111. if opts != nil {
  1112. o = *opts
  1113. }
  1114. dr := transformRect(&s2d, &sr)
  1115. // adr is the affected destination pixels.
  1116. adr := dst.Bounds().Intersect(dr)
  1117. adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
  1118. if adr.Empty() || sr.Empty() {
  1119. return
  1120. }
  1121. if op == Over && o.SrcMask == nil && opaque(src) {
  1122. op = Src
  1123. }
  1124. d2s := invert(&s2d)
  1125. // bias is a translation of the mapping from dst coordinates to src
  1126. // coordinates such that the latter temporarily have non-negative X
  1127. // and Y coordinates. This allows us to write int(f) instead of
  1128. // int(math.Floor(f)), since "round to zero" and "round down" are
  1129. // equivalent when f >= 0, but the former is much cheaper. The X--
  1130. // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
  1131. // adjustment.
  1132. bias := transformRect(&d2s, &adr).Min
  1133. bias.X--
  1134. bias.Y--
  1135. d2s[2] -= float64(bias.X)
  1136. d2s[5] -= float64(bias.Y)
  1137. // Make adr relative to dr.Min.
  1138. adr = adr.Sub(dr.Min)
  1139. if u, ok := src.(*image.Uniform); ok && o.DstMask != nil && o.SrcMask != nil && sr.In(src.Bounds()) {
  1140. transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
  1141. return
  1142. }
  1143. xscale := abs(d2s[0])
  1144. if s := abs(d2s[1]); xscale < s {
  1145. xscale = s
  1146. }
  1147. yscale := abs(d2s[3])
  1148. if s := abs(d2s[4]); yscale < s {
  1149. yscale = s
  1150. }
  1151. // sr is the source pixels. If it extends beyond the src bounds,
  1152. // we cannot use the type-specific fast paths, as they access
  1153. // the Pix fields directly without bounds checking.
  1154. //
  1155. // Similarly, the fast paths assume that the masks are nil.
  1156. if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
  1157. switch op {
  1158. case Over:
  1159. q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
  1160. case Src:
  1161. q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
  1162. }
  1163. } else {
  1164. $switch q.transform_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
  1165. }
  1166. }
  1167. `
  1168. codeKernelScaleLeafX = `
  1169. func (z *kernelScaler) scaleX_$sTypeRN$sratio(tmp [][4]float64, src $sType, sr image.Rectangle, opts *Options) {
  1170. t := 0
  1171. $preKernelOuter
  1172. for y := int32(0); y < z.sh; y++ {
  1173. for _, s := range z.horizontal.sources {
  1174. var pr, pg, pb, pa float64 $tweakVarP
  1175. for _, c := range z.horizontal.contribs[s.i:s.j] {
  1176. p += $srcf[sr.Min.X + int(c.coord), sr.Min.Y + int(y)] * c.weight
  1177. }
  1178. $tweakPr
  1179. tmp[t] = [4]float64{
  1180. pr * s.invTotalWeightFFFF, $tweakP
  1181. pg * s.invTotalWeightFFFF, $tweakP
  1182. pb * s.invTotalWeightFFFF, $tweakP
  1183. pa * s.invTotalWeightFFFF, $tweakP
  1184. }
  1185. t++
  1186. }
  1187. }
  1188. }
  1189. `
  1190. codeKernelScaleLeafY = `
  1191. func (z *kernelScaler) scaleY_$dTypeRN_$op(dst $dType, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
  1192. $preOuter
  1193. for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
  1194. $preKernelInner
  1195. for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { $tweakDy
  1196. var pr, pg, pb, pa float64
  1197. for _, c := range z.vertical.contribs[s.i:s.j] {
  1198. p := &tmp[c.coord*z.dw+dx]
  1199. pr += p[0] * c.weight
  1200. pg += p[1] * c.weight
  1201. pb += p[2] * c.weight
  1202. pa += p[3] * c.weight
  1203. }
  1204. $clampToAlpha
  1205. $outputf[dr.Min.X + int(dx), dr.Min.Y + int(adr.Min.Y + dy), ftou, p, s.invTotalWeight]
  1206. $tweakD
  1207. }
  1208. }
  1209. }
  1210. `
  1211. codeKernelTransformLeaf = `
  1212. func (q *Kernel) transform_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
  1213. // When shrinking, broaden the effective kernel support so that we still
  1214. // visit every source pixel.
  1215. xHalfWidth, xKernelArgScale := q.Support, 1.0
  1216. if xscale > 1 {
  1217. xHalfWidth *= xscale
  1218. xKernelArgScale = 1 / xscale
  1219. }
  1220. yHalfWidth, yKernelArgScale := q.Support, 1.0
  1221. if yscale > 1 {
  1222. yHalfWidth *= yscale
  1223. yKernelArgScale = 1 / yscale
  1224. }
  1225. xWeights := make([]float64, 1 + 2*int(math.Ceil(xHalfWidth)))
  1226. yWeights := make([]float64, 1 + 2*int(math.Ceil(yHalfWidth)))
  1227. $preOuter
  1228. for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
  1229. dyf := float64(dr.Min.Y + int(dy)) + 0.5
  1230. $preInner
  1231. for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { $tweakDx
  1232. dxf := float64(dr.Min.X + int(dx)) + 0.5
  1233. sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
  1234. sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
  1235. if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
  1236. continue
  1237. }
  1238. // TODO: adjust the bias so that we can use int(f) instead
  1239. // of math.Floor(f) and math.Ceil(f).
  1240. sx += float64(bias.X)
  1241. sx -= 0.5
  1242. ix := int(math.Floor(sx - xHalfWidth))
  1243. if ix < sr.Min.X {
  1244. ix = sr.Min.X
  1245. }
  1246. jx := int(math.Ceil(sx + xHalfWidth))
  1247. if jx > sr.Max.X {
  1248. jx = sr.Max.X
  1249. }
  1250. totalXWeight := 0.0
  1251. for kx := ix; kx < jx; kx++ {
  1252. xWeight := 0.0
  1253. if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
  1254. xWeight = q.At(t)
  1255. }
  1256. xWeights[kx - ix] = xWeight
  1257. totalXWeight += xWeight
  1258. }
  1259. for x := range xWeights[:jx-ix] {
  1260. xWeights[x] /= totalXWeight
  1261. }
  1262. sy += float64(bias.Y)
  1263. sy -= 0.5
  1264. iy := int(math.Floor(sy - yHalfWidth))
  1265. if iy < sr.Min.Y {
  1266. iy = sr.Min.Y
  1267. }
  1268. jy := int(math.Ceil(sy + yHalfWidth))
  1269. if jy > sr.Max.Y {
  1270. jy = sr.Max.Y
  1271. }
  1272. totalYWeight := 0.0
  1273. for ky := iy; ky < jy; ky++ {
  1274. yWeight := 0.0
  1275. if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
  1276. yWeight = q.At(t)
  1277. }
  1278. yWeights[ky - iy] = yWeight
  1279. totalYWeight += yWeight
  1280. }
  1281. for y := range yWeights[:jy-iy] {
  1282. yWeights[y] /= totalYWeight
  1283. }
  1284. var pr, pg, pb, pa float64 $tweakVarP
  1285. for ky := iy; ky < jy; ky++ {
  1286. if yWeight := yWeights[ky - iy]; yWeight != 0 {
  1287. for kx := ix; kx < jx; kx++ {
  1288. if w := xWeights[kx - ix] * yWeight; w != 0 {
  1289. p += $srcf[kx, ky] * w
  1290. }
  1291. }
  1292. }
  1293. }
  1294. $clampToAlpha
  1295. $outputf[dr.Min.X + int(dx), dr.Min.Y + int(dy), fffftou, p, 1]
  1296. }
  1297. }
  1298. }
  1299. `
  1300. )