Difference between revisions of "User:LindaB Helendale/BMPbase64"

From Second Life Wiki
Jump to navigation Jump to search
m
Line 1: Line 1:
== Create BMP image in-world ==
== Create BMP image in-world ==


Line 6: Line 5:
Creating textures in-world is not possible in SL, but for some tasks it is useful to be able to produce images with scripts. Such as making sculpt maps, or visualizing some land attributes. The following script functions print out html code for a base64 encoded BMP image.  
Creating textures in-world is not possible in SL, but for some tasks it is useful to be able to produce images with scripts. Such as making sculpt maps, or visualizing some land attributes. The following script functions print out html code for a base64 encoded BMP image.  


== Usage ==
=== Usage ===


Copy and paste the script output from  chat to a text file and save as .htm or .html file on the computer. You don't need to remove other chat lines that may have occurred while the script prints the image. After saving the file, open it with any web browser. The image can  be saved in BMP format form the web browser to upload in SL or to use in any image manipulation applications.
Copy and paste the script output from  chat to a text file and save as .htm or .html file on the computer. You don't need to remove other chat lines that may have occurred while the script prints the image. After saving the file, open it with any web browser. The image can  be saved in BMP format from the web browser to upload in SL or to use in any image manipulation applications.




Line 22: Line 21:




== Main Script ==
=== Main Script ===
<lsl>
<lsl>
//======= BMP image routines ===============================================
//======= BMP image routines ===============================================

Revision as of 01:46, 25 January 2012

Create BMP image in-world

Introduction

Creating textures in-world is not possible in SL, but for some tasks it is useful to be able to produce images with scripts. Such as making sculpt maps, or visualizing some land attributes. The following script functions print out html code for a base64 encoded BMP image.

Usage

Copy and paste the script output from chat to a text file and save as .htm or .html file on the computer. You don't need to remove other chat lines that may have occurred while the script prints the image. After saving the file, open it with any web browser. The image can be saved in BMP format from the web browser to upload in SL or to use in any image manipulation applications.


The following script is a working demo. To use the functions in your script copy the segment from <lsl> //======= BMP image routines =============================================== </lsl> to <lsl> //=== end of BMP image routines ====================== </lsl> into the script.


Main Script

<lsl> //======= BMP image routines =============================================== // // (c) LindaB Helendale, permission to use the routines freely is granted. // Please retain the copyright statement // // These routines print html code for showing a base64 encoded BMP image. // Copy and paste the chat between <html> and </html> to a file, and save, // and open with web browser. You can save it as BMP in the browser to upload in SL. // // Usage: // BMP_open_stream(width, heigth) - opens the BMP data stream and prints the header // The pixels are added with the following functions. The rows run from bottom to top // and columns from left to rigth. // BMP_add_pixel_color(colorVec) - adds pixel defined by color vector to the stream // BMP_add_pixel_RGB(R,G,B) - adds pixel defined by integers R G B to the stream // BMP_close_stream() - closes the stream


// Output line length can be about 1000 in SL, // but take care that the application where you paste the data doesn't add line breaks integer MAX_OUTPUT_LINE_LENGTH = 500;

string HTMLheader= "------ Copy to a file below this line ---------

<html><body><img id='image'><script language='JavaScript'> var data = 'data:image/bmp;base64,";

string HTMLtail= "var s_img = document.getElementById('image'); s_img.src = data; </script></body></html>


Copy to a file above this line ---------";

// to scale the image, you can add the following js commands in the tail before </script> // s_img.setAttribute('width', 512); s_img.setAttribute('height',512);

// header of the BMP image, byte per byte list BMPheader=[66,77, 54,48,0,0, 0,0,0,0, 54,0,0,0, 40,0,0,0, 32,0,0,0, 128,0,0,0, 1,0, 24,0, 0,0,0,0, 0,48,0,0, 194,30,0,0, 194,30,0,0, 0,0,0,0, 0,0,0,0];

list swap_bytes(integer J) {

 return [ J & 0xff , (J>>8) & 0xff, (J>>16) &  0xff, (J>>24) & 0xff];

}

string BMP_encoded_header(integer width, integer heigth) {

   // return encoded BMP header for the given size image, setting width, height, image size and file size
   string encodedHeader="";
   list headerBytes=BMPheader;
   integer imSize = heigth * width * 3;
   integer fileSize = imSize + 54; 
   headerBytes = BMPheader;
   headerBytes = llListReplaceList(headerBytes, swap_bytes(fileSize),2,5);
   headerBytes = llListReplaceList(headerBytes, swap_bytes(width),18,21);
   headerBytes = llListReplaceList(headerBytes, swap_bytes(heigth),22,25);
   headerBytes = llListReplaceList(headerBytes, swap_bytes(imSize),34,37);
   integer p;
   for(p=0;p<54;p+=3) {
       integer x = ((llList2Integer(headerBytes,p) & 0xff) << 24 ) |
                   ((llList2Integer(headerBytes,p+1) & 0xff) << 16 ) |
                   ((llList2Integer(headerBytes,p+2) & 0xff) << 8 ) ;
       string s=llGetSubString(llIntegerToBase64(x),0,3);
       encodedHeader += s;
   }
   return encodedHeader;

}

