[Original] There is a new bottle of old wine - use Delphi to achieve picture interface replacement color color (2004-8)

xiaoxiao2021-03-06  39

The software's "skin care" technology is no new, but the careful friends must have discovered, now there is a new way to improve the visual effect now - here I fight defined as "transcottically" technology Let's! I have used Winamp 5, Windows MediaPlay 9, MSN Messenger 6, QQ2004 these new version of the software, huh, all use the so-called "transcottical" technology of the drug. Very means, let's "do your own fun" below.

First of all, I opened the relevant executable files and dynamic link libraries of WMP9 and MSN6 with Exescrope. I didn't find the resources of the interface, and the younger generation was too much. It may be calculated in real time. QQ2004 and WINAMP5 are more intuitive, one is to use BMP files directly, and the other is PNG format. The BMP file has nothing to say, and I have said two words about PNG format. PNG (Portable Network Graphics) is an image format designed to accommodate network data transmission, which is used to replace the format, and the patented restrictions are strict GIF image file format. The PNG format is roughly the following advantages: high compression ratio, supports Alpha channel (full transparency, all opaque, variable transparency), providing GAMMA (image highlights) correction mechanism, providing two-dimensional cross access mechanism, supporting true color / grayscale / Image of color indexes. Analysis of WinAmp5 graphical interface layout, many beautiful shadows, the gradient effect is not BMP to be done by specifying color; otherwise, the file will be more than if a program uses the skin, BMP is generally at least a few The total size of 100 k; so I think the PNG picture is more suitable for the skin of the brilliant interface. Delphi default is a picture of PNG format, only to download third-party controls. In the DFW Forum, I finally found a lot of finally let me find this good Dongdong, with source code, help file, no need to install, support PNG transparency. Oh, so we can start!

I first looked at the help file of pngimage, "Example 3: Drawing PNG over Other Formats" is an example of reading a specified PNG image after reading a JPG picture, I try it is very Good support with transparent PNG files. Because I have to take these PNG files to make a program interface, I first plan to draw this PNG picture to the form:

Uses ..., pngimage; // plus this

Procedure TForm1.FormPaint (Sender: Tobject); VAR PNG: TPngObject; Rect: TRECT; Begin PNG: = tpngObject.create; png.loadfromfile ('1.png');

Rect.top: = 0; Rect.right: = Rect.Lect png.width; Rect.bottom: = Rect.top png.height;

Png.draw (canvas, rect);

PNG.free;

The above code implements the 1.png file after reading the 1.png file to the form, this picture is the default main interface of WinAmp5, where there is a concave in the lower right corner that is a transparent part, how, the effect comes out (as shown 1).

Next I intend to put the png picture into the TIMAGE control to make an analog button. This is relatively simple, after a few attempts, found as long as "image1.picture.assign (png);", it is possible, and it is also very good to show the gradient transparent effect. (Note: IMAGE1.PICTURE.BITMAP.Assign (PNG); ", although this code can draw a graphic, it is not a good, all become black; other" image1.assign (PNG) "Or" image1.picture.bitmap.canvas.assign (PNG); ", otherwise generate runtime type conversion errors, because TPngObject is not converted to Timage or Tbitmapcanvas type.) In addition, there is already a picture in the Timage control, Want to cover the PNG picture, you can use the DRAW method of the TPngObject object: Rect.Left: = 0; Rect.top: = 0; Rect.right: = Rect.Lect PNG.Width; Rect.Bottom: = RECT. TOP PNG.HEIGHT;

Png.draw (image1.canvas, rect); image1.refresh;

Note: You can't use Timage here, otherwise the original picture is gone; and you need to call Timage.Refresh before you can display the changed picture (as shown in Figure 2, the left is a single PNG picture, the right side is to cover the PNG picture to Existing bitmaps).

Said so much, now I should consider our focus "Change skin". The basic principle I consider is to first make the pictures related to all interfaces into grayscale PNG pictures, which can make color gradients, three-dimensional effects; then use the designated color "Mongoli" to the grayscale picture. Thinking of simply, you can actually move your hand to find it or have encountered a lot of questions. Because the RGB color and bitmap only knows, when it is hidden in the beginning, it is not the RGB value of a bit of pixels in the grayscale picture to do logic and operations (Oh, let people joke), I have docked the code, I really "Mong" in the correct color for several colors (black, white, red, green, blue, yellow, pink), "Mongolia" is compared to the effects of the figure software) Other more than a gradient, very color, etc., just take the picture of the WinAmp5 main interface used in front, turned out and turned into a big face. . . Oh, don't be lazy, still analyze it.

