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
Du musst angemeldet sein, um einen Kommentar abzugeben.
Unten dieser Artikel hat eine ausgezeichnete Weise, es zu tun
http://blog.affirmix.com/2009/01/28/getting-started-with-adobe-air-and-sqlite-and-avoiding-the-problems/
Möchten Sie vielleicht zu prüfen, Lesen der Kommentare, weil jemand erwähnt Fehlervermeidung durch Codierung es zu base64, bevor Sie zu Begehen und die Dekodierung beim Lesen.
Für die Nachwelt Willen:
Dies müsste Teil der Anwendung, der code
Dies müsste Teil der SQLConnectionWrapper
Dies müsste Teil der Anwendung, der code
Als Angefordert:
Und dann laden Sie es wieder:
Ich hoffe, das hilft!
Mein Vergnügen. Um ehrlich zu sein, ich halt normalerweise nehmen Sie die URLLoader.Daten als ein ByteArray, schreiben die bytearray-das BLOB-Feld in SQLite laden und dann wie ein bytearray-wie im obigen Beispiel, ohne die anderen arbeiten oder base64-Codierung. Würde ich schreiben, mein Beispiel, aber ich fühlte, wie sein Weg war ... "righter"
Nein, eigentlich würde ich gerne sehen, Ihre Lösung und vermeiden Sie die Codierung, die wirklich bremst alles runter. Wo ist der URLLoader-für eine spark-Image? Ich fand diese: Bild.loaderInfo.bytes, aber diese löst eine SecurityError - #3226, wenn ich versuche, ordnen Sie es mit einem anderen Bild-Quelle.... kannst du dein Beispiel?
Ich bin mit Omar, ich in der Regel überspringen Sie die base64-Codierung, sofern notwendig
Bitte finden Sie in den aktualisierten Antworten mit meinen eigenen code!
InformationsquelleAutor Omar Mir
Ich glaube, Ihnen fehlen ein paar Dinge:
Können Sie nicht nur die Bildquelle ein ByteArray so. Ich habe erfolgreich die URLloader-Klasse abrufen, die ein ByteArray von Bildern für SQLite einfügen:
Versuchen, dass heraus, und schalten Sie die Ziele, wo nötig.
Ja, Sie können es erhalten, indem Sie die loader-Klassen, die Umwandlung der dataFormat zu BINÄREN und dann wird es ALS ByteArray - Es ist ein Kreisverkehr Art zu bekommen, um es, ich höre Ihnen zu, wenn Sie sagen, Sie sollten in der Lage sein, um es direkt. Aber c ' est la Flex. Lassen Sie mich Wurzel durch meine 4000 Lesezeichen und sehen, ob ich finden kann wo jemand erklärt, dies besser Ausdrücken.
ANMERKUNG: Alternativ können Sie nur verwenden
remoteImage.source = pic1
laden Sie das Bild auf-UI.Got to bounce für jetzt, aber ich werde schauen, dass Sachen, die für Sie später.
OK, ich bin auf der Suche in die Lader um zu sehen, was ist der deal...
InformationsquelleAutor SQLiteNoob