@@ -479,6 +479,10 @@ export class Glyph extends EezObject {
479479
480480 if ( font . bpp === 8 || project . projectTypeTraits . isLVGL ) {
481481 ctx . globalAlpha = pixelValue / 255 ;
482+ } else if ( font . bpp === 4 ) {
483+ ctx . globalAlpha = pixelValue / 15 ;
484+ } else if ( font . bpp === 2 ) {
485+ ctx . globalAlpha = pixelValue / 3 ;
482486 }
483487
484488 if ( pixelValue ) {
@@ -835,12 +839,23 @@ export class Glyph extends EezObject {
835839 0
836840 ) ;
837841
842+ const font = this . font ;
843+ const maxAlpha = ( 1 << font . bpp ) - 1 ;
838844 for ( let x = 0 ; x < this . glyphBitmap . width ; x ++ ) {
839845 for ( let y = 0 ; y < this . glyphBitmap . height ; y ++ ) {
840846 const i = ( y * this . glyphBitmap . width + x ) * 4 ;
841- buffer [ i + 0 ] = 255 - this . getPixel ( x , y ) ;
842- buffer [ i + 1 ] = 255 - this . getPixel ( x , y ) ;
843- buffer [ i + 2 ] = 255 - this . getPixel ( x , y ) ;
847+ const pixel = this . getPixel ( x , y ) ;
848+ const value =
849+ font . bpp === 8
850+ ? pixel
851+ : font . bpp === 1
852+ ? pixel
853+ ? 255
854+ : 0
855+ : Math . round ( ( pixel * 255 ) / maxAlpha ) ;
856+ buffer [ i + 0 ] = 255 - value ;
857+ buffer [ i + 1 ] = 255 - value ;
858+ buffer [ i + 2 ] = 255 - value ;
844859 buffer [ i + 3 ] = 255 ;
845860 }
846861 }
@@ -1264,9 +1279,148 @@ const ChangeBitsPerPixel = observer(
12641279 }
12651280 } ) ;
12661281
1282+ const newBpp = result . values . bpp ;
1283+
1284+ if ( font . bpp === newBpp ) {
1285+ return ;
1286+ }
1287+
1288+ // Group glyphs by their source file path and size.
1289+ // Glyphs with their own GlyphSource use that; others
1290+ // fall back to the font-level FontSource.
1291+ const sourceGroups = new Map <
1292+ string ,
1293+ {
1294+ relativeFilePath : string ;
1295+ size : number ;
1296+ encodings : number [ ] ;
1297+ }
1298+ > ( ) ;
1299+
1300+ for ( const glyph of font . glyphs ) {
1301+ const relPath =
1302+ glyph . source ?. filePath || font . source ?. filePath ;
1303+ const size =
1304+ glyph . source ?. size ||
1305+ font . source ?. size ||
1306+ font . height ;
1307+
1308+ if ( ! relPath ) {
1309+ continue ;
1310+ }
1311+
1312+ const key = `${ relPath } \0${ size } ` ;
1313+ let group = sourceGroups . get ( key ) ;
1314+ if ( ! group ) {
1315+ group = {
1316+ relativeFilePath : relPath ,
1317+ size,
1318+ encodings : [ ]
1319+ } ;
1320+ sourceGroups . set ( key , group ) ;
1321+ }
1322+ group . encodings . push ( glyph . encoding ) ;
1323+ }
1324+
1325+ if ( sourceGroups . size === 0 ) {
1326+ projectStore . updateObject ( font , {
1327+ bpp : newBpp
1328+ } ) ;
1329+ return ;
1330+ }
1331+
1332+ // Extract glyphs from each source file
1333+ const allNewGlyphs = new Map <
1334+ number ,
1335+ {
1336+ x : number ;
1337+ y : number ;
1338+ width : number ;
1339+ height : number ;
1340+ dx : number ;
1341+ glyphBitmap ?: any ;
1342+ }
1343+ > ( ) ;
1344+
1345+ let firstFontProperties : any ;
1346+
1347+ try {
1348+ for ( const group of sourceGroups . values ( ) ) {
1349+ // Build encoding ranges from sorted encodings
1350+ const sorted = group . encodings . slice ( ) . sort (
1351+ ( a , b ) => a - b
1352+ ) ;
1353+ const encodings : EncodingRange [ ] = [ ] ;
1354+ let i = 0 ;
1355+ while ( i < sorted . length ) {
1356+ const from = sorted [ i ] ;
1357+ while (
1358+ i + 1 < sorted . length &&
1359+ sorted [ i + 1 ] === sorted [ i ] + 1
1360+ ) {
1361+ i ++ ;
1362+ }
1363+ encodings . push ( { from, to : sorted [ i ] } ) ;
1364+ i ++ ;
1365+ }
1366+
1367+ const fontProperties = await extractFont ( {
1368+ name : font . name ,
1369+ absoluteFilePath :
1370+ projectStore . getAbsoluteFilePath (
1371+ group . relativeFilePath
1372+ ) ,
1373+ embeddedFontFile : font . embeddedFontFile ,
1374+ relativeFilePath : group . relativeFilePath ,
1375+ renderingEngine : font . renderingEngine ,
1376+ bpp : newBpp ,
1377+ size : group . size ,
1378+ threshold : font . threshold ,
1379+ createGlyphs : true ,
1380+ encodings,
1381+ createBlankGlyphs : false ,
1382+ doNotAddGlyphIfNotFound : true
1383+ } ) ;
1384+
1385+ if ( ! firstFontProperties ) {
1386+ firstFontProperties = fontProperties ;
1387+ }
1388+
1389+ for ( const g of fontProperties . glyphs ) {
1390+ allNewGlyphs . set ( g . encoding , g ) ;
1391+ }
1392+ }
1393+ } catch ( error ) {
1394+ notification . error (
1395+ `Failed to change bits per pixel: ${ error } `
1396+ ) ;
1397+ return ;
1398+ }
1399+
1400+ projectStore . undoManager . setCombineCommands ( true ) ;
1401+
12671402 projectStore . updateObject ( font , {
1268- bpp : result . values . bpp
1403+ bpp : firstFontProperties . bpp ,
1404+ ascent : firstFontProperties . ascent ,
1405+ descent : firstFontProperties . descent ,
1406+ height : firstFontProperties . height
12691407 } ) ;
1408+
1409+ for ( const glyph of font . glyphs ) {
1410+ const newGlyphProps = allNewGlyphs . get ( glyph . encoding ) ;
1411+ if ( newGlyphProps ) {
1412+ projectStore . updateObject ( glyph , {
1413+ x : newGlyphProps . x ,
1414+ y : newGlyphProps . y ,
1415+ width : newGlyphProps . width ,
1416+ height : newGlyphProps . height ,
1417+ dx : newGlyphProps . dx ,
1418+ glyphBitmap : newGlyphProps . glyphBitmap
1419+ } ) ;
1420+ }
1421+ }
1422+
1423+ projectStore . undoManager . setCombineCommands ( false ) ;
12701424 } ;
12711425
12721426 render ( ) {
@@ -1426,7 +1580,9 @@ export class Font extends EezObject {
14261580 readOnlyInPropertyGrid : true ,
14271581 enumDisallowUndefined : true ,
14281582 disabled : ( font : Font ) =>
1429- ( isNotV1Project ( font ) && ! isLVGLProject ( font ) ) ||
1583+ ( isNotV1Project ( font ) &&
1584+ ! isLVGLProject ( font ) &&
1585+ ! isEezGuiLiteProject ( font ) ) ||
14301586 ( isLVGLProject ( font ) && font . lvglUseFreeType )
14311587 } ,
14321588 {
@@ -1436,14 +1592,15 @@ export class Font extends EezObject {
14361592 propertyGridFullRowComponent : ChangeBitsPerPixel ,
14371593 skipSearch : true ,
14381594 disabled : ( font : Font ) =>
1439- ! isLVGLProject ( font ) ||
1595+ ( ! isLVGLProject ( font ) && ! isEezGuiLiteProject ( font ) ) ||
14401596 ( isLVGLProject ( font ) && font . lvglUseFreeType )
14411597 } ,
14421598 {
14431599 name : "threshold" ,
14441600 type : PropertyType . Number ,
14451601 defaultValue : 128 ,
1446- disabled : ( font : Font ) => isLVGLProject ( font ) || font . bpp == 8
1602+ disabled : ( font : Font ) =>
1603+ isLVGLProject ( font ) || font . bpp != 1
14471604 } ,
14481605 {
14491606 name : "height" ,
@@ -1977,8 +2134,10 @@ export class Font extends EezObject {
19772134 name : "bpp" ,
19782135 displayName : "Bits per pixel" ,
19792136 type : "enum" ,
1980- enumItems : [ 1 , 8 ] ,
1981- visible : ( ) => isV1Project ( parent )
2137+ enumItems : [ 1 , 2 , 4 , 8 ] ,
2138+ visible : ( ) =>
2139+ isV1Project ( parent ) ||
2140+ isEezGuiLiteProject ( parent )
19822141 } ,
19832142 {
19842143 name : "size" ,
0 commit comments