integer DATA_SIZE; // the required number of data items (3 byte/4 char) in the stream string LINEBUFF; // output buffer integer DATA_LINES; // the number of printed data lines, used for printing the js code for merging the data integer DATA_ITEMS; // the number of printed data items, used for error checking

BMP_open_stream(integer width, integer heigth) {

   DATA_SIZE = width*heigth;
   DATA_LINES=0;
   DATA_ITEMS=0;
   LINEBUFF="";
   string bmpheader=BMP_encoded_header(width,heigth);
   llOwnerSay("\n\n" + HTMLheader + bmpheader + "';\n/*");

}

BMP_close_stream() {

   if (LINEBUFF != "") {
       llOwnerSay("\n*/\ndata" + (string)DATA_LINES + " = '" + LINEBUFF + "';\n/*");
       LINEBUFF=="";
       DATA_LINES++;
   }
   // print the javascript code to append the data<line> variables to the data stream
   integer i;
   LINEBUFF = "\n*/\ndata+=";
   for(i=0;i<DATA_LINES;i++) {
       string s =  "data" + (string)i  + "+";
       if (llStringLength(LINEBUFF) + llStringLength(s) + llStringLength(HTMLtail) > 1000) {
           llOwnerSay(llGetSubString(LINEBUFF,0,-2) + ";\n/*");
           LINEBUFF =  "\n*/\ndata+=";
       }
       LINEBUFF += s;
       if ((i+1) % 24 == 0) {
           LINEBUFF = llGetSubString(LINEBUFF,0,-2) + ";\ndata+=";
       }
   }
   llOwnerSay(llGetSubString(LINEBUFF,0,-2) + ";\n" + HTMLtail + "\n");
   
   if (DATA_ITEMS != DATA_SIZE) {
       llOwnerSay("\nWarning: the size of the image is " + (string)DATA_SIZE +
                  " pixels. \The number of pixels written is " + (string)DATA_ITEMS);
   }

}

BMP_add_pixel_color(vector rgb) {

   // Add pixel specified by color vector to the stream
   rgb *= 255; 
   integer x = ((integer)rgb.x<<8) | ((integer)rgb.y<<16) | ((integer)rgb.z<<24);
   string s=llGetSubString(llIntegerToBase64(x),0,3);
   BMP_add_3bytes_encoded(s);

}

BMP_add_pixel_RGB(integer R, integer G, integer B) {

   // Add pixel specified by three integer RGB values to the stream
   integer x = (R<<8) | (G<<16) | (B<<24);
   string s=llGetSubString(llIntegerToBase64(x),0,3);
   BMP_add_3bytes_encoded(s);

}

BMP_add_3bytes_encoded(string s) {

   // print the data in the stream, with new line if needed
   if (llStringLength(LINEBUFF) + llStringLength(s) > MAX_OUTPUT_LINE_LENGTH) {
       llOwnerSay("\n*/\ndata" + (string)DATA_LINES + "='" + LINEBUFF + "';\n/*");
       LINEBUFF=s;
       DATA_LINES++;
   }else{
       LINEBUFF += s;
   }
   DATA_ITEMS++;

} //=== end of BMP image routines ======================

// this is needed for the demo pic only vector hsv2rgb(vector hsv) {

   float h=hsv.x;
   float s=hsv.y;
   float v=hsv.z;
   h = 6*h;
   integer k = llFloor(h-6*0.000001); 
   if (k<0) { k=0;}
   float f = h-k;
   float t = 1-s;
   float n = 1-s*f;
   float p = 1-(s*(1-f));
   float r = (k==0)   + (k==1)*n + (k==2)*t + (k==3)*t + (k==4)*p + (k==5);
   float g = (k==0)*p + (k==1)   + (k==2)   + (k==3)*n + (k==4)*t + (k==5)*t;
   float b = (k==0)*t + (k==1)*t + (k==2)*p + (k==3)   + (k==4)   + (k==5)*n;
   float max=r; if (g>max) max=g; if (b>max) max=b;
   f = v/max;
   vector rgb=f*<r,g,b>;
   return(rgb);

}


default {

   // make test image:  64 x 12 image with
   //  2 pixel pink stripe on top
   //  8 pixel HSV chart in middle, with saturation growing upwards
   //  2 pixel lilac stripe below
   // in BMP the starting row is at bottom, columns run from left ro right
       
   touch_start(integer p) {
       if (llDetectedKey(0)!=llGetOwner()) return;
       integer R=12;
       integer C=64;
       BMP_open_stream(C,R);
       
       integer row; integer col;
       for(row=0;row<R;row++) {
           for(col=0;col<C;col++) {
               vector rgb;
               if (row<=1) { 
                   // lilac stripe
                   rgb = <100,0,255>/255.0;
               }else if (row>=10) {
                   // pink stripe
                   rgb = <255,170,230>/255.0;
               }else{
                   // HSV chart
                   vector hsv=<(float)col / (float)(C), (float)(row-2) / 7.01 , 1>;
                   rgb=hsv2rgb(hsv);
               }
               BMP_add_pixel_color(rgb);
           }
       }
       BMP_close_stream();
   }

} </lsl>