Article Preview
Buy Now
| Print: | |
| PDF: |
Beyond the Limits
Building a Graphics Library that Directly Extends the Picture Object
Issue: 3.1 (September/October 2004)
Author: Didier Barbas
Author Bio: Didier has been a dilettante programmer and linguist for more than 20 years. Unusual for a Frenchman, he speaks 11 languages, including Korean and PowerPC machine-language.
Article Description: No description available.
Article Length (in bytes): 6,666
Starting Page Number: 46
RBD Number: 3122
Resource File(s):
3122.sit Updated: Wednesday, September 15, 2004 at 4:28 PM
Related Link(s): None
Known Limitations: None
Excerpt of article text...
In a previous issue (2.3) we saw how to speed up graphic operations like rotation. It did require a bit of coding, but proved to be quite fast. A faithful reader of this column actually used the code and tips for a real-life application, and we have worked together in order to make it even faster and more readable. Some of the things we did together will serve as a basis for this article. Objectives We will produce a basic graphics library that'll extend the Picture object, making the library more portable and the code using it more readable. We will also make full use, when possible, of the .Transform method of the RGBSurface object. This method, which provides a very fast way of mapping colors and applying transformations based on the mappings, proves to be very convenient in some cases. Extends The Extends keyword is used in method declarations in order to provide new methods to an existing class. This is a new addition to RB, and a very welcome one, since it will help make your code more object oriented -- and much more readable. We have seen this happening within RB itself in the last few releases: i=LenB(s) can now be written i=s.LenB, which made many of us happy (since those RB users among us who use other OOP languages tend to think this is the natural way to do things). We will use this keyword in our Library, extending the Picture object with methods that would've normally been called under the form p=method(p). You can only use extends on the first parameter, and such methods have to be stored in a Module. The syntax is: extends variableName As className[additional parameters optional]. Thus, if you declare a Rotate180 method with "extends pix as Picture" as a parameter, you can call .Rotate180 at any time with any picture object. Within the Rotate180 code, the picture will be referred to as "pix", whatever its name was originally. Note that if you plan to use RGBSurfaces within such methods (and I am!), you'll have to make sure that they are created with NewPicture -- if not, the code will fail silently. This is the case anyway, but by extending the Picture class the code will always be available whether the picture was created with NewPicture or not, and you might spend some time wondering why the code is not working... We can now move the code we used in issue 2.3 into a Module, and modify all methods so that they extend the Picture class. We will also add a few more methods that'll use the .Transform method of the RGBSurface class. .Transform .Transform accepts either one or three arrays of integers (0-255) as a map. One array will apply the same transformation to all three color channels, whereas three arrays will provide for different mappings for each channel. The indexes of the array(s) represent the colors. For instance, if you pass three arrays, all pixels that are equal to RGB(255,0,127) will be transformed to RGB(Array1(255), Array2(0), Array3(127)). This is actually much faster than going over all pixels of the RGBSurface and applying the transformation in a loop. Of course, internally, this is exactly what RB does when .Transform is called, but much faster... Of course, not all transformations are possible with .Transform. Since it is a value to value mapping function, don't expect to be able to rotate a picture, or even to transform it to grayscale (providing one array only will not set all three channels to the same value, which is kind of counter-intuitive). However, we still can do quite a bit. Colors Say you have an image editing application in the making, and you'd like to provide a Photoshop-like tool that'll enable the user to alter the quantity of Red, Green, and Blue in the image with sliders. The fastest way to do this is to use .Transform. What you have to do is write a routine that adds an offset (positive or negative) to a color channel. This routine should be called by the .ValueChanged event of the Slider. Check the LiveScroll property for a live refresh: if you don't, the routine will be called only when you release the mouse button. Here's the code for the red channel: Sub RedVariation(extends pix as picture,v1 as integer) dim i,n as integer dim r(255),g(255),b(255) as Integer dim srf as RGBSurface srf=pix.RGBSurface for i=0 to 255 // add the offset to the index // and check for negative values // or values > 255 n=i+v1 If n<0 Then n=0 ElseIf n>255 Then n=255 End If // Set Red[index] r(i)=n // Green and Blue don't change g(i)=i b(i)=i Next srf.Transform r,g,b End Sub This code executes in about 19 milliseconds on a 640x480 image on my TiBook, against 180 milliseconds for a "fast" routine looping over the RGBSurface. That's 9.5 times faster. Brightness If you performed exactly the same operation above on the three channels (or passed only one array), you would provide your application with a Brightness function. The only thing to change in the code above is to replace: g(i)=i b(i)=i with g(i)=n b(i)=n Mind you, you have to use a backup copy of the image for which you are trying to adjust the Brightness: if you reuse the image that has just been adjusted, on the next adjustment (and with LiveScroll on, it is pretty much as you move the Slider) the brightness adjustment will be exponential and not just incremental, not exactly what you wished for... You'll get a white or black picture in no time! Other methods A few "traditional" methods have also been provided (rotation, mirror), along with a real-life example: the imageControl method (to be used with the sample "Lights" picture) calculates whether a sample lighting is uniform enough; pixels that are 110% or above the overall average are represented in red, and those below 90% of the average are represented in green. Finally, I have provided a drag'n'drop'n'export function: drag and drop the image from the main window to the smaller one; the exportPicture function will be called, enabling you to save it in the format of your choice (that is, as long as you have QuickTime installed). At the same time, the image is resized for display in the smaller window's ImageWell; all useful code ready for reuse. Check out the sample project that can be downloaded from REALbasic Developer's website. See how the code in the PushButtons looks much cleaner and more "natural". You can now add your own methods, and use this Module wherever you need it! Remember that RB only compiles what is used, so you don't need to weed out methods when you use only a few of them.
...End of Excerpt. Please purchase the magazine to read the full article.
Article copyrighted by REALbasic Developer magazine. All rights reserved.
|










