Jump to content

Anders Melander

Members
  • Content Count

    2561
  • Joined

  • Last visited

  • Days Won

    133

Everything posted by Anders Melander

  1. Anders Melander

    FireDAC, New OLE DB Driver, and SQL Server

    Um... you aren't using ODBC data sources via FireDAC, are you? ODBC is just the API FireDAC uses to talk to the driver. From your perspective there's nothing ODBC about it - the API could be anything. Maybe they did 🙂 We've just completed replacing MSSQL via ADO with FireDAC and for us it works fine. We had to update the client library to a newer version on a couple of clients but apart from that it's faster, better. I think the oldest SQL server version we connect to is 2014/v12.
  2. Anders Melander

    palette for 8 bit greyscale bitmap

    What you're dealing with is an unavavoidable rounding problem and a misunderstanding of what's going on mathematically. The two versions are equally bad. They just distribute the rounding error differently. You want the first palette entry to have a grey-level value of 0 and the last one to have a value of 255 - not 256. Level = 255 * (Index / (Levels-1)) or Grey := i * 255 div (_NumColors-1)
  3. Anders Melander

    Google WebP Image Format

    https://letmegooglethat.com/?q=delphi+webp Seems Bing has hijacked that service so here's a link without the sarcasm: https://www.google.com/search?q=delphi+webp
  4. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    I had to reread the source 3 times before I spotted the place it occurs. "with" strikes again: ClusterWeight := ClusterX[X].Weight; with HorzBuffer[ClusterX[X].Pos - MapXLoPos] do begin Inc(Cb, B * ClusterWeight); // Note: Fixed precision multiplication done here Inc(Cg, G * ClusterWeight); Inc(Cr, R * ClusterWeight); Inc(Ca, A * ClusterWeight); end; As you can see I have now added a comment to make it obvious 🙂 Anyway, your changes has now been committed. Please verify that the comments I've added in the source are correct. I will continue working on correcting the alpha handling (i.e. do premultiplication).
  5. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Yes, you're right. I understand the midpoint rule but I just can't make your code fit it. Let me have a look again... Ah, now I get it. It was your comments that confused me. For example: // old weight: Filter(x0*Oldscale)*Oldscale If I just read the code and ignore the comments it makes much more sense. That's a new one 🙂 I mean that when you operate on 32-bit integer values which has been multiplied by $800 (= 1 shl 11) it means that the upper 21 bits will contain the integer part and the lower 11 bits the fractional part. In other words [21:11] fixed precision. When applying the weight values you do a shr 22 (= $800*$800) to convert from [10:22] fixed precision back to integer. The [10:22] must mean that you have multiplied two [21:11] values at some point but I can't really spot where that happens. FWIW much of Graphics32 supports the TFixed [16:16] fixed precision type. For example many methods allow you to specify coordinates in either integer, TFixed or floating point format. I don't understand what this refers to.
  6. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Duh! Yes of course. I've just checked and the value was correct in my original resampler source so it appears to be a copy/paste bug introduced when the code was integrated in GR32. As far as I can tell the bug has been there from the start 😕 Regarding this: x0 := J - Center; // old weight: Filter(x0*Oldscale)*Oldscale x1 := max(x0 - 0.5, -FilterWidth); x2 := min(x0 + 0.5, FilterWidth); // intersect symmetric interval of length 1 about x0 with support of scaled filter x3 := 0.5 * (x2 + x1); // new center Weight := Round(Prec * Filter(x3 * OldScale) * OldScale * (x2 - x1)); // intersection with support entered into the weight You say that you're "computing the integral for the convolution with the filter using the midpoint-rule" so I would have expected to see the averaging of two filter values in order to find the midpoint but I can't really match that with the above. Can you explain what's going on, please? Once I understand it I'll comment the code so it's maintainable. Also, am I correct in assuming that you're doing calculation in [21:11] fixed precision and storing the weights in [10:22] instead of the old [24:8] and [16:16]?
  7. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Very, very nice. The performance has suffered a bit but the result is much better. It actually seems that the quality of the Graphics32 resampler now surpasses your original algorithm for most kernels (there's still artifacts with the GR32 box filter). I've integrated your changes locally and will commit once I've done a bit more testing. One thing that almost gave me brain cancer was the abysmal ASM generated by this code (not your fault): C.B := min((max(Cb, 0) + $1FFFFF) shr 22, 255) It goes something like this cmp dword ptr [Cb],$00 jle A mov eax,[Cb] jmp B A: xor eax,eax B: lea edx,[eax+$001fffff] shr edx,$16 cmp edx,$000000ff jnl C add eax,$001fffff shr eax,$16 jmp D C: mov eax,$000000ff D: mov [C.B],al Luckily the path with that code isn't taken in your example.
  8. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Take a bath. Always works for me 🙂
  9. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    I was surprised that this was necessary at all as I really thought that the compiler already made this optimization. Anyway, basically a "for" loop like this (the loop value isn't used inside the loop): for i := LowValue to HighValue do begin ..stuff here end; is compiled to this pseudo code: var i := LowValue; var test := HighValue - i; if (test = 0) then goto end_loop; :start_loop ..stuff here Inc(i); var test := HighValue - i; if (test <> 0) then goto start_loop; :end_loop while this equivalent while loop: i := HighValue - LowValue; while (i >= 0) do begin ..stuff here Dec(i); end; is compiled to: var i := HighValue - LowValue; if (test = 0) then goto end_loop; :start_loop ..stuff here Dec(i); if (test <> 0) then goto start_loop; :end_loop Exact same code if iterating from zero in case you wondered. Similarly a for loop where the loop variable is used inside the loop is also slightly faster when implemented as a while loop.
  10. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    I've now merged your changes into the main Graphics32 branch. In addition I also included the following (very minor) optimizations of the Resample() function: Replaced for loops with while loops where possible. The channels are processed in their physical order: B, G, R, A instead of R, G, B, A. I've replaced the RGB bit-twiddling with regular record field access (32-bit compiler only). For example instead of: with BufferEntry^ do begin B := Integer(SourceColor.ARGB and $000000FF) * ClusterWeight; G := Integer(SourceColor.ARGB and $0000FF00) shr 8 * ClusterWeight; R := Integer(SourceColor.ARGB and $00FF0000) shr 16 * ClusterWeight; A := Integer(SourceColor.ARGB shr 24) * ClusterWeight; end; I now do this: BufferEntry.B := SourceColor.B * ClusterWeight; BufferEntry.G := SourceColor.G * ClusterWeight; BufferEntry.R := SourceColor.R * ClusterWeight; BufferEntry.A := SourceColor.A * ClusterWeight; I'm pretty sure the old method used to be faster but apparently not anymore. Maybe the compiler has gotten better or maybe it's the hardware (I have a pretty old CPU so I doubt it's that). I have only profiled the changes with optimization enabled so it's possible that I've made the unoptimized code slower. With optimization enabled, the performance of Resample() now matches, and in some cases even exceed, your algorithm. However since yours is also alpha-aware I still consider yours faster. There are a few additional things that could be done to make the code faster but I'm not really inclined to go there as it would also make it pretty unreadable. The performance of Resample() with the 64-bit compiler is horrible. For some reason your code is much faster there. I've not done anything to improve that.
  11. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    That's excellent. I'm a bit surprised about the presence of the XY iteration order problem as that's a bit of a rookie mistake. It probably wasn't caught because the outer loop does iterate Y (and then iterates XY in the inner). Anyway, good catch. Would you mind either creating a pull request or posting a patched version of GR32_Resamplers.pas (without the reformat as that makes it hard to spot the actual changes - not that I disagree about the need to reformat). Your algorithm seems to be consistently 5-15% faster than GR32 on my system (tested with your latest changes). The quality is almost identical. For some kernels yours is marginally better, for some GR32 is marginally better. For the box filter GR32 wins in quality of details, but loses on fidelity (artifacts). WIC wins on both quality and speed. I think these results are as expected; GR32 is paying the price of the overhead a generalized framework. The quality could probably be improved to match WIC but the question is if it's worth the trouble or if the current quality is "good enough"...? I haven't had time to investigate why the Resample function doesn't use the alpha-aware methods. I'm knee deep in a quantization/dithering extension for GR32. P.S. "const StopWatch: TStopWatch" really should be "var StopWatch: TStopWatch". The only reason it works with const is Delphi doesn't know/care that the methods are modifying the TStopWatch record.
  12. No. It's empty. I don't know who "we" are but there's nothing unsafe about the code you posted. It's just fundamental string handling.
  13. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Apparently the GetSampleX methods are only used when sampling via a rasterizer or a transformation (e.g. rotate/skev/etc).
  14. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    That's correct. A fully transparent pixel has no color. I'm not sure what it is you're showing here. I contributed code to handle that in 2011. See TKernelResampler.GetSampleFloat. That said there does seem to be a problem because when I resample in my own bitmap editor the alpha isn't handled correctly. I'll look into it.
  15. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Of course it's wanted. Improvements are always welcome and you seem to have a really good understanding of the subject. You might opt to have two versions instead: One for 32-bit opaque RGB and one for 32-bit RGBA. The premultiply/unpremultiply really messes with the quality since you're operating on 8-bit values. One way to avoid this is to premultiply to floating or fixed point, resample the floating/fixed point values and then unpremultiply back to 8-bit. As you can imagine this doesn't exactly improve the performance or memory usage. The memory usage can be lessened by processing one channel at a time.
  16. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Very nice. As a Graphics32 contributor I would have preferred though that you'd spent the (probably considerable) effort improving Graphics32 🙂 A few suggestions: Use TStopWatch to measure elapsed time and add the stopwatch as a parameters to TScaleProcedure. This way the procedure can pause the stopwatch when it's doing something which shouldn't be included in the benchmarking. For example assigning back and forth between TBitmap/TBitmap32. Use TTask instead of TThread. This solves your problem of how to manage the threads and avoids the overhead of creating the threads. I understood that you had problems with TTask, but IMO the solution to that is to locate and fix those problems rather than avoiding TTask. For Graphics32, using the memory backend instead of the GDI backend is better when you don't need to use GDI features. See below. In this case it doesn't make much of a difference though. Your code seems to handle RGBA but as far as I can tell you're doing it wrong. You cannot process each RGBA channel independently. Instead you need to operate on premultiplied RGBA values. For example you wouldn't want an RGBA value of $00FFFFFF to have any influence on neighboring pixels. So: 1) Premultiply, 2) Resample, 3) Unpremultiply. Unfortunately this will probably have a very negative impact on both performance and quality. Have cake/Eat cake - Choose one. FWIW, Graphics32 does have a multi-threaded rasterizer but since it uses TThread it doesn't make sense to use it in your benchmark since the overhead of thread setup/teardown for just a single call would kill performance. procedure LanczosGR32(const Source, Target: TBitmap; parallel: boolean); var Source32, Target32: TBitmap32; Resampler: TKernelResampler; begin Source32 := TBitmap32.Create(TMemoryBackend); Target32 := TBitmap32.Create(TMemoryBackend); try Source32.Assign(Source); Target32.SetSize(Target.Width, Target.Height); Resampler := TKernelResampler.Create; try Resampler.KernelClassName := 'TLanczosKernel'; Resampler.Resample(Target32, Target32.BoundsRect, Target32.BoundsRect, Source32, Source32.BoundsRect, dmOpaque, nil); finally Resampler.Free; end; Target.Assign(Target32); finally Source32.Free; Target32.Free; end; end;
  17. Anders Melander

    EULA declined installing 11.1 with Network Named license

    Hey, that's cheating 🙂
  18. Anders Melander

    Digital Persona UAreU 4500 Fingerprint Reader ActiveX

    Google "OposBiometric activex", 3rd result: http://carol.havocshack.com/carol-winslow-tech-writer/files/one-touch-for-windows-sdk-com-activex-developer-guide.pdf
  19. Anders Melander

    FYI: Old security BUG fixed from ZLib

    From: https://www.openwall.com/lists/oss-security/2022/03/28/1 via https://github.com/madler/zlib/issues/605#issuecomment-1084218467 The following are the only (two) calls to DeflateInit2 in the Delphi source (System.ZLib.pas): procedure ZCompress2(const inBuffer: TBytes; out outBuffer: TBytes); ... begin ... ZCompressCheck(DeflateInit2(zstream, 1, 8, -15, 9, 0)); ... constructor TZCompressionStream.Create(dest: TStream; compressionLevel: TZCompressionLevel; windowBits: Integer); begin ... ZCompressCheck(DeflateInit2(FZStream, ZLevels[compressionLevel], Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY)); end; Note that one uses MemLevel=9 and the other MemLevel=8. None uses the Z_FIXED method the original bug was about.
  20. Anders Melander

    FYI: Old security BUG fixed from ZLib

    As far as I've been able to evaluate this bug isn't much of a problem for Delphi desktop applications. Server applications could have a problem if they do compression of user supplied data (the bug only exists in the zlib compressor) but since it's only a buffer overrun (as far as I can tell) it's not that bad.
  21. Anders Melander

    EULA declined installing 11.1 with Network Named license

    Okay then. I thought that maybe you were just voicing an uninformed opinion. My bad.
  22. Anders Melander

    EULA declined installing 11.1 with Network Named license

    That would mean Windows 8.x isn't supported either: https://sockettools.com/kb/windows-and-supported-tls-versions/
  23. Anders Melander

    EULA declined installing 11.1 with Network Named license

    Are there any particular security update, unavailable for Windows 7, that you can't do without?
  24. Anders Melander

    Delphi 11.1 Provisioning Access Violation

    Looks like a corrupt installation to me, but it's hard to conclude anything from the info available.
  25. Anders Melander

    KILLER PROJECT - RESUSCITATE MWA DB JPEG COMPONENT LIBRARY

    Calm down, dude.
×