Code Optimization

Interesting things in software development and code optimization

Javascript and jQuery - creating a lot of elements like a big grid


Hello dear friends,


Last time I did create a big grid using jQuery and Javascript, and faced with the performance problem.




My task was to create a big calendar grid that should have 20 rows at least and 180 columns (each column for each day for the 6 month period). While developing this grid I had noticed that Microsoft Edge and FireFox browsers hung during this creation cycle for a few seconds (Google Chrome seemed much better). My first method did create each cell for every column and row.

So how to optimize this? I did some googling and found a suggestion to use setTimeout function to avoid browser hanging, but it didn't help a lot in my case. Ugh! What should I do with it. Just in case, here is the piece of code I used to create my grid:

.....

var row, cell;

for(var r=0;r<20;r++)

{

    row = $("<div class='row'></div>");

    for(var i=0; i<180;i++)

    {

         cell = $("<div class='cell'></div>");

         ..........

        row.append(cell);

    }

    ....

    grid.append(row);

}


So, looks pretty simple? I was thinking for a few days on it trying to understand what could I do with it.

At some point I just had thought "what if create one row only and then just clone it as much as needed?". And yes, I was completely right! :) it did reduce time from 4-5 seconds to less than 1 second:

.....
var row, cell;


{
    row = $("<div class='row'></div>");

    for(var i=0; i<180;i++)
    {
         cell = $("<div class='cell'></div>");
         ..........
        row.append(cell);
    }
    ....
    grid.append(row);
}

for (var c = 1; c < 20; c++) {
   grid.append(row.clone(false).off());
}

So now its clear that the clone method grid.append(row.clone(false).off()); much much faster than creating a new elements.



Thank you and see you next time :)


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



MS SQL - Speed up Order By with OFFSET FETCH paging

UPDATE:

So adding nonclustered index, as the MS SQL Execution Plan suggests, seems reduced the query time even more, here is the suggested nonclustered index:

USE [myDB]

GO


CREATE NONCLUSTERED INDEX NONCLUSTERED_INDEX2_tblPictures

ON [dbo].[tblPictures] ([RatingTotal],[shape])

INCLUDE ([PictureID],[OwnerID],[PictureTypeID])

GO

but using only nonclustered index, without my #temp table technic, seems does not help too much.


Hello,

This time I'm going to share my solution on how I did reduce time of my SQL query with Order By clause by almost x2 times.

Firstly let me show my original query:

select @rowstotal = count(*)

From [dbo].[tblPictures]

where (@OwnerId = 0 OR @OwnerId = [OwnerID])

and (@FilterBy = 0 OR @FilterBy = PictureTypeID)

and (@Shape = '' OR @Shape = [shape])



Select

@rowstotal as TotalCount

, PictureID

, OwnerID

, PictureName

, [Description]

, Description2

, Description3

, aspectRatio

, [min]

, [max]

, [percent]

, thumbWidth

, thumbHeight

, processState

, keywords

From [dbo].[tblPictures]

where (@OwnerId = 0 OR @OwnerId = [OwnerID])

and (@FilterBy = 0 OR @FilterBy = PictureTypeID)

and (@Shape = '' OR @Shape = [shape])

Order By RatingTotal Desc

OFFSET @pageNumber ROWS FETCH NEXT @pageSize ROWS ONLY;


So to be able to calculate pages we have to know the total number of rows in the DB. Each row will contain TotalCount - total number of rows


(pay attention, that the techinc COUNT(*) OVER () as TotalCount is slower than just select @rowstotal = count(*) From that I use in my queries )


Then we select all needed columns with the order and paging technic.

Everything looks great, simple and fast unless you got more than 300 000 rows in the table.

Main problem here is that the Order By clause takes 98% of the whole stored procedure and in my case it takes 5 sec in total.

How to speed it up? 

I did google a lot of posts and almost everyone suggests to use indexes or nonclustered indexes, or other things.

As I'm not DBA and do not know a lot about all these things I decided to check what if I would select only one column instead of all of them? 

And when I got my 40 rows for one page I would select the rest of columns?

I did write some test query and had been surprised that it took almost x2 time less than before.


So here is the new query:

IF OBJECT_ID(N'tempdb..#tempPage', N'U') IS NOT NULL

DROP TABLE #tempPage;


create table #tempPage

