1 //////////////////////////////////////////////////////////////////////
2 // hrr: high resolution raster.
3 
4 #include "GeomDraw.h"
5 
6 #include "hrr.h"
7 
8 #include <plugin/jpg/jpg.h>
9 #include <plugin/gif/gif.h>
10 #include <plugin/png/png.h>
11 
12 namespace Upp {
13 
14 #define LLOG(x) // LOG(x)
15 
CalcBitMasks(int bpp,const dword * in_cmasks,dword cmask[],int cshift24[],int cbits[])16 void CalcBitMasks(int bpp, const dword *in_cmasks, dword cmask[], int cshift24[], int cbits[])
17 {
18 	static const dword cmasks16[] = { 0xF800, 0x07E0, 0x001F };
19 	static const dword cmasks32[] = { 0xFF0000, 0x00FF00, 0x0000FF };
20 	if(!in_cmasks)
21 		in_cmasks = (bpp <= 16 ? cmasks16 : cmasks32);
22 	else if((in_cmasks[0] | in_cmasks[1] | in_cmasks[2]) == 0) {
23 		in_cmasks = (bpp <= 16 ? cmasks16 : cmasks32);
24 	}
25 	for(int i = 0; i < 3; i++) {
26 		dword cm = in_cmasks[i];
27 		cmask[i] = cm;
28 		int shift = 0;
29 		if(!(cm & 0xFFFF0000)) {
30 			cm <<= 16;
31 			shift += 16;
32 		}
33 		if(!(cm & 0xFF000000)) {
34 			cm <<= 8;
35 			shift += 8;
36 		}
37 		if(!(cm & 0xF0000000)) {
38 			cm <<= 4;
39 			shift += 4;
40 		}
41 		if(!(cm & 0xC0000000)) {
42 			cm <<= 2;
43 			shift += 2;
44 		}
45 		if(!(cm & 0x80000000)) {
46 			cm <<= 1;
47 			shift += 1;
48 		}
49 		int width = 0;
50 		dword mask = 0x80000000;
51 		while((cm & mask) && width < 8) {
52 			mask >>= 1;
53 			width++;
54 		}
55 		cshift24[i] = shift;
56 		cbits[i] = width;
57 	}
58 }
59 
PixelZStreamInfo(Stream & stream,Size & size,Size & dot_size,Point & hotspot,int & raw_bpp,bool & mono)60 static void PixelZStreamInfo(Stream& stream, Size& size, Size& dot_size, Point& hotspot, int& raw_bpp, bool& mono)
61 {
62 	enum { VERSION = 1 };
63 	int version = VERSION;
64 	stream.Magic(('P' << 24) | ('X' << 16) | ('A' << 8) | 'R');
65 	stream / version;
66 	if(version > VERSION) {
67 		stream.SetError();
68 		return;
69 	}
70 	Pack16(stream, raw_bpp, size.cx, size.cy, hotspot.x, hotspot.y);
71 	stream % mono % dot_size;
72 }
73 
74 struct ZImageDirItem
75 {
76 	Size  size;
77 	Size  dot_size;
78 	Point hotspot;
79 	int   raw_bpp;
80 	bool  mono;
81 	int   alpha_bpp;
82 
SerializeUpp::ZImageDirItem83 	void  Serialize(Stream& stream)
84 	{
85 		PixelZStreamInfo(stream, size, dot_size, hotspot, raw_bpp, mono);
86 		Pack16(stream, alpha_bpp);
87 	}
88 };
89 
90 class ZImageRaster : public StreamRaster {
91 public:
ZImageRaster()92 	ZImageRaster() {}
93 
94 	virtual bool    Create();
95 	virtual Size    GetSize();
96 	virtual Info    GetInfo();
97 	virtual Line    GetLine(int line);
98 	virtual const RGBA *GetPalette();
99 	virtual const RasterFormat *GetFormat();
100 
101 private:
102 	ZImageDirItem   item;
103 	Vector<Color>   palette;
104 	dword           cmask[3];
105 	int             cshift24[3];
106 	int             cbits[3];
107 	int             pixel_row_bytes;
108 	int             alpha_row_bytes;
109 	int             pixel_block_size;
110 	int             alpha_block_size;
111 	int             line_number;
112 	String          block;
113 	int             block_offset;
114 	Vector<byte>    pixel;
115 	Vector<byte>    alpha;
116 	Vector<RGBA>    rgba_palette;
117 	RasterFormat    format;
118 };
119 
Create()120 bool ZImageRaster::Create()
121 {
122 	static const unsigned MAGIC_TAG = 'Z' * 0x1000000 + 'I' * 0x10000 + 'M' * 0x100 + 'G';
123 	static const int VERSION = 1;
124 
125 	format.SetRGBA();
126 
127 	Stream& stream = GetStream();
128 
129 	stream.Magic(MAGIC_TAG);
130 	if(stream.IsError())
131 		return false;
132 	int version = VERSION;
133 	stream / version;
134 	if(version > VERSION) {
135 		LLOG("ImageZStreamInfo: version error: " << version);
136 		stream.SetError();
137 		return false;
138 	}
139 	Array<ZImageDirItem> dir;
140 	int count = 0;
141 	stream % count;
142 	enum { MAX_COUNT = 1000 };
143 	if(count < 0 || count > MAX_COUNT) {
144 		LLOG("ImageZStreamInfo: image count error: " << count);
145 		stream.SetError();
146 		return false;
147 	}
148 	if(stream.IsLoading())
149 		dir.SetCount(count);
150 	for(int i = 0; i < count && !stream.IsError(); i++)
151 		stream % dir[i];
152 	if(stream.IsError() || dir.IsEmpty())
153 		return false;
154 	item = dir[0];
155 
156 	Buffer<int> offsets(dir.GetCount() + 1);
157 	for(int i = 0; i <= dir.GetCount(); i++)
158 		stream % offsets[i];
159 	int64 base = stream.GetPos();
160 	stream.Seek(base + offsets[0]);
161 
162 	if(item.size.cx <= 0 || item.size.cy <= 0)
163 		return false;
164 
165 	version = VERSION;
166 	stream / version;
167 	if(version > VERSION) {
168 		LLOG("PixelZStreamData -> version error: " << version);
169 		stream.SetError();
170 		return false;
171 	}
172 	if(item.raw_bpp) {
173 		int bpp = (item.raw_bpp < 0 ? 24 : item.raw_bpp);
174 		if(bpp <= 8) {
175 			stream % palette;
176 			rgba_palette.SetCount(1 << bpp, RGBAZero());
177 			for(int i = 0; i < palette.GetCount() && i < rgba_palette.GetCount(); i++)
178 				rgba_palette[i] = (RGBA)palette[i];
179 		}
180 		else if(bpp == 16 || bpp == 32) {
181 			stream % cmask[0] % cmask[1] % cmask[2];
182 			CalcBitMasks(bpp, cmask, cmask, cshift24, cbits);
183 		}
184 		pixel_block_size = 0;
185 		Pack16(stream, pixel_block_size);
186 		if(pixel_block_size <= 0) {
187 			LLOG("ZImageRaster::Create -> block size error: " << pixel_block_size);
188 			stream.SetError();
189 			return false;
190 		}
191 		pixel_row_bytes = ((item.size.cx * bpp + 31) >> 5) << 2;
192 		pixel.SetCount(item.size.cy * pixel_row_bytes, 0);
193 		for(int i = 0; i < item.size.cy;) {
194 			int e = min(item.size.cy, i + pixel_block_size);
195 			String part;
196 			stream % part;
197 			String dpart = ZDecompress(part);
198 			if(dpart.IsVoid()) {
199 				LLOG("PixelZStreamData -> decompress error @ row " << i << " (source size = " << part.GetLength() << ")");
200 				stream.SetError();
201 				return false;
202 			}
203 			int x = 0;
204 			memcpy(pixel.GetIter(i * pixel_row_bytes), dpart, min(pixel_row_bytes * (e - i), dpart.GetLength()));
205 			i = e;
206 		}
207 	}
208 
209 	version = VERSION;
210 	stream / version;
211 	if(version > VERSION) {
212 		LLOG("PixelZStreamData -> version error: " << version);
213 		stream.SetError();
214 		return false;
215 	}
216 /*
217 	if(item.alpha_bpp) {
218 		alpha_row_bytes = ((item.size.cx + 31) >> 5) << 2;
219 		alpha.SetCount(item.size.cy * alpha_row_bytes, 0);
220 		Vector<Color> mask_palette;
221 		stream % mask_palette;
222 		Pack16(stream, alpha_block_size);
223 		if(alpha_block_size <= 0) {
224 			LLOG("PixelZStreamData -> block size error: " << alpha_block_size);
225 			stream.SetError();
226 			return false;
227 		}
228 
229 		for(int i = 0; i < item.size.cy;) {
230 			int e = min(item.size.cy, i + alpha_block_size);
231 			String part;
232 			stream % part;
233 			String dpart = ZDecompress(part);
234 			if(dpart.IsVoid()) {
235 				LLOG("PixelZStreamData -> decompress error @ row " << i << " (source size = " << part.GetLength() << ")");
236 				stream.SetError();
237 				return false;
238 			}
239 			memcpy(alpha.GetIter(i * alpha_row_bytes), dpart, min((e - i) * alpha_row_bytes, dpart.GetLength()));
240 			i = e;
241 		}
242 	}
243 */
244 	return true;
245 }
246 
GetSize()247 Size ZImageRaster::GetSize()
248 {
249 	return item.size;
250 }
251 
GetInfo()252 Raster::Info ZImageRaster::GetInfo()
253 {
254 	Info info;
255 	if(item.raw_bpp > 0 && item.raw_bpp <= 8)
256 		info.colors = 1 << item.raw_bpp;
257 	info.bpp = (item.raw_bpp < 0 ? 24 : item.raw_bpp);
258 	info.dots = item.dot_size;
259 	return info;
260 }
261 
GetLine(int ln)262 Raster::Line ZImageRaster::GetLine(int ln)
263 {
264 	RGBA *line = new RGBA[item.size.cx];
265 /*
266 	if(item.alpha_bpp) {
267 		const byte *ao = alpha.GetIter(ln * alpha_row_bytes);
268 		byte active = *ao++;
269 		byte avail = 8;
270 		RGBA *out = line;
271 		for(int width = item.size.cx; --width >= 0; out++) {
272 			if(!avail) {
273 				active = *ao++;
274 				avail = 8;
275 			}
276 			--avail;
277 			out->a = (active & 0x80 ? 0 : 255);
278 			active <<= 1;
279 		}
280 	}
281 	else */ {
282 		RGBA bg;
283 		bg.r = bg.g = bg.b = 0;
284 		bg.a = 255;
285 		Fill(line, bg, item.size.cx);
286 	}
287 	if(item.raw_bpp) {
288 		const byte *po = pixel.GetIter(ln * pixel_row_bytes);
289 		RGBA *out = line;
290 		if(item.raw_bpp == -3) {
291 			for(int width = item.size.cx; --width >= 0; out++, po += 3) {
292 				out->b = po[0];
293 				out->g = po[1];
294 				out->r = po[2];
295 			}
296 		}
297 		else if(item.raw_bpp <= 8) {
298 			byte shift = item.raw_bpp;
299 			byte per_byte = 8 / item.raw_bpp;
300 			byte active = 0;
301 			byte avail = 0;
302 			RGBA zero = RGBAZero();
303 			for(int width = item.size.cx; --width >= 0; out++) {
304 				if(!avail) {
305 					active = *po++;
306 					avail = per_byte;
307 				}
308 				--avail;
309 				int index = (active << shift) >> 8;
310 				active <<= shift;
311 				RGBA value = (index < rgba_palette.GetCount() ? rgba_palette[index] : zero);
312 				out->r = value.r;
313 				out->g = value.g;
314 				out->b = value.b;
315 			}
316 		}
317 		else if(item.raw_bpp == 16 || item.raw_bpp == 24 || item.raw_bpp == 32) {
318 			byte bshift = cshift24[2];
319 			byte bmask = (-256 >> cbits[2]) & 0xFF;
320 			byte gshift = cshift24[1];
321 			byte gmask = (-256 >> cbits[1]) & 0xFF;
322 			byte rshift = cshift24[0];
323 			byte rmask = (-256 >> cbits[0]) & 0xFF;
324 
325 			if(item.raw_bpp == 16) {
326 				for(int width = item.size.cx; --width >= 0; out++, po += 2) {
327 					uint16 w = Peek16le(po);
328 					out->r = byte((w << rshift) >> 24) & rmask;
329 					out->g = byte((w << gshift) >> 24) & gmask;
330 					out->b = byte((w << bshift) >> 24) & bmask;
331 				}
332 			}
333 			else {
334 				for(int width = item.size.cx; --width >= 0; out++, po += 4) {
335 					uint32 w = Peek32le(po);
336 					out->r = byte((w << rshift) >> 24) & rmask;
337 					out->g = byte((w << gshift) >> 24) & gmask;
338 					out->b = byte((w << bshift) >> 24) & bmask;
339 				}
340 			}
341 		}
342 		else {
343 			RLOG("ZImageRaster::GetLine: invalid pixel BPP = " << item.raw_bpp);
344 		}
345 	}
346 	return Raster::Line(line, true);
347 }
348 
GetPalette()349 const RGBA * ZImageRaster::GetPalette()
350 {
351 	return NULL;
352 }
353 
GetFormat()354 const RasterFormat * ZImageRaster::GetFormat()
355 {
356 	return &format;
357 }
358 
RasterCopy(RasterEncoder & dest,Raster & src,const Rect & src_rc)359 void RasterCopy(RasterEncoder& dest, Raster& src, const Rect& src_rc)
360 {
361 	dest.Start(src_rc.Size());
362 	for(int y = src_rc.top; y < src_rc.bottom; y++)
363 		dest.WriteLine((const RGBA *)src.GetLine(y) + src_rc.left);
364 }
365 
Open(ImageBuffer & output_,Point pos_,Rect clip_,bool merge_)366 void ImageWriter::Open(ImageBuffer& output_, Point pos_, Rect clip_, bool merge_)
367 {
368 	format.SetRGBA();
369 	output = &output_;
370 	pos = pos_;
371 	clip = clip_;
372 	merge = merge_;
373 }
374 
Start(Size sz)375 void ImageWriter::Start(Size sz)
376 {
377 	src_size = sz;
378 	line = 0;
379 	left = max(pos.x, clip.left);
380 	width = max(min(pos.x + src_size.cx, clip.right) - left, 0);
381 	offset = (width > 0 ? left - pos.x : 0);
382 }
383 
WriteLineRaw(const byte * s)384 void ImageWriter::WriteLineRaw(const byte *s)
385 {
386 	if(line >= src_size.cy || width <= 0)
387 		return;
388 	int y = line++ + pos.y;
389 	if(y >= clip.top && y < clip.bottom) {
390 		const RGBA *l = (const RGBA *)s;
391 		if(merge)
392 			AlphaBlend(&(*output)[y][left], l + offset, width);
393 		else
394 			memcpy(&(*output)[y][left], l + offset, width * sizeof(RGBA));
395 	}
396 }
397 
ImageBufferRaster(const ImageBuffer & buffer_)398 ImageBufferRaster::ImageBufferRaster(const ImageBuffer& buffer_)
399 : buffer(buffer_)
400 {
401 	crop = buffer.GetSize();
402 }
403 
ImageBufferRaster(const ImageBuffer & buffer_,const Rect & crop_)404 ImageBufferRaster::ImageBufferRaster(const ImageBuffer& buffer_, const Rect& crop_)
405 : buffer(buffer_)
406 {
407 	crop = crop_ & Rect(buffer.GetSize());
408 }
409 
GetSize()410 Size ImageBufferRaster::GetSize()
411 {
412 	return crop.Size();
413 }
414 
GetInfo()415 Raster::Info ImageBufferRaster::GetInfo()
416 {
417 	Info info;
418 	info.bpp = 32;
419 	info.colors = 0;
420 	info.dots = Null;
421 	info.hotspot = Null;
422 	info.kind = buffer.GetKind();
423 	return info;
424 }
425 
GetLine(int line)426 Raster::Line ImageBufferRaster::GetLine(int line)
427 {
428 	return Line(buffer[line + crop.top] + crop.left, false);
429 }
430 
operator %(Stream & strm,Color & color)431 inline Stream& operator % (Stream& strm, Color& color)
432 {
433 	dword dw = color.GetRaw();
434 	strm % dw;
435 	if(strm.IsLoading())
436 		color = Color::FromRaw(dw);
437 	return strm;
438 }
439 
operator %(Stream & strm,Rectf & rc)440 inline Stream& operator % (Stream& strm, Rectf& rc)
441 {
442 	strm % rc.left % rc.top % rc.right % rc.bottom;
443 	return strm;
444 }
445 
Unpack64(dword i)446 static int64 Unpack64(dword i)
447 {
448 	if(!(i & 0x80000000))
449 		return i;
450 	return int64(i & 0x7fffffff) << 8;
451 }
452 
CeilPack64(int64 i)453 static dword CeilPack64(int64 i)
454 {
455 	if(i < 0x7fffffff)
456 		return (dword)i;
457 	if(i < I64(0x3fffffff00))
458 		return (dword)((i + I64(0x80000000ff)) >> 8);
459 	return 0xffffffff;
460 }
461 
GetDecoder() const462 One<StreamRaster> HRRInfo::GetDecoder() const
463 {
464 	switch(method) {
465 	case METHOD_JPG: return new JPGRaster;
466 	case METHOD_GIF: return new GIFRaster;
467 	case METHOD_PNG: return new PNGRaster;
468 	case METHOD_ZIM: return new ZImageRaster;
469 	default:              return 0;
470 	}
471 }
472 
GetEncoder() const473 One<StreamRasterEncoder> HRRInfo::GetEncoder() const
474 {
475 	switch(method) {
476 	case METHOD_JPG: return new JPGEncoder(quality);
477 	case METHOD_GIF: return new GIFEncoder;
478 	case METHOD_PNG: return new PNGEncoder;
479 	default:              return 0;
480 	}
481 }
482 
483 /*
484 One<StreamRasterEncoder> HRR::StdCreateEncoder(const HRRInfo& info)
485 {
486 	switch(info.GetMethod())
487 	{
488 	case HRRInfo::METHOD_JPG: return new JpgEncoder(info.GetQuality());
489 	case HRRInfo::METHOD_GIF: return new GifEncoder;
490 	case HRRInfo::METHOD_RLE: return new RleEncoder;
491 //	case HRRInfo::METHOD_ZIM: return new ZImageEncoder;
492 #ifndef flagNOHRRPNG
493 	case HRRInfo::METHOD_PNG: return new PngEncoder;
494 #endif
495 	default:              return 0;
496 	}
497 }
498 */
499 
EnumMethods()500 Vector<int> HRRInfo::EnumMethods()
501 {
502 	Vector<int> out;
503 	out << METHOD_JPG << METHOD_GIF /* << METHOD_RLE*/ << METHOD_PNG; // << METHOD_ZIM;
504 	return out;
505 }
506 
507 /*
508 enum { wAlphaBlend = 200 };
509 
510 static void Mask1Blt(byte *dest, const byte *src, const byte *mask, int count)
511 {
512 	while(count >= 4)
513 	{
514 		if(mask[0]) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; }
515 		if(mask[1]) { dest[3] = src[3]; dest[4] = src[4]; dest[5] = src[5]; }
516 		if(mask[2]) { dest[6] = src[6]; dest[7] = src[7]; dest[8] = src[8]; }
517 		if(mask[3]) { dest[9] = src[9]; dest[10] = src[10]; dest[11] = src[11]; }
518 		dest += 12;
519 		src += 12;
520 		mask += 4;
521 		count -= 4;
522 	}
523 	if(count & 2)
524 	{
525 		if(mask[0]) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; }
526 		if(mask[1]) { dest[3] = src[3]; dest[4] = src[4]; dest[5] = src[5]; }
527 		dest += 6;
528 		src += 6;
529 		mask += 2;
530 	}
531 	if(count & 1)
532 		if(mask[0]) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; }
533 }
534 */
535 
536 /*
537 static void Mask1Copy(PixelArray& dest, const PixelArray& src, const PixelArray& mask)
538 {
539 	ASSERT(mask.bpp == 8 && src.bpp == 24 && dest.bpp == 24);
540 	Size size = dest.GetSize();
541 	ASSERT(src.GetSize() == size && mask.GetSize() == size);
542 	for(int i = 0; i < size.cy; i++)
543 		Mask1Blt(dest.GetUpScan(i), src.GetUpScan(i), mask.GetUpScan(i), size.cx);
544 }
545 */
546 
547 /*
548 static void StreamAlphaBlend(Stream& stream, Rect& dest, Rect& src, int& alpha,
549 							 AlphaArray& image, Color& blend_bgnd)
550 {
551 	int version = 2;
552 	stream / version / alpha;
553 	Pack16(stream, dest);
554 	Pack16(stream, src);
555 	stream % image;
556 	if(version >= 2)
557 		stream % blend_bgnd;
558 	else if(stream.IsLoading())
559 	{
560 		alpha = tabs(alpha);
561 		blend_bgnd = Null;
562 	}
563 }
564 */
565 
566 /*
567 static void DrawAlphaBlend(Draw& draw, Rect dest, Rect src, int alpha, AlphaArray& image, Color blend_bgnd)
568 {
569 	ASSERT(alpha >= 0);
570 
571 	Rect clip = draw.GetClip(), dclip = dest & clip, dclip0 = dclip.Size();
572 	if(dclip.IsEmpty() || alpha == 0)
573 		return;
574 
575 	Color c0 = (image.pixel.palette.GetCount() >= 1 ? image.pixel.palette[0] : Color(Null));
576 	Color c1 = (image.pixel.palette.GetCount() >= 2 ? image.pixel.palette[1] : Color(Null));
577 	bool mono_pixel = (image.pixel.IsMono() && (IsNull(c0) || IsNull(c1)));
578 	if(mono_pixel && IsNull(c0) && IsNull(c1))
579 		return;
580 
581 	if(draw.IsDrawing())
582 	{
583 		StreamAlphaBlend(draw.DrawingOp(wAlphaBlend), dest, src, alpha, image, blend_bgnd);
584 		return;
585 	}
586 
587 	PixelArray in_blend;
588 	if(alpha < 100 && IsNull(blend_bgnd))
589 	{
590 #ifdef PLATFORM_WIN32
591 		in_blend = ImageToPixelArray(DrawToImage(draw, dest), draw, -3);
592 #else
593 		in_blend = DrawableToPixelArray(draw.GetDrawable(), dest, false, -3, 4);
594 #endif
595 	}
596 	bool resize = (src.Size() != dest.Size() || (dest.Size() != dclip.Size() && draw.Dots()));
597 
598 	if(mono_pixel)
599 	{
600 		if(resize)
601 		{
602 			PixelArray new_data = PixelArray::Mono(dclip.Size(), 8);
603 			PixelCopyAntiAliasMaskOnly(new_data, dest - dclip.TopLeft(), image.pixel, src, false, false, dclip0);
604 			new_data.palette = image.pixel.palette;
605 			image.pixel = new_data;
606 			src = dclip0;
607 			dest = dclip;
608 		}
609 		if(!in_blend.IsEmpty())
610 		{
611 			PixelArray copy_blend;
612 			copy_blend <<= in_blend;
613 			PixelKillMask(copy_blend, image.pixel, Nvl(c0, c1), !IsNull(c0));
614 			PixelAlphaBlend(copy_blend, src, in_blend, Point(0, 0), alpha);
615 			copy_blend.Paint(draw, src, dest);
616 		}
617 		else
618 			image.pixel.Paint(draw, src, dest, c0, c1);
619 		return;
620 	}
621 
622 	if(resize)
623 	{ // scale image offhand
624 		if(image.pixel.GetBPP() > 8)
625 			PixelSetConvert(image.pixel, -3);
626 		if(!image.HasAlpha())
627 		{
628 			PixelArray new_data(dclip.Size(), -3);
629 			PixelCopyAntiAlias(new_data, dest - dclip.TopLeft(), image.pixel, src, dclip0);
630 			image.pixel = new_data;
631 		}
632 		else
633 		{
634 			AlphaArray new_image(dclip.Size(), -3);
635 			PixelCopyAntiAliasMaskOut(new_image, dest - dclip.TopLeft(), image, src, false, false, dclip0);
636 			image = new_image;
637 		}
638 		src = dclip0;
639 		dest = dclip;
640 	}
641 	if(!in_blend.IsEmpty())
642 	{ // blend with display contents
643 		if(image.HasAlpha())
644 		{
645 			PixelSetConvert(image.pixel, -3);
646 			Mask1Copy(image.pixel, in_blend, image.alpha);
647 		}
648 		PixelAlphaBlend(image.pixel, src, in_blend, Point(0, 0), alpha);
649 		image.pixel.Paint(draw, src, dest);
650 	}
651 	else {
652 		if(alpha < 100)
653 			PixelAlphaBlend(image.pixel, blend_bgnd, alpha, src);
654 		if(image.HasAlpha())
655 			image.Paint(draw, src, dest);
656 		else
657 			image.pixel.Paint(draw, src, dest);
658 	}
659 //	RTIMING("DrawAlphaBlend (raw)");
660 }
661 */
662 
663 /*
664 static void wsAlphaBlend(Draw& draw, Stream& stream, const DrawingPos& pos)
665 {
666 	Rect src, dest;
667 	int alpha;
668 	AlphaArray image;
669 	Color blend_bgnd;
670 	StreamAlphaBlend(stream, dest, src, alpha, image, blend_bgnd);
671 	DrawAlphaBlend(draw, pos(dest), src, alpha, image, blend_bgnd);
672 }
673 */
674 
675 //static DrawerRegistrator MK__s(wAlphaBlend, wsAlphaBlend);
676 
GetMaskInfo(const RGBA * rgba,int count)677 static int GetMaskInfo(const RGBA *rgba, int count)
678 {
679 	if(count == 0)
680 		return 0;
681 	if(rgba->a == 255) {
682 		for(; count > 0 && rgba->a == 255; count--, rgba++)
683 			;
684 		return (count ? 2 : 1);
685 	}
686 	else if(rgba->a == 0) {
687 		for(; count > 0 && rgba->a == 0; count--, rgba++)
688 			;
689 		return (count ? 2 : 0);
690 	}
691 	return 2;
692 }
693 
EncodeMask(const ImageBuffer & mask,bool write_size)694 static String EncodeMask(const ImageBuffer& mask, bool write_size)
695 {
696 	StringBuffer out;
697 	if(write_size) {
698 		char temp[4];
699 		Poke16le(temp + 0, mask.GetWidth());
700 		Poke16le(temp + 2, mask.GetHeight());
701 		out.Cat(temp, 4);
702 	}
703 	int full = out.GetLength();
704 	Size size = mask.GetSize();
705 	for(int i = 0; i < size.cy; i++) {
706 		const RGBA *p = mask[size.cy - i - 1], *e = p + size.cx;
707 		int start = out.GetLength();
708 		while(p < e) {
709 			bool init0 = false;
710 			if(p->a < 128)
711 			{ // full part
712 				const RGBA *b = p;
713 				while(++p < e && p->a < 128)
714 					;
715 				int n = p - b;
716 				while(n > 253) {
717 					out.Cat(255);
718 					out.Cat(2);
719 					n -= 253;
720 				}
721 				if(n > 0)
722 					out.Cat(n + 2);
723 			}
724 			else
725 				init0 = true;
726 			if(p < e) {
727 				const RGBA *b = p;
728 				while(++p < e && p->a >= 128)
729 					;
730 				if(p < e) {
731 					if(init0)
732 						out.Cat(2);
733 					int n = p - b;
734 					while(n > 253) {
735 						out.Cat(255);
736 						out.Cat(2);
737 						n -= 253;
738 					}
739 					if(n > 0)
740 						out.Cat(n + 2);
741 				}
742 			}
743 		}
744 		if(out.GetLength() > start)
745 			full = out.GetLength();
746 		out.Cat(1);
747 	}
748 	if(full < out.GetLength())
749 		out.SetLength(full);
750 	return out;
751 }
752 
DecodeMask(ImageBuffer & mask,String s,bool read_size)753 static void DecodeMask(ImageBuffer& mask, String s, bool read_size)
754 {
755 	Size size = mask.GetSize();
756 	const byte *p = s;
757 	if(read_size) {
758 		size.cx = Peek16le(p);
759 		size.cy = Peek16le(p + 2);
760 		p += 4;
761 	}
762 	for(int i = 0; i < size.cy && *p; i++) {
763 		RGBA *d = mask[size.cy - i - 1], *e = d + size.cx;
764 		while(*p >= 2 && d < e) {
765 			int n1 = *p++ - 2;
766 			if(e - d <= n1) {
767 				while(d < e)
768 					d++->a = 0;
769 				break;
770 			}
771 			RGBA *dd = d + n1;
772 			while(d < dd)
773 				d++->a = 0;
774 			if(*p >= 2) {
775 				n1 = *p++ - 2;
776 				if(e - d <= n1)
777 					break;
778 				d += n1;
779 			}
780 		}
781 		while(*p >= 2)
782 			p++;
783 		if(*p)
784 			p++;
785 	}
786 }
787 
788 /*
789 static String EncodeMask(const RawImage& mask)
790 {
791 	ASSERT(mask.bpp == 8);
792 	String out;
793 	int full = 0;
794 	Size size = mask.GetSize();
795 	for(int i = 0; i < size.cy; i++)
796 	{
797 		const byte *p = mask.GetUpScan(i), *e = p + size.cx;
798 		int start = out.GetLength();
799 		while(p < e)
800 		{
801 			const byte *b = p;
802 			while(++p < e && *p)
803 				;
804 			if(p >= e)
805 				break;
806 			int n = p - b;
807 			while(n > 253)
808 			{
809 				out.Cat(255);
810 				out.Cat(2);
811 				n -= 253;
812 			}
813 			out.Cat(n + 2);
814 			b = p;
815 			while(++p < e && !*p)
816 				;
817 			n = p - b;
818 			while(n > 253)
819 			{
820 				out.Cat(255);
821 				out.Cat(2);
822 				n -= 253;
823 			}
824 			if(n > 0 || p < e)
825 				out.Cat(n + 2);
826 		}
827 		if(out.GetLength() > start)
828 			full = out.GetLength();
829 		out.Cat(1);
830 	}
831 	if(full < out.GetLength())
832 		out.Trim(full);
833 	return out;
834 }
835 
836 static void DecodeMask(RawImage& mask, const String& s)
837 {
838 	ASSERT(mask.bpp == 8);
839 	Size size = mask.GetSize();
840 	mask.Set(1);
841 	const byte *p = s;
842 	for(int i = 0; i < size.cy && *p; i++)
843 	{
844 		byte *d = mask.GetUpScan(i), *e = d + size.cx;
845 		while(*p >= 2 && d < e)
846 		{
847 			int n1 = *p++ - 2;
848 			if(e - d <= n1)
849 				break;
850 			d += n1;
851 			if(*p < 2)
852 				break;
853 			n1 = *p++ - 2;
854 			if(e - d <= n1)
855 			{
856 				memset(d, 0, e - d);
857 				break;
858 			}
859 			memset(d, 0, n1);
860 			d += n1;
861 		}
862 		while(*p >= 2)
863 			p++;
864 		if(*p)
865 			p++;
866 	}
867 }
868 */
869 
HRRInfo()870 HRRInfo::HRRInfo()
871 : levels(0)
872 , log_rect(0, 0, 0, 0)
873 , map_rect(0, 0, 0, 0)
874 , background(White)
875 , method(METHOD_JPG)
876 , quality(50)
877 , mono(false)
878 , mono_black(Black)
879 , mono_white(White)
880 {
881 }
882 
HRRInfo(const Rectf & log_rect_,const Rectf & map_rect_,int levels_,Color background_,int method_,int quality_,bool mono_,Color mono_black_,Color mono_white_)883 HRRInfo::HRRInfo(const Rectf& log_rect_, const Rectf& map_rect_,
884 	int levels_, Color background_, int method_, int quality_,
885 	bool mono_, Color mono_black_, Color mono_white_)
886 : log_rect(log_rect_)
887 , map_rect(map_rect_)
888 , levels(levels_)
889 , background(background_)
890 , method(method_)
891 , quality(quality_)
892 , mono(mono_)
893 , mono_black(mono_black_)
894 , mono_white(mono_white_)
895 {
896 	if(IsNull(map_rect)) {
897 		double wadd = log_rect.Height() - log_rect.Width();
898 		map_rect = log_rect;
899 		if(wadd >= 0)
900 			map_rect.right += wadd;
901 		else
902 			map_rect.top += wadd;
903 	}
904 }
905 
Serialize(Stream & stream)906 void HRRInfo::Serialize(Stream& stream)
907 {
908 	int outver = (stream.IsStoring() && !mono && method != METHOD_ZIM && method != METHOD_BZM ? 4 : 5);
909 	int version = StreamHeading(stream, outver, 2, 5, "HRRInfo");
910 	if(version >= 2)
911 		stream / levels % background % log_rect % map_rect;
912 	if(version >= 3)
913 		stream / method;
914 	else if(stream.IsLoading())
915 		method = METHOD_JPG;
916 	if(version >= 4)
917 		stream / quality;
918 	else if(stream.IsLoading())
919 		quality = 0;
920 	if(version >= 5)
921 		stream % mono % mono_black % mono_white;
922 	else if(stream.IsLoading())
923 	{
924 		mono = false;
925 		mono_black = Null;
926 		mono_white = Null;
927 	}
928 }
929 
EnumQualities(int method)930 Vector<int> HRRInfo::EnumQualities(int method)
931 {
932 	Vector<int> out;
933 	switch(method)
934 	{
935 	case METHOD_JPG:
936 		{
937 			for(int i = 10; i <= 100; i += 10)
938 				out << i;
939 		}
940 		break;
941 
942 	case METHOD_GIF:
943 	case METHOD_RLE:
944 	case METHOD_PNG:
945 	case METHOD_ZIM:
946 	case METHOD_BZM:
947 		out << 0;
948 		break;
949 
950 	default:
951 		NEVER();
952 		break;
953 	}
954 	return out;
955 }
956 
GetPackMap()957 VectorMap<int, String> HRRInfo::GetPackMap()
958 {
959 	VectorMap<int, String> out;
960 	Vector<int> methods = EnumMethods();
961 	for(int m = 0; m < methods.GetCount(); m++)
962 	{
963 		Vector<int> qualities = EnumQualities(methods[m]);
964 		if(qualities.IsEmpty())
965 			qualities.Add(0);
966 		for(int q = 0; q < qualities.GetCount(); q++)
967 			out.FindAdd(Pack(methods[m], qualities[q]), GetName(methods[m], qualities[q]));
968 	}
969 	return out;
970 }
971 
GetName(int method,int quality)972 String HRRInfo::GetName(int method, int quality)
973 {
974 	String out;
975 	switch(method)
976 	{
977 	case METHOD_JPG:
978 		out << "JPEG " << (quality ? quality : DFLT_JPG_QUALITY) << "%";
979 		break;
980 
981 	case METHOD_GIF:
982 		out << "GIF";
983 		break;
984 /*
985 	case METHOD_RLE:
986 		out << "RLE";
987 		break;
988 */
989 	case METHOD_PNG:
990 		out << "PNG";
991 		break;
992 
993 /*
994 	case METHOD_ZIM:
995 		out << "ZIM";
996 		break;
997 
998 	case METHOD_BZM:
999 		out << "BZM";
1000 		break;
1001 */
1002 	default:
1003 		out << "?? (" << method << ")";
1004 	}
1005 	return out;
1006 }
1007 
GetEstimatedFileSize(int _levels,int method,int quality)1008 double HRRInfo::GetEstimatedFileSize(int _levels, int method, int quality)
1009 {
1010 	int images = 0;
1011 	for(int i = 0; i < _levels; i++)
1012 		images += 1 << (2 * i);
1013 	int dir_size = images * sizeof(int) // offset table
1014 		+ 256; // estimated heading size
1015 	double data_size = images * double(UNIT * UNIT);
1016 	switch(method)
1017 	{
1018 	case METHOD_JPG:
1019 		data_size *= (quality ? quality : DFLT_JPG_QUALITY) / 400.0; // guessed JPEG size
1020 		break;
1021 
1022 	case METHOD_GIF:
1023 		data_size /= 2;
1024 		break;
1025 
1026 	case METHOD_RLE:
1027 		data_size /= 1.5;
1028 		break;
1029 
1030 	case METHOD_PNG:
1031 		data_size /= 1.6;
1032 		break;
1033 
1034 	case METHOD_ZIM:
1035 		data_size /= 1.6;
1036 		break;
1037 
1038 	case METHOD_BZM:
1039 		data_size /= 1.8;
1040 		break;
1041 
1042 	default:
1043 		NEVER();
1044 		break;
1045 	}
1046 	return data_size;
1047 }
1048 
1049 //////////////////////////////////////////////////////////////////////
1050 // HRR::Block::
1051 
Init(Size s,RGBA color)1052 void HRR::Block::Init(Size s, RGBA color)
1053 {
1054 //	static TimingInspector ti("HRR::Block::Init");
1055 //	ti.Start();
1056 	size = s;
1057 	block.Create(size);
1058 	Fill(~block, color, block.GetLength());
1059 }
1060 
1061 //////////////////////////////////////////////////////////////////////
1062 // HRR::
1063 
1064 One<StreamRaster> (*HRR::CreateDecoder)(const HRRInfo& info) = &HRR::StdCreateDecoder;
1065 One<StreamRasterEncoder> (*HRR::CreateEncoder)(const HRRInfo& info) = &HRR::StdCreateEncoder;
1066 
1067 static const Size SUNIT(HRRInfo::UNIT, HRRInfo::UNIT);
1068 static const Rect RUNIT(0, 0, HRRInfo::UNIT, HRRInfo::UNIT);
1069 
HRR()1070 HRR::HRR()
1071 {
1072 	cache_sizeof_limit = DEFAULT_CACHE_SIZEOF_LIMIT;
1073 }
1074 
HRR(const char * path,bool read_only)1075 HRR::HRR(const char *path, bool read_only)
1076 {
1077 	Open(path, read_only);
1078 }
1079 
StdCreateDecoder(const HRRInfo & info)1080 One<StreamRaster> HRR::StdCreateDecoder(const HRRInfo& info)
1081 {
1082 	switch(info.GetMethod()) {
1083 		case HRRInfo::METHOD_GIF: return new GIFRaster;
1084 		case HRRInfo::METHOD_PNG: return new PNGRaster;
1085 		case HRRInfo::METHOD_JPG: return new JPGRaster;
1086 		case HRRInfo::METHOD_ZIM: return new ZImageRaster;
1087 //		case HRRInfo::METHOD_BMP: return new BMPRaster;
1088 	}
1089 	return NULL;
1090 }
1091 
StdCreateEncoder(const HRRInfo & info)1092 One<StreamRasterEncoder> HRR::StdCreateEncoder(const HRRInfo& info)
1093 {
1094 	switch(info.GetMethod()) {
1095 		case HRRInfo::METHOD_GIF: return new GIFEncoder;
1096 		case HRRInfo::METHOD_PNG: return new PNGEncoder;
1097 		case HRRInfo::METHOD_JPG: return new JPGEncoder(info.GetQuality());
1098 //		case HRRInfo::METHOD_BMP: return new BMPEncoder;
1099 	}
1100 	return NULL;
1101 }
1102 
Open(const char * path,bool read_only)1103 bool HRR::Open(const char *path, bool read_only)
1104 {
1105 	Close();
1106 	if(!path || !*path || !stream.Open(path, read_only ? stream.READ : stream.READWRITE))
1107 		return false;
1108 	stream.SetLoading();
1109 	Serialize();
1110 	if(stream.IsError() || info.levels <= 0
1111 		|| info.map_rect.Width() <= 0 || info.map_rect.Height() <= 0)
1112 	{
1113 		Close();
1114 		return false;
1115 	}
1116 	return true;
1117 }
1118 
Close()1119 void HRR::Close()
1120 {
1121 	stream.Close();
1122 	pixel_directory_offset.Clear();
1123 	mask_directory_offset.Clear();
1124 //	pixel_directory.Clear();
1125 //	mask_directory.Clear();
1126 	image_cache.Clear();
1127 	directory_sizeof = 0;
1128 	cache_sizeof = 0;
1129 	info = HRRInfo();
1130 }
1131 
GetImageSize(Size sz)1132 static int GetImageSize(Size sz)
1133 {
1134 	return sizeof(Image) + 32 + sz.cx * sz.cy * sizeof(RGBA);
1135 }
1136 
GetImageSize(const Image & im)1137 inline static int GetImageSize(const Image& im) { return GetImageSize(im.GetSize()); }
1138 
FlushCache(int limit)1139 void HRR::FlushCache(int limit)
1140 {
1141 	while(!image_cache.IsEmpty() && cache_sizeof > limit) {
1142 		cache_sizeof -= GetImageSize(image_cache[0]);
1143 		image_cache.Remove(0);
1144 	}
1145 }
1146 
ClearCache()1147 void HRR::ClearCache()
1148 {
1149 	image_cache.Clear();
1150 	cache_sizeof = 0;
1151 }
1152 
GetLogBlockSize(Rectf box_rc,Rectf map_rc)1153 static Size GetLogBlockSize(Rectf box_rc, Rectf map_rc)
1154 {
1155 	Size part_size(HRRInfo::UNIT, HRRInfo::UNIT);
1156 	if(box_rc.left >= map_rc.right)
1157 		return Size(0, 0);
1158 	if(box_rc.right >= map_rc.right)
1159 		part_size.cx = fround(part_size.cx * (map_rc.right - box_rc.left) / box_rc.Width());
1160 	if(box_rc.bottom <= map_rc.top)
1161 		return Size(0, 0);
1162 	else if(box_rc.top < map_rc.top)
1163 		part_size.cy = fround(part_size.cy * (box_rc.bottom - map_rc.top) / box_rc.Height());
1164 	return part_size;
1165 }
1166 
BlendColor(Color a,int percent,Color b)1167 static Color BlendColor(Color a, int percent, Color b)
1168 {
1169 	return Color(
1170 		b.GetR() + iscale(a.GetR() - b.GetR(), percent, 100),
1171 		b.GetG() + iscale(a.GetG() - b.GetG(), percent, 100),
1172 		b.GetB() + iscale(a.GetB() - b.GetB(), percent, 100));
1173 }
1174 
StopMsec(int start=0)1175 static int StopMsec(int start = 0)
1176 {
1177 	return GetTickCount() - start;
1178 }
1179 
DrawAlphaImage(Draw & draw,Rect dest,Image img,Rect src,int alpha)1180 static void DrawAlphaImage(Draw& draw, Rect dest, Image img, Rect src, int alpha)
1181 {
1182 	if(alpha <= 0)
1183 		return;
1184 	alpha += alpha >> 7;
1185 	if(alpha >= 256) {
1186 		draw.DrawImage(dest, img, src);
1187 		return;
1188 	}
1189 	Size outsz = min(src.Size(), dest.Size());
1190 	ImageBuffer temp(outsz);
1191 	Rescale(ImageWriter(temp, false), outsz, ImageRaster(img), src);
1192 	byte conv[256];
1193 	for(int i = 0; i < 256; i++)
1194 		conv[i] = (i * alpha) >> 8;
1195 	for(RGBA *p = ~temp, *e = ~temp + temp.GetLength(); p < e; p++) {
1196 //		int a = (p->a + (p->a >> 7)) * alpha;
1197 		p->r = conv[p->r];
1198 		p->g = conv[p->g];
1199 		p->b = conv[p->b];
1200 		p->a = conv[p->a];
1201 	}
1202 //	temp.SetKind(IMAGE_PREMULTIPLIED);
1203 	draw.DrawImage(dest, Image(temp));
1204 }
1205 
Paint(Draw & draw,Rect dest,Rectf src,int alpha,int max_pixel,Color mono_black,Color mono_white,Color blend_bgnd)1206 void HRR::Paint(Draw& draw, Rect dest, Rectf src,
1207 	int alpha, int max_pixel, Color mono_black, Color mono_white, Color blend_bgnd)
1208 {
1209 	LLOG("HRR::Paint: alpha = " << alpha
1210 		<< ", max_pixel = " << max_pixel << ", mono_black = " << mono_black
1211 		<< ", mono_white = " << mono_white << ", blend_bgnd = " << blend_bgnd
1212 		<< ", dest = " << dest << ", src = " << src << BeginIndent);
1213 	draw.Clip(dest);
1214 	Swap(dest.top, dest.bottom);
1215 	Paint(draw, MatrixfScale(src, dest), Null, alpha, max_pixel, mono_black, mono_white, blend_bgnd);
1216 	draw.End();
1217 	LLOG(EndIndent << "// HRR::Paint");
1218 }
1219 
Cursor(HRR & owner_,const Rectf & extent_,double measure_,int alpha_,Color mono_black_,Color mono_white_,Color blend_bgnd_)1220 HRR::Cursor::Cursor(HRR& owner_, const Rectf& extent_, double measure_,
1221 	int alpha_, Color mono_black_, Color mono_white_, Color blend_bgnd_)
1222 : owner(owner_)
1223 , extent(extent_)
1224 , measure(measure_)
1225 , alpha(alpha_)
1226 , mono_black(mono_black_)
1227 , mono_white(mono_white_)
1228 , blend_bgnd(blend_bgnd_)
1229 {
1230 	bool use_pixel = (IsNull(mono_black) && IsNull(mono_white));
1231 
1232 	if(owner.info.IsMono() && use_pixel) {
1233 		mono_black = owner.info.GetMonoBlack();
1234 		mono_white = owner.info.GetMonoWhite();
1235 		use_pixel = (IsNull(mono_black) && IsNull(mono_white));
1236 		if(use_pixel) {
1237 			LLOG(EndIndent << "//HRR::Paint, null color, empty case");
1238 			return;
1239 		}
1240 	}
1241 
1242 //	bool use_bg = (alpha < 100 && IsNull(blend_bgnd) || do_transform);
1243 //	bool use_alpha = !use_pixel || IsNull(info.background);
1244 	bool is_bw = (!IsNull(mono_black) && !IsNull(mono_white));
1245 //	bool out_pixel = (use_pixel || is_bw);
1246 //	bool out_alpha = (use_pixel ? IsNull(info.background) : !is_bw);
1247 
1248 //	LLOG("[" << StopMsec(ticks) << "] use_bg = " << use_bg << ", use_pixel = " << use_pixel << ", use_alpha = " << use_alpha
1249 //		<< ", is_bw = " << is_bw << ", out_pixel = " << out_pixel << ", out_alpha = " << out_alpha);
1250 
1251 	double r = HRRInfo::UNIT / owner.info.GetMapRect().Width();
1252 //	if(draw.Dots())
1253 //		r /= 5; // ad hoc conversion from screen space to dot resolution
1254 	level = 0;
1255 	for(; level < owner.info.GetLevels() - 1 && r < measure; r *= 2, level++)
1256 		;
1257 //	DUMP(level);
1258 
1259 	if(!IsNull(mono_black))
1260 		mono_black = BlendColor(mono_black, alpha, Nvl(owner.info.GetBackground(), White));
1261 	if(!IsNull(mono_white))
1262 		mono_white = BlendColor(mono_white, alpha, Nvl(owner.info.GetBackground(), White));
1263 
1264 	// calculate interest area in Q-tree blocks
1265 	total = 1 << level;
1266 	Rectf blocks = (extent - owner.info.GetMapRect().BottomLeft()) / owner.info.GetMapRect().Size() * double(total);
1267 	rc = Rect(ffloor(blocks.left), ffloor(-blocks.bottom), fceil(blocks.right), fceil(-blocks.top));
1268 	rc &= Rect(0, 0, total, total);
1269 
1270 	// prepare clipping & image loader
1271 	if(!owner.info.IsMono()) {
1272 		raster = CreateDecoder(owner.info);
1273 		if(!raster) {
1274 			LLOG(EndIndent << "//HRR:x: decoder not found, exiting");
1275 			return;
1276 		}
1277 	}
1278 
1279 	// adjust transform parameters to convert from Q-tree space to device coords
1280 //	delta += info.map_rect.BottomLeft() * scale;
1281 //	scale *= Sizef(1, -1) * info.map_rect.Size() / double(1 << level);
1282 
1283 #ifdef _DEBUG
1284 //	int ti = 0;
1285 #endif
1286 
1287 	block = rc.TopLeft();
1288 	block.x--;
1289 }
1290 
Fetch(Rectf & part)1291 bool HRR::Cursor::Fetch(Rectf& part)
1292 {
1293 	for(;;) {
1294 		cimg = -1;
1295 		if(++block.x >= rc.right) {
1296 			block.x = rc.left;
1297 			if(++block.y >= rc.bottom)
1298 				return false;
1299 		}
1300 		LLOG("[" << StopMsec(ticks) << "] block = [" << x << ", " << y << "]");
1301 		int layer_offset = 4 * (block.x + block.y * total);
1302 		int pixel_offset = 0, mask_offset = 0;
1303 		if(level >= 0 && level < owner.pixel_directory_offset.GetCount()) {
1304 			owner.stream.Seek(owner.pixel_directory_offset[level] + layer_offset);
1305 			pixel_offset = owner.stream.Get32le();
1306 		}
1307 		if(level >= 0 && level < owner.mask_directory_offset.GetCount()) {
1308 			owner.stream.Seek(owner.mask_directory_offset[level] + layer_offset);
1309 			mask_offset = owner.stream.Get32le();
1310 		}
1311 		Point pixel_mask(pixel_offset, mask_offset);
1312 		if(!pixel_offset && !mask_offset)
1313 			continue;
1314 		if((cimg = owner.image_cache.Find(pixel_mask)) < 0) {
1315 			ImageBuffer new_image;
1316 			if(pixel_offset) {
1317 				owner.stream.Seek(Unpack64(pixel_offset));
1318 				new_image = raster->Load(owner.stream);
1319 				if(new_image.IsEmpty()) {
1320 					RLOG(NFormat("Failed to load block [%d, %d].", block.x, block.y));
1321 					continue;
1322 				}
1323 //				PixelSetConvert(new_image.pixel, -3);
1324 			}
1325 			if(mask_offset) {
1326 				owner.stream.Seek(Unpack64(mask_offset));
1327 				int len = owner.stream.GetIL();
1328 				ASSERT(len >= 0 && len < HRRInfo::UNIT * (HRRInfo::UNIT + 1) + 1);
1329 				StringBuffer databuf(len);
1330 				owner.stream.Get(databuf, len);
1331 				String data = databuf;
1332 				if(owner.version < 5) {
1333 					Size sz(0, 0);
1334 					if(cimg >= 0)
1335 						sz = new_image.GetSize();
1336 					else if(pixel_offset) {
1337 						int csize = owner.size_cache.Find(pixel_offset);
1338 						if(csize < 0) {
1339 							if(owner.size_cache.GetCount() >= 10000)
1340 								owner.size_cache.Clear();
1341 							int64 pixpos = Unpack64(pixel_offset);
1342 							if(pixpos > owner.stream.GetSize())
1343 								owner.stream.SetSize(pixpos);
1344 	//								stream.Seek(pixpos);
1345 							csize = owner.size_cache.GetCount();
1346 	//								Stream64Stream pixel_stream(stream, pixpos);
1347 							owner.stream.Seek(pixpos);
1348 							raster->Open(owner.stream);
1349 							owner.size_cache.Add(pixel_offset, raster->GetSize());
1350 						}
1351 						sz = owner.size_cache[csize];
1352 					}
1353 					if(sz.cx <= 0 || sz.cy <= 0)
1354 						continue;
1355 //					new_image.alpha = PixelArray::Mono(sz);
1356 				}
1357 				DecodeMask(new_image, data, owner.version >= 5);
1358 			}
1359 			int new_len = new_image.GetLength() * sizeof(RGBA);
1360 			owner.FlushCache(owner.cache_sizeof_limit - new_len);
1361 			owner.cache_sizeof += new_len;
1362 			cimg = owner.image_cache.GetCount();
1363 			owner.image_cache.Add(pixel_mask) = new_image;
1364 		}
1365 		if(cimg >= 0) {
1366 			part = owner.GetLogBlockRect(level, RectC(block.x, block.y, 1, 1));
1367 			Size sz = owner.image_cache[cimg].GetSize();
1368 			part.right = part.left + part.Width() * sz.cx / HRRInfo::UNIT;
1369 			part.top = part.bottom - part.Height() * sz.cy / HRRInfo::UNIT;
1370 			return true;
1371 		}
1372 	}
1373 }
1374 
Get()1375 Image HRR::Cursor::Get()
1376 {
1377 	ASSERT(cimg >= 0);
1378 	return owner.image_cache[cimg];
1379 }
1380 
Paint(Draw & draw,const Matrixf & trg_pix,GisTransform transform,int alpha,int max_pixel,Color mono_black,Color mono_white,Color blend_bgnd)1381 void HRR::Paint(Draw& draw, const Matrixf& trg_pix, GisTransform transform,
1382 	int alpha, int max_pixel, Color mono_black, Color mono_white, Color blend_bgnd)
1383 {
1384 	LLOG("HRR::Paint: alpha = " << alpha
1385 		<< ", max_pixel = " << max_pixel << ", mono_black = " << mono_black
1386 		<< ", mono_white = " << mono_white << ", blend_bgnd = " << blend_bgnd
1387 		<< ", trg_pix = " << trg_pix << BeginIndent);
1388 
1389 	int ticks = StopMsec();
1390 	ASSERT(alpha >= 0);
1391 
1392 	if(alpha == 0 || info.IsEmpty() || !IsOpen()) {
1393 		LLOG(EndIndent << "//HRR::Paint, empty case");
1394 		return;
1395 	}
1396 
1397 	bool do_transform = !transform.IsIdentity();
1398 	bool is_straight = !do_transform && fabs(trg_pix.x.y) <= 1e-10 && fabs(trg_pix.y.x) <= 1e-10;
1399 	bool use_pixel = (IsNull(mono_black) && IsNull(mono_white));
1400 
1401 	if(info.mono && use_pixel) {
1402 		mono_black = info.mono_black;
1403 		mono_white = info.mono_white;
1404 		use_pixel = (IsNull(mono_black) && IsNull(mono_white));
1405 		if(use_pixel) {
1406 			LLOG(EndIndent << "//HRR::Paint, null color, empty case");
1407 			return;
1408 		}
1409 	}
1410 
1411 	bool use_bg = (alpha < 100 && IsNull(blend_bgnd) || do_transform);
1412 	bool use_alpha = !use_pixel || IsNull(info.background);
1413 	bool is_bw = (!IsNull(mono_black) && !IsNull(mono_white));
1414 	bool out_pixel = (use_pixel || is_bw);
1415 	bool out_alpha = (use_pixel ? IsNull(info.background) : !is_bw);
1416 
1417 	LLOG("[" << StopMsec(ticks) << "] use_bg = " << use_bg << ", use_pixel = " << use_pixel << ", use_alpha = " << use_alpha
1418 		<< ", is_bw = " << is_bw << ", out_pixel = " << out_pixel << ", out_alpha = " << out_alpha);
1419 
1420 	Matrixf pix_trg = MatrixfInverse(trg_pix);
1421 	Rect clip = draw.GetPaintRect(); //draw.GetClip();
1422 	Rectf csrc = info.log_rect & transform.SourceExtent(Rectf(clip) * pix_trg);
1423 //	Pointf scale = Sizef(1, -1) * Sizef(dest.Size()) / Sizef(src.Size());
1424 //	Pointf delta = Pointf(dest.TopLeft()) - src.BottomLeft() * scale;
1425 //	Rectf  csrc  = src & info.log_rect;
1426 	Rect   cdest = RectfToRect(transform.TargetExtent(csrc) * trg_pix) & clip;
1427 //	Rect   cdest = RectfToRect(csrc * scale + delta);
1428 //	Swap(cdest.top, cdest.bottom);
1429 //	DrawRectMinusRect(draw, dest, cdest, info.background);
1430 	if(cdest.IsEmpty())
1431 	{ // intersection is less than 1 pixel wide / high
1432 		LLOG(EndIndent << "//HRR::Paint: empty destination, exiting");
1433 		return;
1434 	}
1435 	double r = fpmax(Sizef(cdest.Size()) * Sizef(info.map_rect.Size()) / csrc.Size()) / info.UNIT;
1436 	if(draw.Dots())
1437 		r /= 5; // ad hoc conversion from screen space to dot resolution
1438 	int level = 0;
1439 	for(; level < info.levels - 1 && r > max_pixel; r /= 2, level++)
1440 		;
1441 //	DUMP(level);
1442 
1443 	if(!IsNull(mono_black))
1444 		mono_black = BlendColor(mono_black, alpha, Nvl(info.background, White));
1445 	if(!IsNull(mono_white))
1446 		mono_white = BlendColor(mono_white, alpha, Nvl(info.background, White));
1447 
1448 	ImageBuffer out_blend;
1449 	if(use_bg) {
1450 		out_blend.Create(cdest.Size());
1451 		Fill(out_blend, info.background, out_blend.GetLength());
1452 	}
1453 	LOG("out blend: " << out_blend.GetSize());
1454 
1455 	// calculate interest area in Q-tree blocks
1456 	int total = 1 << level;
1457 	Rectf blocks = (csrc - info.map_rect.BottomLeft()) / info.map_rect.Size() * double(total);
1458 	Rect rc(ffloor(blocks.left), ffloor(-blocks.bottom), fceil(blocks.right), fceil(-blocks.top));
1459 	rc &= Rect(0, 0, total, total);
1460 
1461 	// prepare clipping & image loader
1462 	draw.Clip(cdest);
1463 	One<StreamRaster> decoder;
1464 	if(!info.mono) {
1465 		decoder = CreateDecoder(info);
1466 		if(decoder.IsEmpty()) {
1467 			draw.DrawText(cdest.left, cdest.top,
1468 				String().Cat() << "Unsupported HRR encoding: " << info.GetMethod(), StdFont());
1469 			draw.End();
1470 			LLOG(EndIndent << "//HRR:x: encoder not found, exiting");
1471 			return;
1472 		}
1473 	}
1474 
1475 	// adjust transform parameters to convert from Q-tree space to device coords
1476 //	delta += info.map_rect.BottomLeft() * scale;
1477 //	scale *= Sizef(1, -1) * info.map_rect.Size() / double(1 << level);
1478 
1479 #ifdef _DEBUG
1480 //	int ti = 0;
1481 #endif
1482 
1483 	SegmentTreeInfo seginfo;
1484 	seginfo.src_trg = transform;
1485 	seginfo.trg_pix = trg_pix;
1486 	seginfo.trg_pix.a -= cdest.TopLeft();
1487 	seginfo.antialias = true;
1488 	seginfo.branch = 0;
1489 	seginfo.max_depth = HRRInfo::HALF_BITS - 1;
1490 	double trg_dv = 2 / sqrt(fabs(Determinant(trg_pix)));
1491 	Rect rclip = clip - cdest.TopLeft();
1492 	Font err_font = StdFont();
1493 	for(int y = rc.top; y < rc.bottom; y++)
1494 		for(int x = rc.left; x < rc.right; x++)
1495 		{
1496 			LLOG("[" << StopMsec(ticks) << "] block = [" << x << ", " << y << "]");
1497 			seginfo.img_src = GetPixMapMatrix(level, x, y);
1498 			seginfo.img_src.x.x /= HRRInfo::UNIT;
1499 			seginfo.img_src.y.y /= HRRInfo::UNIT;
1500 			Matrixf src_img = MatrixfInverse(seginfo.img_src);
1501 			Rect src = RectfToRect((RUNIT * seginfo.img_src & csrc) * src_img).Inflated(2) & RUNIT;
1502 			Rectf map = src * seginfo.img_src;
1503 			Rect dest = (transform.TargetExtent(map) * trg_pix).Inflated(1) & Rectf(clip);
1504 //			Rect dest = RectfToRect(Rectf(x, y, x + 1, y + 1) * scale + delta);
1505 //			Rect clip = dest & draw.GetClip();
1506 			Rect rdest = (dest & cdest) - cdest.TopLeft();
1507 			if(rdest.IsEmpty())
1508 				continue;
1509 			LinearSegmentTree tleft, ttop, tright, tbottom;
1510 			PlanarSegmentTree tplanar;
1511 			if(!is_straight) {
1512 				seginfo.max_deviation = trg_dv;
1513 				tleft = CreateLinearTree(src.TopLeft(), src.BottomLeft(), seginfo);
1514 				ttop = CreateLinearTree(src.TopLeft(), src.TopRight(), seginfo);
1515 				tright = CreateLinearTree(src.TopRight(), src.BottomRight(), seginfo);
1516 				tbottom = CreateLinearTree(src.BottomLeft(), src.BottomRight(), seginfo);
1517 				tplanar = CreatePlanarTree(tleft, ttop, tright, tbottom, seginfo);
1518 			}
1519 //			Rect src = (clip - dest.TopLeft()) * SUNIT / dest.Size();
1520 //			src.Inflate(2);
1521 //			src &= RUNIT;
1522 			int layer_offset = 4 * (x + y * total);
1523 			stream.Seek(pixel_directory_offset[level] + layer_offset);
1524 			int pixel_offset = stream.Get32le();
1525 			int mask_offset = 0;
1526 			if(!mask_directory_offset.IsEmpty()) {
1527 				stream.Seek(mask_directory_offset[level] + layer_offset);
1528 				mask_offset = stream.Get32le();
1529 			}
1530 //			int pixel_offset = pixel_directory[level][x + y * total];
1531 			Point pixel_mask(pixel_offset, mask_offset);
1532 			if(!pixel_offset && !mask_offset)
1533 				continue;
1534 			bool newimg = false;
1535 			if(image_cache.Find(pixel_mask) < 0) {
1536 //				Stream64Stream pixel_stream(stream, Unpack64(pixel_offset));
1537 				ImageBuffer new_image;
1538 				if(pixel_offset) {
1539 					stream.Seek(Unpack64(pixel_offset));
1540 					new_image = decoder->Load(stream);
1541 					if(new_image.IsEmpty()) {
1542 						String warn = NFormat("Failed to load block [%d, %d].", x, y);
1543 						Size sz = GetTextSize(warn, err_font);
1544 						draw.DrawRect(Rect(dest.CenterPoint(), Size(1, 1)).Inflated(sz + 2), Color(255, 192, 192));
1545 						draw.DrawText((dest.left + dest.right - sz.cx) >> 1, (dest.top + dest.bottom - sz.cy) >> 1,
1546 							warn, StdFont(), Black);
1547 						continue;
1548 					}
1549 				}
1550 				if(mask_offset && use_alpha) {
1551 					stream.Seek(Unpack64(mask_offset));
1552 					int len = stream.GetIL();
1553 					StringBuffer data(len);
1554 					ASSERT(len >= 0 && len < HRRInfo::UNIT * (HRRInfo::UNIT + 1) + 1);
1555 					stream.Get(data, len);
1556 					if(version < 5) {
1557 						Size sz(0, 0);
1558 						if(pixel_offset)
1559 							sz = new_image.GetSize();
1560 						else {
1561 							int csize = size_cache.Find(pixel_offset);
1562 							if(csize < 0) {
1563 								if(size_cache.GetCount() >= 10000)
1564 									size_cache.Clear();
1565 								int64 pixpos = Unpack64(pixel_offset);
1566 								if(pixpos > stream.GetSize())
1567 									stream.SetSize(pixpos);
1568 	//								stream.Seek(pixpos);
1569 								csize = size_cache.GetCount();
1570 	//								Stream64Stream pixel_stream(stream, pixpos);
1571 								stream.Seek(pixpos);
1572 								Size sz = 0;
1573 								if(decoder->Open(stream))
1574 									sz = decoder->GetSize();
1575 								size_cache.Add(pixel_offset, sz);
1576 							}
1577 							sz = size_cache[csize];
1578 						}
1579 						if(sz.cx <= 0 || sz.cy <= 0)
1580 							continue;
1581 						DecodeMask(new_image, data, version >= 5);
1582 					}
1583 				}
1584 				FlushCache(cache_sizeof_limit - GetImageSize(new_image.GetSize()));
1585 				cache_sizeof += GetImageSize(new_image.GetSize());
1586 				image_cache.Add(pixel_mask) = new_image;
1587 			}
1588 			int cimg = image_cache.Find(pixel_mask);
1589 			if(cimg < 0)
1590 				continue;
1591 /*
1592 			if(cimg < 0) {
1593 				LLOG("[" << StopMsec(ticks) << "] pixel off, mask off");
1594 				if(!is_straight && !IsNull(info.background))
1595 					AlphaTransformPaint(out_blend, Image(), tplanar, tleft, ttop, tright, tbottom, seginfo, info.background);
1596 				else if(use_pixel)
1597 					draw.DrawRect(dest, info.background);
1598 			}
1599 			else
1600 */
1601 			{
1602 				const Image& img = image_cache[cimg];
1603 				if(!use_bg) {
1604 					LLOG("[" << StopMsec(ticks) << "] !use_bg -> direct mask blend");
1605 					if(alpha >= 100)
1606 						draw.DrawImage(dest, img, src);
1607 					else
1608 						DrawAlphaImage(draw, dest, img, src, minmax(alpha * 256 / 100, 0, 255));
1609 //					DrawAlphaBlend(draw, dest, src, 100, out_part, blend_bgnd);
1610 				}
1611 				else if(!is_straight) {
1612 					LLOG("[" << StopMsec(ticks) << "] use_bg -> twisted mask blend");
1613 					AlphaTransformPaint(out_blend, img,
1614 						tplanar, tleft, ttop, tright, tbottom, seginfo, LtRed());
1615 				}
1616 				else {
1617 					LLOG("[" << StopMsec(ticks) << "] use_bg -> buffered colored mask blend");
1618 					ImageWriter writer(out_blend, rdest.TopLeft(), rclip);
1619 					Rescale(writer, rdest.Size(), ImageRaster(img), src);
1620 				}
1621 			}
1622 		}
1623 
1624 	if(use_bg) {
1625 		if(alpha < 100) {
1626 			int coef = alpha * 255 / 100;
1627 			byte conv[256];
1628 			for(int i = 0; i < 256; i++)
1629 				conv[i] = (i * coef) >> 8;
1630 			for(RGBA *p = ~out_blend, *e = p + out_blend.GetLength(); p < e; p++) {
1631 				p->r = conv[p->r];
1632 				p->g = conv[p->g];
1633 				p->b = conv[p->b];
1634 				p->a = conv[p->a];
1635 			}
1636 		}
1637 		draw.DrawImage(cdest, out_blend);
1638 	}
1639 	draw.End();
1640 	LLOG(EndIndent << "[" << StopMsec(ticks) << "] //HRR::Paint");
1641 }
1642 
GetProgressCount(int levels,bool downscale)1643 int HRR::GetProgressCount(int levels, bool downscale)
1644 {
1645 	ASSERT(levels > 0);
1646 	int images = 0;
1647 	if(downscale)
1648 		images = 1 << (2 * (levels - 1));
1649 	else
1650 		for(int i = 0; i < levels; i++)
1651 			images += 1 << (2 * i);
1652 	return images;
1653 }
1654 
Create(const HRRInfo & _info,const char * path)1655 bool HRR::Create(const HRRInfo& _info, const char *path)
1656 {
1657 	ASSERT(_info.levels > 0);
1658 	Close();
1659 	if(!stream.Open(path, stream.CREATE))
1660 		return false;
1661 	info = _info;
1662 	map_offset = 0;
1663 	Serialize();
1664 	return true;
1665 }
1666 
StreamHRRString(Stream & stream,String & string)1667 static void StreamHRRString(Stream& stream, String& string)
1668 {
1669 	int version = 1, len = string.GetLength();
1670 	stream / version / len;
1671 	if(version > 1 || stream.IsLoading() && (unsigned)len > stream.GetLeft())
1672 	{
1673 		stream.SetError();
1674 		return;
1675 	}
1676 	if(stream.IsStoring())
1677 		stream.SerializeRaw((byte *)(const char *)string, len);
1678 	else {
1679 		StringBuffer stringbuf(len);
1680 		stream.SerializeRaw((byte *)~stringbuf, len);
1681 		string = stringbuf;
1682 	}
1683 }
1684 
Serialize()1685 void HRR::Serialize()
1686 {
1687 	int outver = (stream.IsStoring() && (info.mono || info.method >= info.METHOD_ZIM) ? 5 : 4);
1688 	version = StreamHeading(stream, outver, 1, 5, "\r\n"
1689 		"High-Resolution Raster\r\n"
1690 		"Copyright �1999 Cybex Development, spol. s r.o.\r\n");
1691 	if(version >= 1)
1692 		stream % info;
1693 	if(version >= 2)
1694 		stream % map_offset;
1695 	else
1696 		map_offset = 0;
1697 	pixel_directory_offset.SetCount(info.levels);
1698 	if(version >= 1) {
1699 		if(version <= 3 || !info.mono)
1700 			for(int l = 0; l < info.levels; l++) {
1701 				int c = 1 << (2 * l);
1702 				int byte_size = 4 * c;
1703 				pixel_directory_offset[l] = stream.GetPos();
1704 				if(stream.IsStoring() && stream.GetLeft() < byte_size)
1705 					stream.Put(0, byte_size);
1706 				else
1707 					stream.SeekCur(byte_size);
1708 //				stream.SerializeRaw((byte *)pixel_directory[l].Begin(),
1709 //					sizeof(pixel_directory[0][0]) * pixel_directory[l].GetCount());
1710 			}
1711 		if(version >= 3 && (IsNull(info.background) || info.mono)) {
1712 			mask_directory_offset.SetCount(info.levels);
1713 			for(int m = 0; m < info.levels; m++) {
1714 				int c = 1 << (2 * m);
1715 				int byte_size = 4 * c;
1716 				mask_directory_offset[m] = stream.GetPos();
1717 				if(stream.IsStoring() && stream.GetLeft() < byte_size)
1718 					stream.Put(0, byte_size);
1719 				else
1720 					stream.SeekCur(byte_size);
1721 //				stream.SerializeRaw((byte *)mask_directory[m].Begin(),
1722 //					sizeof(mask_directory[0][0]) * mask_directory[m].GetCount());
1723 			}
1724 		}
1725 	}
1726 	if(map_offset && version > 3) {
1727 		int64 mappos = Unpack64(map_offset);
1728 		if(stream.IsStoring() && stream.GetSize() < mappos) {
1729 			stream.Seek(stream.GetSize());
1730 			stream.Put(0, (int)(mappos - stream.GetSize()));
1731 		}
1732 		if(stream.IsStoring() || mappos >= 0 && mappos < stream.GetSize()) {
1733 			stream.Seek(mappos);
1734 			int count = map.GetCount();
1735 			stream / count;
1736 			for(int i = 0; i < count; i++)
1737 			{
1738 				String key;
1739 				String val;
1740 				if(stream.IsStoring())
1741 				{
1742 					key = map.GetKey(i);
1743 					val = map[i];
1744 				}
1745 				StreamHRRString(stream, key);
1746 				StreamHRRString(stream, val);
1747 				if(stream.IsLoading())
1748 					map.Add(key, val);
1749 			}
1750 		}
1751 	}
1752 	else
1753 		map.Clear();
1754 }
1755 
Write(Writeback drawback,bool downscale)1756 void HRR::Write(Writeback drawback, bool downscale)
1757 {
1758 	ASSERT(stream.IsOpen());
1759 	if(map_offset > 0)
1760 	{
1761 		int64 mu = Unpack64(map_offset);
1762 		stream.Seek(mu);
1763 		stream.SetSize(mu);
1764 		map_offset = 0;
1765 	}
1766 	One<StreamRasterEncoder> encoder = CreateEncoder(info);
1767 	if(!encoder)
1768 		throw Exc(String().Cat() << "Unsupported HRR encoding: " << info.GetMethod());
1769 
1770 	bool abort = false;
1771 	try
1772 	{
1773 		Write(drawback, downscale, 0, 0, 0, *encoder, 0);
1774 	}
1775 	catch(AbortExc)
1776 	{
1777 		abort = true;
1778 	}
1779 	map_offset = CeilPack64(stream.GetPos());
1780 	stream.Seek(0);
1781 	Serialize(); // update header
1782 	if(abort)
1783 		throw AbortExc();
1784 }
1785 
GetPixMapMatrix(int level,int x,int y) const1786 Matrixf HRR::GetPixMapMatrix(int level, int x, int y) const
1787 {
1788 	double fac = 1 << level;
1789 	double xx = info.map_rect.Width() / fac, yy = -info.map_rect.Height() / fac;
1790 	return Matrixf(xx, 0, 0, yy, info.map_rect.left + xx * x, info.map_rect.bottom + yy * y);
1791 }
1792 
GetFileWriteSize() const1793 int64 HRR::GetFileWriteSize() const
1794 {
1795 	ASSERT(stream.IsOpen());
1796 	return stream.GetSize();
1797 }
1798 
GetLogBlockRect(int level,const Rect & rc) const1799 Rectf HRR::GetLogBlockRect(int level, const Rect& rc) const
1800 {
1801 	return Rectf(rc) * GetPixMapMatrix(level, 0, 0);
1802 /*	Rectf r(rc);
1803 	double fac = 1.0 / (1 << level);
1804 	r = r * fac;
1805 	double t = r.bottom; r.bottom = 1 - r.top; r.top = 1 - t;
1806 	return r * info.map_rect.Size() + info.map_rect.TopLeft();
1807 */
1808 }
1809 
Write(Writeback drawback,bool downscale,int level,int px,int py,StreamRasterEncoder & format,Block * put)1810 bool HRR::Write(Writeback drawback, bool downscale, int level, int px, int py,
1811 				StreamRasterEncoder& format, Block *put)
1812 {
1813 	static const Size SUNIT(info.UNIT, info.UNIT);
1814 	Block block(*this);
1815 //	TIMING("HRR::Write");
1816 
1817 	if(level >= info.levels - info.LCOUNT)
1818 	{ // generate all at once
1819 //		TIMING("HRR::Write(short step)");
1820 //		static TimingInspector __part("HRR::Write(part)");
1821 //		__part.Start();
1822 		int count = info.levels - level - 1;
1823 		// step & render individual images
1824 		block.Init(SUNIT << count, info.background);
1825 //		__part.End();
1826 		block.level = level + count;
1827 		block.area = RectC(px << count, py << count, 1 << count, 1 << count);
1828 		block.log_area = GetLogBlockRect(block.level, block.area);
1829 		bool done = drawback(block);
1830 		if(!done && downscale)
1831 			return false;
1832 
1833 		while(count >= 0)
1834 		{
1835 			int n = 1 << count;
1836 			for(Size a(0, 0); a.cy < n; a.cy++)
1837 				for(a.cx = 0; a.cx < n; a.cx++)
1838 				{
1839 					Point src = a * info.UNIT;
1840 					Size part_size = GetLogBlockSize(GetLogBlockRect(level + count, RectC(a.cx, a.cy, 1, 1)), info.log_rect);
1841 					if(part_size.cx <= 0 || part_size.cy <= 0)
1842 						continue;
1843 					ImageBuffer part(part_size);
1844 					RasterCopy(ImageWriter(part, false), ImageBufferRaster(block.block), Rect(src, part_size));
1845 					int lin = (int)((px << count) + a.cx + (((py << count) + a.cy) << (count + level)));
1846 //					TIMING("HRR::Write / save (direct)");
1847 					if(info.mono || IsNull(info.background)) {
1848 						int kind = GetMaskInfo(~part, part.GetLength());
1849 						if(kind && !info.mono) {
1850 							int pixoff = CeilPack64(stream.GetPos());
1851 							stream.Seek(pixel_directory_offset[level + count] + 4 * lin);
1852 							stream.Put32le(pixoff);
1853 							stream.SeekEnd();
1854 							int64 pixpos = Unpack64(pixoff);
1855 							if(stream.GetSize() < pixpos)
1856 								stream.Put(0, (int)(pixpos - stream.GetSize()));
1857 							stream.Seek(pixpos);
1858 //							Stream64Stream pixstream(stream, pixpos);
1859 							format.Save(stream, ImageBufferRaster(part));
1860 						}
1861 						if(kind == 2 || (kind == 1 && info.mono)) {
1862 							String s = EncodeMask(part, version >= 5);
1863 							ASSERT(s.GetLength() >= 4);
1864 							int maskoff = CeilPack64(stream.GetPos());
1865 							stream.Seek(mask_directory_offset[level + count] + 4 * lin);
1866 							stream.Put32le(maskoff);
1867 							stream.SeekEnd();
1868 //							mask_directory[level + count][lin] = maskoff;
1869 							int64 maskpos = Unpack64(maskoff);
1870 							if(stream.GetSize() < maskpos)
1871 								stream.Put(0, (int)(maskpos - stream.GetSize()));
1872 							stream.Seek(maskpos);
1873 							stream.PutIL(s.GetLength());
1874 							stream.Put(s, s.GetLength());
1875 						}
1876 					}
1877 					else {
1878 						int pixoff = CeilPack64(stream.GetPos());
1879 						stream.Seek(pixel_directory_offset[level + count] + 4 * lin);
1880 						stream.Put32le(pixoff);
1881 						stream.SeekEnd();
1882 //						pixel_directory[level + count][lin] = pixoff;
1883 						int64 pixpos = Unpack64(pixoff);
1884 						if(stream.GetSize() < pixpos)
1885 							stream.Put(0, (int)(pixpos - stream.GetSize()));
1886 						stream.Seek(pixpos);
1887 //						Stream64Stream pixstream(stream, pixpos);
1888 						format.Save(stream, ImageBufferRaster(part));
1889 					}
1890 				}
1891 			if(--count >= 0) // reduce image
1892 				if(downscale) {
1893 					Size sz = SUNIT << count;
1894 					ImageBuffer new_data(sz);
1895 					Rescale(ImageWriter(new_data, false), sz, ImageBufferRaster(block.block), block.size);
1896 					block.block = new_data;
1897 				}
1898 				else {
1899 					block.Init(SUNIT << count, info.background);
1900 					block.level = level + count;
1901 					block.area = RectC(px << count, py << count, 1 << count, 1 << count);
1902 					drawback(block);
1903 				}
1904 		}
1905 	}
1906 	else
1907 	{ // too big - bisect to generate higher level
1908 //		TIMING("HRR::Write (long step)");
1909 		Block *ptr = 0;
1910 		if(downscale) {
1911 			Size part_size = GetLogBlockSize(GetLogBlockRect(level, RectC(px, py, 1, 1)), info.log_rect);
1912 			if(part_size.cx <= 0 || part_size.cy <= 0)
1913 				return false;
1914 			block.Init(part_size, info.background);
1915 			ptr = &block;
1916 		}
1917 		bool done = Write(drawback, downscale, level + 1, 2 * px + 0, 2 * py + 0, format, ptr);
1918 		done     |= Write(drawback, downscale, level + 1, 2 * px + 1, 2 * py + 0, format, ptr);
1919 		done     |= Write(drawback, downscale, level + 1, 2 * px + 0, 2 * py + 1, format, ptr);
1920 		done     |= Write(drawback, downscale, level + 1, 2 * px + 1, 2 * py + 1, format, ptr);
1921 		if(!done && downscale)
1922 			return false;
1923 		if(!downscale) {
1924 			block.Init(SUNIT, info.background);
1925 			block.level = level;
1926 			block.area = RectC(px, py, 1, 1);
1927 			block.log_area = GetLogBlockRect(block.level, block.area);
1928 			drawback(block);
1929 		}
1930 		int lin = px + (py << level);
1931 //		TIMING("HRR::Write / save (indirect)");
1932 		if(info.mono || IsNull(info.background)) {
1933 			int kind = GetMaskInfo(block.block, block.block.GetLength());
1934 			if(kind && !info.mono) {
1935 				int pixoff = CeilPack64(stream.GetPos());
1936 				stream.Seek(pixel_directory_offset[level] + 4 * lin);
1937 				stream.Put32le(pixoff);
1938 				stream.SeekEnd();
1939 //				pixel_directory[level][lin] = pixoff;
1940 				int64 pixpos = Unpack64(pixoff);
1941 				if(stream.GetSize() < pixpos)
1942 					stream.Put(0, (int)(pixpos - stream.GetSize()));
1943 				stream.Seek(pixpos);
1944 				//Stream64Stream pixstream(stream, pixpos);
1945 				format.Save(stream, ImageBufferRaster(block.block));
1946 			}
1947 			if(kind == 2 || (kind == 1 && info.mono)) {
1948 				String s = EncodeMask(block.block, version >= 5);
1949 				ASSERT(s.GetLength() >= 4);
1950 				int maskoff = CeilPack64(stream.GetPos());
1951 				stream.Seek(mask_directory_offset[level] + 4 * lin);
1952 				stream.Put32le(maskoff);
1953 				stream.SeekEnd();
1954 //				mask_directory[level][lin] = maskoff;
1955 				int64 maskpos = Unpack64(maskoff);
1956 				if(stream.GetSize() < maskpos)
1957 					stream.Put(0, (int)(maskpos - stream.GetSize()));
1958 				stream.Seek(maskpos);
1959 				stream.PutIL(s.GetLength());
1960 				stream.Put(s, s.GetLength());
1961 			}
1962 		}
1963 		else {
1964 			int pixoff = CeilPack64(stream.GetPos());
1965 			stream.Seek(pixel_directory_offset[level] + 4 * lin);
1966 			stream.Put32le(pixoff);
1967 			stream.SeekEnd();
1968 //			pixel_directory[level][lin] = pixoff;
1969 			int64 pixpos = Unpack64(pixoff);
1970 			while(stream.GetSize() < pixpos)
1971 				stream.Put(0, (int)min<int64>(pixpos - stream.GetSize(), 1 << 24));
1972 			stream.Seek(pixpos);
1973 			//Stream64Stream pixstream(stream, pixpos);
1974 			format.Save(stream, ImageBufferRaster(block.block));
1975 		}
1976 	}
1977 	if(put) {
1978 //		TIMING("HRR::Write / put");
1979 		Rect org = RectC((px & 1) << info.HALF_BITS, (py & 1) << info.HALF_BITS,
1980 			1 << info.HALF_BITS, 1 << info.HALF_BITS);
1981 		Rescale(ImageWriter(put->block, org.TopLeft(), false), org.Size(), ImageBufferRaster(block.block), RUNIT);
1982 	}
1983 	return true;
1984 }
1985 
SetMap(String key,String value)1986 void HRR::SetMap(String key, String value)
1987 {
1988 	if(IsNull(value))
1989 	{
1990 		int i = map.Find(key);
1991 		if(i >= 0)
1992 			map.Remove(i);
1993 	}
1994 	else
1995 		map.GetAdd(key) = value;
1996 }
1997 
FlushMap()1998 void HRR::FlushMap()
1999 {
2000 	ASSERT(stream.IsOpen());
2001 	if(map_offset == 0)
2002 		map_offset = CeilPack64(stream.GetSize());
2003 	stream.Seek(0);
2004 	stream.SetStoring();
2005 	Serialize();
2006 }
2007 
SizeOfInstance() const2008 int HRR::SizeOfInstance() const
2009 {
2010 	return sizeof(*this) + directory_sizeof + cache_sizeof;
2011 }
2012 
2013 }
2014