I'm very new to Haskell so I apologise if this is too basic, or if it makes very little sense. I'm trying to read an image; I can get it to a list of pixel data with the following code:
data Pixel = Pixel {
red :: Integer,
green :: Integer,
blue :: Integer,
alpha :: Integer
} deriving (Show)
getImagePixelArray :: FilePath -> IO (Codec.Picture.Repa.Img RGBA)
getImagePixelArray fp = do
img <- (either error return =<< readImageRGBA fp)
return img
getImagePixelData :: Codec.Picture.Repa.Img RGBA -> [(Word8,Word8,Word8,Word8)]
getImagePixelData img = R.toList (collapseColorChannel img)
rawPixelToPixel :: (Word8,Word8,Word8,Word8) -> Pixel
rawPixelToPixel (r, g, b, a) = Pixel {
red = (toInteger r),
green = (toInteger g),
blue = (toInteger b),
alpha = (toInteger a)
}
main = do
imageData <- getImagePixelArray "./images/image1.png"
let imageRawPixels = getImagePixelData imageData
let asPixels = Prelude.map rawPixelToPixel imageRawPixels
mapM print asPixels
I more or less follow what's going on, but my knowledge of Haskell is still limited, so when it comes to making sense of api documentation, I'm struggling a little.
I really want to be able to parse the positions of the pixels; I understand how to do that if I know the width and height of an image, but I can't figure out how to get the width/height of an image.
I'm making my way through a Haskell course, but I'm also trying to put it to some practical use along the way to help the concepts sink in.
Start with the documentation. None of what you're asking for is obviously available on Img, so where else could it be? There's a related Image type, mentioned in convertImage's documentation - I wonder what that is. As it turns out, it has a width and a height. How can we get an Image from our Img, then? imgToImage will give us a DynamicImage, which has several constructors each containing an Image. Figure out what kind of Image you have inside your DynamicImage, and then ask that Image its dimensions.
Perhaps there is something easier with the other lens-y stuff in that module, but it is not obvious to me, and this approach seems simple enough, if a hassle.
Related
Does anyone know how to read a pixel from images using Haskell? I am now using a juicy pixel as a library.
Thanks for your help!
JuicyPixel provides the pixelAt function to get a pixel at a given coordinate.
pixelAt :: Image a -> Int -> Int -> a
Extract a pixel at a given position, (x, y), the origin is assumed to be at the corner top left, positive y to the bottom of the image
I'd like to build a function that takes a given Unicode character and a given TrueType font and rasterises the corresponding glyph into a two-dimensional 1-bit-per-pixel bitmap.
Something similar to this:
rasterize :: Font -> Char -> Size -> Bitmap
rasterize font char size = ...
Requirements
The rasterize function should:
produce a bitmap of maximal width w and height h, such that w <= size and h <= size
rasterize the glyph so that it completely fills the bitmap, leaving no padding.
The Bitmap type should support the following operations (or similar):
width :: Bitmap -> Int
height :: Bitmap -> Int
bit :: Bitmap -> (Int, Int) -> Bool
where bit b (x, y) should evaluate to True if (and only if) the bit within Bitmap b at index position (x, y) is set.
Question
Are there any Haskell libraries that can already do this, or something similar?
Example
Evaluating the expression rasterize fontUtopiaStandard 'o' 64 would result in a Bitmap b that if rendered would look similar to the following image (viewed at 800% scale, with grid), where (width b, height b) = (60, 64):
Notes
I've already tried using the stb-truetype package, but any attempts to get at the pixel data seem to cause segmentation faults, even when compiling with version of GHC (6.12) similar to the version on which the package was tested. (I can provide more details of the segfaulting code if anyone's interested.)
I'm aware of the existence of libraries that render TrueType fonts within an OpenGL context, but I can't see how to get access to the pixel data.
I've been reading the source code of the Haskell Chart package as I find the charts it creates are very good. But I'm stumped on how it works.
In particular, there is a type PickFn that is used by the render function:
type PickFn a = Point -> Maybe a
data Renderable a = Renderable {
minsize :: ChartBackend RectSize,
render :: RectSize -> ChartBackend (PickFn a)
}
class ToRenderable a where
toRenderable :: a -> Renderable ()
Commentary for PickFn is "A function that maps a point in device coordinates to some value." which unfortunately doesn't mean anything to me.
My ultimate goal is to be able to follow the code to learn how it draws its charts, but I'd like to start with "what is a pick function" so that I can at least understand the types.
The pick function is a convenience to the client of the Chart library - it lets you map back from a point in the resulting image to the thing (that's the Maybe a) at that position.
For example, Graphics.Rendering.Chart.Layout.layoutToRenderable returns a Renderable (LayoutPick x y y) so that you can map back from a point in the picture back to a specific component of the layout - its legend, an axis title, the plot area, etc.
Using netwire-4.0.7
As the question title says, I'm trying to create a wire that produces positions (moving the position with a certain velocity in each step), "bouncing" off other objects. The simplest example I could think of was moving within a box, like in some screen savers.
I wrote this function as an attempt to do just that (for one axis only):
import Control.Wire
bouncyWire :: Double -> Double -> Double -> Double -> Wire () IO a Double
bouncyWire startPosition startVelocity lowerBound upperBound = proc _ -> do
rec
v <- delay startVelocity -< if p < lowerBound || p > upperBound
then -v else v
p <- integral_ startPosition -< v
returnA -< p
(I actually use it with a different monad, but this code doesn't actually use it and it would overcomplicate the issue here).
Stepping it with a counterSession $ 1/60 however, I get a problem - instead of "bouncing" off the wall, it gets stuck there. I think what happens is that it keeps flipping the velocity v over and over, but I'm not sure why. I think I might be using delay wrong or something.
As Richard Huxton explained, your wire is getting stuck behind the border. One solution is to check that you don't just reverse velocities, you always point them to the right direction. This way, the wire gets always from behind the border. Another solution is to change the position back inside the borders if it gets out. This way, the wire is never perceived to get behind (which is something you usually want to do in games). Combined together it could look like
import Prelude hiding ((.), id)
import Control.Category
import Control.Wire
import Control.Wire.Wire
import Control.Wire.Prefab.Move
bouncyWire :: (Monad m)
=> Double -> Double -> Double -> Double -> Wire () m a Double
bouncyWire startPosition startVelocity lowerBound upperBound =
objPosition <$> object_ update (ObjectState startPosition startVelocity)
. constant (Accelerate 0, ())
where
update _ s#(ObjectState pos vel)
| (pos > upperBound) = ObjectState (2*upperBound - pos) (- abs vel)
| (pos < lowerBound) = ObjectState (2*lowerBound - pos) (abs vel)
| otherwise = s
I'm not very familiar with the arrow notation so I used Category and Applicative notation (composition of wires using .). For this task, object_ is particularly handy. It integrates the velocity and loops internally and all we need to do is to give it a modifying function and extract position from the output.
Ah, a chance to recyle knowledge from my days messing around writing 8-bit games in a mix of BASIC and assembler!
What's probably happening is that the "ball" is getting stuck just the wrong side of the wall due to rounding errors. So - if your wall is at 10.0, the ball oscillates between 11.0001 and 10.0001 with v=-1.0,+1.0,-1.0 etc. Not sure how you'd print the position to check with wires.
From (ancient) memory, you either want to calculate the bounce including any "leftover" vector from the previous step, or just place the ball exactly on the wall before bouncing it.
I'm using the Fungen framework for Haskell and there is a function that uses BitmapFonts. The thing is, that the only BitmapFonts I can use are the ones that come with GLUT, here is the data:
data BitmapFont
= Fixed8By13
| Fixed9By15
| TimesRoman10
| TimesRoman24
| Helvetica10
| Helvetica12
| Helvetica18
These fonts are very small for my application, and I want to use another BitmapFont, not just these, or make one of these bigger. How can I do it?
Here's the source of putGameText:
putGameText :: [Text] -> IO ()
putGameText [] = return ()
putGameText ((text,font,(x,y),r,g,b):ts) = do
loadIdentity
color (Color3 r g b)
rasterPos (Vertex2 x y)
renderString font text
putGameText ts
As I understand it, FunGEn's Text type constrains font to a fixed-size BitMapFont:
type Text = (String, BitmapFont, (GLdouble, GLdouble), GLclampf, GLclampf, GLclampf)
but renderString can also take a StrokeFont, which is even more limited in font family but responds to standard OpenGL scaling/transformation/rotation.
So, a good start might be to make myPutGameText that accepts a StrokeFont-capable MyText and does a scaling transform before rendering. Here's some pseudo-code which I hope someone will correct:
type MyText = (String, StrokeFont, (GLdouble, GLdouble), GLclampf, GLclampf, GLclampf)
myPutGameText :: [MyText] -> (GLDouble,GLDouble,GLDouble) -> IO ()
myPutGameText [] _ = return ()
myPutGameText ((text,font,(x,y),r,g,b):ts) (sx,sy,sz) = do
loadIdentity
preservingMatrix $ do
scale sx sy sz
color (Color3 r g b)
rasterPos (Vertex2 x y)
renderString font text
putGameText ts
For richer font rendering, the answer is probably to integrate something like FTGL.