#FEATURE by cg
class: Image
added:
#chromaBlueOfYCbCr:
#chromaRedOfYCbCr:
#lumaOfYCbCr:
changed: #rgbFromValue:
--- a/Image.st Sun Aug 27 19:59:56 2017 +0200
+++ b/Image.st Sun Aug 27 20:00:15 2017 +0200
@@ -13957,6 +13957,98 @@
"Created: 22.10.1997 / 23:52:40 / cg"
!
+chromaBlueOfYCbCr:pixel
+ "if the receiver is an YCbCr-image:
+ return the blue-chroma (Cb) component, scaled to (0 .. 1)"
+
+ |cbBits "{ Class: SmallInteger }"
+ crBits "{ Class: SmallInteger }"
+ s "{ Class: SmallInteger }"|
+
+ photometric == #YCbCr ifTrue:[
+ samplesPerPixel == 3 ifTrue:[
+ "/ assume that the Y bits are the leftMost bits
+ cbBits := bitsPerSample at:2.
+ cbBits == 0 ifTrue:[^ 0].
+ crBits := bitsPerSample at:3.
+
+ s := (1 bitShift:cbBits) - 1.
+
+ ^ 1.0 / s * ((pixel rightShift:crBits) bitAnd:(1 bitShift:cbBits)-1)
+ ].
+ ].
+ self subclassResponsibility
+
+ "Created: / 26-08-2017 / 22:09:31 / cg"
+!
+
+chromaRedOfYCbCr:pixel
+ "if the receiver is an YCbCr-image:
+ return the red-chroma (Cr) component, scaled to (0 .. 1)"
+
+ |crBits "{ Class: SmallInteger }"
+ s "{ Class: SmallInteger }"|
+
+ samplesPerPixel >= 3 ifTrue:[
+ "/ assume that the red bits are the leftMost bits
+
+ crBits := bitsPerSample at:3.
+ crBits == 0 ifTrue:[^ 0].
+
+ s := (1 bitShift:crBits) - 1.
+
+ ^ 1.0 / s * (pixel bitAnd:(1 bitShift:crBits)-1)
+ ].
+
+ self subclassResponsibility
+
+ "
+ (self basicNew
+ bitsPerSample:#(8 8 8);
+ photometric:#YCbCr;
+ samplesPerPixel:3;
+ yourself
+ ) chromaRedOfYCbCr: 16r10107F
+
+ (self basicNew
+ bitsPerSample:#(8 8 8);
+ photometric:#YCbCr;
+ samplesPerPixel:3;
+ yourself
+ ) chromaRedOfYCbCr: 16r1010FF
+
+ (self basicNew
+ bitsPerSample:#(8 8 8);
+ photometric:#YCbCr;
+ samplesPerPixel:3;
+ yourself
+ ) chromaBlueOfYCbCr: 16r107F10
+
+ (self basicNew
+ bitsPerSample:#(8 8 8);
+ photometric:#YCbCr;
+ samplesPerPixel:3;
+ yourself
+ ) chromaBlueOfYCbCr: 16r10FF10
+
+ (self basicNew
+ bitsPerSample:#(8 8 8);
+ photometric:#YCbCr;
+ samplesPerPixel:3;
+ yourself
+ ) lumaOfYCbCr: 16r7F1010
+
+ (self basicNew
+ bitsPerSample:#(8 8 8);
+ photometric:#YCbCr;
+ samplesPerPixel:3;
+ yourself
+ ) lumaOfYCbCr: 16rFF1010
+ "
+
+ "Created: / 26-08-2017 / 22:11:31 / cg"
+!
+
colorFromValue:pixelValue
"given a pixel value, return the corresponding color.
Pixel values start with 0.
@@ -14223,6 +14315,23 @@
"Created: 22.4.1997 / 14:12:02 / cg"
!
+lumaOfYCbCr:pixel
+ "if the receiver is an YCbCr-image:
+ return the luma (Y) component, scaled to (0 .. 1)"
+
+ photometric == #YCbCr ifTrue:[
+ samplesPerPixel == 3 ifTrue:[
+ "/ assume that the Y bits are the leftMost bits
+ (#[8 8 8] isSameSequenceAs:bitsPerSample)ifTrue:[
+ ^ 1.0 / 255 * ((pixel bitShift:-16) bitAnd:16rFF)
+ ]
+ ].
+ ].
+ self subclassResponsibility
+
+ "Created: / 26-08-2017 / 22:06:36 / cg"
+!
+
magentaComponentOfCMY:pixel
"if the receiver is a cmy-image:
return the magenta component scaled to a percentage (0 .. 100) of a pixelValue."
@@ -14506,7 +14615,7 @@
The implementation below is generic and slow
- this method is typically redefined in subclasses."
- |p maxPixel clr r g b c m y k|
+ |p maxPixel clr r g b c m y k cb cr|
p := photometric.
p isNil ifTrue:[
@@ -14567,9 +14676,40 @@
^ (Color cyan:c magenta:m yellow:y) rgbValue.
].
+ p == #YCbCr ifTrue:[
+ y := self lumaOfYCbCr:pixelValue.
+ cb := self chromaBlueOfYCbCr:pixelValue.
+ cr := self chromaRedOfYCbCr:pixelValue.
+ ^ (Color luma:y chromaBlue:cb chromaRed:cr) rgbValue.
+ ].
+
self error:'invalid (unsupported) photometric'
- "Modified: / 22-08-2017 / 18:31:36 / cg"
+ "
+ (self basicNew
+ bitsPerSample:#(8 8 8);
+ photometric:#YCbCr;
+ samplesPerPixel:3;
+ yourself
+ ) rgbFromValue: 16r7F1010
+
+ (self basicNew
+ bitsPerSample:#(8 8 8);
+ photometric:#YCbCr;
+ samplesPerPixel:3;
+ yourself
+ ) rgbFromValue: 16rFF1010
+
+ (self basicNew
+ bitsPerSample:#(8 8 8);
+ photometric:#YCbCr;
+ samplesPerPixel:3;
+ yourself
+ ) rgbFromValue: 16rFF0000
+ "
+
+ "Modified: / 26-08-2017 / 20:56:49 / cg"
+ "Modified (comment): / 26-08-2017 / 22:18:14 / cg"
!
usedColors