Take the "light-dark" gradient picture as an example, suppose we want to turn all the pixels containing "dark" colors into designated colors, which is to turn into white-red, pale yellow-deep yellow gradient. We know that TColor is actually represented by a range of hexadecimal values, and saves red, green, and blue values ​​from the low to high bytes. For grayscale, the three values ​​of each "gray" R, G, B are equal, from black (RGB (0, 0, 0)) to white (RGB (255, 255, 255)). After a period of pondering, I found that the color conversion of a pixel point should be:

This point target color is from the "distance" (between the difference between the difference, the auctions, and the specified color from the "distance" = this point gray from the white "distance" / most deepened white "distance"

The "distance" here is actually the absolute value of the difference between the colors of R, G, B, and 255. Is it a bit faint? Oh, it should actually be more understandable, intuitive original formula (calculated R, G, B triple) is: (255 - target color R value) / (255 - specified color R value) = (255 - gray R value) / (255 - the most dark R value)

After the movement can be obtained:

Target color R value = 255 - (255 - gray R value) * (255 - specified color R value) / (255 - most dark R value)

Similarly, the G, B value of the target color can be obtained. Now you can take a specified color (a light red) (RGB (153, 0, 0)) and a gray (RGB (204, 204, 204)), the result of the results, respectively, the results of the four, respectively, RGB (235, 204, 204), get it Draw the picture software to compare it, and the results of the color gradient generated in the picture software can't see the difference! Since the algorithm has been found, it is easy to turn into a code.

PROCEDURE TFORM1.BUTTON2CLICK (Sender: TOBJECT); VAR I, J: Integer; R, G, B, RGbTemp: Cardinal; T1, T2: Cardinal; PNG: TpngObject; RECT: TRECT; .Loadfromfile ('2.png');

T1: = GettickCount;

For i: = 0 to png.width - 1 do begin for j: = 0 to png.height - 1 do begin rgbtemp: = png.pixels [i, j]; r: = getRvalue (RGBTEMP); g: = getgvalue (RGBTEMP); B: = getBValue (RGBTEMP); {Calculation formula: Target color R / g / b value = 255 - (255 - gray R / g / b value) * (255 - specified color R / g / b value ) / (255 - most deeper R / g / b)} PNG.Pixels [i, j]: = RGB (255 - (255 - r) * (255 - 153) Div 255, // Calculate the current pixel according to formula The value of R is 255 - (255 - g) * (255 - 0) DIV 255, // calculates G value 255 - (255 - b) * (255 - 0) DIV 255); // calculate B value end; end ;

Rect.Top: = 152; Rect.right: = Rect.Lect Png.width; Rect.Bottom: = Rect.top PNG.Height;

Png.draw (canvas, rect);

T2: = GetTickCount - T1; ShowMessage (INTTOSTR (T2));

PNG.free;

The effect after color conversion is shown in Figure 3.

The target seems to be reached, but look at this rough algorithm, the two cycles are traversed to each pixel must be very slow, tested the picture of this 200 * 200 (pixel) under the CPU of P4 2.4 Time-consuming average 94ms (I used a RGBTEMP temporary variable to save the RGB value of the current pixel, or when calculating R, G, B, respectively read PNG.Pixels [i, j], the time is basically doubled. ). day! This time is time consuming very considerable! Later, I changed the code to copy the scanline property of the picture to a pointer array, which greatly improved the arithmetic speed: {Definition pointer array type} const marxpixelcount = 65536;

Type prgbarray = ^ trgbarray; trgbarray = array [0..maxpixelcount - 1] of trgbtriple;

Procedure TForm1.Button3Click (Sender: Tobject); Var i, J: Integer; row: prgbarray; png: tpngobject; Rect: TRECT; begin png: = tpngObject.create; png.loadfromfile ('2.png');

For i: = 0 to png.height - 1 do begin row: = png.scanline [i]; // copy scanline property to ROW pointer array for j: = 0 to png.width - 1 do begin row [j]. RGBTRED: = 255 - (255 - row [j] .rgbtred * (255 - 153) Div 255; Row [J] .rgbtgreen: = 255 - (255 - row [j] .rgbtgreen * (255 - 0) Div 255; row [j] .rgbtblue: = 255 - (255 - row [j] .rgbtblue) * (255 - 0) Div 255; end; end; {...} {Back draw picture code identical}

After this algorithm is optimized, the runtime is shortened to almost 0ms (occasionally 16ms)!

I finally finished writing ^^. The above algorithm is I figured out, I didn't find anything on the Internet. If a friend has a better way, please give more points, I hope to contact me (islet8 at yahoo.com.cn, put "AT" Change to "@"). I hope this article can give you a friend to the role of torch jade! The above code is debugged under WinXP Delphi7. PNGIMAGE control: http://www.delphibox.com/go.asp? Id = 1769 & url = http://downloads.2ccc.com/vcl/graphics/pngimage143.zip

转载请注明原文地址:https://www.9cbs.com/read-75752.html

New Post(0)