(

TotalCount int null

, PictureID int

, OwnerID int null

, PictureName nvarchar(500) null

, [Description] nvarchar(500) null

, Description2 nvarchar(500) null

, Description3 nvarchar(max) null

, aspectRatio decimal(18,2) null

, [min] money null

, [max] money null

, [percent] decimal(18,2) null

, thumbWidth decimal(18,2) null

, thumbHeight decimal(18,2) null

, processState varchar(50) null

, keywords varchar(500) null

)


insert into #tempPage

Select

null --@rowstotal

,PictureID

,null

,null

,null

,null

,null

,null

,null

,null

,null

,null

,null

,null

,null

From [dbo].[tblPictures]

where (@OwnerId = 0 OR @OwnerId = [OwnerID])

and (@FilterBy = 0 OR @FilterBy = PictureTypeID)

and (@Shape = '' OR @Shape = [shape])

Order By RatingTotal Desc

OFFSET @pageNumber ROWS FETCH NEXT @pageSize ROWS ONLY


Update t

Set t.OwnerID = p.OwnerID

,t.TotalCount = @rowstotal

,t.PictureName=p.PictureName

,t.[Description]=p.[Description]

,t.Description2=p.Description2

,t.Description3=p.Description3

,t.aspectRatio=p.aspectRatio

,t.[min]=p.[min]

,t.[max]=p.[max]

,t.[percent]=p.percent

,t.thumbWidth=p.thumbWidth

,t.thumbHeight=p.thumbHeight

,t.processState=p.processState

,t.keywords=p.keywords

From #tempPage as t

INNER JOIN [dbo].[tblPictures] as p on p.PictureID = t.PictureID;

select * from #tempPage;

DROP TABLE #tempPage;


 Now we use a temp sql table to select only IDs firstly and then we update all 40 rows and set all other columns' values.

Also do not forget to drop temp table before and after to avoid existing table errors.


So this is the way that reduced my query time from 5 seconds to almost 2 seconds in total.


(SQL Server 2012 version: x64 11.0.3156.0)


Of course, if I would add nonclustered index, as MS SQL Graphical Execution Plan suggests, it may be even faster, but to be able to add them we have to understand what it is and how to use it. So maybe next step will be to learn and add nonclustered index ;)



Thank you and see you soon :)

 







1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



C#, .NET, x32/x64 Assembler and cross-platform code

Hello my dear friends.


Today we will look into such popular thing like cross-platform code, and such powerful thing like assembler. Of course, we will use C#.NET for this all as usually  :)

To make a cross-platform code we have to be aware of two main things:

- method call conventions 

- system API

We need different platform dependent system APIs to allocate and free executing memory and we need universal code to avoid method call convention problems.

To call system dependent APIs we need to understand what OS we are running under, here is code how we can do it:

 

private enum Platform

{

Windows,

Linux,

Mac

}

private static Platform RunningPlatform()

{

switch (Environment.OSVersion.Platform)

{

case PlatformID.Unix: // Well, there are chances MacOSX is reported as Unix instead of MacOSX. // Instead of platform check, we'll do a feature checks (Mac specific root folders) if (Directory.Exists("/Applications")

& Directory.Exists("/System")

& Directory.Exists("/Users") & Directory.Exists("/Volumes")) return Platform.Mac; else return Platform.Linux; case PlatformID.MacOSX: return Platform.Mac; default: return Platform.Windows;

}

}

Now we are going to declare PInvokes for linux and windows and implement logic to allocate and free memory with regards to OS we are running under (linux pinvokes were taken from the Mono source code):

#region Windows

[Flags]

private enum AllocationTypes : uint

{

Commit = 0x1000, Reserve = 0x2000,

Reset = 0x80000, LargePages = 0x20000000,

Physical = 0x400000, TopDown = 0x100000,

WriteWatch = 0x200000

}

[Flags]

private enum MemoryProtections : uint

{

Execute = 0x10, ExecuteRead = 0x20,

ExecuteReadWrite = 0x40, ExecuteWriteCopy = 0x80,

NoAccess = 0x01, ReadOnly = 0x02,

ReadWrite = 0x04, WriteCopy = 0x08,

GuartModifierflag = 0x100, NoCacheModifierflag = 0x200,

WriteCombineModifierflag = 0x400

}

[Flags]

private enum FreeTypes : uint

{

Decommit = 0x4000, Release = 0x8000

}

[DllImport("kernel32.dll", SetLastError = true)]

