Say I have an ASCII encoded text file mytextfile.txt and I want to print it.
I have found various sources on MSDN, but none of it seems useful:
From here:
Defines a reusable object that sends output to a printer, when printing from a Windows Forms application.
public ref class PrintDocument : Component
However this is meant for C++ (not C)
I also found this, which defines several functions, none of which actually seem to have the ability to print:
IPrintDocumentPackageStatusEvent: Represents the progress of the print job.
IPrintDocumentPackageTarget: Allows users to enumerate the supported package target types and to create one with a given type ID. IPrintDocumentPackageTarget also supports the tracking of the package printing progress and cancelling.
IPrintDocumentPackageTargetFactory: Used with IPrintDocumentPackageTarget for starting a print job.
Ah! That looks like it! Well it turns out that this is also for C++:
IPrintDocumentPackageTargetFactory::CreateDocumentPackageTargetForPrintJob
I think it is impracticle (and difficult) to try and imitate classes in C.
I could use the print command:
system("print mytextfile.txt");
But this does seem to be a bit of a hack, is there a better way to print a file using functions?
To clarify: I want this printing on paper not in terminal.
Here is some sample printing code for you that should do the job properly. It is a minimal, self-contained example that you should be able to just compile and run. Based on that, you should then be able to adapt it to your specific needs. First, here's the code, and then some explanatory notes.
Please note that I have written this as a Console app, but that's probably not what you actually want. Also, the function that does all the work (print_file()) is now callable from C as requested. OK, here's the code:
#include <windows.h>
#include <conio.h>
#include <string>
#include <fstream>
#include <iostream>
#define SCALE_FACTOR 100 // percent
inline static int MM_TO_PIXELS (int mm, int dpi)
{
return MulDiv (mm * 100, dpi, 2540);
}
// Calculate the wrapped height of a string
static int calculate_wrapped_string_height (HDC hDC, int width, const std::string& s)
{
RECT r = { 0, 0, width, 16384 };
DrawText (hDC, s.c_str (), (int) s.length (), &r, DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK);
return (r.bottom == 16384) ? calculate_wrapped_string_height (hDC, width, " ") : r.bottom;
}
// Print a string in the width provided.
static void print_string (HDC hDC, int x, int y, int width, const std::string& s)
{
RECT r = { x, y, x + width, 16384 };
DrawText (hDC, s.c_str (), (int) s.length (), &r, DT_NOPREFIX | DT_WORDBREAK);
}
// Print page number. Returns (y + vertical space consumed)
static int print_pagenum (HDC hDC, int x, int y, int width, int& pagenum)
{
std::string hdr = "Page: " + std::to_string (++pagenum) + "\n";
int space_needed = calculate_wrapped_string_height (hDC, width, hdr);
print_string (hDC, x, y, width, hdr);
std::cout << "Printing page: " << pagenum << "\n";
return space_needed;
}
extern "C" bool print_file (const char *filename)
{
std::ifstream f;
f.open ("g:\\temp\\print_me.txt", std::ios_base::in);
if (!f)
{
std::cout << "Cannot open input file, error " << GetLastError () << "\n";
return false;
}
// Display print dialog
PRINTDLGEX pdex = { sizeof (pdex) };
PRINTPAGERANGE pr [10] = { };
HDC hDC;
pdex.hwndOwner = GetDesktopWindow ();
pdex.Flags = PD_ALLPAGES | PD_RETURNDC | PD_NOCURRENTPAGE | PD_NOSELECTION;
pdex.nMaxPageRanges = _countof (pr);
pdex.nPageRanges = 1;
pr [0].nFromPage = pr [0].nToPage = 1;
pdex.lpPageRanges = pr;
pdex.nMinPage = 1;
pdex.nMaxPage = 999999;
pdex.nCopies = 1;
pdex.nStartPage = START_PAGE_GENERAL;
HRESULT hr = PrintDlgEx (&pdex);
if (hr != S_OK)
{
std::cout << "PrintDlgEx failed, error " << GetLastError () << "\n";
return false;
}
if (pdex.dwResultAction == PD_RESULT_CANCEL)
return false;
hDC = pdex.hDC;
if (pdex.dwResultAction != PD_RESULT_PRINT)
{
DeleteDC (hDC);
return false;
}
// Only print what we need to
int max_page = 0x7fffffff;
if (pdex.Flags & PD_PAGENUMS)
{
max_page = 0;
for (int i = 0; i < (int) pdex.nPageRanges; ++i)
{
if ((int) pdex.lpPageRanges [i].nToPage > max_page)
max_page = pdex.lpPageRanges [i].nToPage;
}
}
constexpr int dpi = 96 * 100 / SCALE_FACTOR;
int lpx = GetDeviceCaps (hDC, LOGPIXELSX);
int lpy = GetDeviceCaps (hDC, LOGPIXELSX);
int res_x = GetDeviceCaps (hDC, HORZRES);
int res_y = GetDeviceCaps (hDC, VERTRES);
// margins
int left_margin = MM_TO_PIXELS (10, dpi);
int top_margin = MM_TO_PIXELS (20, dpi);
int right_margin = MM_TO_PIXELS (20, dpi);
int bottom_margin = MM_TO_PIXELS (20, dpi);
int width = MulDiv (res_x, dpi, lpx) - (left_margin + right_margin);
int y_max = MulDiv (res_y, dpi, lpy) - bottom_margin;
// Set up for SCALE_FACTOR
SetMapMode (hDC, MM_ANISOTROPIC);
SetWindowExtEx (hDC, dpi, dpi, NULL);
SetViewportExtEx (hDC, lpx, lpy, NULL);
SetStretchBltMode (hDC, HALFTONE);
DOCINFO di = { 0 };
di.cbSize = sizeof (di);
di.lpszDocName = "Stack Overflow";
int job_id = StartDoc (hDC, &di);
if (job_id <= 0)
{
std::cout << "StartDoc failed, error " << GetLastError () << "\n";
DeleteDC (hDC);
return false;
}
SetBkMode (hDC, TRANSPARENT);
LOGFONT lf = { 0 };
lf.lfWeight = FW_NORMAL;
lf.lfHeight = -12;
HFONT hTextFont = CreateFontIndirect (&lf);
HFONT hOldFont = (HFONT) GetCurrentObject (hDC, OBJ_FONT);
SelectObject (hDC, hTextFont);
int x = left_margin;
int y = top_margin;
int pagenum = 0;
int err = StartPage (hDC);
if (err <= 0)
{
std::cout << "StartPage failed, error " << GetLastError () << "\n";
DeleteDC (hDC);
return false;
}
y += print_pagenum (hDC, x, y, width, pagenum);
// Printing loop, per line
for ( ; ; )
{
if (_kbhit ())
{
AbortDoc (hDC);
break;
}
std::string line;
std::getline (f, line);
if (!f)
break;
int space_needed = calculate_wrapped_string_height (hDC, width, line);
if (space_needed > y_max - y)
{
if (pagenum >= max_page)
break;
if (EndPage (hDC) < 0 || StartPage (hDC) < 0)
break;
y = top_margin;
y += print_pagenum (hDC, x, y, width, pagenum);
}
print_string (hDC, x, y, width, line);
y += space_needed;
}
EndPage (hDC);
EndDoc (hDC);
SelectObject (hDC, hOldFont);
DeleteObject (hTextFont);
DeleteDC (hDC);
return true;
}
// main
int main ()
{
bool ok = print_file ("g:\\temp\\print_me.txt");
return !ok;
}
Notes:
The code shows how to paginate the output properly. I included page numbers in he printed output, just for fun.
Input filename is hard-coded. Please adapt this to your needs.
As I say, this is written as a Console app. If you were including this in a Windows app you would use a different parent window handle and a different mechanism (a modeless dialog, typically) to report progress and to allow the user to cancel the print job.
The code as written expects to be compiled as ANSI (purely for convenience). I'm sure you can fix that.
This code doesn't handle page ranges entered by the user in the Windows standard Print dialog properly. I leave that as an exercise for the reader.
To make this code callable from C, compile it as a separate .cpp file (excluding main of course) and then prototype print_file (in a
separate .h file) as:
extern "C" bool print_file (const char *filename);
Then #include this file in both your .cpp file and your .c file (s).
Please note that bool is a predefined type - sort of - in C99 and later, see:
https://stackoverflow.com/a/1608350/5743288
You could read a line, print a line, in a loop, until EOF
Following EDITED to output to printer
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUF_SIZE 1024
int main( void )
{
char buffer[ MAX_BUF_SIZE ];
FILE *fin = fopen( "mytextfile.txt", "f" );
if( ! fin )
{
perror( "fopen failed for reading file" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
FILE *printer = fopen("LPT1", "w");
if( !printer )
{
perror( "fopen failed for printing" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
while( fgets( buffer, sizeof buffer, fin ) )
{
fprintf( printer, "%s", buffer );
}
fprintf( printer, "%s", "\n" );
fclose( fin );
fclose( printer );
return 0;
}
Related
I am super new to creating efi application. My aim is to create a small application in efi, that displays some text on a background. But I am stuck with trying to display text on the display (Great would be to have a custom font, but that is not necessary at this stage). I want the app (also) to run on apple systems (to boot from a usb)
How do I find good documentation on the EFI functions? It seems super hard to find good examples etc.
How can I display a text on a background with EFI?
This is what I got so far. I change the background to a color using the graphics protocol. How do I display a text on it. The Output String doesn't seem to work.
#include "efibind.h"
#include "efidef.h"
#include "efidevp.h"
#include "eficon.h"
#include "efiapi.h"
#include "efierr.h"
#include "efiprot.h"
static EFI_GUID GraphicsOutputProtocolGUID = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
/**
* efi_main - The entry point for the EFI application
* #image: firmware-allocated handle that identifies the image
* #SystemTable: EFI system table
*/
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) {
EFI_BOOT_SERVICES *bs = systemTable->BootServices;
EFI_STATUS status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *graphicsProtocol;
SIMPLE_TEXT_OUTPUT_INTERFACE *conOut = systemTable->ConOut;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
UINTN SizeOfInfo, sWidth, sHeight;
status = bs->LocateProtocol(&GraphicsOutputProtocolGUID, NULL,
(void**)&graphicsProtocol);
if (EFI_ERROR(status) || graphicsProtocol == NULL) {
conOut->OutputString(conOut, L"Failed to init gfx!\r\n");
return status;
}
conOut->ClearScreen(conOut);
//Switch to current mode so gfx is started.
status = graphicsProtocol->SetMode(graphicsProtocol, graphicsProtocol->Mode->Mode);
if (EFI_ERROR(status)) {
conOut->OutputString(conOut, L"Failed to set default mode!\r\n");
return status;
}
EFI_GRAPHICS_OUTPUT_BLT_PIXEL p;
p.Red = 200;
p.Green = 77;
p.Blue = 13;
graphicsProtocol->QueryMode(graphicsProtocol, graphicsProtocol->Mode->Mode, &SizeOfInfo, &info);
sWidth = info->HorizontalResolution;
sHeight = info->VerticalResolution;
status = graphicsProtocol->Blt(graphicsProtocol, &p, EfiBltVideoFill, 0, 0, 0, 0, sWidth, sHeight, 0);
while (1) {
conOut->OutputString(conOut, L"Some text that I want to display\r\n");
bs->Stall(500000);
}
return EFI_SUCCESS;
}
UEFI supports graphics output. It also supports text output (which can mean either output to a serial console, or text rendered to a graphical console, or both). But there is no defined way to interact between these in a controlled manner.
Applications that provide a graphical environment with text elements (BIOS configuration menu, GRUB) generally do this using their own frameworks to draw text on the graphical console using GRAPHICS_OUTPUT_PROTOCOL.
This is a short example of a text renderer using the font module from LVGL (which can be used standalone, replace #include "../../lv_conf.h" in the lv_font.h file with #define USE_LV_FONT_DEJAVU_20 8) and the Blt method from the GRAPHICS_OUTPUT_PROTOCOL
#include <Uefi.h>
#include <Library\UefiLib.h>
#include <Protocol\GraphicsOutput.h>
#include "lv_font.h"
#define LETTER_SPACE 2
#define WAIT_SECONDS 10
#define FONT &lv_font_dejavu_20
static EFI_BOOT_SERVICES *gBS;
static EFI_RUNTIME_SERVICES *gRT;
static EFI_GRAPHICS_OUTPUT_PROTOCOL *gGOP = (EFI_GRAPHICS_OUTPUT_PROTOCOL *)NULL;
static EFI_GRAPHICS_OUTPUT_BLT_PIXEL gWhite = { 255,255,255,0 };
static void _util_render_glyph(UINT32 x, UINT32 y, CHAR8 letter)
{
UINT32 height;
UINT32 width;
UINT32 pm_x;
UINT32 pm_y;
UINT32 index;
const UINT8* bitmap;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *pixelmap;
if (gGOP == NULL) {
return;
}
height = lv_font_get_height(FONT);
width = lv_font_get_width(FONT, letter);
// glyph is not defined in this font
if (width == 0) {
return;
}
bitmap = lv_font_get_bitmap(FONT, letter);
// using 8 bpp for simplicity
if (EFI_ERROR(gBS->AllocatePool(EfiLoaderData, height * width * sizeof(*pixelmap), (VOID**)&pixelmap))) {
return;
}
gBS->SetMem((VOID*)pixelmap, height * width * sizeof(*pixelmap), 0);
// get the current content of the framebuffer to allow 'transparent' blt operations
gGOP->Blt(gGOP, pixelmap, EfiBltVideoToBltBuffer, x, y, 0, 0, width, height, 0);
for (pm_y = 0; pm_y < height; pm_y++) {
for (pm_x = 0; pm_x < width; pm_x++) {
index = width * pm_y + pm_x;
if (bitmap[index] > 200) {
pixelmap[index].Red = 0;
pixelmap[index].Blue = 0;
pixelmap[index].Green = 0;
pixelmap[index].Reserved = 0;
}
else if (bitmap[index] > 100) {
pixelmap[index].Red = 105;
pixelmap[index].Blue = 105;
pixelmap[index].Green = 105;
pixelmap[index].Reserved = 0;
}
}
}
gGOP->Blt(gGOP, pixelmap, EfiBltBufferToVideo, 0, 0, x, y, width, height, 0);
gBS->FreePool(pixelmap);
}
static void _util_render_text(UINT32 x, UINT32 y, const CHAR8 *string)
{
UINT32 index;
UINTN length;
UINT32 scr_w;
UINT32 scr_h;
UINT32 str_x;
UINT32 gly_w;
UINT32 gly_h;
if (string == NULL) {
return;
}
if (gGOP == NULL) {
return;
}
scr_w = gGOP->Mode->Info->HorizontalResolution;
scr_h = gGOP->Mode->Info->VerticalResolution;
length = AsciiStrnLenS(string, 32);
gly_h = lv_font_get_height(FONT);
// check if the string can be printed
if ((y + gly_h) > scr_h) {
return;
}
if (x > scr_w) {
return;
}
// print the string glyph by glyph
str_x = x;
for (index = 0; index < length; index++) {
// check if the glyph can be printed
gly_w = lv_font_get_width(FONT, string[index]);
if ((str_x + gly_w) > scr_w) {
break;
}
// print the glyph
_util_render_glyph(str_x, y, string[index]);
// calculate the position of the next glyph
str_x += gly_w + LETTER_SPACE;
}
}
static void _util_fill_screen(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color)
{
if (gGOP == NULL) {
return;
}
gGOP->Blt(gGOP, color, EfiBltVideoFill, 0, 0, 0, 0, gGOP->Mode->Info->HorizontalResolution, gGOP->Mode->Info->VerticalResolution, 0);
}
static void _util_wait(UINT32 seconds)
{
EFI_TIME time;
UINT8 current_second = 255;
UINT32 elapsed_seconds = 0;
//wait for some seconds
while (elapsed_seconds <= WAIT_SECONDS) {
if (!EFI_ERROR(gRT->GetTime(&time, (EFI_TIME_CAPABILITIES*)NULL))) {
if (current_second != time.Second) {
elapsed_seconds++;
current_second = time.Second;
}
}
else {
break;
}
CpuPause();
}
}
EFI_STATUS
EFIAPI
UefiMain(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable)
{
EFI_STATUS eRc;
gBS = SystemTable->BootServices;
gRT = SystemTable->RuntimeServices;
eRc = gBS->LocateProtocol(
&gEfiGraphicsOutputProtocolGuid,
NULL,
(VOID**)&gGOP);
if (EFI_ERROR(eRc) || gGOP == NULL) {
return EFI_SUCCESS;
}
_util_fill_screen(&gWhite);
_util_render_text(0, 0, "HELLO WORLD!");
_util_wait(WAIT_SECONDS);
return EFI_SUCCESS;
}
I tested it on a pc and on a mac it runs on both. Using the tools provided by LVGL on their website you can use any font you want.
If you target MacEFI specifically, you'll need an additional protocol call to force the console into text mode, like this.
I am sorry my bad english. I work with Raspberry pi 3's sample code. I try run sample code on Code Blocks and I work for learn. I configured debug setting based on Makefile of sample code. I configure linker setting. When I build the code on Code Blocks, it doesn't show error. But when I run code. I taked error on console. Error this:
Font_example: /home/pi/Desktop/Font_example/main.c: 101: main:Assertion 's==0' failed.
I remarked line. Code this:
// Test app for VG font library.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include "/opt/vc/src/hello_pi/libs/vgfont/bcm_host.h"
#include "/opt/vc/src/hello_pi/libs/vgfont/vgfont.h"
static const char *strnchr(const char *str, size_t len, char c)
{
const char *e = str + len;
do {
if (*str == c) {
return str;
}
} while (++str < e);
return NULL;
}
int32_t render_subtitle(GRAPHICS_RESOURCE_HANDLE img, const char *text, const int skip, const uint32_t text_size, const uint32_t y_offset)
{
uint32_t text_length = strlen(text)-skip;
uint32_t width=0, height=0;
const char *split = text;
int32_t s=0;
int len = 0; // length of pre-subtitle
uint32_t img_w, img_h;
graphics_get_resource_size(img, &img_w, &img_h);
if (text_length==0)
return 0;
while (split[0]) {
s = graphics_resource_text_dimensions_ext(img, split, text_length-(split-text), &width, &height, text_size);
if (s != 0) return s;
if (width > img_w) {
const char *space = strnchr(split, text_length-(split-text), ' ');
if (!space) {
len = split+1-text;
split = split+1;
} else {
len = space-text;
split = space+1;
}
} else {
break;
}
}
// split now points to last line of text. split-text = length of initial text. text_length-(split-text) is length of last line
if (width) {
s = graphics_resource_render_text_ext(img, (img_w - width)>>1, y_offset-height,
GRAPHICS_RESOURCE_WIDTH,
GRAPHICS_RESOURCE_HEIGHT,
GRAPHICS_RGBA32(0xff,0xff,0xff,0xff), /* fg */
GRAPHICS_RGBA32(0,0,0,0x80), /* bg */
split, text_length-(split-text), text_size);
if (s!=0) return s;
}
return render_subtitle(img, text, skip+text_length-len, text_size, y_offset - height);
}
int main(void)
{
GRAPHICS_RESOURCE_HANDLE img;
uint32_t width, height;
int LAYER=1;
bcm_host_init();
int s;
s = gx_graphics_init(".");
assert(s == 0); //101. line
s = graphics_get_display_size(0, &width, &height);
assert(s == 0);
s = gx_create_window(0, width, height, GRAPHICS_RESOURCE_RGBA32, &img);
assert(s == 0);
// transparent before display to avoid screen flash
graphics_resource_fill(img, 0, 0, width, height, GRAPHICS_RGBA32(0,0,0,0x00));
graphics_display_resource(img, 0, LAYER, 0, 0, GRAPHICS_RESOURCE_WIDTH, GRAPHICS_RESOURCE_HEIGHT, VC_DISPMAN_ROT0, 1);
uint32_t text_size = 10;
while (1) {
const char *text = "The quick brown fox jumps over the lazy dog";
uint32_t y_offset = height-60+text_size/2;
graphics_resource_fill(img, 0, 0, width, height, GRAPHICS_RGBA32(0,0,0,0x00));
// blue, at the top (y=40)
graphics_resource_fill(img, 0, 40, width, 1, GRAPHICS_RGBA32(0,0,0xff,0xff));
// green, at the bottom (y=height-40)
graphics_resource_fill(img, 0, height-40, width, 1, GRAPHICS_RGBA32(0,0xff,0,0xff));
// draw the subtitle text
render_subtitle(img, text, 0, text_size, y_offset);
graphics_update_displayed_resource(img, 0, 0, 0, 0);
text_size += 1;
if (text_size > 50)
text_size = 10;
}
graphics_display_resource(img, 0, LAYER, 0, 0, GRAPHICS_RESOURCE_WIDTH, GRAPHICS_RESOURCE_HEIGHT, VC_DISPMAN_ROT0, 0);
graphics_delete_resource(img);
return 0;
}
1- What is wrong ?
2- Why this error on console why I couldn't see during on compiler?
NOTE: I can running this code on terminal (First go file and use make on console after use ./hello_font.bin) work fine.
Thanks your time. Best regards.
1- What is wrong ?
2- Why this error on console why I couldn't see during on compiler?
The assert you are using is a run-time assert.
If you want a compile-time assert, you have to use static_assert.
Using static_assert allows you to print your own message that will appear as compiler error.
Simple example:
int main()
{
static_assert(0 == 1, "Zero is not equal to one");
}
Compiler output:
main.cpp: In function 'int main()':
main.cpp:3:21: error: static assertion failed: Zero is not equal to one
static_assert(0 == 1, "Zero is not equal to one");
As in the comments of #Scheff. You should add macro. I added NDEBUG macro (on my project build setting and added macro to tab of other compiler under options). So my problem solved.
I am attempting to create a thumbnailer (for i3wm on linux) which generates an icon from a screenshot for all the available windows. The aim being to replicate something like how windows uses Alt-Tab to produce a pane of windows to choose from;
The current prototype uses pygtk to generate the dialog, and it creates thumbnails of the windows in the _NET_CLIENT_LIST using XGetImage where the windows have been redirected using XCompositeRedirectWindow. It works pretty well except for that images captured from windows which are browsers, (e.g. firefox, chrome, electron) are mangled, or wrong;
Basically, tools like xwd, scrot and import don't work for the hidden windows in i3, presumably because they are unmapped. So I have pulled some code together to create the thumbnails. The core of it is based on an example using XCompositeRedirectWindow from X11/extensions/Xcomposite.h from here.
My attempt at creating a short example is here;
https://gist.github.com/tolland/4bb1e97db258b92618adfb783ce66fac
it can be compiled with;
$ gcc example.c -lX11 -lXcomposite -lXrender -lpng -o example
and then to output png files for each of the windows;
$ mkdir -p /tmp/png_out && ./example
will produce pngs for each of the images
window found was 58720312
found window name for 58720312 : build : sudo
filename /tmp/png_out/58720312_test3.png
window found was 79691781
found window name for 79691781 : .xsession-errors - glogg
filename /tmp/png_out/79691781_test3.png
window found was 62914576
found window name for 62914576 : Edit - Stack Overflow - Mozilla Firefox
filename /tmp/png_out/62914576_test3.png
So the code I am currently using to walk the _NET_CLIENT_LIST is this;
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <libpng16/png.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>
//Compile hint: gcc -shared -O3 -lX11 -fPIC -Wl,-soname,prtscn -o prtscn.so prtscn.c
typedef int bool;
#define true 1
#define false 0
const int DEBUG = 0;
void getScreen2(const int, const int, const int, const int, const XID);
void write_png_for_image(XImage *image, XID xid, int width, int height,
char *filename);
typedef int (*handler)(Display *, XErrorEvent *);
XID getWindows(Display *display, Window parent, Window window, XID xid,
int depth);
int main() {
Display *display = XOpenDisplay(NULL);
Window root = DefaultRootWindow(display);
uint nwindows;
Window root_return, parent_return, *windows;
Atom a = XInternAtom(display, "_NET_CLIENT_LIST", true);
Atom actualType;
int format;
unsigned long numItems, bytesAfter;
unsigned char *data = 0;
int status = XGetWindowProperty(display, root, a, 0L, (~0L),
false,
AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, &data);
char* window_name_return;
if (status >= Success && numItems) {
long *array = (long*) data;
for (long k = 0; k < numItems; k++) {
Window window = (Window) array[k];
//not finding chrome window name
printf("window found was %d \n", window);
if (XFetchName(display, window, &window_name_return)) {
printf("found window name for %d : %s \n", window,
window_name_return);
}
//XMapWindow(display, parent);
XMapWindow(display, window);
XWindowAttributes attr;
Status status = XGetWindowAttributes(display, window, &attr);
if (status == 0)
printf("Fail to get window attributes!\n");
getScreen2(0, 0, attr.width, attr.height, window);
}
XFree(data);
}
return 0;
}
which calls this function to map the window and call XCompositeRedirectWindow;
void getScreen2(const int xx, const int yy, const int W, const int H,
const XID xid) {
Display *display = XOpenDisplay(NULL);
Window root = DefaultRootWindow(display);
// turn on --sync to force error on correct method
//https://www.x.org/releases/X11R7.6/doc/man/man3/XSynchronize.3.xhtml
XSynchronize(display, True);
int counter = 1;
// select which xid to operate on, the winder or its parent
//XID xwid = fparent;
XID xwid = xid;
// Requests the X server to direct the hierarchy starting at window to off-screen storage
XCompositeRedirectWindow(display, xwid, CompositeRedirectAutomatic);
XWindowAttributes attr;
Status status = XGetWindowAttributes(display, xwid, &attr);
int width = attr.width;
int height = attr.height;
int depth = attr.depth;
Pixmap xc_pixmap = XCompositeNameWindowPixmap(display, xwid);
if (!xc_pixmap) {
printf("xc_pixmap not found\n");
}
//XWriteBitmapFile(display, "test1.xpm", pixmap, W, H, -1, -1);
XRenderPictFormat *format = XRenderFindVisualFormat(display, attr.visual);
XRenderPictureAttributes pa;
pa.subwindow_mode = IncludeInferiors;
Picture picture = XRenderCreatePicture(display, xwid, format,
CPSubwindowMode, &pa);
char buffer[50];
int n;
int file_counter = 1;
n = sprintf(buffer, "/tmp/%d_test%d.xpm", xid, file_counter++);
XWriteBitmapFile(display, buffer, xc_pixmap, W, H, -1, -1);
n = sprintf(buffer, "/tmp/%d_test%d.xpm", xid, file_counter++);
XWriteBitmapFile(display, buffer, xid, W, H, -1, -1);
XImage *image = XGetImage(display, xid, 0, 0, W, H, AllPlanes, ZPixmap);
if (!image) {
printf("XGetImage failed\n");
}
char filename[255];
int n2;
n2 = sprintf(filename, "/tmp/png_out/%d_test%d.png", xid, file_counter++);
printf("filename %s \n", filename);
write_png_for_image(image, xid, W, H, filename);
//XFree(image);
XDestroyImage(image);
XDestroyWindow(display, root);
XCloseDisplay(display);
}
and then this to write out the png;
void write_png_for_image(XImage *image, XID xid, int width, int height,
char *filename) {
int code = 0;
FILE *fp;
png_structp png_ptr;
png_infop png_info_ptr;
png_bytep png_row;
char buffer[50];
int n;
n = sprintf(buffer, filename, xid);
// Open file
fp = fopen(buffer, "wb");
if (fp == NULL) {
fprintf(stderr, "Could not open file for writing\n");
code = 1;
}
// Initialize write structure
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fprintf(stderr, "Could not allocate write struct\n");
code = 1;
}
// Initialize info structure
png_info_ptr = png_create_info_struct(png_ptr);
if (png_info_ptr == NULL) {
fprintf(stderr, "Could not allocate info struct\n");
code = 1;
}
// Setup Exception handling
if (setjmp(png_jmpbuf (png_ptr))) {
fprintf(stderr, "Error during png creation\n");
code = 1;
}
png_init_io(png_ptr, fp);
// Write header (8 bit colour depth)
png_set_IHDR(png_ptr, png_info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
// Set title
char *title = "Screenshot";
if (title != NULL) {
png_text title_text;
title_text.compression = PNG_TEXT_COMPRESSION_NONE;
title_text.key = "Title";
title_text.text = title;
png_set_text(png_ptr, png_info_ptr, &title_text, 1);
}
png_write_info(png_ptr, png_info_ptr);
// Allocate memory for one row (3 bytes per pixel - RGB)
png_row = (png_bytep) malloc(3 * width * sizeof(png_byte));
unsigned long red_mask = image->red_mask;
unsigned long green_mask = image->green_mask;
unsigned long blue_mask = image->blue_mask;
// Write image data
//int xxx, yyy;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
unsigned long pixel = XGetPixel(image, x, y);
unsigned char blue = pixel & blue_mask;
unsigned char green = (pixel & green_mask) >> 8;
unsigned char red = (pixel & red_mask) >> 16;
png_byte *ptr = &(png_row[x * 3]);
ptr[0] = red;
ptr[1] = green;
ptr[2] = blue;
}
png_write_row(png_ptr, png_row);
}
// End write
png_write_end(png_ptr, NULL);
// Free
fclose(fp);
if (png_info_ptr != NULL)
png_free_data(png_ptr, png_info_ptr, PNG_FREE_ALL, -1);
if (png_ptr != NULL)
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
if (png_row != NULL)
free(png_row);
}
However when the windows is browser based, the image is mangled like so;
Do I need to do something special to get browser windows working?
References;
https://www.talisman.org/~erlkonig/misc/x11-composite-tutorial/
Get a screenshot of a window that is cover or not visible or minimized with Xcomposite extension for X11
This is the code i have., which will detect the faces in the image and draws rectangle around the face.
CvHaarClassifierCascade *cascade;
CvMemStorage *storage;
void detectFaces (IplImage *newframe);
int key;
int iImg;
int Num_Images=20;
int main( int argc, char** argv )
{
string filename = M:/Trend/FaceDetection/MyCascadeFolder/haarcascade_frontalface_alt2.xml";
storage = cvCreateMemStorage(0) ;
cascade = ( CvHaarClassifierCascade* )cvLoad( filename.c_str());
**//to load a single image**
**IplImage* inImage = cvLoadImage("M:/Trend/FaceDetection775/MyImages/face1.jpg",1);**
//IplImage* inImage = cvLoadImage(argv[1],1); >> It also works fine through command line
detectFaces( inImage );
cvShowImage("FaceDetection2",inImage);
cvSaveImage("M:/FaceDetection/MyImages/OpImages/faces.jpg",inImage);
cvReleaseImage( &inImage);
// **to load no. of images or a complete folder**
char buf[20];
for(iImg=0; iImg<=Num_Images; iImg++)
{
**sprintf(buf, "M:/FaceDetection/ImagesFolder/P%04d.jpg", iImg);**
*// sprintf(buf, argv[2], iImg); // I Tried with this., but its not working*
printf("\n");
inImage = cvLoadImage(buf, CV_LOAD_IMAGE_UNCHANGED);
printf("Input Image = P%04d.jpg\n", iImg);
detectFaces( inImage );
cvShowImage("FaceDetection",inImage);
cvReleaseImage( &inImage );
key= cvWaitKey(0);
if ( key == 'q' || key == 'Q' )
return(0);
}
cvReleaseHaarClassifierCascade( &cascade );
cvReleaseMemStorage( &storage );
return 0;
}
**// the actual detectfaces() function goes like this**
void detectFaces( IplImage *newframe)
{
CvSeq *faces = cvHaarDetectObjects( newframe, cascade, storage, 1.15, 5, 0, cvSize( 30, 30 ) );
for( int i = 0 ; i < ( faces ? faces->total : 0 ) ; i++ )
{
CvRect *r = ( CvRect *)cvGetSeqElem( faces, i );
cvRectangle(newframe,cvPoint( r->x, r->y ),cvPoint( r->x + r->width, r->y + r->height ),CV_RGB( 0, 255, 0 ), 2, 8, 0 );
}
}
Here., sprintf() method is taking multiple images statically (within the program itself). But I want to pass those multiple images as a single folder through command line argument.
I try to use cvLoadImage() function, but it also takes only one image as input instead of a folder.
Also I am not able to count the number of rectangles it draws for every single face in the image., how can I do that also...?
Please help me in this regards.
I am working on face detection project "www.MahdiRezaei.com" for my academics., and I am using visual studio-2010 with C, C++ and OpenCV.
Thankz in advance.
You can change the following code to use it with arguments.
#include<Windows.h>
#include<iostream>
#include<opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;
int main()
{
WIN32_FIND_DATA data;
HANDLE h = FindFirstFile(L"c:\\Images\\*.*", &data); // first file is the current directory
FindNextFile(h, &data); //second file is the parent directory
vector<Mat> Images;
if (h != INVALID_HANDLE_VALUE)
{
while (FindNextFile(h, &data))
{
string filename = data.cFileName;
sprintf(filename, "%s%s","C:\\Images\\", filename.c_str());
Images.push_back(imread(filename, 1));
delete[] nPtr;
}
}
else
cout << "Error: No such folder." << endl;
FindClose(h);
return 0;
}
As a preface, I really do not want the exact solution to my problem, just guidance. I don't want you to give me the code. This isn't homework, it's just an exercise I'm trying to solve.
I just want you to tell me how to access VDU and directly change character on same screen.
The screen is divided into 25 rows and 80 columns. The characters that are displayed on the
screen are stored in a special memory called VDU memory (not to be confused with ordinary
memory). Each character displayed on the screen occupies two bytes in VDU memory.
The first of these bytes contains the ASCII value of the character being displayed, whereas, the second byte contains the colour in which the character is displayed. For example, the ASCII value of the character present on zeroth row and zeroth column on the screen is stored at location number 0xB8000000.
Therefore the colour of this character would be present at location number 0xB8000000 + 1. Similarly ASCII value of character in row 0, col 1 will be at location 0xB8000000 + 2, and its colour at 0xB8000000 + 3.
My task:
With this knowledge write a program which when executed would keep converting every capital letter on the screen to small case letter and every small case letter to capital letter. The procedure should stop the moment the user hits a key from the keyboard. This is an activity of a rampant Virus called Dancing Dolls. (For monochrome adapter, use 0xB0000000 instead of 0xB8000000).
Really I don't have any idea to build this code. I'm stuck at even getting started.
You are referring to what was once called the video refresh buffer. It's important to state that Dancing Dolls was a virus for DOS.
Basically, you are expecting video memory to be at address 0xB8000000 on your program's memory. However, modern Operating Systems (like Linux/Windows/Mac OS X) provide a virtual memory mechanism that prevents applications from manipulating devices directly. So the 0xB8000000 address your application sees is not the physical address 0xb8000000 that corresponds to the video refresh buffer. The last post of this thread also has some interesting info on this subject.
Nevertheless, the technique you are interested in is still valid for 16-bit DOS and is covered on the book Assembly Language Step-by-step: Programming with DOS and Linux. This book has a great section on chapter 6 that explains how this work exactly. The section is named Inspecting the Video Refresh Buffer with DEBUG, and has an interesting example that shows how to use debug.exe to access the video memory and modify it. I tested it successfully on cmd.exe of my Win 7 box.
But if you want to manipulate the screen of a Linux terminal, check ncurses:
It is a library of functions that manage an application's display on character-cell terminals
I think, most important is to be aware that your question is about an exercise that (apparently) at one time was designed to be easy and interesting.
However, that was long ago, and meanwhile both hardware and software has progressed. It is no longer easy to access physical memory. And, at least for the beginner, it is no longer interesting to do that.
Thus, the main goodness points of the exercise have been chopped off by time’s inexorable entropic action.
However, for one who absolutely want to do this exercise, that once-so-easily-accessible hardware can be simulated. Doing such a simulation transparently, so that the student code is the same as if it was for real, is rather difficult and system-dependent. However, if you (the student) just agree to explicitly call some “update” routine in order to simulate the hardware screen update, then it’s more near managable – and thus, old exercises can be reused! :-)
One can then imagine that main does some initialization of things, and calls a routine doTheDancingDolls with arguments that give access to simulated video memory, and the aforementioned “update” functionality:
void doTheDancingDolls(
curses::Console& console,
b8000::DisplayMemorySim& memorySim
)
{
do
{
// Whatever - this is where you Do Things to the simulated video memory.
// Then:
memorySim.update( console );
} while( !console.keyboard().keypressIsAvailable() );
console.keyboard().getKey(); // Consume the keypress.
}
… where the memorySim object somehow provides the necessary pointer to the simulated video memory – a pointer that corresponds to the B8000000 address in the exercise.
That’s the main idea, how to get a starting point for solving this exercise that's designed for now ANTIQUATED equipment.
Fleshing it out a bit more, here’s one possible implementation of the video memory simulation (note that this is not code that addresses the things that you were meant to do in the exercise, it just addresses the things that you were never meant to do, but possibly would have to today):
File [b8000.h]
#ifndef B8000_H
#define B8000_H
// A simulation of the early PC's 25*80 color text mode video memory.
// The structure of the memory is INTENTIONALLY not modelled in the
// exposed interface. A student can learn from imposing such structure.
//
// Copyright (c) 2011 Alf P. Steinbach.
//------------------------------------------ Dependencies:
#include "curses_plus_plus.h" // curses::Console
#include <vector> // std::vector
//------------------------------------------ Interface:
namespace b8000 {
typedef unsigned char Byte;
class DisplayMemorySim
{
private:
std::vector< Byte > buf_;
public:
enum { nColumns = 80, nLines = 25 };
DisplayMemorySim(): buf_( 2*nLines*nColumns ) {}
void* bufferPointer() { return &buf_[0]; }
void const* bufferPointer() const { return &buf_[0]; }
void update( curses::Console& console ) const
{
assert( console.nLines() >= nLines );
assert( console.nColumns() >= nColumns );
assert( console.colors().nColors() >= 16 );
for( int y = 0; y < nLines; ++y )
{
for( int x = 0; x < nColumns; ++x )
{
int const iCell = 2*(y*nColumns + x);
Byte const charCode = buf_[iCell];
Byte const colors = buf_[iCell + 1];
Byte const fg = colors & 0xF;
Byte const bg = colors >> 4;
console.colors().setFgBg( fg, bg );
console.putAt( x, y, charCode );
}
}
console.updateScreen();
}
};
} // namespace b8000
#endif
And the curses::Console class might be a simple wrapper over the curses library, e.g. like …
File [curses_plus_plus.h]
#ifndef CURSES_PLUS_PLUS_H
#define CURSES_PLUS_PLUS_H
// Sort of minimal C++ interface to the "curses" library.
// Copyright (c) 2011 Alf P. Steinbach.
//------------------------------------------ Dependencies:
#include "curses.h"
#if defined( _MSC_VER ) && defined( __PDCURSES__ )
# pragma comment( lib, "pdcurses.lib" )
#endif
#ifdef _MSC_VER
# pragma warning( disable: 4355 ) // 'this' used in member initializer
#endif
#include <assert.h> // assert
#include <stddef.h> // NULL
//------------------------------------------ Interface:
namespace curses {
class Console;
namespace detail {
template< class Number > inline Number square( Number x ) { return x*x; }
template< class Derived >
struct SingleInstance
{
static int& instanceCount()
{
static int n = 0;
return n;
}
SingleInstance( SingleInstance const& ); // No such.
SingleInstance& operator=( SingleInstance const& ); // No such.
SingleInstance()
{
++instanceCount();
assert(( "can only have one instance at a time", (instanceCount() == 1) ));
}
~SingleInstance() { --instanceCount(); }
};
} // namespace detail
namespace color {
#ifdef _WIN32 // Any Windows, 32-bit or 64-bit.
int const lightness = 0x08; // Windows only. 8
// The portable colors, expressed for Windows systems.
int const black = COLOR_BLACK; // 0
int const blue = COLOR_BLUE; // 1
int const green = COLOR_GREEN; // 2
int const cyan = COLOR_CYAN; // 3
int const red = COLOR_RED; // 4
int const magenta = COLOR_MAGENTA; // 5
int const yellow = COLOR_YELLOW | lightness; // 6 + 8
int const white = COLOR_WHITE | lightness; // 7 + 8
// Windows-specific colors.
int const gray = COLOR_BLACK | lightness;
int const lightBlue = COLOR_BLUE | lightness;
int const lightGreen = COLOR_GREEN | lightness;
int const lightCyan = COLOR_CYAN | lightness;
int const lightRed = COLOR_RED | lightness;
int const lightMagenta = COLOR_MAGENTA | lightness;
int const brown = COLOR_YELLOW & ~lightness; // A bit greenish.
int const lightGray = COLOR_WHITE & ~lightness;
#else
// The portable colors, expressed for non-Windows systems.
int const black = COLOR_BLACK;
int const blue = COLOR_BLUE;
int const green = COLOR_GREEN;
int const cyan = COLOR_CYAN;
int const red = COLOR_RED;
int const magenta = COLOR_MAGENTA;
int const yellow = COLOR_YELLOW;
int const white = COLOR_WHITE;
#endif
} // namespace color
class Colors
: private detail::SingleInstance< Colors >
{
private:
Colors( Colors const& ); // No such.
Colors& operator=( Colors const& ); // No such.
int n_;
int nPairs_;
int rawIndexOfPair0_;
int rawIndexFor( int fg, int bg ) const
{
return bg*n_ + fg;
}
public:
int nColors() const { return n_; }
int nColorPairs() const { return nPairs_; }
int indexFor( int fg, int bg ) const
{
int const rawIndex = rawIndexFor( fg, bg );
return 0?0
: (rawIndex == rawIndexOfPair0_)? 0
: (rawIndex == 0)? rawIndexOfPair0_
: rawIndex;
}
void setColorPair( int i )
{
::color_set( short( i ), NULL ); //attrset( COLOR_PAIR( i ) );
}
void setFgBg( int fg, int bg )
{
setColorPair( indexFor( fg, bg ) );
}
Colors( Console& )
{
::start_color(); // Initialize color support.
// Although these look like global constants, they're global variables
// that are initialized by the call to Curses' `start_color` (above).
n_ = ::COLORS; nPairs_ = ::COLOR_PAIRS;
assert( detail::square( n_ ) <= nPairs_ ); // Our requirement.
// Obtain curses' default colors, those are at color pair index 0.
{
short fg0 = -1;
short bg0 = -1;
::pair_content( 0, &fg0, &bg0 );
assert( fg0 != -1 );
assert( bg0 != -1 );
rawIndexOfPair0_ = rawIndexFor( fg0, bg0 );
}
// Initialize color pair table to support finding index for given colors.
// The color pair at index 0 can't be specified (according to docs),
// so trickery is required. Here like swapping index 0 to elsewhere.
for( int fg = 0; fg < n_; ++fg )
{
for( int bg = 0; bg < n_; ++bg )
{
int const i = indexFor( fg, bg );
if( i == 0 ) { continue; } // It's initialized already.
::init_pair( short( i ), short( fg ), short( bg ) );
}
}
}
};
class Keyboard
: private detail::SingleInstance< Keyboard >
{
private:
WINDOW* pCursesWin_;
bool isBlocking_;
int bufferedKeypress_;
bool hasBufferedKeypress_;
void setBlocking( bool desiredBlocking )
{
if( isBlocking_ != desiredBlocking )
{
::nodelay( pCursesWin_, !desiredBlocking );
isBlocking_ = desiredBlocking;
}
}
public:
int getKey()
{
if( hasBufferedKeypress_ )
{
hasBufferedKeypress_ = false;
return bufferedKeypress_;
}
setBlocking( true );
return ::getch();
}
bool keypressIsAvailable()
{
if( hasBufferedKeypress_ ) { return true; }
setBlocking( false );
int const key = ::getch();
if( key == ERR ) { return false; }
hasBufferedKeypress_ = true;
bufferedKeypress_ = key;
return true;
}
Keyboard( WINDOW& pCursesWin )
: pCursesWin_( &pCursesWin )
, isBlocking_( true )
, hasBufferedKeypress_( false )
{
::keypad( pCursesWin_, true ); // Assemble multi-character sequences into key symbols.
::nodelay( pCursesWin_, false );
assert( isBlocking_ == true );
}
~Keyboard()
{
setBlocking( true );
}
};
class Console
: private detail::SingleInstance< Console >
{
private:
::WINDOW* pCursesWin_;
Colors colors_;
Keyboard keyboard_;
Console( Console const& ); // No such.
Console& operator=( Console const& ); // No such.
static ::WINDOW* beginWin()
{
return ::initscr();
}
public:
// At least with pdcurses in Windows, these numbers are for the
// console window, i.e. not for its underlying text buffer.
int nColumns() const { return ::getmaxx( pCursesWin_ ); }
int nLines() const { return ::getmaxy( pCursesWin_ ); }
Colors& colors() { return colors_; }
Colors const& colors() const { return colors_; }
Keyboard& keyboard() { return keyboard_; }
Keyboard const& keyboard() const { return keyboard_; }
void putAt( int x, int y, char const s[] )
{
::mvaddstr( y, x, s );
}
void putAt( int x, int y, char c )
{
::mvaddch( y, x, c );
}
void updateScreen() { ::refresh(); }
Console()
: pCursesWin_( beginWin() )
, colors_( *this )
, keyboard_( *pCursesWin_ )
{
::cbreak(); // Immediate input (no line buffering).
::noecho(); // No input echo.
}
~Console()
{
::endwin();
}
};
} // namespace curses
#endif
To drive it all, in the main program you’d check whether the terminal window (Windows “ console window”) is sufficiently large, etc.:
File [main.cpp]
#include "string_util.h" // strUtil::S
#include "b8000.h" // b8000::DisplayMemorySim
#include "curses_plus_plus.h" // curses::Console
#include <algorithm> // std::max
#include <assert.h> // assert
#include <iostream> // std::cerr, std::endl
#include <stdexcept> // std::runtime_error, std::exception
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
void doTheDancingDolls(
curses::Console& console,
b8000::DisplayMemorySim& memorySim
)
{
do
{
// Whatever - this is where you Do Things to the simulated video memory.
// The following three lines are just to see that something's going on here.
using stringUtil::S;
static int x = 0;
console.putAt( 30, 5, S() << "I have now counted to " << ++x << "..." );
// Then:
//memorySim.update( console );
} while( !console.keyboard().keypressIsAvailable() );
console.keyboard().getKey(); // Consume the keypress.
}
bool throwX( std::string const& s ) { throw std::runtime_error( s ); }
void cppMain()
{
using std::max;
using stringUtil::S;
curses::Console console;
enum
{
w = b8000::DisplayMemorySim::nColumns,
h = b8000::DisplayMemorySim::nLines
};
(console.colors().nColors() >= 16)
|| throwX( "The console window doesn't support 16 colors." );
(console.nColumns() >= w)
|| throwX( S() << "The console window has less than " << w << " columns." );
(console.nLines() >= h)
|| throwX( S() << "The console window has less than " << h << " lines." );
namespace color = curses::color;
console.colors().setFgBg( color::lightRed, color::yellow );
console.putAt( 30, 0, " The Dancing Dolls! " );
console.putAt( 30, 1, S() << " In " << h << "x" << w << " color mode." );
console.putAt( 30, 3, S() << " Press ANY key to start... " );
console.keyboard().getKey();
console.putAt( 30, 3, S() << " Press ANY key to stop... " );
b8000::DisplayMemorySim displayMemorySim;
doTheDancingDolls( console, displayMemorySim );
}
int main()
{
using namespace std;
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cout << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
This post got a bit long, so I’m not adding in the code for the S() thing (it's not much code but still).
Anyway, this should provide a starting point for experimentation.
Disclaimer: I just cobbled this together. It’s not very extensively tested. I may, for example, have misunderstood things about the curses library’ keyboard handling –. And I’m hoping that it will work also in *nix-land, but I don’t know.
Cheers & hth.,
#include<conio.h>
#include<dos.h>
#define MEMORY_SIZE 3999 // 2 bytes for each character total char 2000
void main(){
char far *vidmem = 0xB8000000; // video memory address row & column zero
int i,o=0;
for(i=0;i<=MEMORY_SIZE;i+=2){
if (o%2==0)
*( vidmem + i) = 'A';
else
*( vidmem + i) = 'a';
o++;
}
while(!kbhit()){
for(i=0;i<=MEMORY_SIZE;i+=2){
if(*( vidmem +i) == 'A')
*( vidmem + i) = 'a';
else
*( vidmem + i) = 'A';
}
delay(200); // wait for 200 ms
}
}
/* run and compile success fully in Turbo C++ v3.0 non error just warring during running programme u just want to disable it option>>compiler>>message>>portablity */
Are we talking about actually performing modifications to what is displayed on your screen or do we just take the above assignment as an exercise.
In the latter case it's just looping over the described memory region (0xb8000000 + 25 (rows) * 80 (columns) * 2(bytes/displayed char). Reading the char portion for each displayed character and converting it from upper/lower to lower/upper case.
Conversion is simply done by simple arithmetic. Look at http://www.asciitable.com/ :
E.g: A = 0x41, a = 0x61
So in order to convert one to the other just add/remove 0x20 from the read value.