Skip to content

Commit 4893907

Browse files
author
Wenzong Wang
committed
final-v
0 parents  commit 4893907

File tree

8 files changed

+424
-0
lines changed

8 files changed

+424
-0
lines changed

.DS_Store

6 KB
Binary file not shown.

editor/.DS_Store

6 KB
Binary file not shown.

editor/editor.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"flag"
6+
"fmt"
7+
"math"
8+
"os"
9+
"proj2/png"
10+
"runtime"
11+
"proj2/src"
12+
)
13+
14+
func printUsage() {
15+
fmt.Printf("Usage: editor [-p=[number of threads]]\n")
16+
fmt.Printf("\t-p=[number of threads] = An optional flag to run the editor in its parallel version.\nCall and pass the runtime.GOMAXPROCS(...) function the integer\nspecified by [number of threads].\n")
17+
}
18+
19+
func sequentialRun(){
20+
dec := json.NewDecoder(os.Stdin)
21+
var tmp src.Request
22+
23+
for{
24+
// decode an image process request
25+
err := dec.Decode(&tmp)
26+
if err != nil {
27+
return
28+
}
29+
// load img
30+
filePath := tmp.InPath
31+
pngImg, err := png.Load(filePath)
32+
if err != nil {
33+
panic(err)
34+
}
35+
// apply effects
36+
for i := range tmp.Effects{
37+
_, height := pngImg.GetSize()
38+
pngImg.AddEffect(tmp.Effects[i], 0, height)
39+
if i != len(tmp.Effects) - 1{
40+
//pngImg.ReLoad()
41+
pngImg.Swap()
42+
}
43+
}
44+
//Saves the image to a new file
45+
err = pngImg.Save(tmp.OutPath)
46+
if err != nil {
47+
panic(err)
48+
}
49+
}
50+
51+
}
52+
53+
func main() {
54+
/******
55+
The following code shows you how to work with PNG files in Golang. Please
56+
write your actual implementation of the project by removing the below code.
57+
******/
58+
var p int
59+
flag.IntVar(&p, "p", 0, "An optional flag to run the editor in its parallel version.\nCall and pass the runtime.GOMAXPROCS(...) function the integer\nspecified by [number of threads].")
60+
flag.Parse()
61+
62+
if p == 0{
63+
// sequential version
64+
sequentialRun()
65+
}else{
66+
// parallel version
67+
runtime.GOMAXPROCS(p)
68+
numOfReaders := int(math.Ceil(float64(p)*(1.0/5.0)))
69+
src.CreateReadersWithPPLPool(numOfReaders, p)
70+
}
71+
72+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module proj2
2+
3+
go 1.14

png/effects.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Package png allows for loading png images and applying
2+
// image flitering effects on them.
3+
package png
4+
5+
import (
6+
"image/color"
7+
)
8+
9+
var sharp = [9]float64{
10+
0, -1, 0,
11+
-1, 5, -1,
12+
0, -1, 0}
13+
14+
var edge = [9]float64{
15+
-1, -1, -1,
16+
-1, 8, -1,
17+
-1, -1, -1}
18+
19+
var blur = [9]float64{
20+
1. / 9, 1. / 9, 1. / 9,
21+
1. / 9, 1. / 9, 1. / 9,
22+
1. / 9, 1. / 9, 1. / 9}
23+
24+
// apply a certain effect to a rect area [(0,y0), (width, y1)] of the img
25+
func (img *Image) AddEffect(effect string, y0 int, y1 int){
26+
27+
switch effect{
28+
case "S":
29+
img.FilterRect(sharp, y0, y1)
30+
case "E":
31+
img.FilterRect(edge, y0, y1)
32+
case "B":
33+
img.FilterRect(blur, y0, y1)
34+
case "G":
35+
img.GrayscaleRect(y0, y1)
36+
default:
37+
img.GrayscaleRect(y0, y1)
38+
}
39+
}
40+
41+
// apply a certain effect to a rect area [(0,y0), (width, y1)] of the img
42+
func (img *Image) AddEffectRect(effect string, y0 int, y1 int, ch chan bool){
43+
img.AddEffect(effect, y0, y1)
44+
ch <- true
45+
}
46+
47+
// apply filter k to a rect area [(0,y0), (width, y1)] of the img
48+
func (img *Image) FilterRect(k [9]float64, y0 int, y1 int){
49+
bounds := img.out.Bounds()
50+
for y := y0; y < y1; y++ {
51+
for x := bounds.Min.X; x < bounds.Max.X; x++ {
52+
var sum_r float64
53+
var sum_g float64
54+
var sum_b float64
55+
var i int
56+
_, _, _, a := img.mid.At(x, y).RGBA()
57+
for yo := y - 1; yo <= y+1; yo++ {
58+
for xo := x - 1; xo <= x+1; xo++ {
59+
if img.Contains(xo, yo) {
60+
r, g, b, _ := img.mid.At(xo, yo).RGBA()
61+
sum_r += k[i] * float64(r)
62+
sum_g += k[i] * float64(g)
63+
sum_b += k[i] * float64(b)
64+
}
65+
i++
66+
}
67+
}
68+
img.out.Set(x, y, color.RGBA64{clamp(sum_r), clamp(sum_g), clamp(sum_b), uint16(a)})
69+
}
70+
}
71+
}
72+
73+
// apply greyscale effect to a rect area [(0,y0), (width, y1)] of the img
74+
func (img *Image) GrayscaleRect(y0 int, y1 int) {
75+
bounds := img.out.Bounds()
76+
for y := y0; y < y1; y++ {
77+
for x := bounds.Min.X; x < bounds.Max.X; x++ {
78+
r, g, b, a := img.mid.At(x, y).RGBA()
79+
greyC := clamp(float64(r+g+b) / 3)
80+
img.out.Set(x, y, color.RGBA64{greyC, greyC, greyC, uint16(a)})
81+
}
82+
}
83+
}
84+
85+
86+
87+
88+
89+

png/png.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Package png allows for loading png images and applying
2+
// image flitering effects on them
3+
package png
4+
5+
import (
6+
"image"
7+
"image/color"
8+
"image/png"
9+
"math"
10+
"os"
11+
)
12+
13+
// The Image represents a structure for working with PNG images.
14+
type Image struct {
15+
in image.Image
16+
mid *image.RGBA64
17+
out *image.RGBA64
18+
19+
}
20+
21+
//
22+
// Public functions
23+
//
24+
25+
// Load returns a Image that was loaded based on the filePath parameter
26+
func Load(filePath string) (*Image, error) {
27+
28+
inReader, err := os.Open(filePath)
29+
30+
if err != nil {
31+
return nil, err
32+
}
33+
defer inReader.Close()
34+
35+
inImg, err := png.Decode(inReader)
36+
37+
if err != nil {
38+
return nil, err
39+
}
40+
41+
inBounds := inImg.Bounds()
42+
43+
outImg := image.NewRGBA64(inBounds)
44+
45+
midImg := image.NewRGBA64(inBounds)
46+
47+
InitForMid(inImg, midImg)
48+
49+
return &Image{inImg, midImg, outImg}, nil
50+
}
51+
52+
func (img *Image)Swap(){
53+
img.mid = img.out
54+
img.out = image.NewRGBA64(img.in.Bounds())
55+
}
56+
57+
func InitForMid(inImg image.Image, midImg *image.RGBA64) {
58+
inBounds := inImg.Bounds()
59+
for y := inBounds.Min.Y; y < inBounds.Max.Y; y++ {
60+
for x := inBounds.Min.X; x < inBounds.Max.X; x++ {
61+
r, g, b, a := inImg.At(x, y).RGBA()
62+
midImg.Set(x, y, color.RGBA64{clamp(float64(r)), clamp(float64(g)), clamp(float64(b)), uint16(a)})
63+
}
64+
}
65+
}
66+
67+
func (img *Image) GetSubImage(x0 int, y0 int, x1 int, y1 int) image.Image{
68+
rect := image.Rect(x0,y0, x1, y1)
69+
return img.mid.SubImage(rect)
70+
}
71+
72+
// Save saves the image to the given file
73+
func (img *Image) Save(filePath string) error {
74+
75+
outWriter, err := os.Create(filePath)
76+
if err != nil {
77+
return err
78+
}
79+
defer outWriter.Close()
80+
81+
err = png.Encode(outWriter, img.out)
82+
if err != nil {
83+
return err
84+
}
85+
return nil
86+
}
87+
88+
func (img *Image) Contains(x int, y int) bool {
89+
90+
91+
bounds := img.out.Bounds()
92+
93+
if x < bounds.Min.X || x >= bounds.Max.X{
94+
return false
95+
}
96+
if y < bounds.Min.Y || y >= bounds.Max.Y{
97+
return false
98+
}
99+
return true
100+
}
101+
102+
func (img *Image) GetSize() (int, int){
103+
bounds := img.in.Bounds()
104+
width := bounds.Max.X
105+
height := bounds.Max.Y
106+
return width, height
107+
}
108+
109+
110+
111+
//clamp will clamp the comp parameter to zero if it is less than zero or to 65535 if the comp parameter
112+
// is greater than 65535.
113+
func clamp(comp float64) uint16 {
114+
return uint16(math.Min(65535, math.Max(0, comp)))
115+
}

src/reader.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package src
2+
3+
import (
4+
"encoding/json"
5+
"os"
6+
"proj2/png"
7+
"sync"
8+
)
9+
10+
// struct for decoding image process request
11+
type Request struct{
12+
InPath string
13+
OutPath string
14+
Effects []string
15+
}
16+
17+
// struct for a pre-processed request
18+
type FilterRequest struct{
19+
img *png.Image
20+
req Request
21+
}
22+
23+
// A reader reads from os.stdin and create its own work pipeline for image process
24+
func readAndProcess(wg *sync.WaitGroup, id int, cond *sync.Cond, dec *json.Decoder, n int){
25+
defer wg.Done()
26+
done := make(chan bool, 1)
27+
filterReq := make(chan FilterRequest, 10)
28+
29+
var tmp Request
30+
for{
31+
cond.L.Lock()
32+
err := dec.Decode(&tmp)
33+
cond.L.Unlock()
34+
if err != nil {
35+
close(filterReq)
36+
return
37+
}
38+
39+
filePath := tmp.InPath
40+
pngImg, err := png.Load(filePath)
41+
if err != nil {
42+
panic(err)
43+
}
44+
45+
var tmpReq FilterRequest
46+
tmpReq.img = pngImg
47+
tmpReq.req = tmp
48+
filterReq <- tmpReq
49+
// process the image process with a pipeline
50+
go pipelineWork(filterReq, n, done)
51+
<-done
52+
}
53+
}
54+
55+
// create a pool of Readers and their work pipeline with a total number of #numOfReaders
56+
func CreateReadersWithPPLPool(numOfReaders int, numOfThreads int) {
57+
var wg sync.WaitGroup
58+
var m sync.Mutex
59+
cond := sync.NewCond(&m)
60+
dec := json.NewDecoder(os.Stdin)
61+
62+
for i := 0; i < numOfReaders; i++ {
63+
wg.Add(1)
64+
go readAndProcess(&wg, i, cond, dec, numOfThreads)
65+
}
66+
67+
wg.Wait()
68+
}

0 commit comments

Comments
 (0)