private static extern IntPtr VirtualAlloc(

IntPtr lpAddress,

UIntPtr dwSize,

AllocationTypes flAllocationType,

MemoryProtections flProtect);

 

[DllImport("kernel32")]

[return: MarshalAs(UnmanagedType.Bool)]

private static extern bool VirtualFree(

IntPtr lpAddress,

uint dwSize,

FreeTypes flFreeType);

#endregion

#region Unix

[AttributeUsage(

AttributeTargets.Class |

AttributeTargets.Delegate |

AttributeTargets.Enum |

AttributeTargets.Field |

AttributeTargets.Struct)]

private class MapAttribute : Attribute

{

private string nativeType;

private string suppressFlags;

public MapAttribute()

{

}

public MapAttribute(string nativeType)

{

this.nativeType = nativeType;

}

public string NativeType

{

get { return nativeType; }

}

public string SuppressFlags

{

get { return suppressFlags; }

set { suppressFlags = value; }

}

}

private const string MPH = "MonoPosixHelper";

private const string LIBC = "msvcrt";

[Map]

[Flags]

private enum MmapProts : int

{

PROT_READ = 0x1, // Page can be read.

PROT_WRITE = 0x2, // Page can be written.

PROT_EXEC = 0x4, // Page can be executed.

PROT_NONE = 0x0, // Page can not be accessed.

PROT_GROWSDOWN = 0x01000000, // Extend change to start of

// growsdown vma (mprotect only).

PROT_GROWSUP = 0x02000000, // Extend change to start of

// growsup vma (mprotect only).

}

[Map]

[Flags]

private enum MmapFlags : int

{

MAP_SHARED = 0x01, // Share changes.

MAP_PRIVATE = 0x02, // Changes are private.

MAP_TYPE = 0x0f, // Mask for type of mapping.

MAP_FIXED = 0x10, // Interpret addr exactly.

MAP_FILE = 0,

MAP_ANONYMOUS = 0x20, // Don't use a file.

MAP_ANON = MAP_ANONYMOUS,

// These are Linux-specific.

MAP_GROWSDOWN = 0x00100, // Stack-like segment.

MAP_DENYWRITE = 0x00800, // ETXTBSY

MAP_EXECUTABLE = 0x01000, // Mark it as an executable.

MAP_LOCKED = 0x02000, // Lock the mapping.

MAP_NORESERVE = 0x04000, // Don't check for reservations.

MAP_POPULATE = 0x08000, // Populate (prefault) pagetables.

MAP_NONBLOCK = 0x10000, // Do not block on IO.

}

[DllImport(MPH, SetLastError = true,

EntryPoint = "Mono_Posix_Syscall_mmap")]

private static extern IntPtr mmap(IntPtr start, ulong length,

MmapProts prot, MmapFlags flags, int fd, long offset);

[DllImport(MPH, SetLastError = true,

EntryPoint = "Mono_Posix_Syscall_munmap")]

public static extern int munmap(IntPtr start, ulong length);

[DllImport(MPH, SetLastError = true,

EntryPoint = "Mono_Posix_Syscall_mprotect")]

private static extern int mprotect(IntPtr start, ulong len, MmapProts prot);


[DllImport(MPH, CallingConvention = CallingConvention.Cdecl,

SetLastError = true, EntryPoint = "Mono_Posix_Stdlib_malloc")] private static extern IntPtr malloc(ulong size);

[DllImport(LIBC, CallingConvention = CallingConvention.Cdecl)] public static extern void free(IntPtr ptr);

#endregion


[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]

public unsafe delegate void asmFunc();

public static IntPtr VirtualAlloc(uint size)

{

IntPtr ptr = IntPtr.Zero;

if (RunningPlatform() == Platform.Windows)

{

ptr = VirtualAlloc(

IntPtr.Zero,

new UIntPtr(size),

AllocationTypes.Commit | AllocationTypes.Reserve,

MemoryProtections.ExecuteReadWrite);

}

else

{

Console.WriteLine("Linux memory allocation...");

ptr = mmap(IntPtr.Zero, 4096, MmapProts.PROT_EXEC | MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_ANONYMOUS | MmapFlags.MAP_PRIVATE, 0, 0);

Console.WriteLine("memory ptr: " + ptr.ToInt64());

}

return ptr;

}


public static void VirtualFree(IntPtr ptr, uint size)

