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 = █
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