diff --git a/uppsrc/Draw/Draw.upp b/uppsrc/Draw/Draw.upp index ea744d5d1..89949f95d 100644 --- a/uppsrc/Draw/Draw.upp +++ b/uppsrc/Draw/Draw.upp @@ -54,6 +54,7 @@ file RescaleFilter.cpp optimize_speed, MakeCache.cpp, DrawRasterData.cpp, + Iml.cpp, iml.h, iml_header.h, iml_source.h, diff --git a/uppsrc/Draw/Image.cpp b/uppsrc/Draw/Image.cpp index 3d6ed518a..901cd9c5f 100644 --- a/uppsrc/Draw/Image.cpp +++ b/uppsrc/Draw/Image.cpp @@ -48,16 +48,36 @@ void ImageBuffer::Create(int cx, int cy) } #endif kind = IMAGE_UNKNOWN; + InitAttrs(); +} + +void ImageBuffer::InitAttrs() +{ spot2 = hotspot = Point(0, 0); dots = Size(0, 0); + resolution = IMAGE_RESOLUTION_NONE; +} + +void ImageBuffer::CopyAttrs(const ImageBuffer& img) +{ + SetHotSpot(img.GetHotSpot()); + Set2ndSpot(img.Get2ndSpot()); + SetDots(img.GetDots()); + SetResolution(img.GetResolution()); +} + +void ImageBuffer::CopyAttrs(const Image& img) +{ + if(img.data) + CopyAttrs(img.data->buffer); + else + InitAttrs(); } void ImageBuffer::DeepCopy(const ImageBuffer& img) { Create(img.GetSize()); - SetHotSpot(img.GetHotSpot()); - Set2ndSpot(img.Get2ndSpot()); - SetDots(img.GetDots()); + CopyAttrs(img); memcpy(pixels, img.pixels, GetLength() * sizeof(RGBA)); } @@ -67,9 +87,7 @@ void ImageBuffer::Set(Image& img) if(img.data->refcount == 1) { size = img.GetSize(); kind = IMAGE_UNKNOWN; - hotspot = img.GetHotSpot(); - spot2 = img.Get2ndSpot(); - dots = img.GetDots(); + CopyAttrs(img); pixels = pick(img.data->buffer.pixels); img.Clear(); } @@ -105,10 +123,8 @@ ImageBuffer::ImageBuffer(ImageBuffer& b) { kind = b.kind; size = b.size; - dots = b.dots; pixels = pick(b.pixels); - hotspot = b.hotspot; - spot2 = b.spot2; + CopyAttrs(b); } void ImageBuffer::SetDPI(Size dpi) @@ -178,6 +194,11 @@ Size Image::GetDPI() return data ? Size(int(600.*size.cx/dots.cx), int(600.*size.cy/dots.cy)): Size(0, 0); } +int Image::GetResolution() const +{ + return data ? data->buffer.GetResolution() : IMAGE_RESOLUTION_NONE; +} + int Image::GetKindNoScan() const { return data ? data->buffer.GetKind() : IMAGE_EMPTY; @@ -227,7 +248,7 @@ void Image::Serialize(Stream& s) } len -= INT_MAX; offset += INT_MAX; - } + } if(!s.GetAll((void*)(ptr+offset), (int)len)) s.SetError(); @@ -304,7 +325,7 @@ Image::~Image() } Image::Image(const Init& init) -{ +{ // Legacy (before cca 2008) iml support ASSERT(init.info[0] >= 1); Size sz; sz.cx = Peek32le(init.info + 1); @@ -372,8 +393,7 @@ static Image sMultiply(const Image& img, int (*op)(RGBA *t, const RGBA *s, int l if(k == IMAGE_OPAQUE || k == IMAGE_EMPTY) return img; ImageBuffer ib(img.GetSize()); - ib.SetHotSpot(img.GetHotSpot()); - ib.Set2ndSpot(img.Get2ndSpot()); + ib.CopyAttrs(img); ib.SetKind((*op)(~ib, ~img, ib.GetLength())); return ib; } @@ -388,177 +408,12 @@ Image Unmultiply(const Image& img) return sMultiply(img, Unmultiply); } -void Iml::Init(int n) -{ - for(int i = 0; i < n; i++) - map.Add(name[i]); -} - -void Iml::Reset() -{ - int n = map.GetCount(); - map.Clear(); - Init(n); -} - -void Iml::Set(int i, const Image& img) -{ - map[i].image = img; - map[i].loaded = true; -} - -static StaticMutex sImlLock; - -Image Iml::Get(int i) -{ - IImage& m = map[i]; - if(!m.loaded) { - Mutex::Lock __(sImlLock); - if(data.GetCount()) { - int ii = 0; - for(;;) { - const Data& d = data[ii]; - if(i < d.count) { - static const char *cached_data; - static Vector cached; - if(cached_data != d.data) { - cached_data = d.data; - cached = UnpackImlData(d.data, d.len); - if(premultiply) - for(int i = 0; i < cached.GetCount(); i++) - cached[i] = Premultiply(cached[i]); - } - m.image = cached[i]; - break; - } - i -= d.count; - ii++; - } - } - else - m.image = Premultiply(Image(img_init[i])); - m.loaded = true; - } - return m.image; -} - -#ifdef _DEBUG -int Iml::GetBinSize() const -{ - int size = 0; - for(int i = 0; i < map.GetCount(); i++) { - const Image::Init& init = img_init[i]; - size += (int)strlen(name[i]) + 1 + 24; - for(int q = 0; q < init.scan_count; q++) - size += (int)strlen(init.scans[q]); - } - return size; -} -#endif - -Iml::Iml(const Image::Init *img_init, const char **name, int n) -: img_init(img_init), - name(name) -{ -#ifdef flagCHECKINIT - RLOG("Constructing iml " << *name); -#endif - premultiply = true; - Init(n); -} - -void Iml::AddData(const byte *_data, int len, int count) -{ - Data& d = data.Add(); - d.data = (const char *)_data; - d.len = len; - d.count = count; - data.Shrink(); -} - -static StaticCriticalSection sImgMapLock; - -static VectorMap& sImgMap() -{ - static VectorMap x; - return x; -} - -void Register(const char *imageclass, Iml& list) -{ -#ifdef flagCHECKINIT - RLOG("Registering iml " << imageclass); -#endif - INTERLOCKED_(sImgMapLock) - sImgMap().GetAdd(imageclass) = &list; -} - -int GetImlCount() -{ - int q = 0; - INTERLOCKED_(sImgMapLock) - q = sImgMap().GetCount(); - return q; -} - -Iml& GetIml(int i) -{ - return *sImgMap()[i]; -} - -String GetImlName(int i) -{ - Mutex::Lock __(sImlLock); - return sImgMap().GetKey(i); -} - -int FindIml(const char *name) -{ - Mutex::Lock __(sImlLock); - return sImgMap().Find(name); -} - -Image GetImlImage(const char *name) -{ - Image m; - const char *w = strchr(name, ':'); - if(w) { - Mutex::Lock __(sImlLock); - int q = FindIml(String(name, w)); - if(q >= 0) { - Iml& iml = *sImgMap()[q]; - while(*w == ':') - w++; - q = iml.Find(w); - if(q >= 0) - m = iml.Get(q); - } - } - return m; -} - -void SetImlImage(const char *name, const Image& m) -{ - const char *w = strchr(name, ':'); - if(w) { - Mutex::Lock __(sImlLock); - int q = FindIml(String(name, w)); - if(q >= 0) { - Iml& iml = *sImgMap()[q]; - while(*w == ':') - w++; - q = iml.Find(w); - if(q >= 0) - iml.Set(q, m); - } - } -} - String StoreImageAsString(const Image& img) { if(img.GetKind() == IMAGE_EMPTY) return Null; int type = img.GetKind() == IMAGE_OPAQUE ? 3 : 4; + type |= decode(img.GetResolution(), IMAGE_RESOLUTION_STANDARD, 0x40, IMAGE_RESOLUTION_UHD, 0x80, 0); StringStream ss; ss.Put(type); Size sz = img.GetSize(); @@ -600,6 +455,8 @@ Image LoadImageFromString(const String& src) return Null; StringStream ss(src); int type = ss.Get(); + int resolution = decode(type & 0xc0, 0x40, IMAGE_RESOLUTION_STANDARD, 0x80, IMAGE_RESOLUTION_UHD, 0); + type &= 0x3f; Size sz; sz.cx = ss.Get16le(); sz.cy = ss.Get16le(); @@ -623,6 +480,7 @@ Image LoadImageFromString(const String& src) ImageBuffer ib(sz); ib.SetHotSpot(p); ib.SetDots(dots); + ib.SetResolution(resolution); RGBA *t = ib; const RGBA *e = t + ib.GetLength(); const byte *s = data; diff --git a/uppsrc/Draw/Image.h b/uppsrc/Draw/Image.h index c41f09d02..5cea61a57 100644 --- a/uppsrc/Draw/Image.h +++ b/uppsrc/Draw/Image.h @@ -54,6 +54,12 @@ inline byte Saturate255(int x) { return byte(~(x >> 24) & (x | (-(x class Image; +enum ImageResolutionIntent { + IMAGE_RESOLUTION_NONE = -1, + IMAGE_RESOLUTION_STANDARD = 0, + IMAGE_RESOLUTION_UHD = 1, +}; + class ImageBuffer : NoCopy { mutable int kind; Size size; @@ -61,12 +67,14 @@ class ImageBuffer : NoCopy { Point hotspot; Point spot2; Size dots; + int8 resolution; void Set(Image& img); void DeepCopy(const ImageBuffer& img); RGBA* Line(int i) const { ASSERT(i >= 0 && i < size.cy); return (RGBA *)~pixels + i * size.cx; } friend void DropPixels___(ImageBuffer& b) { b.pixels.Clear(); } + void InitAttrs(); friend class Image; @@ -89,6 +97,12 @@ public: void SetDPI(Size sz); Size GetDPI(); + void CopyAttrs(const ImageBuffer& img); + void CopyAttrs(const Image& img); + + void SetResolution(int i) { resolution = i; } + int GetResolution() const { return resolution; } + Size GetSize() const { return size; } int GetWidth() const { return size.cx; } int GetHeight() const { return size.cy; } @@ -165,11 +179,12 @@ public: Point GetHotSpot() const; Point Get2ndSpot() const; Size GetDots() const; - Size GetDPI(); + Size GetDPI(); int GetKindNoScan() const; int GetKind() const; + int GetResolution() const; - const RGBA *Begin() const { return data ? ~data->buffer : NULL; } + const RGBA *Begin() const { return data ? ~data->buffer : NULL; } const RGBA *End() const { return Begin() + GetLength(); } const RGBA* operator~() const { return Begin(); } operator const RGBA*() const { return Begin(); } diff --git a/uppsrc/Draw/ImageBlit.cpp b/uppsrc/Draw/ImageBlit.cpp index 50ccc1da3..e9196b88a 100644 --- a/uppsrc/Draw/ImageBlit.cpp +++ b/uppsrc/Draw/ImageBlit.cpp @@ -383,39 +383,6 @@ int GetChMaskPos32(dword mask) return 0; } -Vector UnpackImlData(const void *ptr, int len) -{ - Vector img; - String data = ZDecompress(ptr, len); - const char *s = data; - while(s + 6 * 2 + 1 <= data.End()) { - ImageBuffer ib(Peek16le(s + 1), Peek16le(s + 3)); - ib.SetHotSpot(Point(Peek16le(s + 5), Peek16le(s + 7))); - ib.Set2ndSpot(Point(Peek16le(s + 9), Peek16le(s + 11))); - s += 13; - int len = ib.GetLength(); - RGBA *t = ib; - const RGBA *e = t + len; - if(s + 4 * len > data.End()) - break; - while(t < e) { - t->a = s[3]; - t->r = s[0]; - t->g = s[1]; - t->b = s[2]; - s += 4; - t++; - } - img.Add() = ib; - } - return img; -} - -Vector UnpackImlData(const String& d) -{ - return UnpackImlData(~d, d.GetLength()); -} - void TransformComponents(RGBA *t, const RGBA *s, int len, const byte r[], const byte g[], const byte b[], const byte a[]) { diff --git a/uppsrc/Draw/Iml.cpp b/uppsrc/Draw/Iml.cpp new file mode 100644 index 000000000..8278c3dba --- /dev/null +++ b/uppsrc/Draw/Iml.cpp @@ -0,0 +1,207 @@ +#include "Draw.h" + +NAMESPACE_UPP + +Vector UnpackImlData(const void *ptr, int len) +{ + Vector img; + String data = ZDecompress(ptr, len); + const char *s = data; + int version = 0; + while(s + 6 * 2 + 1 <= data.End()) { + ImageBuffer ib(Peek16le(s + 1), Peek16le(s + 3)); + int q = byte(*s) >> 6; + ib.SetResolution(decode(q, 0, IMAGE_RESOLUTION_STANDARD, 1, IMAGE_RESOLUTION_UHD, IMAGE_RESOLUTION_NONE)); + ib.SetHotSpot(Point(Peek16le(s + 5), Peek16le(s + 7))); + ib.Set2ndSpot(Point(Peek16le(s + 9), Peek16le(s + 11))); + s += 13; + int len = ib.GetLength(); + RGBA *t = ib; + const RGBA *e = t + len; + if(s + 4 * len > data.End()) + break; + while(t < e) { + t->a = s[3]; + t->r = s[0]; + t->g = s[1]; + t->b = s[2]; + s += 4; + t++; + } + img.Add() = ib; + } + return img; +} + +Vector UnpackImlData(const String& d) +{ + return UnpackImlData(~d, d.GetLength()); +} + +void Iml::Init(int n) +{ + for(int i = 0; i < n; i++) + map.Add(name[i]); +} + +void Iml::Reset() +{ + int n = map.GetCount(); + map.Clear(); + Init(n); +} + +void Iml::Set(int i, const Image& img) +{ + map[i].image = img; + map[i].loaded = true; +} + +static StaticMutex sImlLock; + +Image Iml::Get(int i) +{ + IImage& m = map[i]; + if(!m.loaded) { + Mutex::Lock __(sImlLock); + if(data.GetCount()) { + int ii = 0; + for(;;) { + const Data& d = data[ii]; + if(i < d.count) { + static const char *cached_data; + static Vector cached; + if(cached_data != d.data) { + cached_data = d.data; + cached = UnpackImlData(d.data, d.len); + if(premultiply) + for(int i = 0; i < cached.GetCount(); i++) + cached[i] = Premultiply(cached[i]); + } + m.image = cached[i]; + break; + } + i -= d.count; + ii++; + } + } + else + m.image = Premultiply(Image(img_init[i])); + m.loaded = true; + } + return m.image; +} + +#ifdef _DEBUG +int Iml::GetBinSize() const +{ + int size = 0; + for(int i = 0; i < map.GetCount(); i++) { + const Image::Init& init = img_init[i]; + size += (int)strlen(name[i]) + 1 + 24; + for(int q = 0; q < init.scan_count; q++) + size += (int)strlen(init.scans[q]); + } + return size; +} +#endif + +Iml::Iml(const Image::Init *img_init, const char **name, int n) +: img_init(img_init), + name(name) +{ +#ifdef flagCHECKINIT + RLOG("Constructing iml " << *name); +#endif + premultiply = true; + Init(n); +} + +void Iml::AddData(const byte *_data, int len, int count) +{ + Data& d = data.Add(); + d.data = (const char *)_data; + d.len = len; + d.count = count; + data.Shrink(); +} + +static StaticCriticalSection sImgMapLock; + +static VectorMap& sImgMap() +{ + static VectorMap x; + return x; +} + +void Register(const char *imageclass, Iml& list) +{ +#ifdef flagCHECKINIT + RLOG("Registering iml " << imageclass); +#endif + INTERLOCKED_(sImgMapLock) + sImgMap().GetAdd(imageclass) = &list; +} + +int GetImlCount() +{ + int q = 0; + INTERLOCKED_(sImgMapLock) + q = sImgMap().GetCount(); + return q; +} + +Iml& GetIml(int i) +{ + return *sImgMap()[i]; +} + +String GetImlName(int i) +{ + Mutex::Lock __(sImlLock); + return sImgMap().GetKey(i); +} + +int FindIml(const char *name) +{ + Mutex::Lock __(sImlLock); + return sImgMap().Find(name); +} + +Image GetImlImage(const char *name) +{ + Image m; + const char *w = strchr(name, ':'); + if(w) { + Mutex::Lock __(sImlLock); + int q = FindIml(String(name, w)); + if(q >= 0) { + Iml& iml = *sImgMap()[q]; + while(*w == ':') + w++; + q = iml.Find(w); + if(q >= 0) + m = iml.Get(q); + } + } + return m; +} + +void SetImlImage(const char *name, const Image& m) +{ + const char *w = strchr(name, ':'); + if(w) { + Mutex::Lock __(sImlLock); + int q = FindIml(String(name, w)); + if(q >= 0) { + Iml& iml = *sImgMap()[q]; + while(*w == ':') + w++; + q = iml.Find(w); + if(q >= 0) + iml.Set(q, m); + } + } +} + +END_UPP_NAMESPACE diff --git a/uppsrc/IconDes/IconDes.cpp b/uppsrc/IconDes/IconDes.cpp index 5bc6861bd..a303b5f43 100644 --- a/uppsrc/IconDes/IconDes.cpp +++ b/uppsrc/IconDes/IconDes.cpp @@ -7,6 +7,9 @@ IconDes::Slot::Slot() pastepos = Null; supersampling = false; exp = false; + ImageBuffer b; + b.SetResolution(IMAGE_RESOLUTION_STANDARD); + image = b; } IconDes::Slot& IconDes::Current() diff --git a/uppsrc/IconDes/IconDes.lay b/uppsrc/IconDes/IconDes.lay index 2532b8ae0..2cecb8077 100644 --- a/uppsrc/IconDes/IconDes.lay +++ b/uppsrc/IconDes/IconDes.lay @@ -1,13 +1,15 @@ -LAYOUT(ImageLayout, 168, 108) +LAYOUT(ImageLayout, 168, 188) ITEM(Label, dv___0, SetLabel(t_("Name")).LeftPosZ(8, 40).TopPosZ(8, 19)) ITEM(EditString, name, LeftPosZ(52, 108).TopPosZ(8, 19)) ITEM(Label, dv___2, SetLabel(t_("Size")).LeftPosZ(8, 40).TopPosZ(32, 19)) ITEM(EditIntSpin, cx, Max(8192).Min(1).LeftPosZ(52, 44).TopPosZ(32, 19)) ITEM(EditIntSpin, cy, Max(8192).Min(1).LeftPosZ(116, 44).TopPosZ(32, 19)) ITEM(Label, dv___5, SetLabel(t_("x")).LeftPosZ(100, 12).TopPosZ(32, 16)) - ITEM(Option, exp, SetLabel(t_("Export as icon.ico and .png")).LeftPosZ(8, 160).TopPosZ(56, 16)) - ITEM(Button, ok, SetLabel(t_("OK")).LeftPosZ(28, 64).TopPosZ(80, 24)) - ITEM(Button, cancel, SetLabel(t_("Cancel")).LeftPosZ(96, 64).TopPosZ(80, 24)) + ITEM(Option, exp, SetLabel(t_("Export as icon.ico and .png")).LeftPosZ(8, 160).TopPosZ(132, 16)) + ITEM(Button, ok, SetLabel(t_("OK")).LeftPosZ(28, 64).TopPosZ(156, 24)) + ITEM(Button, cancel, SetLabel(t_("Cancel")).LeftPosZ(96, 64).TopPosZ(156, 24)) + ITEM(LabelBox, dv___9, SetLabel(t_("Resolution")).LeftPosZ(8, 152).TopPosZ(56, 68)) + ITEM(Switch, resolution, SetLabel(t_("Standard\nUHD\nNone")).LeftPosZ(16, 144).TopPosZ(72, 52)) END_LAYOUT LAYOUT(ImageSizeLayout, 168, 68) diff --git a/uppsrc/IconDes/ImageOp.cpp b/uppsrc/IconDes/ImageOp.cpp index 160d99512..9076d7800 100644 --- a/uppsrc/IconDes/ImageOp.cpp +++ b/uppsrc/IconDes/ImageOp.cpp @@ -146,9 +146,9 @@ String PackImlData(const Vector& image) { StringBuffer block; for(int i = 0; i < image.GetCount(); i++) { - Image img = image[i]; + const Image& img = image[i]; StringStream ss; - ss.Put(0); + ss.Put(img.GetResolution() << 6); Size sz = img.GetSize(); ss.Put16le(sz.cx); ss.Put16le(sz.cy); diff --git a/uppsrc/IconDes/List.cpp b/uppsrc/IconDes/List.cpp index 010b9b49b..516ee895d 100644 --- a/uppsrc/IconDes/List.cpp +++ b/uppsrc/IconDes/List.cpp @@ -6,7 +6,9 @@ static String sFormatImageName(const String& name, const Image& img, bool exp) { Size sz = img.GetSize(); String r; - r << name << " (" << sz.cx << " x " << sz.cy << ')'; + r << name << " (" << sz.cx << " x " << sz.cy + << decode(img.GetResolution(), IMAGE_RESOLUTION_UHD, " UHD", IMAGE_RESOLUTION_NONE, " n.r.", "") + << ')'; if(exp) r << " ex."; return r; @@ -63,6 +65,10 @@ void IconDes::PrepareImageDlg(WithImageLayout& dlg) Size sz = GetImageSize(); dlg.cx <<= sz.cx; dlg.cy <<= sz.cy; + int resolution = IMAGE_RESOLUTION_STANDARD; + if(IsCurrent()) + resolution = Current().image.GetResolution(); + dlg.resolution <<= decode(resolution, IMAGE_RESOLUTION_STANDARD, 0, IMAGE_RESOLUTION_UHD, 1, 2); } dlg.name.SetFilter(sCharFilterCid); } @@ -112,6 +118,13 @@ void IconDes::ImageInsert(const String& name, const Image& m, bool exp) GoTo(ii); } +void SetRes(Image& m, int resolution) +{ + ImageBuffer ib = m; + ib.SetResolution(decode(resolution, 0, IMAGE_RESOLUTION_STANDARD, 1, IMAGE_RESOLUTION_UHD, IMAGE_RESOLUTION_NONE)); + m = ib; +} + void IconDes::InsertImage() { WithImageLayout dlg; @@ -121,7 +134,9 @@ void IconDes::InsertImage() return; } while(!CheckName(dlg)); - ImageInsert(~dlg.name, CreateImage(Size(~dlg.cx, ~dlg.cy), Null), dlg.exp); + Image m = CreateImage(Size(~dlg.cx, ~dlg.cy), Null); + SetRes(m, ~dlg.resolution); + ImageInsert(~dlg.name, m, dlg.exp); } void IconDes::Duplicate() @@ -310,6 +325,7 @@ void IconDes::EditImage() if(!CheckName(dlg)) break; c.name = ~dlg.name; c.exp = ~dlg.exp; + SetRes(c.image, ~dlg.resolution); ilist.Set(1, sFormatImageName(c.name, c.image, c.exp)); int q = ilist.GetKey(); Reset();