Speichern und laden von abbild auf die lokale SQLite-BLOB mit Flex 4.5

Ich muss in der Lage sein zu speichern und laden Sie Bilder in eine SQLite-Datenbank, die mithilfe von Flex 4.5, die für eine mobile Anwendung. Der Anwendungsfall ist:

  • Innerhalb der Ansicht es ist ein spark-Image-Objekt mit einer URL als Quelle
  • Wenn Benutzer klickt auf die Schaltfläche, wird das Bild gespeichert, um eine SQLite-db innerhalb eines BLOB-Feld.
  • In einem separaten Bild der Quelle, die in das ByteArray gespeichert in der db.

Ist die größte Frage so weit ist: wo bekomme ich das ByteArray für ein geladenes Bild? Ich habe versucht zu Debuggen und prüfen von Bild -, BitmapImage-und BitMapData-aber es gibt keine Zeichen das byte-array.... vielleicht ist es innerhalb der ContentLoader? Aber das ist null-es sei denn, ich caching aktivieren.

Ich habe einige der Forschung getan und es gibt keine vollständige Beispiele dafür, wie Sie damit umgehen können. Ich habe geschrieben, eine einfache Ansicht, jeder kann kopieren und einfügen in ein neues Projekt. Es kompiliert ohne Fehler und kann zum testen verwendet werden. Ich werde aktualisieren diesen code, wie ich die Antworten bekommen, die ich brauche, so dass jeder ein voll funktionsfähiges Beispiel dieses Workflows. Der einzige Nachteil: ich habe mit einer synchronen Verbindung zu der DB zu vermeiden, erschweren Sie den code mit event-Handlern, ich wollte es so einfach wie möglich.

Ich nur daneben, wie diese Frage beantwortet wird, sobald es vollständig funktionieren beide Wege.

UPDATE SEPT. 09 2011:

Den code unten ist jetzt voll funktionsfähig in beiden Richtungen (laden und speichern). Hier sind einige der Dinge, die ich gelernt habe:

  • Es stellt sich heraus, dass das ByteArray an ein spark-Image kann sein gefunden innerhalb des LoaderInfo-des Bildes selbst. Wie diese:

Bild.loaderInfo.bytes

  • Jedoch, die versuchen, dieses ByteArray als Quelle ein anderes Bild ( image2.source = image1.loaderInfo.bytes) Ergebnisse, die in diesem security-Fehler:

Fehler #3226: kann Nicht importieren einer SWF-Datei, wenn
LoaderContext.allowCodeImport ist falsch.

  • Das ist schade, denn es wäre sparen so viel Zeit und Rechenleistung. Wenn jemand weiß, wie man in der Vergangenheit dieser Fehler, es wäre sehr geschätzt werden!

  • Sowieso, der workaround ist zu Kodieren, wird das ByteArray unter Verwendung entweder eines JPEGEncoder oder eine PNGEncoder. Ich benutzte die JPEGEncoder produziert wesentlich kleinere Dateien. Hier ist, wie:

var encoder:JPEGEncoder = new JPEGEncoder(75);  
var imageByteArray:ByteArray = encoder.encode(imageToSave.bitmapData);
  • Das problem ist nun speichern Sie diese bytes in die DB. Sparen Sie so wie Sie jetzt sind, werden nicht funktionieren, wenn wir Sie Lesen aus, ich bin nicht sicher, warum. Also die Lösung ist zu Kodieren, in einen base64-string wie diesen:
var baseEncoder:Base64Encoder = new Base64Encoder();
baseEncoder.encodeBytes(imageByteArray); 
var encodedBytes:String = baseEncoder.toString();
  • So, jetzt nur noch speichern, string in das Feld "BLOB" und später Auslesen. Sie haben jedoch zu Dekodieren aus base64-string in ein ByteArray wie diese:
var encodedBytes:String = result.data[0].imagedata;
var baseDecoder:Base64Decoder = new Base64Decoder();
baseDecoder.decode(encodedBytes);
var byteArray:ByteArray = baseDecoder.toByteArray();
  • Weisen Sie nun die bytearray als Quelle für Ihr Bild und Sie sind fertig. Einfach rechts?

  • Danke an alle die geholfen haben und bitte kommentieren, wenn Sie irgendwelche Optimierungen oder alternative Möglichkeiten, dies zu tun. Ich werde Antworten, und halten Sie diesen code aktualisiert, wenn es sein muss.

HINWEIS: Der folgende code ist voll funktionsfähig.