{

if (RunningPlatform() == Platform.Windows)

{

VirtualFree(ptr, size, FreeTypes.Release);

}

else

{

Console.WriteLine("Free memory ptr: " + ptr.ToInt64());

int r = munmap(ptr, size);

Console.WriteLine("memory free status: " + r);

}

}


Ok, we have methods to allocate and free memory and now, we need some predefined assembly code and template to avoid any calling convention problems. To do it we will declare our methods and delegates as parameter-less and will pass parameters as declared bytes:

 

byte[] codeArray = new byte[]

{

0xE8, // call next code after data

0x00,

0x00,

0x00,

0x00,

//

//data will go here

//


0x5B, // pop e/rbx - now e/rbx looks into data address

0xFF, // inc dword [e/rbx]

0x03,

(byte)(IntPtr.Size > 4 ? 0x48 : 0x90),

0xFF, // inc e/rbx

0xC3,

(byte)(IntPtr.Size > 4 ? 0x48 : 0x90),

0xFF, // inc e/rbx

0xC3,

(byte)(IntPtr.Size > 4 ? 0x48 : 0x90),

0xFF, // inc e/rbx

0xC3,

(byte)(IntPtr.Size > 4 ? 0x48 : 0x90),

0xFF, // inc e/rbx

0xC3,

(byte)(IntPtr.Size > 4 ? 0x48 : 0x90), // dec d/qword [rbx]

0xFF,

0x0B,


0xC3 // retn - return from your method

};

byte[] dataArray = new byte[]

{

0xFF, //parameter Int32

0x00,

0x00,

0x00,

0x00, //parameter Int64

0x00,

0x00,

0x00,

0x00,

0x00,

0x00,

0x00

};


Console.WriteLine("Ptr size: " + IntPtr.Size);

//allocate memory for our asm method

IntPtr pp = Native.VirtualAlloc((uint)(codeArray.Length + dataArray.Length));

unsafe

{

IntPtr p = pp;

int n = 0;

byte* bptr = (byte*)p;

Marshal.Copy(codeArray, 0, p, 4);

p += 1;

//write offset to the next code line

Marshal.WriteInt32(p, dataArray.Length);

p += 4;

//copy data

Marshal.Copy(dataArray, 0, p, dataArray.Length);

p += dataArray.Length;

//copy rest of the code

Marshal.Copy(codeArray, 5, p, codeArray.Length - 5);

bptr[n] = bptr[n];

n = 0;

}

Native.asmFunc asmFunc = (Native.asmFunc)System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer(pp, typeof(Native.asmFunc));

Console.WriteLine("in param int32 = " + BitConverter.ToInt32(dataArray, 0));

Console.WriteLine("in param int64 = " + BitConverter.ToInt64(dataArray, sizeof(Int32)));

Console.WriteLine("call asm method...");

asmFunc();

Console.WriteLine("exit asm method");

As our methods are parameter-less a system will not use stack and we will not have to care about stack. To get address of our first parameter we will use well-known technic, such as call addr and pop reg, that moves to our next processor instruction and pops back an address, this address will be the address of our first parameter.

To pass back any parameters from our assembly method we will use the same address to put them before return back.

//copy params back to array

Marshal.Copy(pp + 5, dataArray, 0, dataArray.Length);

Console.WriteLine("out param int32 = " + BitConverter.ToInt32(dataArray, 0));

Console.WriteLine("out param int64 = " + BitConverter.ToInt64(dataArray, sizeof(Int32)));

//free allocated memory

Native.VirtualFree(pp, (uint)(codeArray.Length + dataArray.Length));

GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);

Console.WriteLine("any key to exit");

Console.ReadLine();


Now run it and test it. Remember that running this code, or any assembly code, under visual studio may cause error and exception, so always test your code out of any debugger.


I did test this code under Windows 10 64 bit and compiling in x32 and x64 modes, and Linux Ubuntu 14.04 64 bit mode.


Comments are welcome.


Thank you all,

See you later :)


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



Multiplication and Division - could be even faster?

Hi friends,


today we are going to work on something that looks and sounds crazy, we are going to speed up multiplication and division.

First, lets look into a code that we will try to speed up: 

double p1 = 0, p2 = 0;

int count = 100000000;

Stopwatch sw = new Stopwatch();

Int32 a = 0, b = 0;

sw.Start();

for (int i = 0; i < count; i++)

{

a = i;

a *= 2;

b += a;

}

sw.Stop();

p1 = sw.ElapsedMilliseconds;

