2010-06-27 18 views
6

मैं एक पीएनजी फ़ाइल लोड करने की कोशिश कर रहा हूं, असंपीड़ित आरजीबीए बाइट्स प्राप्त करें, फिर उन्हें gzip या zlib संकुल में भेजें।मैं एक आलसी बाइटस्ट्रिंग में एक (StorableArray (Int, Int) Word8) को कैसे परिवर्तित कर सकता हूं?

pngload पैकेज छवि डेटा को एक (StorableArray (Int, Int) Word8) देता है, और संपीड़न पैकेज आलसी बाइटस्ट्रिंग लेते हैं। इसलिए, मैं एक (StorableArray (Int, Int) Word8 -> बाइटस्ट्रिंग) फ़ंक्शन बनाने का प्रयास कर रहा हूं।

import qualified Codec.Image.PNG as PNG 
import Control.Monad (mapM) 
import Data.Array.Storable (withStorableArray) 
import qualified Data.ByteString.Lazy as LB (ByteString, pack, take) 
import Data.Word (Word8) 
import Foreign (Ptr, peekByteOff) 

main = do 
    -- Load PNG into "image"... 
    bytes <- withStorableArray 
     (PNG.imageData image) 
     (bytesFromPointer lengthOfImageData) 

bytesFromPointer :: Int -> Ptr Word8 -> IO LB.ByteString 
bytesFromPointer count pointer = LB.pack $ 
    mapM (peekByteOff pointer) [0..(count-1)] 

यह स्मृति से बाहर चलाने के लिए ढेर का कारण बनता है, तो स्पष्ट रूप से मैं कुछ बहुत गलत कर रहा हूँ:

अब तक, मैं निम्नलिखित की कोशिश की है। पीआरटी और विदेशी पीआरटी के साथ मैं और अधिक चीजें कोशिश कर सकता हूं, लेकिन वहां बहुत सारे "असुरक्षित" कार्य हैं।

यहां कोई भी सहायता की सराहना की जाएगी; मैं काफी स्टंप हूँ।

उत्तर

7

आम तौर पर, पैक और अनपैक प्रदर्शन के लिए एक बुरा विचार है। यदि आप एक PTR और बाइट्स में लंबाई है, तो आप दो अलग अलग तरीकों एक सख्त bytestring उत्पन्न कर सकते हैं:

इस तरह

:

import qualified Codec.Image.PNG as PNG 
import Control.Monad 
import Data.Array.Storable (withStorableArray) 

import Codec.Compression.GZip 

import qualified Data.ByteString.Lazy as L 
import qualified Data.ByteString.Unsafe as S 

import Data.Word 
import Foreign 

-- Pack a Ptr Word8 as a strict bytestring, then box it to a lazy one, very 
-- efficiently 
bytesFromPointer :: Int -> Ptr Word8 -> IO L.ByteString 
bytesFromPointer n ptr = do 
    s <- S.unsafePackCStringLen (castPtr ptr, n) 
    return $! L.fromChunks [s] 

-- Dummies, since they were not provided 
image = undefined 
lengthOfImageData = 10^3 

-- Load a PNG, and compress it, writing it back to disk 
main = do 
    bytes <- withStorableArray 
     (PNG.imageData image) 
     (bytesFromPointer lengthOfImageData) 
    L.writeFile "foo" . compress $ bytes 

मैं ओ (1) संस्करण का उपयोग कर रहा हूं, जो सिर्फ StorableArray से पीआरटी को दोबारा मरम्मत करता है। आप "packCStringLen" के माध्यम से इसे पहले कॉपी करना चाहेंगे।

+0

यह बहुत अच्छी तरह से काम करता है। सहायता के लिए धन्यवाद! –

3

आपके "बाइट्सप्रोमॉन्टर" के साथ समस्या यह है कि आप पैक किए गए प्रतिनिधित्व, stgalArray को pngload से लेते हैं, और आप इसे एक दूसरे पैक किए गए प्रतिनिधित्व, एक बाइटस्ट्रिंग में परिवर्तित करना चाहते हैं, जो मध्यवर्ती सूची में जा रहा है। कभी-कभी आलस्य का मतलब है कि मध्यवर्ती सूची स्मृति में नहीं बनाई जाएगी, लेकिन यह मामला यहां नहीं है।

फ़ंक्शन "मैपएम" पहला अपराधी है। आप mapM (peekByteOff pointer) [0..(count-1)] का विस्तार यदि आप

el0 <- peekByteOff pointer 0 
el1 <- peekByteOff pointer 1 
el2 <- peekByteOff pointer 2 
... 
eln <- peekByteOff pointer (count-1) 
return [el0,el1,el2,...eln] 

क्योंकि इन कार्यों सभी आईओ इकाई के भीतर हो, वे क्रम में क्रियान्वित कर रहे हैं मिलता है। इसका मतलब यह है कि आउटपुट सूची के हर तत्व को सूची बनाने से पहले बनाया जाना चाहिए और आलस्य में कभी आपकी मदद करने का मौका नहीं है।

भले ही सूची को आलसी बनाया गया हो, भले ही डॉन स्टीवर्ट "पैक" फ़ंक्शन को इंगित करता है, फिर भी आपके प्रदर्शन को बर्बाद कर देगा। "पैक" के साथ समस्या यह है कि यह जानने की जरूरत है कि स्मृति में सही मात्रा आवंटित करने के लिए सूची में कितने तत्व हैं। सूची की लंबाई खोजने के लिए, कार्यक्रम को अंत तक इसे पार करने की आवश्यकता है। लंबाई की गणना करने की आवश्यकता के कारण, सूची को पूरी तरह से लोड करने की आवश्यकता होगी इससे पहले कि इसे एक बाईट्रिंग में पैक किया जा सके।

मैं कोड पैक के साथ "पैक" के साथ "मैपएम" पर विचार करता हूं। कभी-कभी आप "mapM_" के साथ "mapM" को प्रतिस्थापित कर सकते हैं, लेकिन इस मामले में बाइटस्ट्रिंग सृजन कार्यों का उपयोग करना बेहतर होता है, उदा। "PackCStringLen"।

संबंधित मुद्दे