<?xml version="1.0" encoding="utf-8"?>
<s:View 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    actionBarVisible="false"
    creationComplete="init(event)">

    <s:layout>
        <s:VerticalLayout />
    </s:layout>

    <s:TextArea id="logOutput" width="100%" height="200" fontSize="10" editable="false" />

    <s:Image id="remoteImage" source="http://l.yimg.com/g/images/soup_hero-02.jpg.v1" enableLoadingState="true" />

    <s:Button label="Save Image" click="saveImage()" />

    <s:Image id="savedImage" source="" enableLoadingState="true" />

    <s:Button label="Load Image" click="loadImage()" />

    <s:Button label="Copy Image" click="copyImage()" />

    <fx:Script>
        <![CDATA[
            import mx.core.FlexGlobals;
            import mx.events.FlexEvent;
            import mx.graphics.codec.JPEGEncoder;
            import mx.utils.Base64Decoder;
            import mx.utils.Base64Encoder;

            public var dbName:String;
            public var file:File;
            public var sqlConnection:SQLConnection;

            import spark.components.supportClasses.StyleableTextField;

            protected function init(event:FlexEvent):void
            {
                dbName = FlexGlobals.topLevelApplication.className+".db";
                file = File.documentsDirectory.resolvePath(dbName);
                printToLog("Database resolved to path '"+file.nativePath+"'");
                sqlConnection = new SQLConnection();

                //open the database in synchronous mode to avoid complicating code with event handlers.
                //alternatively use the openAsync function.
                sqlConnection.open(file); 
                printToLog("Connection to database has been opened successfully.");

                var sql:String = "CREATE TABLE IF NOT EXISTS my_table(id INTEGER PRIMARY KEY, title VARCHAR(100), width INTEGER, height INTEGER, imagedata BLOB)";
                var createStatement:SQLStatement = new SQLStatement();
                createStatement.sqlConnection = sqlConnection;
                createStatement.text = sql;
                try
                {
                    printToLog("Executing sql statement:\n"+sql);
                    createStatement.execute();
                    printToLog("Success.");
                }
                catch(err:SQLError)
                {
                    printToLog(err.message + " Details: " + err.details);
                }
            }

            public function saveImage():void
            {
                //create some dummy parameters for now
                var id:int = 1;
                var imageTitle:String = "Test Image";
                var imageToSave:Image = remoteImage;

                //The JPEGEncoder and PNGEncoder allow you to convert BitmapData object into a ByteArray, 
                //ready for storage in an SQLite blob field
                var encoder:JPEGEncoder = new JPEGEncoder(75);  //quality of compression. 75 is a good compromise
                //var encoder:PNGEncoder = new PNGEncoder();
                var imageByteArray:ByteArray = encoder.encode(imageToSave.bitmapData);

                //insert data to db
                var insertStatement:SQLStatement = new SQLStatement();
                insertStatement.sqlConnection = sqlConnection;
                insertStatement.text = "INSERT INTO my_table (id, title, width, height, imagedata) VALUES (@id, @title, @width, @height, @imageByteArray)";
                insertStatement.parameters["@id"] = id; //Integer with id
                insertStatement.parameters["@title"] = imageTitle; //String containing title

                //also save width and height of image so you can recreate the image when you get it out of the db.
                //NOTE: the width and height will be those of the originally loaded image, 
                //     even if you explicitly set width and height on your Image instance.
                insertStatement.parameters["@width"] = imageToSave.bitmapData.width; 
                insertStatement.parameters["@height"] = imageToSave.bitmapData.height;

                //Encode the ByteArray into a base64 string, otherwise it won't work when reading it back in
                var baseEncoder:Base64Encoder = new Base64Encoder();
                baseEncoder.encodeBytes(imageByteArray);
                var encodedBytes:String = baseEncoder.toString();
                insertStatement.parameters["@imageByteArray"] = encodedBytes; //ByteArray containing image
                try
                {
                    printToLog("Executing sql statement:\n"+insertStatement.text);
                    printToLog("id="+id);
                    printToLog("title="+imageTitle);
                    printToLog("imageByteArray="+imageByteArray);
                    insertStatement.execute();
                    printToLog("Success.");
                }
                catch(err:SQLError)
                {
                    printToLog(err.message + " Details: " + err.details);
                }
            }

            public function loadImage():void
            {
                //select data from db
                var selectStatement:SQLStatement = new SQLStatement();
                selectStatement.sqlConnection = sqlConnection;
                selectStatement.text = "SELECT title, width, height, imagedata FROM my_table WHERE id = @id;";
                selectStatement.parameters["@id"] = 1; //Id of target record
                try
                {
                    printToLog("Executing sql statement:\n"+selectStatement.text);
                    selectStatement.execute();
                    printToLog("Success.");
                }
                catch(err:SQLError)
                {
                    printToLog(err.message + " Details: " + err.details);
                    return;
                }

                //parse results
                var result:SQLResult = selectStatement.getResult();
                if (result.data != null) 
                {
                    var row:Object = result.data[0];

                    var title:String = result.data[0].title;
                    var width:int = result.data[0].width;
                    var height:int = result.data[0].height;

                    //read the image data as a base64 encoded String, then decode it into a ByteArray
                    var encodedBytes:String = result.data[0].imagedata;
                    var baseDecoder:Base64Decoder = new Base64Decoder();
                    baseDecoder.decode(encodedBytes);
                    var byteArray:ByteArray = baseDecoder.toByteArray();

                    //assign the ByteArray to the image source
                    savedImage.width = width;
                    savedImage.height = height;
                    savedImage.source = byteArray;
                }
            }

            //This is just a quick test method to see how we can pull out the 
            //original ByteArray without passing through the DB
            public function copyImage():void
            {
                //var imageByteArray:ByteArray = remoteImage.loaderInfo.bytes;
                //This throws the following error: 
                //Error #3226: Cannot import a SWF file when LoaderContext.allowCodeImport is false.
                //That's too bad because it would save a lot of time encoding the same bytes we 
                //already have (not to mention the loss of quality if we compress JPEG less than 100).

                //This is the only solution I've found so far, but slows everything up
                var encoder:JPEGEncoder = new JPEGEncoder(75);
                //var encoder:PNGEncoder = new PNGEncoder();  -- alternative encoder: huge files
                var imageByteArray:ByteArray = encoder.encode(remoteImage.bitmapData);

                savedImage.source = imageByteArray;
            }

            public function printToLog(msg:String):void
            {
                logOutput.appendText(msg + "\n");
                StyleableTextField(logOutput.textDisplay).scrollV++;  //this is to scroll automatically when text is added.
            }
        ]]>
    </fx:Script>
</s:View>

InformationsquelleAutor Andy | 2011-09-08

Schreibe einen Kommentar