@@ 40,108 40,123 @@ type Options struct {
func Corrupt(m image.Image, opts Options) (*image.NRGBA, error) {
seededRand := rand.New(rand.NewSource(opts.Seed))
+ println(seededRand)
- // trying to obtain raw pointers to color data, since .At(), .Set() are very slow
- m_raw_stride, m_raw_pix := 0, []uint8(nil)
+ var src *image.NRGBA
+ // trying to obtain raw pointers to color data, since .At(), .Set() are very slow
switch m.(type) {
default:
return nil, errors.New("unknown image type")
case *image.NRGBA:
- m_raw := m.(*image.NRGBA)
- m_raw_stride = m_raw.Stride
- m_raw_pix = m_raw.Pix
+ src = m.(*image.NRGBA)
case *image.RGBA:
m_raw := m.(*image.RGBA)
- m_raw_stride = m_raw.Stride
- m_raw_pix = m_raw.Pix
+ src = image.NewNRGBA(m.Bounds())
+ src.Stride = m_raw.Stride
+ src.Pix = m_raw.Pix
}
b := m.Bounds()
// first stage is dissolve+block corruption
- new_img := image.NewNRGBA(b)
+ new_img1 := image.NewNRGBA(b)
+ DissolveAndBlockCorruption(new_img1, src, b, seededRand, opts)
+
+ // second stage is adding per-channel scan inconsistency and brightening
+ new_img2 := image.NewNRGBA(b)
+ ChannelInconsistencyAndBrightening(new_img2, new_img1, b, seededRand, opts)
+
+ // third stage is to add chromatic abberation+chromatic trails
+ // (trails happen because we're changing the same image we process)
+ new_img3 := new_img2
+ ChromaticAbberationAndTrails(new_img3, b, seededRand, opts)
+
+ return new_img3, nil
+}
+
+func DissolveAndBlockCorruption(dst, src *image.NRGBA, b image.Rectangle, rng *rand.Rand, opts Options) {
line_off := 0
stride := 0.
yset := 0
for y := 0; y < b.Max.Y; y++ {
for x := 0; x < b.Max.X; x++ {
// Every BHEIGHT lines in average a new distorted block begins
- if seededRand.Intn(opts.Bheight*b.Max.X) == 0 {
- line_off = offset(seededRand, opts.Boffset)
- stride = seededRand.NormFloat64() * opts.Stride
+ if rng.Intn(opts.Bheight*b.Max.X) == 0 {
+ line_off = offset(rng, opts.Boffset)
+ stride = rng.NormFloat64() * opts.Stride
yset = y
}
+
// at the line where the block has begun, we don't want to offset the image
// so stride_off is 0 on the block's line
stride_off := int(stride * float64(y-yset))
// offset is composed of the blur, block offset, and skew offset (stride)
- offx := offset(seededRand, opts.Mag) + line_off + stride_off
- offy := offset(seededRand, opts.Mag)
+ offx := offset(rng, opts.Mag) + line_off + stride_off
+ offy := offset(rng, opts.Mag)
// copy the corresponding pixel (4 bytes) to the new image
- src_idx := m_raw_stride*wrap(y+offy, b.Max.Y) + 4*wrap(x+offx, b.Max.X)
- dst_idx := new_img.Stride*y + 4*x
+ src_idx := src.Stride*wrap(y+offy, b.Max.Y) + 4*wrap(x+offx, b.Max.X)
+ dst_idx := dst.Stride*y + 4*x
- copy(new_img.Pix[dst_idx:dst_idx+4], m_raw_pix[src_idx:src_idx+4])
+ copy(dst.Pix[dst_idx:dst_idx+4], src.Pix[src_idx:src_idx+4])
}
}
+}
- // second stage is adding per-channel scan inconsistency and brightening
- new_img1 := image.NewNRGBA(b)
-
+// per-channel scan inconsistency and brightening
+func ChannelInconsistencyAndBrightening(dst, src *image.NRGBA, b image.Rectangle, rng *rand.Rand, opts Options) {
lr, lg, lb := opts.Lr, opts.Lg, opts.Lb
for y := 0; y < b.Max.Y; y++ {
for x := 0; x < b.Max.X; x++ {
- lr += seededRand.NormFloat64() * opts.Lag
- lg += seededRand.NormFloat64() * opts.Lag
- lb += seededRand.NormFloat64() * opts.Lag
- offx := offset(seededRand, opts.StdOffset)
+ lr += rng.NormFloat64() * opts.Lag
+ lg += rng.NormFloat64() * opts.Lag
+ lb += rng.NormFloat64() * opts.Lag
+ offx := offset(rng, opts.StdOffset)
// obtain source pixel base offsets. red/blue border is also smoothed by offx
- ra_idx := new_img.Stride*y + 4*wrap(x+int(lr)-offx, b.Max.X)
- g_idx := new_img.Stride*y + 4*wrap(x+int(lg), b.Max.X)
- b_idx := new_img.Stride*y + 4*wrap(x+int(lb)+offx, b.Max.X)
+ ra_idx := src.Stride*y + 4*wrap(x+int(lr)-offx, b.Max.X)
+ g_idx := src.Stride*y + 4*wrap(x+int(lg), b.Max.X)
+ b_idx := src.Stride*y + 4*wrap(x+int(lb)+offx, b.Max.X)
// pixels are stored in (r, g, b, a) order in memory
- r := new_img.Pix[ra_idx]
- a := new_img.Pix[ra_idx+3]
- g := new_img.Pix[g_idx+1]
- b := new_img.Pix[b_idx+2]
+ r := src.Pix[ra_idx]
+ a := src.Pix[ra_idx+3]
+ g := src.Pix[g_idx+1]
+ b := src.Pix[b_idx+2]
r, g, b = brighten(r, uint8(opts.Add)), brighten(g, uint8(opts.Add)), brighten(b, uint8(opts.Add))
// copy the corresponding pixel (4 bytes) to the new image
- dst_idx := new_img1.Stride*y + 4*x
- copy(new_img1.Pix[dst_idx:dst_idx+4], []uint8{r, g, b, a})
+ dst_idx := dst.Stride*y + 4*x
+ copy(dst.Pix[dst_idx:dst_idx+4], []uint8{r, g, b, a})
}
}
+}
- // third stage is to add chromatic abberation+chromatic trails
- // (trails happen because we're changing the same image we process)
+// chromatic abberation+chromatic trails
+func ChromaticAbberationAndTrails(dst *image.NRGBA, b image.Rectangle, rng *rand.Rand, opts Options) {
for y := 0; y < b.Max.Y; y++ {
for x := 0; x < b.Max.X; x++ {
- offx := int(opts.MeanAbber) + offset(seededRand, opts.StdAbber) // lower offset arg = longer trails
+ offx := int(opts.MeanAbber) + offset(rng, opts.StdAbber) // lower offset arg = longer trails
// obtain source pixel base offsets. only red and blue are distorted
- ra_idx := new_img1.Stride*y + 4*wrap(x+offx, b.Max.X)
- g_idx := new_img1.Stride*y + 4*x
- b_idx := new_img1.Stride*y + 4*wrap(x-offx, b.Max.X)
+ ra_idx := dst.Stride*y + 4*wrap(x+offx, b.Max.X)
+ g_idx := dst.Stride*y + 4*x
+ b_idx := dst.Stride*y + 4*wrap(x-offx, b.Max.X)
// pixels are stored in (r, g, b, a) order in memory
- r := new_img1.Pix[ra_idx]
- a := new_img1.Pix[ra_idx+3]
- g := new_img1.Pix[g_idx+1]
- b := new_img1.Pix[b_idx+2]
+ r := dst.Pix[ra_idx]
+ a := dst.Pix[ra_idx+3]
+ g := dst.Pix[g_idx+1]
+ b := dst.Pix[b_idx+2]
// copy the corresponding pixel (4 bytes) to the SAME image. this gets us nice colorful trails
- dst_idx := new_img1.Stride*y + 4*x
- copy(new_img1.Pix[dst_idx:dst_idx+4], []uint8{r, g, b, a})
+ dst_idx := dst.Stride*y + 4*x
+ copy(dst.Pix[dst_idx:dst_idx+4], []uint8{r, g, b, a})
}
}
-
- return new_img1, nil
}
// force x to stay in [0, b) range. x is assumed to be in [-b,2*b) range