Console.WriteLine(sw.ElapsedMilliseconds + " : " + a);

As you can see the code just measures time that multiplication takes, on my PC this cycle takes about 160 ms.

Now lets add similar code but optimized and we are expecting it will be faster: 

-

static void Main(string[] args)

{

double p1 = 0, p2 = 0;

int count = 100000000;


Stopwatch sw = new Stopwatch();

Int32 a = 0, b = 0;

sw.Start();

for (int i = 0; i < count; i++)

{

a = i;

//multiply by 2

a *= 2;

b += a;

}

sw.Stop();

p1 = sw.ElapsedMilliseconds;

Console.WriteLine(sw.ElapsedMilliseconds + " : " + a + " : " + b);

sw.Reset();

sw.Start();

b = 0;

for (int i = 0; i < count; i++)

{

a = i;

//multiply by 2

a <<= 1;

b += a;

}

sw.Stop();

p2 = sw.ElapsedMilliseconds;

Console.WriteLine(sw.ElapsedMilliseconds + " : " + a + " : " + b);

Console.WriteLine("percent faster: " + 100.0 / p1 * (p1 - p2));

Console.WriteLine("times faster: " + (p1 / p2));

Console.ReadLine();

}

If you will compile it and run (make sure you compile it in Release mode and run outside of Visual Studio) you will see almost no difference

in speed between these two cases of multiplication. On my PC it shows something like that:


161 : 199999998 : 1774919424
157 : 199999998 : 1774919424
percent faster: 2.48447204968944
times faster: 1.02547770700637


but we can say that the result almost the same. Interesting and not really, but do not be  sad, every next step will amaze you ;)


Another type


So, the next step is to test it with another type of integer - Int64 (or long), and what we see? We see that now it is about two times faster, here is my result:


846 : 199999998 : 9999999900000000
342 : 199999998 : 9999999900000000
percent faster: 59.5744680851064
times faster: 2.47368421052632


ha, interesting? So using simple bit scrolling to multiply integer value by 2, 4, 8, 16 ... much faster than multiplication itself.

Lets continue with division.


Division


Ok, now, lets go through the same steps but this time with division, here is the code:

static void Main(string[] args)

{

double p1 = 0, p2 = 0;

int count = 100000000;

Stopwatch sw = new Stopwatch();

Int32 a = 0, b = 0;

sw.Start();

for (int i = 0; i < count; i++)

{

a = i;

//div by 2

a /= 2;

b += a;

}

sw.Stop();

p1 = sw.ElapsedMilliseconds;

Console.WriteLine(sw.ElapsedMilliseconds + " : " + a + " : " + b);

sw.Reset();

sw.Start();

b = 0;

for (int i = 0; i < count; i++)

{

a = i;

//div by 2

a >>= 1;

b += a;

}

sw.Stop();

p2 = sw.ElapsedMilliseconds;

Console.WriteLine(sw.ElapsedMilliseconds + " : " + a + " : " + b);

Console.WriteLine("percent faster: " + 100.0 / p1 * (p1 - p2));

Console.WriteLine("times faster: " + (p1 / p2));

Console.ReadLine();

}

Compile and run it and you will see that the speed also almost the same:


180 : 49999999 : -1728753792
158 : 49999999 : -1728753792
percent faster: 12.2222222222222
times faster: 1.13924050632911


And as you may expect changing from Int32 to Int64 should be even more faster, and this is true, and in my case it more than 8 times faster:


2978 : 49999999 : 2499999950000000
344 : 49999999 : 2499999950000000
percent faster: 88.4486232370719
times faster: 8.65697674418605


So, the main thing here is that multiplication and division on non-native types are complex operations that involve more processor consumption than simple bit scrolling.

On the other hand the Int64 type is not native type for 32 bit environment and it takes more time to operate with it.

But if you will compile this code as x64 and run it under 64 bit operating system, you will see completely another result, here is mine:


229 : 49999999 : 2499999950000000
151 : 49999999 : 2499999950000000
percent faster: 34.061135371179
times faster: 1.51655629139073


this is because of under 64 bit operating system the Int32 and Int64 are native types (means a CPU register may handles whole value).

One more thing is the Any CPU compilation - it seems not so good as you may expect.


Thank you, and do not hesitate to comment it.


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



SQL COUNT(*) is slow - how to increase the performance

Hi friends,

