mir war gestern und heute etwas langweilig und da hab ich mal diese hübsche Procedures geschrieben, mit denen man PB-Images möglichst schnell und Cache-optimiert mittels 'DrawingBuffer()' und passenden Konvertierungsfunktionen für das interne Pixelformat in reine 2D-RGB- oder 2D-YCbCr-Arrays konvertieren kann.
Dabei ist ein Beispiel, das ein ausgewähltes JPG öffnet und die einzelnen Farbkanäle als neue JPGs mit passender Endung im selben Verzeichnis abspeichert.
Viel Spaß damit und wer Fehler findet -> Kommentar!
Achja, als Testbild bietet sich zum Beispiel dieses hier aus Wikimedia an: Barns grand tetons.jpg
Am Ende sollte diese Aufteilung heraus kommen: Barns grand tetons YCbCr separation.jpg
Code: Alles auswählen
EnableExplicit
Prototype.l getDrawingBufferRGB(*address.Integer)
Prototype setDrawingBufferRGB(*address.integer, rgb.l)
Procedure.l getDrawingBufferRGB_8Bits(*address.Integer) ;RRRGGGBB
Protected g.a = PeekA(*address\i)
*address\i + 1
ProcedureReturn RGB((g >> 5) << 5, ((g >> 2) & $7) << 5, (g & $7) << 6)
EndProcedure
Procedure.l getDrawingBufferRGB_15Bits(*address.Integer) ;0RRRRRGG GGGBBBBB
Protected g.u = PeekU(*address\i)
*address\i + 2
ProcedureReturn RGB((g >> 10) << 3, ((g >> 5) & $1F) << 3, (g & $1F) << 3)
EndProcedure
Procedure.l getDrawingBufferRGB_16Bits(*address.Integer) ;RRRRRGGG GGGBBBBB
Protected g.u = PeekU(*address\i)
*address\i + 2
ProcedureReturn RGB((g >> 11) << 3, ((g >> 5) & $3F) << 2, (g & $1F) << 3)
EndProcedure
Procedure.l getDrawingBufferRGB_24Bits_RGB(*address.Integer) ;RRRRRRRR GGGGGGGG BBBBBBBB
Protected r.a = PeekA(*address\i)
Protected g.a = PeekA(*address\i + 1)
Protected b.a = PeekA(*address\i + 2)
*address\i + 3
ProcedureReturn RGB(r, g, b)
EndProcedure
Procedure.l getDrawingBufferRGB_24Bits_BGR(*address.Integer) ;BBBBBBBB GGGGGGGG RRRRRRRR
Protected r.a = PeekA(*address\i)
Protected g.a = PeekA(*address\i + 1)
Protected b.a = PeekA(*address\i + 2)
*address\i + 3
ProcedureReturn RGB(b, g, r)
EndProcedure
Procedure.l getDrawingBufferRGB_32Bits_RGBA(*address.Integer) ;RRRRRRRR GGGGGGGG BBBBBBBB 00000000
Protected r.a = PeekA(*address\i)
Protected g.a = PeekA(*address\i + 1)
Protected b.a = PeekA(*address\i + 2)
Protected a.a = PeekA(*address\i + 3)
*address\i + 4
ProcedureReturn RGB(r, g, b)
EndProcedure
Procedure.l getDrawingBufferRGB_32Bits_BGRA(*address.Integer) ;BBBBBBBB GGGGGGGG RRRRRRRR 00000000
Protected b.a = PeekA(*address\i)
Protected g.a = PeekA(*address\i + 1)
Protected r.a = PeekA(*address\i + 2)
Protected a.a = PeekA(*address\i + 3)
*address\i + 4
ProcedureReturn RGB(r, g, b)
EndProcedure
Procedure.i getDrawingBufferRGB(pixelFormat.i)
pixelFormat & ~#PB_PixelFormat_ReversedY
Select pixelFormat
Case #PB_PixelFormat_15Bits
ProcedureReturn @getDrawingBufferRGB_15Bits()
Case #PB_PixelFormat_16Bits
ProcedureReturn @getDrawingBufferRGB_16Bits()
Case #PB_PixelFormat_24Bits_BGR
ProcedureReturn @getDrawingBufferRGB_24Bits_BGR()
Case #PB_PixelFormat_24Bits_RGB
ProcedureReturn @getDrawingBufferRGB_24Bits_RGB()
Case #PB_PixelFormat_32Bits_BGR
ProcedureReturn @getDrawingBufferRGB_32Bits_BGRA()
Case #PB_PixelFormat_32Bits_RGB
ProcedureReturn @getDrawingBufferRGB_32Bits_RGBA()
Case #PB_PixelFormat_8Bits
ProcedureReturn @getDrawingBufferRGB_8Bits()
EndSelect
ProcedureReturn 0
EndProcedure
Procedure setDrawingBufferRGB_8Bits(*address.Integer, rgb.l) ;RRRGGGBB
PokeA(*address\i, (((Red(rgb) >> 5) << 5) | ((Green(rgb) >> 5) << 2) | (Blue(rgb) >> 6)))
*address\i + 1
EndProcedure
Procedure setDrawingBufferRGB_15Bits(*address.Integer, rgb.l) ;0RRRRRGG GGGBBBBB
PokeU(*address\i, (((Red(rgb) >> 3) << 10) | ((Green(rgb) >> 3) << 5) | (Blue(rgb) >> 3)))
*address\i + 2
EndProcedure
Procedure setDrawingBufferRGB_16Bits(*address.Integer, rgb.l) ;RRRRRGGG GGGBBBBB
PokeU(*address\i, (((Red(rgb) >> 3) << 11) | ((Green(rgb) >> 2) << 5) | (Blue(rgb) >> 3)))
*address\i + 2
EndProcedure
Procedure setDrawingBufferRGB_24Bits_RGB(*address.Integer, rgb.l) ;RRRRRRRR GGGGGGGG BBBBBBBB
PokeA(*address\i, Red(rgb))
PokeA(*address\i + 1, Green(rgb))
PokeA(*address\i + 2, Blue(rgb))
*address\i + 3
EndProcedure
Procedure setDrawingBufferRGB_24Bits_BGR(*address.Integer, rgb.l) ;BBBBBBBB GGGGGGGG RRRRRRRR
PokeA(*address\i, Blue(rgb))
PokeA(*address\i + 1, Green(rgb))
PokeA(*address\i + 2, Red(rgb))
*address\i + 3
EndProcedure
Procedure setDrawingBufferRGB_32Bits_RGBA(*address.Integer, rgba.l) ;RRRRRRRR GGGGGGGG BBBBBBBB 00000000
PokeA(*address\i, Red(rgba))
PokeA(*address\i + 1, Green(rgba))
PokeA(*address\i + 2, Blue(rgba))
PokeA(*address\i + 3, Alpha(rgba))
EndProcedure
Procedure setDrawingBufferRGB_32Bits_BGRA(*address.Integer, rgba.l) ;BBBBBBBB GGGGGGGG RRRRRRRR 00000000
PokeA(*address\i, Blue(rgba))
PokeA(*address\i + 1, Green(rgba))
PokeA(*address\i + 2, Red(rgba))
PokeA(*address\i + 3, Alpha(rgba))
EndProcedure
Procedure.i setDrawingBufferRGB(pixelFormat.i)
pixelFormat & ~#PB_PixelFormat_ReversedY
Select pixelFormat
Case #PB_PixelFormat_15Bits
ProcedureReturn @setDrawingBufferRGB_15Bits()
Case #PB_PixelFormat_16Bits
ProcedureReturn @setDrawingBufferRGB_16Bits()
Case #PB_PixelFormat_24Bits_BGR
ProcedureReturn @setDrawingBufferRGB_24Bits_BGR()
Case #PB_PixelFormat_24Bits_RGB
ProcedureReturn @setDrawingBufferRGB_24Bits_RGB()
Case #PB_PixelFormat_32Bits_BGR
ProcedureReturn @setDrawingBufferRGB_32Bits_BGRA()
Case #PB_PixelFormat_32Bits_RGB
ProcedureReturn @setDrawingBufferRGB_32Bits_RGBA()
Case #PB_PixelFormat_8Bits
ProcedureReturn @setDrawingBufferRGB_8Bits()
EndSelect
ProcedureReturn 0
EndProcedure
Structure YCbCr
y.a
cb.a
cr.a
EndStructure
Structure RGB
r.a
g.a
b.a
EndStructure
Structure YCbCrImage
width.i
height.i
Array img.YCbCr(0, 0)
EndStructure
Structure RGBImage
width.i
height.i
Array img.RGB(0, 0)
EndStructure
Procedure convertRGB2YCbCr(*in.RGBImage, *out.YCbCrImage)
Protected y.i, x.i, yc.f, cb.f, cr.f
Dim *out\img(*in\height, *in\width)
*out\width = *in\width
*out\height = *in\height
For y = 0 To *in\height - 1
For x = 0 To *in\width - 1
With *in\img(y, x)
yc = (0.299 * \r) + (0.587 * \g) + (0.114 * \b)
cb = 127.5 - (0.168736 * \r) - (0.331264 * \g) + (0.5 * \b)
cr = 127.5 + (0.5 * \r) - (0.418688 * \g) - (0.081312 * \b)
EndWith
With *out\img(y, x)
\y = Bool(yc >= 0.0) * yc - Bool(yc >= 255.5)
\cb = Bool(cb >= 0.0) * cb - Bool(cb >= 255.5)
\cr = Bool(cr >= 0.0) * cr - Bool(cr >= 255.5)
EndWith
Next
Next
ProcedureReturn #True
EndProcedure
Procedure convertYCbCr2RGB(*in.YCbCrImage, *out.RGBImage)
Protected y.i, x.i, r.f, g.f, b.f
Dim *out\img(*in\height, *in\width)
*out\width = *in\width
*out\height = *in\height
For y = 0 To *in\height - 1
For x = 0 To *in\width - 1
With *in\img(y, x)
r = (1.0 * \y) - (0.00000121889 * (\cb - 127.5)) + (1.402 * (\cr - 127.5))
g = (1.0 * \y) - (0.344136 * (\cb - 127.5)) - (0.714136 * (\cr - 127.5))
b = (1.0 * \y) + (1.772 * (\cb - 127.5)) + (0.00000406298 * (\cr - 127.5))
EndWith
With *out\img(y, x)
\r = Bool(r >= 0.0) * r - Bool(r >= 255.5)
\g = Bool(g >= 0.0) * g - Bool(g >= 255.5)
\b = Bool(b >= 0.0) * b - Bool(b >= 255.5)
EndWith
Next
Next
ProcedureReturn #True
EndProcedure
Procedure convertImg2RGB(in.i, *out.RGBImage)
Protected x.i, y.i = 0, yDir.i = 1
Protected color.l, pixelFormat.i, getRGB.getDrawingBufferRGB
Protected *pixelLine, *pixel
If Not IsImage(in)
ProcedureReturn #False
EndIf
*out\width = ImageWidth(in)
*out\height = ImageHeight(in)
Dim *out\img(*out\height, *out\width)
If StartDrawing(ImageOutput(in))
*pixelLine = DrawingBuffer()
pixelFormat = DrawingBufferPixelFormat()
getRGB = getDrawingBufferRGB(pixelFormat)
If pixelFormat & #PB_PixelFormat_ReversedY
y = *out\height - 1
yDir = -1
EndIf
While y >= 0 And y < *out\height
*pixel = *pixelLine
For x = 0 To *out\width - 1
With *out\img(y, x)
color = getRGB(@*pixel)
\r = Red(color)
\g = Green(color)
\b = Blue(color)
EndWith
Next
y + yDir
*pixelLine + DrawingBufferPitch()
Wend
StopDrawing()
Else
ProcedureReturn #False
EndIf
ProcedureReturn #True
EndProcedure
Procedure convertRGB2Img(*in.RGBImage, out.i)
Protected x.i, y.i = 0, yDir.i = 1
Protected color.l, pixelFormat.i, setRGB.setDrawingBufferRGB
Protected *pixelLine, *pixel
If Not IsImage(out)
ProcedureReturn #False
EndIf
If *in\width <> ImageWidth(out) Or *in\height <> ImageHeight(out)
ResizeImage(out, *in\width, *in\height, #PB_Image_Raw)
EndIf
If StartDrawing(ImageOutput(out))
*pixelLine = DrawingBuffer()
pixelFormat = DrawingBufferPixelFormat()
setRGB = setDrawingBufferRGB(pixelFormat)
If pixelFormat & #PB_PixelFormat_ReversedY
y = *in\height - 1
yDir = -1
EndIf
While y >= 0 And y < *in\height
*pixel = *pixelLine
For x = 0 To *in\width - 1
With *in\img(y, x)
setRGB(@*pixel, RGB(\r, \g, \b))
EndWith
Next
y + yDir
*pixelLine + DrawingBufferPitch()
Wend
StopDrawing()
Else
ProcedureReturn #False
EndIf
ProcedureReturn #True
EndProcedure
Procedure convertImg2YCbCr(in.i, *out.YCbCr)
Protected rgbImg.RGBImage
If convertImg2RGB(in, rgbImg)
ProcedureReturn convertRGB2YCbCr(rgbImg, *out)
EndIf
ProcedureReturn #False
EndProcedure
Procedure convertYCbCr2Img(*in.YCbCr, out.i)
Protected rgbImg.RGBImage
If convertYCbCr2RGB(*in, rgbImg)
ProcedureReturn convertRGB2Img(rgbImg, out)
EndIf
ProcedureReturn #False
EndProcedure
Procedure setYCbCr(*in.YCbCrImage, y.i = #PB_Ignore, cb.i = #PB_Ignore, cr.i = #PB_Ignore)
Protected xp.i, yp.i
With *in
For yp = 0 To \height - 1
For xp = 0 To \width - 1
If y <> #PB_Ignore
\img(yp, xp)\y = y
EndIf
If cb <> #PB_Ignore
\img(yp, xp)\cb = cb
EndIf
If cr <> #PB_Ignore
\img(yp, xp)\cr = cr
EndIf
Next
Next
EndWith
EndProcedure
;---------------------------------------------
Procedure.s addSuffixToPath(path.s, suffix.s)
Protected filePart.s = GetFilePart(path)
Protected extPart.s = GetExtensionPart(path)
ProcedureReturn GetPathPart(path) + Left(filePart, Len(filePart) - Len(extPart) - 1) + suffix + "." + extPart
EndProcedure
UseJPEGImageDecoder()
UseJPEGImageEncoder()
Define hImg.i, file.s, newFile.s, rgbImg.RGBImage, ycbcrImg.YCbCrImage
Define.i time
file.s = OpenFileRequester("JPG-Datei wählen...", GetHomeDirectory(), "JPG-Dateien (*.jpg)|*.jpg|Alle Dateien|*.*", 0)
time = ElapsedMilliseconds()
hImg = LoadImage(#PB_Any, file)
If Not hImg
MessageRequester("Fehler!", "Konnte Bild nicht öffnen.")
End
EndIf
DisableDebugger
;Konvertiere PB-Image in RGB-Image
convertImg2RGB(hImg, rgbImg)
;Konvertiere RGB-Image in YCbCr-Image nach JPG-Standard
convertRGB2YCbCr(rgbImg, ycbcrImg)
;Ignoriere Cb- und Cr-Kanal
setYCbCr(ycbcrImg, #PB_Ignore, 128, 128)
;Konvertiere zurück zu Image
convertYCbCr2Img(ycbcrImg, hImg)
;Speichere
newFile = addSuffixToPath(file, "_Y")
If Not SaveImage(hImg, newFile, #PB_ImagePlugin_JPEG)
MessageRequester("Fehler!", "Bild konnte nicht gespeichert werden: " + newFile)
EndIf
;Tu das selbe für die anderen Kanäle
convertRGB2YCbCr(rgbImg, ycbcrImg)
setYCbCr(ycbcrImg, 128, #PB_Ignore, 128)
convertYCbCr2Img(ycbcrImg, hImg)
newFile = addSuffixToPath(file, "_Cb")
If Not SaveImage(hImg, newFile, #PB_ImagePlugin_JPEG)
MessageRequester("Fehler!", "Bild konnte nicht gespeichert werden: " + newFile)
EndIf
convertRGB2YCbCr(rgbImg, ycbcrImg)
setYCbCr(ycbcrImg, 128, 128, #PB_Ignore)
convertYCbCr2Img(ycbcrImg, hImg)
newFile = addSuffixToPath(file, "_Cr")
If Not SaveImage(hImg, newFile, #PB_ImagePlugin_JPEG)
MessageRequester("Fehler!", "Bild konnte nicht gespeichert werden: " + newFile)
EndIf
time = ElapsedMilliseconds() - time
MessageRequester("Hinweis", "Konvertierung beendet." + #CRLF$ + "Benötigte Zeit: " + time + " ms")
EnableDebugger