1#include "HalftoneView.h"
2
3#include <Bitmap.h>
4#include <StringView.h>
5
6
7HalftonePreviewView::HalftonePreviewView(BRect frame, const char* name,
8	uint32 resizeMask, uint32 flags)
9	:
10	BView(frame, name, resizeMask, flags)
11{
12}
13
14
15void
16HalftonePreviewView::Preview(float gamma, float min,
17	Halftone::DitherType ditherType, bool color)
18{
19	const color_space kColorSpace = B_RGB32;
20	const float right = Bounds().Width();
21	const float bottom = Bounds().Height();
22	BRect rect(0, 0, right, bottom);
23
24	BBitmap testImage(rect, kColorSpace, true);
25	BBitmap preview(rect, kColorSpace);
26	BView view(rect, "", B_FOLLOW_ALL, B_WILL_DRAW);
27
28	// create test image
29	testImage.Lock();
30	testImage.AddChild(&view);
31
32	// color bars
33	const int height = Bounds().IntegerHeight()+1;
34	const int width  = Bounds().IntegerWidth()+1;
35	const int delta  = height / 4;
36	const float red_bottom   = delta - 1;
37	const float green_bottom = red_bottom + delta;
38	const float blue_bottom  = green_bottom + delta;
39	const float gray_bottom  = height - 1;
40
41	for (int x = 0; x <= right; x ++) {
42		uchar value = x * 255 / width;
43
44		BPoint from(x, 0);
45		BPoint to(x, red_bottom);
46		// red
47		view.SetHighColor(255, value, value);
48		view.StrokeLine(from, to);
49		// green
50		from.y = to.y+1;
51		to.y = green_bottom;
52		view.SetHighColor(value, 255, value);
53		view.StrokeLine(from, to);
54		// blue
55		from.y = to.y+1;
56		to.y = blue_bottom;
57		view.SetHighColor(value, value, 255);
58		view.StrokeLine(from, to);
59		// gray
60		from.y = to.y+1;
61		to.y = gray_bottom;
62		view.SetHighColor(value, value, value);
63		view.StrokeLine(from, to);
64	}
65
66	view.Sync();
67	testImage.RemoveChild(&view);
68	testImage.Unlock();
69
70	// create preview image
71	Halftone halftone(kColorSpace, gamma, min, ditherType);
72	halftone.SetBlackValue(Halftone::kLowValueMeansBlack);
73
74	const int widthBytes = (width + 7) / 8; // byte boundary
75	uchar* buffer = new uchar[widthBytes];
76
77	const uchar* src = (uchar*)testImage.Bits();
78	uchar* dstRow = (uchar*)preview.Bits();
79
80	const int numPlanes = color ? 3 : 1;
81	if (color) {
82		halftone.SetPlanes(Halftone::kPlaneRGB1);
83	}
84
85	for (int y = 0; y < height; y ++) {
86		for (int plane = 0; plane < numPlanes;  plane ++) {
87			// halftone the preview image
88			halftone.Dither(buffer, src, 0, y, width);
89
90			// convert the plane(s) to RGB32
91			ColorRGB32Little* dst = (ColorRGB32Little*)dstRow;
92			const uchar* bitmap = buffer;
93			for (int x = 0; x < width; x ++, dst ++) {
94				const int bit = 7 - (x % 8);
95				const bool isSet = (*bitmap & (1 << bit)) != 0;
96				uchar value = isSet ? 255 : 0;
97
98				if (color) {
99					switch (plane) {
100						case 0: dst->red = value;
101							break;
102						case 1: dst->green = value;
103							break;
104						case 2: dst->blue = value;
105							break;
106					}
107				} else {
108					dst->red = dst->green = dst->blue = value;
109				}
110
111				if (bit == 0) {
112					bitmap ++;
113				}
114			}
115		}
116
117		// next row
118		src += testImage.BytesPerRow();
119		dstRow += preview.BytesPerRow();
120	}
121
122	delete[] buffer;
123
124	SetViewBitmap(&preview);
125	Invalidate();
126}
127
128
129HalftoneView::HalftoneView(BRect frame, const char* name, uint32 resizeMask,
130	uint32 flags)
131	:
132	BView(frame, name, resizeMask, flags)
133{
134	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
135
136	BRect r(frame);
137	float size, max;
138
139	r.OffsetTo(0, 0);
140	const int height = r.IntegerHeight()+1;
141	const int delta  = height / 4;
142	const float red_top   = 0;
143	const float green_top = delta;
144	const float blue_top  = green_top + delta;
145	const float gray_top  = r.bottom - delta;
146
147	const char* kRedLabel   = "Red: ";
148	const char* kGreenLabel = "Green: ";
149	const char* kBlueLabel  = "Blue: ";
150	const char* kGrayLabel  = "Black: ";
151
152
153	BFont font(be_plain_font);
154	font_height fh;
155	font.GetHeight(&fh);
156
157	max = size = font.StringWidth(kRedLabel);
158	r.Set(0, 0, size, fh.ascent + fh.descent);
159	r.OffsetTo(0, red_top);
160	r.right = r.left + size;
161	AddChild(new BStringView(r, "red", kRedLabel));
162
163	size = font.StringWidth(kGreenLabel);
164	r.Set(0, 0, size, fh.ascent + fh.descent);
165	if (max < size) max = size;
166	r.OffsetTo(0, green_top);
167	r.right = r.left + size;
168	AddChild(new BStringView(r, "green", kGreenLabel));
169
170	size = font.StringWidth(kBlueLabel);
171	r.Set(0, 0, size, fh.ascent + fh.descent);
172	if (max < size) max = size;
173	r.OffsetTo(0, blue_top);
174	r.right = r.left + size;
175	AddChild(new BStringView(r, "blue", kBlueLabel));
176
177	size = font.StringWidth(kGrayLabel);
178	r.Set(0, 0, size, fh.ascent + fh.descent);
179	if (max < size) max = size;
180	r.OffsetTo(0, gray_top);
181	r.right = r.left + size;
182	AddChild(new BStringView(r, "gray", kGrayLabel));
183
184	r = frame;
185	r.OffsetTo(max, 0);
186	r.right -= max;
187	fPreview = new HalftonePreviewView(r, "preview", resizeMask, flags);
188	AddChild(fPreview);
189}
190
191
192void
193HalftoneView::Preview(float gamma, float min,
194	Halftone::DitherType ditherType, bool color)
195{
196	fPreview->Preview(gamma, min, ditherType, color);
197}
198