today I'm going to show you one possible way to speed up the COUNT(*)  performance in case when you need to know the total amount of rows of your select query with paging.

Here is the example of my first and slow query:

Select

    COUNT(*) OVER () as TotalCount

    , ID

    , OwnerID

    , Name

    , [Description]

    , keywords

From [dbo].[tblData]

where pState = N'a' and [status] <> 'P'

    and (@FilterBy = 0 OR @FilterBy = TypeID)

Order By DateAdded Desc

OFFSET @p0 ROWS FETCH NEXT @p1 ROWS ONLY;


this query did take from 4 seconds up to 9 seconds selecting 315000 rows from about 450000 rows -

that is really slow. It seems like OVER () overloads the query itself (but this is just my guess).

Also converting from nchar to char takes a lot of time, so I did change it (notice the N letter before string)

After some time of thinking and playing with that around, I did come to the following solution:

select @rowstotal = count(*)

From [dbo].[tblData]

where pState = 'a' and [status] <> 'P'

     and (@FilterBy = 0 OR @FilterBy = TypeID)


select

      @rowstotal as TotalCount

    , ID

    , OwnerID

    , Name

    , [Description]

    , keywords

From [dbo].[tblData]

where pState = 'a' and [status] <> 'P'

    and (@FilterBy = 0 OR @FilterBy = TypeID)

Order By DateAdded Desc

OFFSET @p0 ROWS FETCH NEXT @p1 ROWS ONLY;


(pay attention that to calculate total number of rows to be selected you do not need ordering. I think count(*) with ordering works much slower)


Now this query takes up to 1 second to select the same 315000 rows from about 450000 that is minimum 4 times faster :) 


I'm not sure if this is really best solution as I'm not a DBA master :)

but in my case it sped up the query enough.


Thank you.


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



Swap two variables without using a third one

Hello friends,


Going to ask you - do you know how to swap two variables without of using another one variable?

If your answer is no then here you are:

- we need two variables

- we need three XOR operations

int a = 1;

int b = 2;

a ^= b;

b ^= a;

a ^= b;

now b = 1 and a = 2


Thank you ;)


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



Silverligh 3D Icons

Hello,


Today, I'm going to share my experience with the Silverlight and 3D. One time I saw a Microsoft presentation about a game platform or something, and there were 3D buttons like you see bellow, they did attract my attention so much that I started to make something similar. After a few days video review and thinking I started to implement it myself.

The main thing here is adding image layers and rotate them at once, plus some additional visual effects. So, here is the mouse move handler:

p = e.GetPosition(LayoutRoot);

ry = (mx - p.X) / 2;

rx = -((my - p.Y) / 2);

degree = Math.Atan2(p.Y - my, p.X - mx) * -180 / Math.PI;

degree = 180.0 + degree;

LayoutRoot.Effect.SetValue(DropShadowEffect.DirectionProperty, degree);

BorderControl.Projection.SetValue(PlaneProjection.RotationXProperty, rx);

BorderControl.Projection.SetValue(PlaneProjection.RotationYProperty, ry);

bgTranslate.X = offsetBackgroundX + ry / k;

bgTranslate.Y = offsetBackgroundY + (-rx / k);

foreach (IconImage ii in images)

{

ii.Image.Projection.SetValue(PlaneProjection.RotationXProperty, rx + (ii.ZIndex / globalZIndexStart));

ii.Image.Projection.SetValue(PlaneProjection.RotationYProperty, ry + (ii.ZIndex / globalZIndexStart));

ii.Image.Effect.SetValue(DropShadowEffect.DirectionProperty, degree);

}

So, you calculate angle from two points and rotate each image by the angle value.

Source code is bellow, thank you :)

Icon3D.zip (9.3KB)

1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



C#.Net - Perspective Image Transform

Hello,


Today, I'm going to share one interesting thing that everyone may need - perspective image transformation.

Its 2D transformation that makes image look like in perspective view like 3D but without any 3D:


So, the main thing there is math. We take an image, specify four points and math will do the trick.

First step is to create and calculate matrices from the new four points:

//original points

Point p1 = new Point(0, 0);

Point p2 = new Point(width, 0);

Point p3 = new Point(width, height);

Point p4 = new Point(0, height);

//create matrix

A = Matrix3x3.Homogenous(p1, p2, p3, p4);

//new points

Point n1 = points[0];

Point n2 = points[1];

Point n3 = points[2];

Point n4 = points[3];

