I need to convert a GIF image to Jpeg image using C programming language. I searched the web, but I didn't find an example which could help me. Any suggestion are appreciated!
EDIT: I want to do this using an cross-platform open-source library like SDL.
Try the GD or ImageMagick libraries
I found libafterimage to be incredibly simple to use.
In this snippet I also scale the image to at most width or at most height, while preserving aspect:
#include <libAfterImage/afterimage.h>
int convert_image_to_jpeg_of_size(const char* infile, const char* outfile, const double max_width, const double max_height)
{
ASImage* im;
ASVisual* asv;
ASImage* scaled_im;
double height;
double width;
double pixelzoom;
double proportion;
im = file2ASImage(infile, 0xFFFFFFFF, SCREEN_GAMMA, 0, ".", NULL);
if (!im) {
return 1;
}
proportion = (double)im->width / (double)im->height;
asv = create_asvisual(NULL, 0, 0, NULL);
if (proportion > 1) {
/* Oblong. */
width = max_width;
pixelzoom = max_width / im->width;
height = (double)im->height * pixelzoom;
} else {
height = max_height;
pixelzoom = max_height / im->height;
width = (double)im->width * pixelzoom;
}
scaled_im = scale_asimage(asv, im, width, height, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
/* writing result into the file */
ASImage2file(scaled_im, NULL, outfile, ASIT_Jpeg, NULL);
destroy_asimage(&scaled_im);
destroy_asimage(&im);
return 0;
}
Not the easiest to use, but the fastest way is almost surely using libavcodec/libavformat from ffmpeg.
Related
I keep getting the error "func.h:23: error: cannot cast 'int' to 'struct Texture'" even though im inputting text as tile in renderTiles(). Am i just being dumb here? ¯_(ツ)_/¯ Im new to C so this might just be me. i copied and pasted the basic window example to create this. i know there isnt char before tile in "renderTiles(tile)" i tried that as well and it still did not work
main.c:
*
* raylib [core] example - Basic window
*
* Welcome to raylib!
*
* To test examples, just press F6 and execute raylib_compile_execute script
* Note that compiled executable is placed in the same folder as .c file
*
* You can find all basic examples on C:\raylib\raylib\examples folder or
* raylib official webpage: www.raylib.com
*
* Enjoy using raylib. :)
*
* Example originally created with raylib 1.0, last time updated with raylib 1.0
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2013-2022 Ramon Santamaria (#raysan5)
*
********************************************************************************************/
#include "raylib.h"
#include "func.h"
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 768;
const int screenHeight = 576;
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// textures
Texture2D grass = LoadTexture("grass.png");
Texture2D stone = LoadTexture("stone.png");
Texture2D sand = LoadTexture("sand.png");
Texture2D stone_oasis = LoadTexture("stone-oasis.png");
Texture2D sand_oasis = LoadTexture("sand-oasis.png");
Texture2D UI = LoadTexture("ui.png");
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update your variables here
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
DrawTexture(UI, 0, 0, RAYWHITE);
renderTiles("grass");
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
}
func.h
#ifndef FUNC
#define FUNC
const int screenWidth = 768;
const int screenHeight = 576;
int centerX(int x)
{
int ox = x + (screenWidth / 2);
return (ox);
}
int centerY(int y)
{
int oy = y + (screenHeight / 2);
return(oy);
}
void renderTiles(tile)
{
for( int b = 0; b < 12; b = b + 1)
{
for( int a = 0; a < 12; a = a + 1 ){
DrawTexture(tile, (a * 48) + 96, (b * 48), RAYWHITE);
}
}
}
#endif
Answering the question title, you have already converted the string to a texture struct with
Texture2D grass = LoadTexture("grass.png");
The raylib cheat sheet shows the function you are calling to be
void DrawTexture(Texture2D texture, int posX, int posY, Color tint);
but you have passed the char* value "grass" to your function, which has an untyped argument, so the compiler assumes it to be type int.
Your function should be
/* void renderTiles(tile) */
void renderTiles(Texture2D tile)
and you should call it with
/* renderTiles("grass"); */
renderTiles(grass);
Also, you should not have executable code in a header file.
Cookie cuttered (from supposedly working code) a trivial C program to perform a Xlib image grab using XGetImage(). At this point I'm not trying to process the image, this is just a proof-of-concept to see if the image grab works - and it doesn't. The XGetImage() call fails like:
X Error of failed request: BadMatch (invalid parameter attributes)
Major opcode of failed request: 73 (X_GetImage)
Serial number of failed request: 21
Current serial number in output stream: 21
I spent a fair amount of time researching this and apparently this problem has plagued other developers and no definitive answer was ever arrived at. Does someone know how I could go about resolving this? I can tell from the printf that the window of interest was correctly identified. The XMapRaised() is a suggestion from a prior thread on this problem, but doesn't seem to help. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "/usr/include/X11/Xlib.h"
Window findScidWindow(Display *display )
{
Bool found = False;
Window rootWindow = RootWindow(display, DefaultScreen(display));
Atom atom = XInternAtom(display, "_NET_CLIENT_LIST", True);
Atom actualType;
int format;
unsigned long numItems;
unsigned long bytesAfter;
unsigned char *data = '\0';
Window *list;
char *windowName;
int status = XGetWindowProperty(display, rootWindow, atom, 0L, (~0L), False,
AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, &data);
list = (Window *)data;
if (status >= Success && numItems)
{
for (int i = 0; i < numItems; ++i)
{
status = XFetchName(display, list[i], &windowName);
if (status >= Success)
{
if(strstr(windowName, "Scid vs. PC") != NULL)
{
XFree(windowName);
XFree(data);
return list[i];
}
}
}
}
}
void
main( int argc, char*argv )
{
Display* d = XOpenDisplay(":0.0");
XImage *image;
Window root = (Window)0x0560003b; /* obtained via 'wmctrl -l -G' */
Window ScidWindow = findScidWindow(d);
XWindowAttributes attrib;
XGetWindowAttributes(d, ScidWindow, &attrib);
int width = attrib.width;
int height = attrib.height;
printf("width: %d height: %d\n",width,height);
XMapRaised(d, root);
/* coordinates 438,110 obtained via 'wmctrl -l -G' */
image = XGetImage( d, ScidWindow, 438, 110, width, height, AllPlanes, ZPixmap);
}
The issue is
image = XGetImage( d, ScidWindow, 438, 110, width, height, AllPlanes, ZPixmap);
uses x = 438 and y = 110 that is particular a problem if x + width is actually bigger as the window width (same for the height)
So here I have to assume you're not attempting to crop the window image but rather want to take a plain raw screenshot, then you just need to pass 0 for x and y:
image = XGetImage( d, ScidWindow, 0, 0, width, height, AllPlanes, ZPixmap);
The explanation is that the coordination system is not the full display or screen but the one of the window you are grabbing. Means the window starts at (0, 0).
This took me also some time to figure out.
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 have captured video using AVFoundation .i have set (video setting )and get in outputsamplebuffer kCVPixelFormatType_420YpCbCr8BiPlanarFullRange format. But i need YUV420 format for further processing.
For that i use libyuv framework.
LIBYUV_API
int NV12ToI420(const uint8* src_y, int src_stride_y,
const uint8* src_uv, int src_stride_uv,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
libyuv::NV12ToI420(src_yplane, inWidth ,
src_uvplane, inWidth,
dst_yplane, inWidth,
dst_vplane, inWidth / 2,
dst_uplane, inWidth / 2,
inWidth, inHeight);
But i am getting output buffer is full green color? i done any mistake for that process pls help me?
Looks right. Make sure your src_uvplane points to src_yplane + inWidth * inHeight
You need convert your data to I420, I am processing camera too, but on Android. I think it should be similar on iOS. Android raw camera is NV21 or NV16 format, I convert from NV21 or NV16 to YV12, I420 is almost the same as YV12:
BYTE m_y[BIG_VIDEO_CX * BIG_VIDEO_CY],
m_u[(BIG_VIDEO_CX/2) * (BIG_VIDEO_CY/2)],
m_v[(BIG_VIDEO_CX/2) * (BIG_VIDEO_CY/2)];
void NV21_TO_YV12(BYTE *data)
{
int width = BIG_VIDEO_CX;
int height = BIG_VIDEO_CY;
m_y2=data;
data=&data[width*height];
for (uint32_t i=0; i<(width/2)*(height/2); ++i)
{
m_v[i]=*data;
m_u[i]=*(data+1);
data+=2;
}
}
void NV16_TO_YV12(BYTE *data)
{
int width = BIG_VIDEO_CX;
int height = BIG_VIDEO_CY;
m_y2=data;
const BYTE* src_uv = (const BYTE*)&data[width*height];
BYTE* dst_u = m_u;
BYTE* dst_v = m_v;
for (uint32_t y=0; y<height/2; ++y)
{
const BYTE* src_uv2 = src_uv + width;
for (uint32_t x=0; x<width/2; ++x)
{
dst_u[x]=(src_uv[0]+src_uv2[0]+1)>>1;
dst_v[x]=(src_uv[1]+src_uv2[1]+1)>>1;
src_uv+=2;
src_uv2+=2;
}
src_uv=src_uv2;
dst_u+=width/2;
dst_v+=width/2;
}
}
Android is NV21, which libyuv supports with Arm as well as Intel. It can also rotate by 90, 180 or 270 as part of the conversion if necessary for orientation.
The Arm optimized version is about 2x faster than C
C
NV12ToI420_Opt (782 ms)
NV21ToI420_Opt (764 ms)
Arm (Neon optimized)
NV12ToI420_Opt (398 ms)
NV21ToI420_Opt (381 ms)
Curious you use NV16 on Android. I'd expect NV61 for consistency with NV21. Your code looks correct, but would nicely optimize into Neon using vrhadd.u8. File a libyuv issue if you'd like to see that. https://code.google.com/p/libyuv/issues/list
Here is how I do it on iOS in my captureOutput after I get a raw video frame from AVCaptureSession(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange):
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
CVImageBufferRef videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer);
CFRetain(sampleBuffer);
CVPixelBufferLockBaseAddress(videoFrame, 0);
size_t _width = CVPixelBufferGetWidth(videoFrame);
size_t _height = CVPixelBufferGetHeight(videoFrame);
const uint8* plane1 = (uint8*)CVPixelBufferGetBaseAddressOfPlane(videoFrame,0);
const uint8* plane2 = (uint8*)CVPixelBufferGetBaseAddressOfPlane(videoFrame,1);
size_t plane1_stride = CVPixelBufferGetBytesPerRowOfPlane (videoFrame, 0);
size_t plane2_stride = CVPixelBufferGetBytesPerRowOfPlane (videoFrame, 1);
size_t plane1_size = plane1_stride * CVPixelBufferGetHeightOfPlane(videoFrame, 0);
size_t plane2_size = CVPixelBufferGetBytesPerRowOfPlane (videoFrame, 1) * CVPixelBufferGetHeightOfPlane(videoFrame, 1);
size_t frame_size = plane1_size + plane2_size;
uint8* buffer = new uint8[ frame_size ];
uint8* dst_u = buffer + plane1_size;
uint8* dst_v = dst_u + plane1_size/4;
// Let libyuv convert
libyuv::NV12ToI420(/*const uint8* src_y=*/plane1, /*int src_stride_y=*/plane1_stride,
/*const uint8* src_uv=*/plane2, /*int src_stride_uv=*/plane2_stride,
/*uint8* dst_y=*/buffer, /*int dst_stride_y=*/plane1_stride,
/*uint8* dst_u=*/dst_u, /*int dst_stride_u=*/plane2_stride/2,
/*uint8* dst_v=*/dst_v, /*int dst_stride_v=*/plane2_stride/2,
_width, _height);
CVPixelBufferUnlockBaseAddress(videoFrame, 0);
CFRelease( sampleBuffer)
// TODO: call your method here with 'buffer' variable. note that you need to deallocated the buffer after using it
}
I made the code a bit more descriptive for clarity.
In order to convert almost any type of image into a PPM I'm using ImageMagick's wand API.
From the wand how do I extract the PPM properties of width, height, modval and raw RGB data?
Here is some skeleton code.
Many thanks in advance for reading the question.
/* Read an image. */
MagickWandGenesis();
magick_wand = NewMagickWand();
status = MagickReadImage(magick_wand, argv[1]);
if (status == MagickFalse)
ThrowWandException(magick_wand);
/* TODO convert to P6 PPM */
/* TODO get PPM properties */
ppm->width = ...
ppm->height = ...
ppm->modval = 3 * ppm->width;
ppm->data = malloc(ppm->width * ppm->height * 3);
/* TODO fill ppm->data */
From ImageMagick Forum
width = MagickGetImageWidth(magick_wand);
height = MagickGetImageHeight(magick_wand);
ppm->width = width;
ppm->height = height;
ppm->modval = 3 * width;
ppm->data = malloc (3 * width * height);
status = MagickExportImagePixels(magick_wand, 0, 0, width, height, "RGB",
CharPixel, ppm->data);