B = Matrix3x3.Homogenous(n1, n2, n3, n4);

A.Inverse();

C = B.MultMat(A);

C.Inverse();

Second step is to go through each pixel on your image and calculate new pixel:

Point ptDest = new Point(0, 0);

PointF ptOriginF = new Point(0, 0);

int iOrigX = 0;

Color pix = new Color();

for (int x = 0; x < width; ++x)

{

for (int y = 0; y < height; ++y)

{

ptDest.X = x;

ptDest.Y = y;

ptOriginF = C.Update(ptDest);

if (ptOriginF.X >= -5 && ptOriginF.X < width && ptOriginF.Y >= -5 && ptOriginF.Y < height)

{


iOrigX = (int)ptOriginF.X; // round to lowest integer

int iOrigY = (int)ptOriginF.Y; // round to lowest integer

double dx = ptOriginF.X - iOrigX;

double dy = ptOriginF.Y - iOrigY;

Point ptOrigin = new Point(iOrigX, iOrigY);

if (dx != 0.0f || dy != 0.0)

{

Color pix1 = Color.FromArgb(0, 255, 255, 255);

Color pix2 = Color.FromArgb(0, 255, 255, 255);

Color pix3 = Color.FromArgb(0, 255, 255, 255);

Color pix4 = Color.FromArgb(0, 255, 255, 255);

//

// Correct square's direction

//

int idx = (dx >= 0.0) ? 1 : -1;

int idy = (dy >= 0.0) ? 1 : -1;


dx = Math.Abs(dx);

dy = Math.Abs(dy);

//

// Get pixels of square

//

if (ptOrigin.X >= 0 && ptOrigin.X < width && ptOrigin.Y >= 0 && ptOrigin.Y < height)

pix1 = src.GetPixel(ptOrigin.X, ptOrigin.Y);

if (ptOrigin.X + idx >= 0 && ptOrigin.X + idx < width && ptOrigin.Y >= 0 && ptOrigin.Y < height)

pix2 = src.GetPixel(ptOrigin.X + idx, ptOrigin.Y);

if (ptOrigin.X >= 0 && ptOrigin.X < width && ptOrigin.Y + idy >= 0 && ptOrigin.Y + idy < height)

pix3 = src.GetPixel(ptOrigin.X, ptOrigin.Y + idy);

if (ptOrigin.X + idx >= 0 && ptOrigin.X + idx < width && ptOrigin.Y + idy >= 0 && ptOrigin.Y + idy < height)

pix4 = src.GetPixel(ptOrigin.X + idx, ptOrigin.Y + idy);

//

// Use bilinear interpolation

//

double r = pix1.R + (pix2.R - pix1.R) * dx + (pix3.R - pix1.R) * dy + (pix1.R - pix2.R - pix3.R + pix4.R) * dx * dy;

double g = pix1.G + (pix2.G - pix1.G) * dx + (pix3.G - pix1.G) * dy + (pix1.G - pix2.G - pix3.G + pix4.G) * dx * dy;

double b = pix1.B + (pix2.B - pix1.B) * dx + (pix3.B - pix1.B) * dy + (pix1.B - pix2.B - pix3.B + pix4.B) * dx * dy;

double a = pix1.A + (pix2.A - pix1.A) * dx + (pix3.A - pix1.A) * dy + (pix1.A - pix2.A - pix3.A + pix4.A) * dx * dy;

pix = Color.FromArgb((byte)a, (byte)r, (byte)g, (byte)b);

}

else

{

pix = src.GetPixel(ptOrigin.X, ptOrigin.Y);

}

dst.SetPixel(ptDest.X, ptDest.Y, pix);

}

}

}

So this is bilinear interpolation is the main thing to transform your image.


Thank you.

PS

will extend this and provide source code if you will request.




1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



Microsoft Expression Encoder - How to use and without installation

Hello friends,


Today I will share my experience with the Microsoft Expression Encoder 4 free version.

Download it and install from the link above, add references to the libraries:


- Microsoft.Expression.Encoder.dll

- Microsoft.Expression.Encoder.Api2.dll

- Microsoft.Expression.Encoder.Types.dll

- Microsoft.Expression.Encoder.Utilities.dll


So the minimum code you need to implement to be able to preview and capture video and audio and list devices is the following:

video.Clear();

audio.Clear();

foreach (var dev in EncoderDevices.FindDevices(EncoderDeviceType.Video))

{

video.Add(new ComboboxItem() { Text = dev.Name, Value = dev })

}


foreach (var dev in EncoderDevices.FindDevices(EncoderDeviceType.Audio))

{

audio.Add(new ComboboxItem() { Text = dev.Name, Value = dev });

}

try

{

if (ljob == null)

{

ljob = new LiveJob();

source = ljob.AddDeviceSource((EncoderDevice)((ComboboxItem)cbVideoDevice.SelectedItem).Value,

(EncoderDevice)((ComboboxItem)cbAudioDevice.SelectedItem).Value);

source.PickBestVideoFormat(videoSize, 400000); //in 100 nanoseconds = 40 ms = 25 frames per seconds

source.SetTransportMode(TransportMode.FastForward);


ljob.OutputFormat.VideoProfile = new Microsoft.Expression.Encoder.Profiles.AdvancedVC1VideoProfile() { };

ljob.OutputFormat.VideoProfile.Size = videoSize;

ljob.OutputFormat.VideoProfile.FrameRate = 25;

ljob.OutputFormat.AudioProfile = new Microsoft.Expression.Encoder.Profiles.WmaAudioProfile() { };

ljob.OutputFormat.AudioProfile.Codec = Microsoft.Expression.Encoder.Profiles.AudioCodec.Wma;

}

source.PreviewWindow = new PreviewWindow(new System.Runtime.InteropServices.HandleRef(capForm.Panel, ca pForm.Panel.Handle));

ljob.ActivateSource(source);

}

catch (Microsoft.Expression.Encoder.SystemErrorException ex)

{

if (ex.ErrorCode == -2126905299)

{

MessageBox.Show("Device in use by another application.", "Test EE 4");

}

}

and to start capture:

ljob.PublishFormats.Add(new FileArchivePublishFormat(System.IO.Path.GetFullPath(filePath + fileName)));

ljob.StartEncoding();


Another important thing is to avoid using the installation package of the Microsoft Expression Encoder but just use those four Dlls.

If you will try to run your app on another PC you will get error that Expression Encoder has no license key or something. So to avoid this you have to cases:


- bring the install package and install it on every PC where is your app

- make some changes into registry


I will show you what changes should we make to be able to use it on every PC without installation of Microsoft Expression Encoder, here is the code:

private void TellExpressionEncoderWhereItIs()

{

try

{

var key = "SOFTWARE\\Microsoft\\Expression\\Encoder\\4.0";

 

using (var registryKey = Registry.LocalMachine.OpenSubKey(key))

{

if (registryKey == null)

{

using (var newKey = Registry.LocalMachine.CreateSubKey(key))

{

CheckInstallKey(newKey);

}

}

}

key = "SOFTWARE\\Microsoft\\Expression\\Encoder\\eaa89a7c-d288-4a52-9b68-54930f18ffb7";


using (var registryKey = Registry.LocalMachine.OpenSubKey(key))

{

if (registryKey == null)

{

using (var newKey = Registry.LocalMachine.CreateSubKey(key))

{

CheckInstallKey(newKey);

}

}

}

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void CheckInstallKey(RegistryKey registryKey)

{

var path = "c:\\Program Files\\Microsoft Expression\\Encoder 4\\";

var installKey = "InstallDir";

if (registryKey != null)

{

string text = registryKey.GetValue(installKey) as string;

if (string.IsNullOrEmpty(text))

{

registryKey.SetValue(installKey, path);

}

}

path = "4.0.4276.0";

installKey = "Version";

if (registryKey != null)

{

string text = registryKey.GetValue(installKey) as string;

if (string.IsNullOrEmpty(text))

{

registryKey.SetValue(installKey, path);

}

}

path = "c:\\Program Files\\Microsoft Expression\\Encoder 4\\Encoder.exe";

installKey = "Encoder";

if (registryKey != null)

{

string text = registryKey.GetValue(installKey) as string;

if (string.IsNullOrEmpty(text))

{

registryKey.SetValue(installKey, path);

}

}

path = "c:\\Program Files\\Microsoft Expression\\Encoder 4\\Encoder.exe";

installKey = "InstallPath";

if (registryKey != null)

{

string text = registryKey.GetValue(installKey) as string;

if (string.IsNullOrEmpty(text))

{

registryKey.SetValue(installKey, path);

}

}

}


Also, you will be able to select screen as a video device and capture your screen.


Thank you and let me know if you have questions or better idea :)


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y